pxfm-0.1.23/.cargo_vcs_info.json0000644000000001360000000000100120710ustar { "git": { "sha1": "c6b00ea1eeca086ef50b38442c06798214ccbd45" }, "path_in_vcs": "" }pxfm-0.1.23/.github/FUNDING.yml000064400000000000000000000000761046102023000140410ustar 00000000000000# These are supported funding model platforms github: awxkee pxfm-0.1.23/.github/workflows/build_push.yml000064400000000000000000000047301046102023000171430ustar 00000000000000name: Build concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: push: branches: - 'master' - '!ci_test_*' tags-ignore: - '*' pull_request: branches: - 'master' jobs: build: name: Build runs-on: ubuntu-latest strategy: fail-fast: false matrix: rust: [ "1.85.0", stable ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ matrix.rust }} - run: rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu i686-unknown-linux-gnu powerpc-unknown-linux-gnu wasm32-unknown-unknown - run: RUSTFLAGS="-C target-feature=+neon" cargo build --target aarch64-unknown-linux-gnu - run: RUSTFLAGS="-C target-feature=+avx2" cargo build --target i686-unknown-linux-gnu - run: cargo build --target powerpc-unknown-linux-gnu - run: RUSTFLAGS="-C target-feature=+avx2,+fma" cargo build --target x86_64-unknown-linux-gnu - run: RUSTFLAGS="-C target-feature=+simd128" cargo build --target wasm32-unknown-unknown tests_arm: name: Tests runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: cargo test tests_x86: name: Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: cargo test clippy_x86: name: Clippy x86 Stable runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: cargo clippy -- -D warnings clippy_x86_nightly: name: Clippy x86 Nightly runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly - run: rustup component add clippy - run: cargo clippy -- -D warnings clippy_arm: name: Clippy ARM runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: cargo clippy -- -D warnings fuzz_reader: name: Fuzzing runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly - run: cargo install cargo-fuzz - run: cargo fuzz run math -- -max_total_time=25 -max_len=128 - run: cargo fuzz run accuracy_sp -- -max_total_time=35 -max_len=128 - run: cargo fuzz run accuracy_dp -- -max_total_time=35 -max_len=128 pxfm-0.1.23/.github/workflows/no-response.yml000064400000000000000000000023621046102023000172540ustar 00000000000000name: no-response on: schedule: - cron: '0 0 * * *' # Runs daily at midnight workflow_dispatch: jobs: noResponse: permissions: issues: write pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/stale@v9 with: repo-token: ${{ github.token }} days-before-stale: -1 days-before-close: 14 only-labels: 'waiting for author' stale-issue-label: 'waiting for author' stale-pr-label: 'waiting for author' remove-stale-when-updated: true ignore-updates: false close-issue-message: This issue has been automatically closed due to inactivity. We requested additional information but have not received a response from the original author. Without the requested details, we cannot proceed. If you have or find the information needed, please comment so we can reopen the issue. close-pr-message: This pull request has been automatically closed due to inactivity. We requested additional information but have not received a response from the original author. Without the requested details, we cannot proceed. If you have the needed information or updates, please reopen the PR or comment so we can continue the review.pxfm-0.1.23/.github/workflows/publish_release.yml000064400000000000000000000007601046102023000201520ustar 00000000000000name: Create Release concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: push: tags: - '*' jobs: build_and_publish: name: Build runs-on: ubuntu-latest environment: Cargo steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Make a release env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }} run: cargo publish --manifest-path Cargo.tomlpxfm-0.1.23/.gitignore000064400000000000000000000002361046102023000126520ustar 00000000000000/target Cargo.lock .idea app/target rust-toolchain.toml .cargo /notes/.ipynb_checkpoints/* .ipynb_checkpoints notes/coefficients.txt notes/tmp_interval.sollyapxfm-0.1.23/Cargo.lock0000644000000011300000000000100100370ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "pxfm" version = "0.1.23" dependencies = [ "num-traits", ] pxfm-0.1.23/Cargo.toml0000644000000022240000000000100100670ustar # 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 = "2024" rust-version = "1.85" name = "pxfm" version = "0.1.23" authors = ["Radzivon Bartoshyk"] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Fast and accurate math" documentation = "https://github.com/awxkee/pxfm" readme = "README.md" keywords = [ "libm", "math", ] categories = ["mathematics"] license = "BSD-3-Clause OR Apache-2.0" repository = "https://github.com/awxkee/pxfm" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [lib] name = "pxfm" path = "src/lib.rs" [dependencies.num-traits] version = "0.2" [profile.dev.package.bessel] opt-level = 3 pxfm-0.1.23/Cargo.toml.orig0000644000000012510000000000100110250ustar workspace = { members = ["app", "bessel", "fuzz"] } [package] name = "pxfm" version = "0.1.23" edition = "2024" documentation = "https://github.com/awxkee/pxfm" keywords = ["libm", "math"] license = "BSD-3-Clause OR Apache-2.0" authors = ["Radzivon Bartoshyk"] readme = "README.md" repository = "https://github.com/awxkee/pxfm" rust-version = "1.85" categories = ["mathematics"] description = "Fast and accurate math" [dependencies] num-traits = "0.2" [profile.dev.package] bessel.opt-level = 3 [package.metadata.docs.rs] # To build locally: # RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --open all-features = true rustdoc-args = ["--cfg", "docsrs"]pxfm-0.1.23/Cargo.toml.orig000064400000000000000000000012511046102023000135470ustar 00000000000000workspace = { members = ["app", "bessel", "fuzz"] } [package] name = "pxfm" version = "0.1.23" edition = "2024" documentation = "https://github.com/awxkee/pxfm" keywords = ["libm", "math"] license = "BSD-3-Clause OR Apache-2.0" authors = ["Radzivon Bartoshyk"] readme = "README.md" repository = "https://github.com/awxkee/pxfm" rust-version = "1.85" categories = ["mathematics"] description = "Fast and accurate math" [dependencies] num-traits = "0.2" [profile.dev.package] bessel.opt-level = 3 [package.metadata.docs.rs] # To build locally: # RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --open all-features = true rustdoc-args = ["--cfg", "docsrs"]pxfm-0.1.23/LICENSE-APACHE.md000064400000000000000000000261241046102023000132110ustar 00000000000000 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. Copyright 2024 Radzivon Bartoshyk 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. pxfm-0.1.23/LICENSE.md000064400000000000000000000027421046102023000122720ustar 00000000000000Copyright (c) Radzivon Bartoshyk. 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. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.pxfm-0.1.23/README.md000064400000000000000000000001351046102023000121370ustar 00000000000000# Math routines Mostly fast and accurate math. Most of the methods have ULP less than 0.5. pxfm-0.1.23/notes/Atan2.ipynb000064400000000000000000000372461046102023000140350ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 4, "id": "ac18201b-1c3f-4ec8-8c3c-8b6eaf493683", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Minus Pi\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -126,\n", " mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128,\n", "},\n", "\n", "PI over 2\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128,\n", "},\n", "\n", "Minus PI over 2\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -127,\n", " mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128,\n", "},\n" ] } ], "source": [ "from sage.all import *\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")\n", "\n", "D3 = RealField(157)\n", "\n", "print(\"Minus Pi\")\n", "print_dyadic(-D3.pi())\n", "\n", "print(\"\\nPI over 2\")\n", "print_dyadic(D3.pi() / 2) \n", "\n", "print(\"\\nMinus PI over 2\")\n", "print_dyadic(-D3.pi() / 2) " ] }, { "cell_type": "code", "execution_count": 19, "id": "3ce0ae25-d4de-4578-a0ab-a1e79ddd76b7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -129,\n", " mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xcccccccc_cccccccc_cccccccc_cccccccd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -130,\n", " mantissa: 0x92492492_49249249_24924924_92492492_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,\n", "},\n" ] } ], "source": [ "# print(\"-1/3\")\n", "print_dyadic(-D3(1)/D3(3)) \n", "\n", "# print(\"1/5\")\n", "print_dyadic(D3(1)/D3(5)) \n", "\n", "# print(\"-1/7\")\n", "print_dyadic(-D3(1)/D3(7)) \n", "\n", "# print(\"1/9\")\n", "print_dyadic(D3(1)/D3(9)) " ] }, { "cell_type": "code", "execution_count": 15, "id": "92f4c6e9-50ec-4cfd-bef6-4f2f19e7420e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static ATAN_RATIONAL_128: [DyadicFloat128; 65] = [\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: 0,\n", " mantissa: 0x0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -134,\n", " mantissa: 0xfffaaadd_db94d5bb_e78c5640_15f76048_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -133,\n", " mantissa: 0xffeaaddd_4bb12542_779d776d_da8c6214_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -132,\n", " mantissa: 0xbfdc0c21_86d14fcf_220e10d6_1df56ec7_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -132,\n", " mantissa: 0xffaaddb9_67ef4e36_cb2792dc_0e2e0d51_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0x9facf873_e2aceb58_99c50bbf_08e6cdf6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xbf70c130_17887460_93567e78_4cf83676_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xdf1cf5f3_783e1bef_71e5340b_30e5d9ef_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xfeadd4d5_617b6e32_c897989f_3e888ef8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0x8f0fd7d8_21b93725_bd375929_83a0af9a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0x9eb77746_331362c3_47619d25_0360fe85_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xae4c08f1_f6134efa_b54d3fef_0c2de994_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xbdcbda5e_72d81134_7b0b4f88_1c9c7488_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xcd35474b_643130e7_b00f3da1_a46eeb3b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xdc86ba94_93051022_f621a5c1_cb552f03_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xebbeaef9_02b9b38c_91a2a68b_2fbd78e8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xfadbafc9_6406eb15_6dc79ef5_f7a217e6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x84ee2cbe_c31b12c5_c8e72197_0cabd3a3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x8c5fad18_5f8bc130_ca4748b1_bf88298d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x93c1b902_bf7a2df1_06459240_6fe1447a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x9b13b9b8_3f5e5e69_c5abb498_d27af328_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xa25521b6_15784d45_43787549_88b8d9e3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xa9856cca_8e6a4eda_99b7f77b_f7d9e8c1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xb0a42018_4e7f0cb1_b51d51dc_200a0fc3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xb7b0ca0f_26f78473_8aa32122_dcfe4483_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xbeab025b_1d9fbad3_910b8564_93411026_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xc59269ca_50d92b6d_a1746e91_f50a28de_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xcc66aa2a_6b58c33c_d9311fa1_4ed9b7c4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xd327761e_611fe5b6_427c95e9_001e7136_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xd9d488ed_32e3635c_30f6394a_0806345d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xe06da64a_764f7c67_c631ed96_798cb804_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xe6f29a19_609a84ba_60b77ce1_ca6dc2c8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xed63382b_0dda7b45_6fe445ec_bc3a8d03_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xf3bf5bf8_bad1a21c_a7b837e6_86adf3fa_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xfa06e85a_a0a0be5c_66d23c7d_5dc8ecc2_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x801ce39e_0d205c99_a6d6c6c5_4d938596_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x832bf4a6_d9867e2a_4b6a09cb_61a515c1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x8630a2da_da1ed065_d3e84ed5_013ca37e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x892aecdf_de9547b5_094478fc_472b4afc_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x8c1ad445_f3e09b8c_439d8018_60205921_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x8f005d5e_f7f59f9b_5c835e16_65c43748_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x91db8f16_64f350e2_10e4f9c1_126e0220_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x94ac72c9_847186f6_18c4f393_f78a32f9_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x97731420_365e538b_abd3fe19_f1aeb6b3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x9a2f80e6_71bdda20_4226f8e2_204ff3bd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x9ce1c8e6_a0b8cdb9_f799c4e8_174cf11c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x9f89fdc4_f4b7a1ec_f8b49264_4f0701e0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xa22832db_cadaae08_92fe9c08_637af0e6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xa4bc7d19_34f70924_19a87f2a_457dac9f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xa746f2dd_b7602294_67b7d66f_2d74e019_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xa9c7abdc_4830f5c8_916a84b5_be7933f6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xac3ec0fb_997dd6a1_a36273a5_6afa8ef4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xaeac4c38_b4d8c080_14725e2f_3e52070a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb110688a_ebdc6f6a_43d65788_b9f6a7b5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb36b31c9_1f043691_59014174_4462f93a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb5bcc490_59ecc4af_f8f3cee7_5e3907d5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb8053e2b_c2319e73_cb2da552_10a4443d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xba44bc7d_d470782f_654c2cb1_0942e386_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xbc7b5dea_e98af280_d4113006_e80fb290_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xbea94144_fd049aac_1043c5e7_55282e7d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc0ce85b8_ac526640_89dd62c4_6e92fa25_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc2eb4abb_661628b5_b373fe45_c61bb9fb_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc4ffaffa_bf8fbd54_8cb43d10_bc9e0221_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc70bd54c_e602ee13_e7d54fbd_09f2be38_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128,\n", "},\n", "];\n" ] } ], "source": [ "print(\"pub(crate) static ATAN_RATIONAL_128: [DyadicFloat128; 65] = [\")\n", "for i in range(65):\n", " x = D3(i)/D3(64)\n", " v = atan(x)\n", " print_dyadic(v) \n", "\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": null, "id": "97e7cbe8-8152-42d5-8de5-cb75ea7e902e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "22e2313a-695b-4399-b30b-011e79f1389e", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Bessel_j1_taylor.ipynb000064400000000000000000004602721046102023000162700ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "1600c783-153f-4523-838a-336f41daa5a4", "metadata": {}, "outputs": [], "source": [ "from scipy.special import j1\n", "from scipy.optimize import brentq\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(52)\n", "\n", "DD = RealField(157)\n", "\n", "def double_to_hex(f):\n", " # Converts Python float (f64) to hex string\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "0c71f4bf-0551-4346-9e65-e99cbf830878", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Zero 1: x ≈ 3.8317059702075123156144358863081609582911078521244950401886\n", "Zero 2: x ≈ 7.0155866698156187535370499814765222133211799657697498562727\n", "Zero 3: x ≈ 10.173468135062722077185711776775842874118325466668199285671\n", "Zero 4: x ≈ 13.323691936314223032393684126947876836246966256828906387054\n", "Zero 5: x ≈ 16.47063005087763281255246047098955460257890840875283477081\n", "Zero 6: x ≈ 19.615858510468242021125065884137511712322940855970695228805\n", "Zero 7: x ≈ 22.760084380592771898053005152182260032194822293609582761429\n", "Zero 8: x ≈ 25.903672087618382625495855445979875220850924725526971473225\n", "Zero 9: x ≈ 29.046828534916855066647819883531963887188166731590534232106\n", "Zero 10: x ≈ 32.189679910974403626622984104460371875478032041055034115317\n", "Zero 11: x ≈ 35.332307550083865102634479022519015000383928144530784171094\n", "Zero 12: x ≈ 38.47476623477161511205219755771661236717103805681843387566\n", "Zero 13: x ≈ 41.617094212814450885863516805060288649321765027325910311976\n", "Zero 14: x ≈ 44.759318997652821732779352713212144805527050106004245235266\n", "Zero 15: x ≈ 47.901460887185447121274008722507510606090340432217198664216\n", "Zero 16: x ≈ 51.043535183571509468733034633224064223940401220527595825313\n", "Zero 17: x ≈ 54.185553641061320532099966214533888722863601345165535245984\n", "Zero 18: x ≈ 57.327525437901010745090504243750521990195239019055722165916\n", "Zero 19: x ≈ 60.469457845347491559398749808383148215264825792836696672175\n", "Zero 20: x ≈ 63.611356698481232631039762417873623076713264180867051323918\n", "Zero 21: x ≈ 66.753226734098493415305259750042396239171789203090216697113\n", "Zero 22: x ≈ 69.895071837495773969730536435499809980997967252113712925054\n", "Zero 23: x ≈ 73.036895225573834826506117569092051498329725501044154535344\n", "Extrema (peaks/valleys) of J1(x):\n", "nExtrema: 1.841183781340659302643629513644439520964818374318352014927\n", "nExtrema: 5.3314427735250326368840161834339132081547293413224236441488\n", "nExtrema: 8.5363163663462858343589608864120482965837358587753983517152\n", "nExtrema: 11.706004902592064100192670477239524000448927061310287253099\n", "nExtrema: 14.863588633909033105004905304985977691427348785932252434149\n", "nExtrema: 18.015527862681803727025625542010494601693647252747417376607\n", "nExtrema: 21.164369859188790027767973293705129247975983996953386626527\n", "nExtrema: 24.311326857210776091733221673753676306378480011942360360454\n", "nExtrema: 27.457050571059245888223275587901978010370806843697132034285\n", "nExtrema: 30.601922972669094192330163628525055274165359139581824366136\n", "nExtrema: 33.746182898667382556147730594290576334249423037008184846603\n", "nExtrema: 36.889987409236810736184291115055094401160040486328494345988\n", "nExtrema: 40.033444053350675483595577824821022828463547144934866936034\n", "nExtrema: 43.176628965448822065171326670934501571066365344001255868622\n", "nExtrema: 46.319597561173912431514896922520702473277867957869702305385\n", "nExtrema: 49.462391139702755522817961514250937385678740975236699817546\n", "nExtrema: 52.605041111556684816016445795619378892481337744928955035137\n", "nExtrema: 55.747571792251006871041271951261258413853108852487038435094\n", "nExtrema: 58.890002299185703524557516663955600609834094444605673558084\n", "nExtrema: 62.032347870661986904980183177973296987103767798776122898255\n", "nExtrema: 65.17462080254445314091307969916123952087003501418858119203\n", "nExtrema: 68.31683112595180831007553283620391416177243057400015156204\n", "nExtrema: 71.458987105851000181223748893951481700627639700184149171624\n", "nExtrema: 74.601095613456402477925006047822591617571255814146598762252\n", "Peak or zero 1: x ≈ 1.841183781340659302643629513644439520964818374318352014927\n", "Peak or zero 2: x ≈ 3.8317059702075123156144358863081609582911078521244950401886\n", "Peak or zero 3: x ≈ 5.3314427735250326368840161834339132081547293413224236441488\n", "Peak or zero 4: x ≈ 7.0155866698156187535370499814765222133211799657697498562727\n", "Peak or zero 5: x ≈ 8.5363163663462858343589608864120482965837358587753983517152\n", "Peak or zero 6: x ≈ 10.173468135062722077185711776775842874118325466668199285671\n", "Peak or zero 7: x ≈ 11.706004902592064100192670477239524000448927061310287253099\n", "Peak or zero 8: x ≈ 13.323691936314223032393684126947876836246966256828906387054\n", "Peak or zero 9: x ≈ 14.863588633909033105004905304985977691427348785932252434149\n", "Peak or zero 10: x ≈ 16.47063005087763281255246047098955460257890840875283477081\n", "Peak or zero 11: x ≈ 18.015527862681803727025625542010494601693647252747417376607\n", "Peak or zero 12: x ≈ 19.615858510468242021125065884137511712322940855970695228805\n", "Peak or zero 13: x ≈ 21.164369859188790027767973293705129247975983996953386626527\n", "Peak or zero 14: x ≈ 22.760084380592771898053005152182260032194822293609582761429\n", "Peak or zero 15: x ≈ 24.311326857210776091733221673753676306378480011942360360454\n", "Peak or zero 16: x ≈ 25.903672087618382625495855445979875220850924725526971473225\n", "Peak or zero 17: x ≈ 27.457050571059245888223275587901978010370806843697132034285\n", "Peak or zero 18: x ≈ 29.046828534916855066647819883531963887188166731590534232106\n", "Peak or zero 19: x ≈ 30.601922972669094192330163628525055274165359139581824366136\n", "Peak or zero 20: x ≈ 32.189679910974403626622984104460371875478032041055034115317\n", "Peak or zero 21: x ≈ 33.746182898667382556147730594290576334249423037008184846603\n", "Peak or zero 22: x ≈ 35.332307550083865102634479022519015000383928144530784171094\n", "Peak or zero 23: x ≈ 36.889987409236810736184291115055094401160040486328494345988\n", "Peak or zero 24: x ≈ 38.47476623477161511205219755771661236717103805681843387566\n", "Peak or zero 25: x ≈ 40.033444053350675483595577824821022828463547144934866936034\n", "Peak or zero 26: x ≈ 41.617094212814450885863516805060288649321765027325910311976\n", "Peak or zero 27: x ≈ 43.176628965448822065171326670934501571066365344001255868622\n", "Peak or zero 28: x ≈ 44.759318997652821732779352713212144805527050106004245235266\n", "Peak or zero 29: x ≈ 46.319597561173912431514896922520702473277867957869702305385\n", "Peak or zero 30: x ≈ 47.901460887185447121274008722507510606090340432217198664216\n", "Peak or zero 31: x ≈ 49.462391139702755522817961514250937385678740975236699817546\n", "Peak or zero 32: x ≈ 51.043535183571509468733034633224064223940401220527595825313\n", "Peak or zero 33: x ≈ 52.605041111556684816016445795619378892481337744928955035137\n", "Peak or zero 34: x ≈ 54.185553641061320532099966214533888722863601345165535245984\n", "Peak or zero 35: x ≈ 55.747571792251006871041271951261258413853108852487038435094\n", "Peak or zero 36: x ≈ 57.327525437901010745090504243750521990195239019055722165916\n", "Peak or zero 37: x ≈ 58.890002299185703524557516663955600609834094444605673558084\n", "Peak or zero 38: x ≈ 60.469457845347491559398749808383148215264825792836696672175\n", "Peak or zero 39: x ≈ 62.032347870661986904980183177973296987103767798776122898255\n", "Peak or zero 40: x ≈ 63.611356698481232631039762417873623076713264180867051323918\n", "Peak or zero 41: x ≈ 65.17462080254445314091307969916123952087003501418858119203\n", "Peak or zero 42: x ≈ 66.753226734098493415305259750042396239171789203090216697113\n", "Peak or zero 43: x ≈ 68.31683112595180831007553283620391416177243057400015156204\n", "Peak or zero 44: x ≈ 69.895071837495773969730536435499809980997967252113712925054\n", "Peak or zero 45: x ≈ 71.458987105851000181223748893951481700627639700184149171624\n", "Peak or zero 46: x ≈ 73.036895225573834826506117569092051498329725501044154535344\n", "Peak or zero 47: x ≈ 74.601095613456402477925006047822591617571255814146598762252\n", "\n", "pub(crate) static J1_ZEROS: [(u64, u64); 48] = [\n", "(0x0, 0x0),\n", "(0x3c5616d820cfdae6, 0x3ffd757d1fec8a3a),\n", "(0xbca60155a9d1b256, 0x400ea75575af6f09),\n", "(0x3ca5c646a75d7539, 0x40155365bc032467),\n", "(0xbc9b226d9d243827, 0x401c0ff5f3b47250),\n", "(0xbca63e17ec20a31d, 0x402112980f0b88a1),\n", "(0x3cc02610a51562b6, 0x402458d0d0bdfc29),\n", "(0x3cc9a84d3a5fedc2, 0x40276979797ee5ac),\n", "(0x3cb2bce7fd18e693, 0x402aa5baf310e5a2),\n", "(0xbcc6932b987094f0, 0x402dba284a17ac59),\n", "(0xbcdd2a68e88ab317, 0x4030787b360508c5),\n", "(0xbca022f6b2b54db8, 0x403203f9a24e6527),\n", "(0xbcd21830197e9e86, 0x40339da8e7416ca4),\n", "(0x3cdeaafeaf8ec1af, 0x40352a1424a1a9fa),\n", "(0xbcc1bf33afef88f1, 0x4036c294e3d4d8ac),\n", "(0xbcb2d773b50cf8b8, 0x40384fb31dee1635),\n", "(0x3cc1a2686480d882, 0x4039e7570dcea106),\n", "(0x3cd0bdee27293d79, 0x403b75014427514d),\n", "(0xbcb42ce39ec976fb, 0x403d0bfcf471fccc),\n", "(0x3cbda49c2c143484, 0x403e9a179fba532a),\n", "(0xbcdbe3a1cd066b66, 0x404018476e6b2bf0),\n", "(0xbce6b00c1279ef0a, 0x4040df82ebd54e32),\n", "(0xbced5fbbff045068, 0x4041aa890dc5e97c),\n", "(0x3cd7d864bbf17a31, 0x404271eb1b80430e),\n", "(0x3cc9eafeca0ca4fd, 0x40433cc523d5cb69),\n", "(0xbce5cecac300a9a1, 0x40440447e50db184),\n", "(0x3cc489bd556e510a, 0x4044cefcf1734b62),\n", "(0x3cdd0fd96f29c212, 0x4045969bc7271083),\n", "(0x3ce4f716f3179d90, 0x404661315d6b133f),\n", "(0xbce158b763edd0e8, 0x404728e892a88fc9),\n", "(0xbcef3950a842db79, 0x4047f36312028ad6),\n", "(0x3ce97656bbc2396e, 0x4048bb2fa2037de3),\n", "(0x3ce85d7bdb30baf1, 0x404985928f96d51e),\n", "(0xbce71f8560ac9f18, 0x404a4d71fcb56f8c),\n", "(0x3ce3d41e041caa68, 0x404b17c038c2018c),\n", "(0xbcde6d04716d8d20, 0x404bdfb06eb790aa),\n", "(0x3cda139ce2cd08ac, 0x404ca9ec5a82324b),\n", "(0x3cc8b5cc7b4501c2, 0x404d71eb98682f07),\n", "(0xbcb12e6ef2e594e1, 0x404e3c1731d64f1e),\n", "(0x3cb399bfca430022, 0x404f0423f99b4b53),\n", "(0x3cdfd1ee8286358a, 0x404fce40efb1156e),\n", "(0x3c800660b51502f1, 0x40504b2cfcbb084d),\n", "(0x3ced3cacfc720419, 0x4050b034dde75b42),\n", "(0x3cc4b877d4f6d901, 0x40511446f60f1458),\n", "(0xbcee669304bfe748, 0x40517948db63675c),\n", "(0x3cfad20ca758a715, 0x4051dd600b743a9b),\n", "(0x3cf8eb4a94b63936, 0x4052425c7dcacdf6),\n", "(0xbcfa196892f68385, 0x4052a67859bc641e),\n", "];\n", "pub(crate) static J1_COEFFS_TAYLOR: [J1TaylorExtendedSeries; 47] = [\n", "[\n", "(0x3c61f1c324453b30, 0x3fe29ea3d19f035f),\n", "(0xb5b2f6354c9ff45d, 0x392031b7410e0111),\n", "(0xbc6e3631ae171270, 0xbfca41115c5df243),\n", "(0xbc18acc5100eb0b3, 0x3f78d1448e6fed48),\n", "(0x3c0e85a7d0bc098f, 0x3f8c441a2f9de22b),\n", "(0x3bd94ca1b6912493, 0xbf386671c18b088a),\n", "(0x3bd950cc4e8482d1, 0xbf39e2504ddc7608),\n", "(0xbb61b481438e4089, 0x3ee34ccbca0c75d1),\n", "(0x3b7aba05e287d170, 0x3eda4973784d1087),\n", "(0x3b1ffacaebcbb72b, 0xbe81045322aaab45),\n", "(0x3b03dabae8fea73e, 0xbe70fae0da6cdcef),\n", "(0x3abc719b8692aa74, 0x3e13546cef5ed00a),\n", "(0xba8ac75d7c570055, 0x3dfe5ee82e667708),\n", "(0xba263b1d65111e4c, 0xbd9ec80cc8b63c39),\n", "(0xba145e6e27b1490b, 0xbd83eb2e99629b44),\n", "(0x39b7626e428b4f57, 0x3d222bfcdb19561c),\n", "(0xb98421e04d0e0d8c, 0x3d03fb3376a42e35),\n", "(0xb922e25ac68f0c81, 0xbca0901287d105ae),\n", "(0x391c50bf6cf518de, 0xbc7fa6a90c6a0c33),\n", "(0xb8b3ffd27bab3779, 0x3c180774f17c486b),\n", "(0x38976f3626c20293, 0x3bf44b79578fc6fb),\n", "(0xb82c4199c877aeaa, 0xbb8c6ab05fe77307),\n", "(0x380edbb8b3f4ef74, 0xbb65805fbd38e218),\n", "(0x3787f411d416c35b, 0x3afbed5bcea231a2),\n", "],\n", "[\n", "(0x356eab958ab851b5, 0xb8d9a91f973ec303),\n", "(0x3c62de1143765a96, 0xbfd9c6cf582cbf7f),\n", "(0xbc46b8d73329ae53, 0x3faae8a39f51ad04),\n", "(0xbc47767d9698b536, 0x3fab589d1da13905),\n", "(0x3c0e65e41f8b156f, 0xbf7537544c331da7),\n", "(0x3bc117d15907382b, 0xbf624b3409959064),\n", "(0x3bb8c81b03584e43, 0x3f26e4c2d5354224),\n", "(0x3b9859e8c0ae37ce, 0x3f083a06e30c4109),\n", "(0x3b51fe68ee4dfe26, 0xbec9799d4c9f2549),\n", "(0xbb4ffb11fda5bef3, 0xbea33825cd2e2c16),\n", "(0x3ae8a5cec4a77c6c, 0x3e617069233e916c),\n", "(0xbaabdbb69c094017, 0x3e34569b22afc3c8),\n", "(0x3a76236a521c1ecc, 0xbdf03b9e9651056a),\n", "(0xba58526061a7319e, 0xbdbec62310af5f52),\n", "(0x39f8c0813d01aca5, 0x3d75ec84e47b6f4f),\n", "(0x39df157bfc6eaf25, 0x3d417a40c9422e17),\n", "(0x399dbf21a6dd6ae2, 0xbcf67cb1d0030c9c),\n", "(0xb95f5d6974a310bb, 0xbcbee7ff918f9b69),\n", "(0xb8ed0057404186a7, 0x3c721fb8bdc4d7fa),\n", "(0x38a1a3560d39e992, 0x3c35e0517dd0b5c9),\n", "(0x388155451c853ffa, 0xbbe792595a1eec68),\n", "(0xb829a85503eb4baf, 0xbba95a682022dcb8),\n", "(0x37f61a6a78be1e62, 0x3b59438c464a0b99),\n", "(0x37ba49a9e0951317, 0x3b187f5c94382543),\n", "],\n", "[\n", "(0xbc782d627160714a, 0xbfd626ee83500bf2),\n", "(0x35a0f040f68d1816, 0x3909887c15bb2d86),\n", "(0x3c6ae8952e6f1d99, 0x3fc55f6bec9ef962),\n", "(0x3c0d30f1a30652af, 0xbf83d23336fd10e4),\n", "(0x3c2695c3589cdcfe, 0xbf88c77a983a0814),\n", "(0x3bea1200f3887332, 0x3f45cdc98db1cbe2),\n", "(0x3bd343248cea52bc, 0x3f373576ff46ee3b),\n", "(0x3b8a8cd6bedb881b, 0xbef2461447d7b423),\n", "(0x3b6a8a902c87e6bb, 0xbed7b853456b6eaa),\n", "(0xbaff7253673d7fa0, 0x3e90abfc68274a98),\n", "(0xbae9e22e3ad66ed4, 0x3e6ea7a1ee26124d),\n", "(0xbac56987dde26b61, 0xbe235c0413e01418),\n", "(0x3a9eb6867453dd1c, 0xbdfb5c5d512fbb00),\n", "(0x3a3a4481d08d2199, 0x3daf4c5e26fd6e90),\n", "(0xba21e34f6852a2b6, 0x3d81e4c43397be51),\n", "(0x39d14c360485170d, 0xbd32addefc4d51c5),\n", "(0xb9605d05ffcc6dea, 0xbd01e4fadc0e435c),\n", "(0xb923b05198207824, 0x3cb12a0b88508f37),\n", "(0x391a5ac22b8f14bd, 0x3c7c4246a0342e39),\n", "(0xb8ce78a27a5aabf3, 0xbc290ede5816f2ce),\n", "(0xb8986d234d468db8, 0xbbf211307906e314),\n", "(0x381bc4668970e7dc, 0x3b9dc7bf70396b28),\n", "(0x380949fa46f6dd76, 0x3b6316e7f158a264),\n", "(0xb79167d26945830c, 0xbb0d623edc3b24ac),\n", "],\n", "[\n", "(0x35a1c201de6b176a, 0xb90f8a0b194e92aa),\n", "(0x3c7af22d033ee0a5, 0x3fd33518b3874e8a),\n", "(0xbc23b4d6298472ae, 0xbf95e70dc60362bf),\n", "(0xbc476d8715df682d, 0xbfa80c83bdeee5b0),\n", "(0x3c03dac20ab22d50, 0x3f69a4b292e3de42),\n", "(0x3bd887eed6e6880a, 0x3f613fbc7d698217),\n", "(0xbbac52a925910e75, 0xbf207358bbdbff91),\n", "(0xbb64763d026d3263, 0xbf0796a751f89051),\n", "(0xbb6df65f1fdd48ef, 0x3ec4255b015aded4),\n", "(0xbb3ae816d26784fd, 0x3ea3026e0ce97ab9),\n", "(0xbaf57b3883b98fa3, 0xbe5d48dcdae92f2c),\n", "(0x3aca4c50b5ee02fb, 0xbe344639d7eeb0a6),\n", "(0xba8fd8f34b9ecafc, 0x3dec62ccb4a32eb5),\n", "(0xba5032cb87171f64, 0x3dbecae92e854457),\n", "(0xba1beb1ed7eaf160, 0xbd73bb6898d73cd2),\n", "(0xb9dd5420c79c50f5, 0xbd4183edbb8ef55e),\n", "(0x399a66b105ba2d65, 0x3cf4ae3e7e4cce3d),\n", "(0xb918cb92ea651e7f, 0x3cbefbb1e700730a),\n", "(0xb9146c2f2b670d08, 0xbc70f28da3efa3c7),\n", "(0x38c4ac35b8206d4a, 0xbc35ec318df9b467),\n", "(0x388be1913e828c5e, 0x3be6555a952345fa),\n", "(0x384ff998fe9bf37c, 0x3ba9633c7f133c92),\n", "(0x37f9fe5cad2d2342, 0xbb583145f93c70ae),\n", "(0x37bb7a15502058b2, 0xbb1881cb99e6a1d9),\n", "],\n", "[\n", "(0xbc7d48dbfa0ea1a4, 0x3fd17dbf09d40d25),\n", "(0x35a4427f3ab43500, 0x3910992c4b87a2c6),\n", "(0xbc61eb914d33c2fa, 0xbfc1404bf647c28f),\n", "(0x3c098a23a3934c81, 0x3f74f4df2769f830),\n", "(0x3c24ae93dcbae42e, 0x3f85c6285429b66d),\n", "(0x3bdddb259d6919ae, 0xbf3d68ab722881bd),\n", "(0xbbd8cd731f6bf3ff, 0xbf356acb6452d860),\n", "(0x3b60d2b8ff5b8f47, 0x3eec10b47cf7ef69),\n", "(0xbb3cc7e8d830a4e7, 0x3ed67eaae97bbc86),\n", "(0x3b0230ef0e6803fa, 0xbe8bb6530c63f2df),\n", "(0xbaf83f73085e8893, 0xbe6d87201e450edd),\n", "(0xbaaefe243bce74cc, 0x3e20f47c83ec550b),\n", "(0x3a995905da4f9c80, 0x3dfa98331f6ea799),\n", "(0x3a40b4039f32743f, 0xbdac70414a236a67),\n", "(0xba249d55aee4b10f, 0xbd817c057a5fcd3d),\n", "(0x39d02164b46fc11f, 0x3d316fea14d1fe7c),\n", "(0x39990498a42b8b9e, 0x3d0189bd3ec36234),\n", "(0x39512fd1dca06419, 0xbcb05af44aaf2ab4),\n", "(0x38fe8d7eea675e23, 0xbc7bbdb47ae6b94d),\n", "(0xb8b4cc5b1f63c320, 0x3c28435e8461ed37),\n", "(0x3882cf7a81930228, 0x3bf1bfd66fba7b36),\n", "(0xb828cec539879f22, 0xbb9d3526fa2c65e2),\n", "(0xb7f6bbe8d3df2731, 0xbb62c1e2b3f208cd),\n", "(0x376ec8c34abcf067, 0x3b0d1f12fb9ae97d),\n", "],\n", "[\n", "(0x359d2cb8a50a29e8, 0x38f8cdeedd7089d9),\n", "(0xbc5052a3a2541c57, 0xbfcff654544ebcd1),\n", "(0xbc01b402d42ea509, 0x3f89223ff2c0785b),\n", "(0xbc323a275590a85f, 0x3fa4b0c5d5da6789),\n", "(0x3bb3ea54ac68ef82, 0xbf5f91a9ee0d2897),\n", "(0x3bfc41f7f61682c1, 0xbf5f51c2489b9e6f),\n", "(0x3bad7af9f28c7680, 0x3f16b4c9ca0f770d),\n", "(0xbbadd3415a058d7b, 0x3f063c5475439cb2),\n", "(0x3b59f6c7b33666e7, 0xbebe3725daf69867),\n", "(0x3b21f2a7db95aa23, 0xbea25c1238b32e59),\n", "(0xbaeb35e7c5937061, 0x3e57486f6b9aa951),\n", "(0x3ad95c3e197deb05, 0x3e33e3bf248277ee),\n", "(0xba77b9fdb9bee258, 0xbde78a38a73e7c0a),\n", "(0xba480ea277e7ec50, 0xbdbe844eb6b211b0),\n", "(0x3a0c6dae4342e4f7, 0x3d70e24abb40708e),\n", "(0xb9e5f9316e1c5efa, 0x3d41797e5eacddfb),\n", "(0x398387d37934edf1, 0xbcf21fc0f1265a7c),\n", "(0xb95b8aad5aec742b, 0xbcbf0c12e445cb41),\n", "(0x390e42f5b55d3825, 0x3c6e4423559080b2),\n", "(0x38cc1d5a56b93a77, 0x3c36080463b41f1d),\n", "(0xb87dbc48deb40e7d, 0xbbe43e38b263073e),\n", "(0x38442a4086626b0d, 0xbba98fa121c815cb),\n", "(0x37e94a11e9993a14, 0x3b56325cba16fa62),\n", "(0x378f6607677ad6cb, 0x3b18b3fd438c6ab3),\n", "],\n", "[\n", "(0x3c50f8942d3f902b, 0xbfcddceb4ce1bf4a),\n", "(0xb5776203d5c7d545, 0x39009f7250661abf),\n", "(0x3c433d5334b42c83, 0x3fbda52116c0a640),\n", "(0xbbe72468a28942f7, 0xbf6a9da4603b67ea),\n", "(0xbc0c5e08317c5bc1, 0xbf8331e74ea59ab8),\n", "(0xbbdac4579bb7d320, 0x3f33e5cb6eba6eaa),\n", "(0x3bd0ad973dfed7a9, 0x3f33885fe9afa541),\n", "(0xbb74d72fe9613abb, 0xbee494c0f4b0680b),\n", "(0x3b783e70ffbfc8f8, 0xbed512b9d37762d7),\n", "(0x3b137aef41758720, 0x3e85a861082bfb7f),\n", "(0xbb059fce2a743f33, 0x3e6c323ea0a042c3),\n", "(0xbaaeb25b7edb5f5d, 0xbe1bcc962f7b91eb),\n", "(0x3a6a5caf0a45be46, 0xbdf9bc94e2f29a52),\n", "(0x3a4115f7a8e1da37, 0x3da82bc6fcfa8e89),\n", "(0x3a2ca2e9a78a230c, 0x3d81141ce7b78460),\n", "(0x399649188487057f, 0xbd2e79ccb1860d7a),\n", "(0x397e5f7602a25533, 0xbd013e1fbe0a5971),\n", "(0xb91843ce4e8dd1b6, 0x3cad36d12b0d249d),\n", "(0xb9191629f123918b, 0x3c7b66072bbdf478),\n", "(0x38cfbb54dd8d36aa, 0xbc260cb923a35433),\n", "(0x385274d20bfe6ac3, 0xbbf196237500b24e),\n", "(0x383559483b284848, 0x3b9aeba1005e1830),\n", "(0x380a4bb85b8cb2ba, 0x3b62a07d164c6a6f),\n", "(0xb76cc607fa3605e1, 0xbb0b27ac12f04a31),\n", "],\n", "[\n", "(0x3540e66d0c71e44c, 0x38b8ae14acc03cc2),\n", "(0x3c6c8c66d2e42062, 0x3fcbf3337873a7d8),\n", "(0x3c25e81c4baa84e9, 0xbf80c83a2d7add33),\n", "(0x3c44192692d7c9db, 0xbfa251858011816b),\n", "(0x3bd0475c4916a7f2, 0x3f559eb160bf72d8),\n", "(0x3b9e04d41bf0d87b, 0x3f5c5bce33af2d77),\n", "(0x3b7eb490c3282478, 0xbf10413e306e0039),\n", "(0xbb9e3a426e412d42, 0xbf04a6704d05ad0b),\n", "(0xbb5a4f33202681b2, 0x3eb6c43eedfed6c9),\n", "(0x3b2d2f110d38d23b, 0x3ea16abd7815de74),\n", "(0xbae416eabc41ca79, 0xbe5257f16f5d4346),\n", "(0xbad1043744ab6130, 0xbe332db1b4b2ff8b),\n", "(0xba872ca31e31d0a7, 0x3de33acccf7bfdce),\n", "(0x3a00b03336c2218e, 0x3dbdc8f5682566ba),\n", "(0xb9e9cd15ad06d38b, 0xbd6c6513386daae2),\n", "(0x39d8466ad52efa61, 0xbd413585a9b7473f),\n", "(0xb9408c90ab21329f, 0x3cef322ea2e20db6),\n", "(0x3952e07fa31826b3, 0x3cbec749ba31d0ed),\n", "(0x3904a43ae3e1adf7, 0xbc6a8abab44a5a16),\n", "(0x38bd7572726e9fd6, 0xbc35f2aba27d0156),\n", "(0xb8753cce6cac9ae4, 0x3be20705169a0885),\n", "(0x38458824bb426ee4, 0x3ba98e9c9fa1064a),\n", "(0xb7e6e8cdd35eeba7, 0xbb540557c89d65c9),\n", "(0x3759f423b384f394, 0xbb18c41cdedb0d3e),\n", "],\n", "[\n", "(0xbc26397095487bb8, 0x3fca7f63fea81f26),\n", "(0xb579a23f3e01c02a, 0x3900cbe4fe15df81),\n", "(0x3c4341d92ebaf0e5, 0xbfba60afb06640cf),\n", "(0x3c0aa0cf7edfc4af, 0x3f62c1e930935d3c),\n", "(0x3c2253175b5dc28b, 0x3f814506466d7f1f),\n", "(0x3bcf594f6cb1e048, 0xbf2cca8c0c0eaa3f),\n", "(0xbbc23306ba391f44, 0xbf31df821cc1377e),\n", "(0xbb6f4273eb18d486, 0x3edee8814ed0ac45),\n", "(0x3b3531e00c0b1e91, 0x3ed3a365a4199dd1),\n", "(0xbb2539aeb3d4946a, 0xbe80ed2f9c3e458e),\n", "(0xbae7dc7c41800a98, 0xbe6ab3b37c5271b3),\n", "(0xbabe3080b40ebc8e, 0x3e1684d6e62b5c66),\n", "(0xba980fe8dabe0c36, 0x3df8b105a5120ed2),\n", "(0xba34afb054573ddf, 0xbda42dc5991b9d01),\n", "(0x3a24e165917f0851, 0xbd808d6405ffe3dc),\n", "(0xb9bea36c059d9a67, 0x3d2a15203365a9e0),\n", "(0x397717476aec9541, 0x3d00d7c118bbeb37),\n", "(0x39474ba7f9cdad9c, 0xbca984ffd2857b4d),\n", "(0xb8f090df156cf8ee, 0xbc7aecb2d322693f),\n", "(0xb8b29f8b4dabfed8, 0x3c2396ff2d246042),\n", "(0xb86310d4b1263ad5, 0x3bf15cbae441ca24),\n", "(0xb8388b6c6238abda, 0xbb9841be044fa28d),\n", "(0xb7f60da5e67d9193, 0xbb627467b799ccfc),\n", "(0xb7ab569bc7745d94, 0x3b08c28575d745a7),\n", "],\n", "[\n", "(0xb5a0840c646e7364, 0xb909bb79105907c8),\n", "(0x3c6e9557ccd1703f, 0xbfc925c6fca08f55),\n", "(0x3c091bef69239af0, 0x3f786dd32e059b0e),\n", "(0x3c3dac1b118bb946, 0x3fa09463bbd0367f),\n", "(0x3be231ff19225462, 0xbf4fda0298c8768b),\n", "(0xbbf0185527e9208e, 0xbf59f4be60758fb1),\n", "(0xbbac474063460803, 0x3f0877991af9d1bb),\n", "(0x3b85632e0e751036, 0x3f032cb00ee8c1f3),\n", "(0x3b46a0371f5eb5de, 0xbeb19d8ce8c35f58),\n", "(0x3b44398edcd31b46, 0xbea06a042fbba455),\n", "(0xbaeabb097c7d4aab, 0x3e4d3a689e677731),\n", "(0x3adf851e84662874, 0x3e325108c4ce2b63),\n", "(0x3a700c6a94a96471, 0xbddf7b8e9ab53152),\n", "(0xb9e39398140885a8, 0xbdbcc40d05652642),\n", "(0xb9debdd38ee83cbd, 0x3d67cd76e2d7e2cb),\n", "(0xb9d4060b8e456ec8, 0x3d40c58770231c0a),\n", "(0xb986fdcd6522fa14, 0xbceaafec4cd92006),\n", "(0x395ac6a53012f35d, 0xbcbe36dd57088c43),\n", "(0xb90acfe289832416, 0x3c67199e80bb8ec3),\n", "(0xb8d65ad3a5a6b128, 0x3c35ab8b86951bb2),\n", "(0xb87d16fd2ded0f9a, 0xbbdfd7377ba12be2),\n", "(0xb83aa7858e0cbb98, 0xbba9595b17afa78d),\n", "(0xb7f5f340e3e25bf0, 0x3b51e6cee419b353),\n", "(0xb7a44c40cb1a1e24, 0x3b18a74f87d027a4),\n", "],\n", "[\n", "(0x3c2a5f1938003f5d, 0xbfc810f50225b04b),\n", "(0x358a4e47631896a5, 0xb8fd56c48838f152),\n", "(0x3c5462bc86c50f0a, 0x3fb7fdf97ac36b1f),\n", "(0x3beaefb0d3d06c9d, 0xbf5c3c256a8caa05),\n", "(0xbc191dbdbe4ca6d9, 0xbf7f98feb7286b47),\n", "(0xbbcd0c6b4f6c3ad8, 0x3f25f6559e5686e2),\n", "(0xbbd9de4a645cf978, 0x3f3080f57ac215af),\n", "(0xbb69ed06d60efe89, 0xbed80c51397e5eba),\n", "(0x3ae04eb6bd1f24a9, 0xbed256db543cd140),\n", "(0x3b1af2db1b084be5, 0x3e7af7598a219824),\n", "(0x3b0693a9fa38dfa0, 0x3e69398226ca2305),\n", "(0x3a95f5676bd10cd5, 0xbe1260985d92587d),\n", "(0x3a8d5612be0b4b05, 0xbdf792bb3eea6f6a),\n", "(0x3a4432d95d96cbda, 0x3da0d862695e1a7a),\n", "(0x39d7cd101d99d4e5, 0x3d7fe52adc2baacf),\n", "(0x39baa545a1a5eb63, 0xbd263801377398f0),\n", "(0xb90a458f0e1e2682, 0xbd005a1befdbe42c),\n", "(0x39473f5560f8b44e, 0x3ca6205041739aa5),\n", "(0x38f53ca728fe9101, 0x3c7a4e1503b6d0e4),\n", "(0x38a22b93c20b3937, 0xbc213ef141f6d641),\n", "(0x3854274bba40b623, 0xbbf10ccc96cd4c02),\n", "(0x382225ebf160c143, 0x3b95a2fe023aea26),\n", "(0x380398ff54fa8423, 0x3b6232d7c90d33bc),\n", "(0x37acf10d8068ed39, 0xbb0656435697f160),\n", "],\n", "[\n", "(0x3590c69d1d5ad990, 0x38fbdadd24cf38cb),\n", "(0x3c62da0057f84d3c, 0x3fc70c511227d5aa),\n", "(0xbbfb574e506cf75b, 0xbf72ccb0e97558da),\n", "(0x3c2e61277dedf705, 0xbf9e7dc08e70e99a),\n", "(0x3ba77952da42c6eb, 0x3f48acdc5b058c0e),\n", "(0xbbf340f4df9939b5, 0x3f580503724ad30a),\n", "(0xbba115f69745949b, 0xbf032ee4ca1fcafb),\n", "(0x3ba6a66de44f6f2b, 0xbf01e5d2836c8d99),\n", "(0xbb2b264207f7cf59, 0x3eac129f077bb163),\n", "(0x3b3381f3bd8fb4b6, 0x3e9ef161591181a2),\n", "(0x3ae466d818a45b43, 0xbe47b9bb07f19f82),\n", "(0x3ac2d952a84a8f21, 0xbe316f3937595d96),\n", "(0xba7571ae406938c3, 0x3dda0bc8665b687b),\n", "(0x3a588295d4921561, 0x3dbba135f99a9e19),\n", "(0xb9ff299934254ca8, 0xbd640d543d2cbdf0),\n", "(0x3982fb1c3cc08579, 0xbd403d0592185f1c),\n", "(0xb925c1461a28ff32, 0x3ce6db5e22d3be75),\n", "(0xb939bcdb12fd3c24, 0x3cbd745a1f778590),\n", "(0xb8f8314c949b4d69, 0xbc64141c4b5a4105),\n", "(0x38a825ab0fff4716, 0xbc353f4e6ca53f65),\n", "(0x387f0bb5f3376671, 0x3bdc09c1732e9344),\n", "(0x3845a8dc1ed995e7, 0x3ba8f971fa1f374a),\n", "(0xb7ce30cb1f02717b, 0xbb4fe39c23f51b6c),\n", "(0x37b9858646741b7e, 0xbb1862f419e2ba54),\n", "],\n", "[\n", "(0xbc6b166d180d579d, 0x3fc633e7f7f05301),\n", "(0x356d48b037092f86, 0x38f9187186657edf),\n", "(0xbc100659a075d9a7, 0xbfb6273784c1c06e),\n", "(0x3bfcb74bd0872e23, 0x3f563ae94ade18d4),\n", "(0x3c02a45d712a2f91, 0x3f7d4666536c88b9),\n", "(0x3b825e9acb600ae8, 0xbf216d528345ca11),\n", "(0x3bbb9405b8c58d57, 0xbf2ec0dcdbb7c5fe),\n", "(0xbb7cb6e04f4b97e8, 0x3ed34e966b0b09f8),\n", "(0xbb7a79e09bd0a7d3, 0x3ed135c64dc2d8d0),\n", "(0x3b01284c6af65eda, 0xbe75f7bc78b5fc2b),\n", "(0xbaf68597192a53a4, 0xbe67dc35b0764096),\n", "(0xbaab08d1b3bdd3d7, 0x3e0e6d697361ea54),\n", "(0x3a825acf92327a4e, 0x3df679e3704987b4),\n", "(0x3a25a180ac4a289b, 0xbd9c595f278a4d6c),\n", "(0xba0b8a094432fbc2, 0xbd7ea36aef56eec0),\n", "(0x39c8d7c90342cb95, 0x3d22fd66b4e62185),\n", "(0xb99cefe59fbb0bf2, 0x3cffa04c9faacec1),\n", "(0x3947eb4362c2f94b, 0xbca32f47f03857d7),\n", "(0x3912dc0b9f745208, 0xbc799658479ebb31),\n", "(0xb8ab4e5c1533c13c, 0x3c1e4c26032e5de5),\n", "(0x389fabe9c1dc18b3, 0x3bf0ab1b47f9c785),\n", "(0xb83bf6eec6ed25da, 0xbb933a3c78295756),\n", "(0xb7f90ac82d0d0179, 0xbb61de19b957005d),\n", "(0x37ab71627757371c, 0x3b040e310c05ed67),\n", "],\n", "[\n", "(0x35ac924d3bf8bf5b, 0xb900f098dc38e480),\n", "(0x3c6a47ab4241a9f5, 0xbfc5664e13b70622),\n", "(0x3c04d78c254f4422, 0x3f6e16555e108dc6),\n", "(0x3c1fe75afd6ce0fa, 0x3f9c5e1ad9fb2f40),\n", "(0x3be099fe50e43632, 0xbf43d369f958e56a),\n", "(0xbbf3ed70de366684, 0xbf566f4ec27a96e9),\n", "(0xbb9b30f071ce70bb, 0x3eff0de0532652d5),\n", "(0xbb747f8eea3cc056, 0x3f00cf264341409e),\n", "(0x3b4f2ff7c971467d, 0xbea6f46d51e5766f),\n", "(0xbb3708c3f9c7bd34, 0xbe9d407f7c248d45),\n", "(0xbaee70df563a5b0f, 0x3e43a33cd9df6696),\n", "(0x3ad300d61c332fb0, 0x3e309901b0a816e5),\n", "(0x3a69fdf1dd8c15b3, 0xbdd5d856a58443f5),\n", "(0xba3f02f5ec08db44, 0xbdba7cbcd8fc0758),\n", "(0xb9fcaa58f7c81511, 0x3d610b62c2fd47f6),\n", "(0xb9bf896eb454c48a, 0x3d3f56a09da19f70),\n", "(0xb97cb0796a5c153d, 0xbce3ae6849b36426),\n", "(0x39389530ecefefbd, 0xbcbc977524a64328),\n", "(0x390af889f4247b24, 0x3c617fc9db74cefd),\n", "(0x38de6ffabef002da, 0x3c34bbe426d77a28),\n", "(0x387b388027811ac5, 0xbbd8b5659628a8e3),\n", "(0xb83cddf274f119b8, 0xbba87bcc22e21171),\n", "(0x37ec559bf73a5d47, 0x3b4c62cff42626ad),\n", "(0x37656c3911a78ec3, 0x3b1800b5df5b52ae),\n", "],\n", "[\n", "(0xbc4f6f339127993d, 0xbfc4b71d4ca2cc69),\n", "(0x359c1da4eb8655d5, 0xb8f3a018f8f76877),\n", "(0x3c5422c1a1ae8ec4, 0x3fb4ae245697fba6),\n", "(0xbbf4ff572c18742a, 0xbf5215e4e1a5f1d6),\n", "(0xbbf259ec9ab217a9, 0xbf7b633ed6d9cf61),\n", "(0x3bab33aa46f3e729, 0x3f1c7f17b4b7dbbd),\n", "(0xbb79333ace27b68d, 0x3f2ce01b8b6aa34c),\n", "(0x3b5f4e5e8507bc88, 0xbecfced71b11e35b),\n", "(0x3b57f324d6293b07, 0xbed03c9d5823261d),\n", "(0xbb15cd82948c15bb, 0x3e724508091063b2),\n", "(0x3b02ba31739f7dac, 0x3e66a2d20111e303),\n", "(0x3aae84f884334dbd, 0xbe0995a18f8e6888),\n", "(0x3a67a35968d37628, 0xbdf572d1a074f647),\n", "(0xba3a336c953bedde, 0x3d981df03c1911f1),\n", "(0xba104dc5bcacab30, 0x3d7d6895e48f475d),\n", "(0x39c36eea9cd69feb, 0xbd205887f0b3df78),\n", "(0xb98ded8dfba53f0d, 0xbcfe86703ddf1bbb),\n", "(0x394a6d81e9b745de, 0x3ca0b3c70ca73df2),\n", "(0xb91aba894f18e42b, 0x3c78d28ba328c189),\n", "(0x38aea5b88a7dff57, 0xbc1aa9275d6882a0),\n", "(0xb88b4724ad7898dc, 0xbbf03e89774aa977),\n", "(0x3836acf6717c7348, 0x3b911679204a4a38),\n", "(0xb7fc2c9e5a53a6f2, 0x3b617bd36a04e549),\n", "(0x37a2112e77b7283b, 0xbb01fc50745d8566),\n", "],\n", "[\n", "(0x357f9e30ee0b6fbb, 0x38e84b55d671e3ab),\n", "(0x3c6316f8ffd294bc, 0x3fc40f90793605bb),\n", "(0xbbd411ad350e6def, 0xbf68c833077fbeae),\n", "(0x3c051eb6f09db1a0, 0xbf9aa0ce0421d1a8),\n", "(0xbbec0fe78acda469, 0x3f405fa598ef5d1d),\n", "(0x3bff2085596ae958, 0x3f551d30d78ab526),\n", "(0x3b92b31b33779fc8, 0xbef9c5807675c5f6),\n", "(0xbb7cb5b0088841fe, 0xbeffc1bbf57e3ae2),\n", "(0x3b3cc2b42d9f0f1a, 0x3ea32dfea2518ce6),\n", "(0x3b18c85914c086a8, 0x3e9bc212085dcbc6),\n", "(0xbaed44a5431df5e5, 0xbe408b946d64c5c2),\n", "(0x3ac14bfc6bd39224, 0xbe2fa8f9d8da736a),\n", "(0xba679104007a668d, 0x3dd293fe14af1d0f),\n", "(0x3a2b5ef4a8a2fdf9, 0x3db96544cb75a58d),\n", "(0xb9d2b2107643b642, 0xbd5d4750748e2ce8),\n", "(0xb9d8369e87f01d70, 0xbd3e341812329072),\n", "(0x398c6f9e47f04995, 0x3ce112aa495187a4),\n", "(0xb950e224f8078ca7, 0x3cbbb1656dc67704),\n", "(0x38e16eb1b3f03824, 0xbc5ea7b98f478c96),\n", "(0x38b9cf2d9132a338, 0xbc342cad7eaaf63a),\n", "(0xb82267864912b80e, 0x3bd5d798d87eadd4),\n", "(0xb83715c9cdc64b23, 0x3ba7ec2199e9d0da),\n", "(0xb7e050cf70a270e2, 0xbb494f3573e03531),\n", "(0x379b105713845f41, 0xbb178a4eaef852c1),\n", "],\n", "[\n", "(0x3c4f5ffd019535e2, 0x3fc37dfa8f5a550a),\n", "(0xb5701036f2fd5ce7, 0x38d71a135ef735e1),\n", "(0xbc5c4cd2161ee713, 0xbfb3775c1a04f09c),\n", "(0x3bd3d562913301ed, 0x3f4e2b4810a46c60),\n", "(0xbc1b976f3317abb9, 0x3f79d151a72b83a8),\n", "(0x3bbcef8b523f5a0b, 0xbf17d8e5a090e4e6),\n", "(0xbbcb7ef16d9cb057, 0xbf2b49a6427386a0),\n", "(0x3b59248209e494f4, 0x3ecac10957ddd2eb),\n", "(0x3b424396e09f7471, 0x3ececa620745d3d3),\n", "(0xbaf3438d41f60802, 0xbe6eefc7e795dcdd),\n", "(0x3ae3b35ebff03a32, 0xbe658c5d2a0da41d),\n", "(0x3aa0b413dedd34fc, 0x3e05d4721f44a8f9),\n", "(0x3a892a275db60362, 0x3df481ce2314af59),\n", "(0x3a3feec436d1ef8f, 0xbd94c0d3279e920d),\n", "(0x3a19e07a129c683f, 0xbd7c3ea707530563),\n", "(0x39a52b925c059e39, 0x3d1c61d5b165f7da),\n", "(0xb94e05a7550119da, 0x3cfd72bf189b67b4),\n", "(0xb9108732c7d2e8ad, 0xbc9d427a9769e9ed),\n", "(0xb91f784bb6f88124, 0xbc780c9653705698),\n", "(0x38b8d964fc9666c3, 0x3c178e36fc02b9df),\n", "(0x38865f872c0449a7, 0x3bef9a2c168b6442),\n", "(0x38235589e9a3fa21, 0xbb8e71f82f6f0229),\n", "(0x37fbb8f42441d570, 0xbb6111ac11e28162),\n", "(0x377b5f7617aeeb8e, 0x3b0025a92b5f22a5),\n", "],\n", "[\n", "(0x35952cb8f89f3c55, 0xb901222bb44bcf14),\n", "(0x3c689d1f48185c7e, 0xbfc2f2072e638cf4),\n", "(0x3c0f48257333acd5, 0x3f64df208bbd44f1),\n", "(0xbc282c4cf012e7aa, 0x3f992bb5e1e159fc),\n", "(0x3bb5967313b48e35, 0xbf3ba181c06897cd),\n", "(0xbbea6566cfb06bed, 0xbf53fe9d5baa4a3d),\n", "(0xbb98b4ff1892c87c, 0x3ef5d17602b01cac),\n", "(0xbb84f1d79d1c68cf, 0x3efe26d3747fe829),\n", "(0xbb47899cac28d06e, 0xbea0509768ab6ecb),\n", "(0xbb30edc18e594fda, 0xbe9a70f232d9d06c),\n", "(0x3adf4967ed4b405c, 0x3e3c509252de33f9),\n", "(0x3ac643cb92fae2ea, 0x3e2e454fee07116e),\n", "(0xba7c2d5f536fab40, 0xbdd0015b062ba125),\n", "(0xba43993ecbbb44ab, 0xbdb860e95adf840f),\n", "(0x39fd1ca7896c45b4, 0x3d59691e90f7d9c0),\n", "(0x39bccb74999a40d8, 0x3d3d1ce7997b3c0d),\n", "(0x397d856301e23d11, 0xbcdddcd1c54cee54),\n", "(0xb958f0d58afd0876, 0xbcbacd10a03552dc),\n", "(0xb8f2692f00e7abd7, 0x3c5b043a7a08961a),\n", "(0x38a216228008b2d7, 0x3c3399ba2ef94a8a),\n", "(0xb87b2260cea416f3, 0xbbd3650fec070f67),\n", "(0xb84885e84e43eded, 0xbba7538b0e0444f1),\n", "(0x37e7ac0e69e3062b, 0x3b46a2dce760f8a5),\n", "(0x37b02054fc976f06, 0x3b1707ea3ba222e3),\n", "],\n", "[\n", "(0xbc6b9fbd89653a0b, 0xbfc2768d29c69936),\n", "(0xb5883d7e7aae0fdd, 0xb8ec8fe2d361f507),\n", "(0xbc592c5350d4d775, 0x3fb271811730b0ef),\n", "(0xbbcd42067c3280c8, 0xbf49a8df96a1225e),\n", "(0xbbde819659787fc8, 0xbf787c81cf1c6fc4),\n", "(0x3ba0986868518e75, 0x3f14549cdbb77978),\n", "(0xbbcc0c937839cf2f, 0x3f29ed2568116e19),\n", "(0xbb638a1daff4bf5c, 0xbec6e4136f033ace),\n", "(0xbb692b821c2e6f36, 0xbecd53330316cde7),\n", "(0x3af82b5a8a9ea4e0, 0x3e6a983b5782dfca),\n", "(0x3b0d6817ea51c39b, 0x3e64952ba7c5a1dc),\n", "(0x3a858779f386d0c6, 0xbe02df3ad6f82e0d),\n", "(0xba85be3593e2be88, 0xbdf3a70f9a89d2c2),\n", "(0xba32f63410f44e43, 0x3d920e086c17f5dc),\n", "(0xb9feeb5c5526cc87, 0x3d7b29a554c1159f),\n", "(0xb9b6a518f14f6a05, 0xbd18dbe08f4a9f69),\n", "(0x396f8eba4a78c6ed, 0xbcfc6bd9fc45c380),\n", "(0x390a2175db343220, 0x3c99ce5a735b2911),\n", "(0x390e5b428d8e3c26, 0x3c774ade0ebbb04a),\n", "(0x38a68dee1fa00957, 0xbc14eb88e02b008f),\n", "(0x3835846ba71a1987, 0xbbeeb63f264071fb),\n", "(0x38105020072f2234, 0x3b8b39319da680c5),\n", "(0xb80e1b59bc2fb16c, 0x3b60a4325ae8cea7),\n", "(0xb79ae8092aa3eb9d, 0xbafd11021ccd9832),\n", "],\n", "[\n", "(0x359a05b7bb6a66e7, 0x38ff07a73b062717),\n", "(0x3c51f9b16832f362, 0x3fc1ff5eec6a01cd),\n", "(0xbc0f89ce0d1cb83e, 0xbf61e438b722c3b5),\n", "(0x3c39a4b7b3ed5b9d, 0xbf97ed5fffc1c774),\n", "(0xbbdc35d9a8dca8fd, 0x3f37b7997babd9ca),\n", "(0xbbe39da4066981e2, 0x3f53081def9612c5),\n", "(0x3b8551b9a497b582, 0xbef2c5f5edafc4e9),\n", "(0xbb9dbae692eab5c3, 0xbefcc11a59e13739),\n", "(0x3b351580930803f5, 0x3e9c2c3a1b8014a3),\n", "(0xbb333a214b9dbd86, 0x3e9946d1dab7bd01),\n", "(0x3ad8fc5f68299915, 0xbe388db61946be64),\n", "(0x3ac5620984f97782, 0xbe2d04d33be580e8),\n", "(0xba6d7f1c30d157b7, 0x3dcbe64386d2c5d0),\n", "(0xba48b7e9cdf3e557, 0x3db77142e0e4497b),\n", "(0x39fe42ca4fdc0820, 0xbd56458476679697),\n", "(0x39cde02178f2e8a7, 0xbd3c15e96b25adba),\n", "(0xb96d7f2805e659cb, 0x3cda545e6ec71d21),\n", "(0xb95169031622e59c, 0x3cb9f0a9b74e034f),\n", "(0xb8f6c8c4cb1d2951, 0xbc57f751eaad5943),\n", "(0x38b9f3826864d2b2, 0xbc33083bfba900b3),\n", "(0xb83ad0a2f62d2470, 0x3bd14f7886799e5e),\n", "(0xb846ea6a99d583b1, 0x3ba6b8756a3461ea),\n", "(0xb7bff8edb785364b, 0xbb44533c12e31410),\n", "(0x37b9373ae2b3a681, 0xbb167fc01d26c703),\n", "],\n", "[\n", "(0x3c54fa3fb220c497, 0x3fc194eba75b32f9),\n", "(0x35968efa101689a5, 0x38fdc9a2706a3090),\n", "(0x3c59f5fdd12caa11, 0xbfb190f7dc27362b),\n", "(0xbbd96244746ca1b2, 0x3f462bb47a5c5f7f),\n", "(0x3c106edbe0bb689e, 0x3f7756ef20f5d2e2),\n", "(0x3bb1231bc44f6f51, 0xbf1198b0ba97ecfb),\n", "(0xbbafcaf4935a1752, 0xbf28be8cf9358d55),\n", "(0x3b341ada5c144f0c, 0x3ec3dd6f7c8cc3c0),\n", "(0xbb22797862876f18, 0x3ecc09c80ee7f9af),\n", "(0xbb04005395d49e04, 0xbe6728e46a451e32),\n", "(0xbb056333198576a9, 0xbe63b91113508622),\n", "(0xbaa195a6693f0d85, 0x3e0080fddad62bf8),\n", "(0x3a8352e1bf38cbc8, 0x3df2e111e88dae1f),\n", "(0xba2109236d67d65e, 0xbd8fbae88bdab215),\n", "(0x39fdc60e2c5c7d37, 0xbd7a2a4fbea868a8),\n", "(0x39b8e39633481264, 0x3d15f540e9769e8b),\n", "(0x39976a66d79bb910, 0x3cfb74c0b2686df3),\n", "(0xb92c1d434c75162e, 0xbc96eb75a7dd13a2),\n", "(0x390c7fe154372598, 0xbc76910c1dc865c3),\n", "(0xb8a43f5790d81d03, 0x3c12af36490b5c71),\n", "(0x3886f89d2e40041f, 0x3bedd7036ea48d55),\n", "(0xb82a048b55f91332, 0xbb88734f1fdd1068),\n", "(0xb7dfa5ba1f878585, 0xbb6036af368c39fc),\n", "(0xb7993db41d2f7ce5, 0x3afa3fd8a11def52),\n", "],\n", "[\n", "(0xb5745b4e1af1b85e, 0xb8d7a991cf97ce2e),\n", "(0x3c6e71c482be67bd, 0xbfc12dd57bf18ada),\n", "(0xbbe9a8a827c4a2d4, 0x3f5f1e1e7f393e83),\n", "(0x3c3286f932bea2b2, 0x3f96d9afe88301fa),\n", "(0xbbd360330deffaa0, 0xbf34a538a482979b),\n", "(0x3bef838ddd540b11, 0xbf52316250b4ae37),\n", "(0xbb94c13fb3eaf5ab, 0x3ef05f11577b4627),\n", "(0x3b6771ef99211bfa, 0x3efb86bad42fc220),\n", "(0x3b1a6b7e5cebbbf8, 0xbe98a1b3a9e92749),\n", "(0x3b32d778489fadef, 0xbe983dcaf3f8fcc5),\n", "(0x3abceef7b37a414b, 0x3e3589a7ca5fdcf1),\n", "(0x3ac97ff4495956a4, 0x3e2be3ee3298bb99),\n", "(0x3a6770b1a9ab05ca, 0xbdc8913f1d0ff12a),\n", "(0x3a430c1f9492528b, 0xbdb695c386660813),\n", "(0xb9fd8f50c7d974dd, 0x3d53b25d364762e7),\n", "(0xb9d664d160d01e32, 0x3d3b20c42e642ccd),\n", "(0x397bc60dbe38d043, 0xbcd7650532b4f1e0),\n", "(0xb920283e56ce5b47, 0xbcb91f514b70b40a),\n", "(0x38fcae3e188ec691, 0x3c55661aac4dcfde),\n", "(0xb8b0ad982f98ebec, 0x3c327b48d9478b06),\n", "(0x38441168fe323c23, 0xbbcf11115f1e0760),\n", "(0x383a0b5e44af3cea, 0xbba61f1bd02130ad),\n", "(0x37eb4e4f03156997, 0x3b4254646f0f97c7),\n", "(0x37b0ea6aa46492cb, 0x3b15f63be5634cd2),\n", "],\n", "[\n", "(0xbc27736b1f56d701, 0xbfc0d0d36473e98c),\n", "(0x356c9dc61ea15303, 0xb90248314540cb10),\n", "(0xbc517d3bbb8e7764, 0x3fb0cda9974abe2b),\n", "(0xbbe2a43b589b29f9, 0xbf4367f38f201c25),\n", "(0xbc17d1323005eae7, 0xbf7656b75e3c242e),\n", "(0x3b94b9f5a7acb7cc, 0x3f0ed82abf7489f1),\n", "(0xbbcb0bedf1c81292, 0x3f27b4e5b83eeb36),\n", "(0x3b0621247626b416, 0xbec171fd0fb670e7),\n", "(0xbb638b7d64b281f7, 0xbecae62b4ad017fb),\n", "(0x3b0b83d61a6ff722, 0x3e64648495a7b49e),\n", "(0x3b05f0212db7e5c2, 0x3e62f42a577135ad),\n", "(0xba76b0fd54cd9d5a, 0xbdfd286e7fa32656),\n", "(0xba30ca02b11abb11, 0xbdf22dbcbf76a1c7),\n", "(0x3a27e83235238ba2, 0x3d8c222accc0d2d2),\n", "(0x3a056929761e3d77, 0x3d793fc7f6c8d355),\n", "(0x39bc237122bbb790, 0xbd138c7e1f668eb4),\n", "(0xb99070434bc7e0cc, 0xbcfa8e4efc6deb61),\n", "(0x3935816fed04585f, 0x3c947e808eb72ce3),\n", "(0xb91069ce4b7c1dbd, 0x3c75e0f075f73393),\n", "(0xb8ab681bd123ab34, 0xbc10c866ba43aebb),\n", "(0xb87344f73adf2486, 0xbbecffe1c0e02083),\n", "(0x3821df2bad78c005, 0x3b86102f988e0a87),\n", "(0xb7f3ec5f37bb8303, 0x3b5f96a57efd09fb),\n", "(0x379def01809beed4, 0xbaf7cbac5fb57a91),\n", "],\n", "[\n", "(0x35391b3b00fc7751, 0xb8c00dbc5df9a26a),\n", "(0x3c61a13e2fee5687, 0x3fc076826cc2c191),\n", "(0xbbcb789ffb667f58, 0xbf5b62885e0070c6),\n", "(0x3c35dbe9d7210c2e, 0xbf95e7f53001e4b1),\n", "(0xbbddb8eb1d2032f3, 0x3f322ebeb8dc2202),\n", "(0xbbf72618e87154fc, 0x3f517444a7a04cd0),\n", "(0x3b7b01e81c8c370d, 0xbeece06f1f1fcd7e),\n", "(0x3b80168184fb2a2f, 0xbefa7006e6ad9cfe),\n", "(0x3b13ac36b9efbb35, 0x3e95c42f02cf15ca),\n", "(0x3b08b69b698a2f2f, 0x3e9750ca5e1366b4),\n", "(0xbac08a205d6fbd27, 0xbe3314982df7eaa2),\n", "(0x3abf2c98d7c5b0b0, 0xbe2aded75306b3b3),\n", "(0xba2551d965dce668, 0x3dc5d47847d8ebf1),\n", "(0x3a2b475ee50f9af2, 0x3db5ccf44d287a21),\n", "(0x39d9490ac846b5fb, 0xbd518fce3e04028a),\n", "(0xb9d525cc1707dd4e, 0xbd3a3d6bcad0c3fc),\n", "(0x39615f1fc81188f8, 0x3cd4efbd76727c05),\n", "(0x3954cf183e4c6eef, 0x3cb85a4b163fcc04),\n", "(0xb8eb35201a650448, 0xbc5339ddeca79d0a),\n", "(0xb8df2fda8e574f19, 0xbc31f48b47bc4419),\n", "(0x384d7bc59effa619, 0x3bcc06bd6710b45b),\n", "(0xb84a385b5ed821eb, 0x3ba58a1ad9e65449),\n", "(0xb7c4e5225bdf41b3, 0xbb409abe2b8be0ed),\n", "(0xb7ba1343bcfa4e16, 0xbb156e575d965e88),\n", "],\n", "[\n", "(0x3c61a6e02553980f, 0x3fc02455675ab6d2),\n", "(0x35884b224ed40dc9, 0x38eb5eb0626a64d4),\n", "(0xbc5a58b3083e7e3d, 0xbfb021c155a720df),\n", "(0xbbea19c1039d30bd, 0x3f412be56fc1449a),\n", "(0x3c01bad3e8f9abb9, 0x3f75749d556ad61c),\n", "(0xbb75621370147dfe, 0xbf0b51f1f9bea93e),\n", "(0x3bc81ccb29b6a851, 0xbf26c96a07e236bd),\n", "(0xbb218064e9ecad2c, 0x3ebef3a7abd5ac6b),\n", "(0xbb6f6ed0aeaecba4, 0x3ec9e207c257433a),\n", "(0xbaf0aed16a93326e, 0xbe6220b96eef8058),\n", "(0xbad4d7e3d546f2c4, 0xbe624317cb296737),\n", "(0xba91f73fb3d22bed, 0x3df9fc2f2cd3917f),\n", "(0x3a9403e6cf9143a4, 0x3df18ae8347e8256),\n", "(0x3a2f17c7d5411c26, 0xbd892540423f2dda),\n", "(0x3a04a4080028f5b2, 0xbd78687dcdc2e3a9),\n", "(0x39a201bd34791753, 0x3d1187909103d474),\n", "(0x39844a97e12dfc96, 0x3cf9b8362872c324),\n", "(0x393da5147587382e, 0xbc92711ecdaaeca0),\n", "(0x38fae8f5aa2732b8, 0xbc753b342a24814e),\n", "(0x388ad67623e40669, 0x3c0e50eba2ee4760),\n", "(0xb86ad1f354cf2e6b, 0x3bec32aa5f596a62),\n", "(0xb8257b3c1a8fb2c7, 0xbb8400cf17d2fcd3),\n", "(0x37f2a48d3485143a, 0xbb5ec6ef456ce7f9),\n", "(0xb79fa0988ef64e6e, 0x3af5a82ff0aad8bd),\n", "],\n", "[\n", "(0xb57640b478e02a1f, 0x38d6a301383ff88d),\n", "(0x3c5d7cc4171715a0, 0xbfbfa8b41711c83a),\n", "(0x3bf6219a48a25ba1, 0x3f5857d3969997d1),\n", "(0xbc395ccf34fc85bb, 0x3f9511c6dadaaa12),\n", "(0x3bd13cc55ae24369, 0xbf302c289dbdbd4f),\n", "(0xbbde8aacf935744f, 0xbf50cc2238d229f9),\n", "(0x3b831f1c91d27574, 0x3ee9b64d5c63668f),\n", "(0xbb967f7ad529fbab, 0x3ef976fb023f0f79),\n", "(0xbb26431725df20f0, 0xbe93693ba0b5ba70),\n", "(0xbb30bc5202714831, 0xbe967b952987350c),\n", "(0xbadfac3d160cee71, 0x3e310cb79a2addac),\n", "(0x3abbc10a636cca3c, 0x3e29f2079f8e397f),\n", "(0xba6f1f3686791203, 0xbdc38d957eaa53ad),\n", "(0x3a5a464b4d5f0cbd, 0xbdb51511e93ba74c),\n", "(0xb9d76cb5fc51dd5d, 0x3d4f8bb4d9d2f3a4),\n", "(0x39d5f6bc31063165, 0x3d396afe82155a3c),\n", "(0xb9789c1d34756db7, 0xbcd2dc3c5a412fc8),\n", "(0x394e5ac9a5d43674, 0xbcb7a1c8dec76ff7),\n", "(0x38fa62b937a855d9, 0x3c51600c3d779ccc),\n", "(0x3891168a3d883e25, 0x3c3174c64bf0b16a),\n", "(0xb8380d11dc898cc6, 0xbbc969e37524ef7c),\n", "(0xb8337a7c5fb777c9, 0xbba4faf03e3cc2d5),\n", "(0x37d9f91b76239dc9, 0x3b3e37a63e276939),\n", "(0x37b81fff9e082645, 0x3b14e9f8e51a9731),\n", "],\n", "[\n", "(0x3c50e4250a158a22, 0xbfbf161d0c28b48c),\n", "(0x3588b2630fb1ecb4, 0xb8fcdc55525190c5),\n", "(0x3c421e360c4c70dd, 0x3faf11d837aa6f64),\n", "(0x3bd18f48c3547c45, 0xbf3eab76da4d07a0),\n", "(0x3c1ebe3b9893ac4d, 0xbf74ab329f067aea),\n", "(0xbb5e80c3b0d6f6c7, 0x3f086ada57bc1c51),\n", "(0x3bc03960ef6e6bc0, 0x3f25f6e78f11ab9a),\n", "(0x3b5e77180c5644f6, 0xbebbb271f54c8965),\n", "(0x3b5cfd1d7da5a2ee, 0xbec8f85328c26cb7),\n", "(0x3b05a5d710343230, 0x3e603f82aebdeac1),\n", "(0x3b008f5133b080df, 0x3e61a3010279a195),\n", "(0x3a8746b6f6e07b70, 0xbdf75660809cdedf),\n", "(0xba824b566432a315, 0xbdf0f6931774a05f),\n", "(0xb9f3c0bb6b052f2c, 0x3d86a2e61267070b),\n", "(0xba1950de7a0ba4a4, 0x3d77a2a8e0311c3a),\n", "(0xb9a048f7d1f2b252, 0xbd0fa4c8e3ce0140),\n", "(0x3973ca66f22df187, 0xbcf8f1926f4e33ae),\n", "(0x391f7bbe0252e068, 0x3c90b165b2615bc8),\n", "(0xb90630bee239e401, 0x3c749fd329a93d0e),\n", "(0xb8723f37b0afb367, 0xbc0b864a393597bd),\n", "(0xb88ea6b58b8f277b, 0xbbeb70236cfe6bd6),\n", "(0xb81ff9b7e892d837, 0x3b823801bcba96ae),\n", "(0xb7f460e58de7fcd8, 0x3b5dffc2deb31092),\n", "(0x379c28f920f7c081, 0xbaf3c9fe3b84a659),\n", "],\n", "[\n", "(0xb57bd9f791078c7d, 0x38d74664ec9bed14),\n", "(0x3c0020b4016594ac, 0x3fbe8727daa3daed),\n", "(0xbbea4d873618788f, 0xbf55d353e2854a37),\n", "(0x3c3361836c532514, 0xbf94524d4813cc25),\n", "(0xbbb70735fa989563, 0x3f2d037574e28370),\n", "(0x3bf7f1d7c0f30b41, 0x3f50356bb747a763),\n", "(0x3b73015c07f2d91b, 0xbee7156bfccef376),\n", "(0xbb99523f4f9b3609, 0xbef896d7dc819faf),\n", "(0x3b307f0e451ebc2a, 0x3e9172c6dadf4149),\n", "(0xbb334d6933f971d7, 0x3e95baae8efc2e31),\n", "(0x3aba01d72c453106, 0xbe2eb347eb4d6941),\n", "(0x3acc3dd30f660e51, 0xbe291a60a72a20e0),\n", "(0xba0f68f511402a90, 0x3dc1a345a9a6a5f7),\n", "(0x3a3173892dc95a66, 0x3db46c56b01906be),\n", "(0x39d1db37247899b5, 0xbd4c84bb37677838),\n", "(0x39de56935f64b195, 0xbd38a83e6e4c168c),\n", "(0xb968986bb0f698d5, 0x3cd11796d017a52c),\n", "(0x394e35cdfe4ad2e0, 0x3cb6f5675cf3bead),\n", "(0xb8e0c38450c266b7, 0xbc4f936d06630982),\n", "(0xb8da35936b142aeb, 0xbc30fc2f8042c9f9),\n", "(0x38692f73e25e293e, 0x3bc7281c276f90d6),\n", "(0xb8390095011ee718, 0x3ba4725b73c87824),\n", "(0xb7a6c2d5c298847c, 0xbb3b9d22918ceeba),\n", "(0x37901e1a341f19f8, 0xbb146a436f16dfe0),\n", "],\n", "[\n", "(0xbc5b4c98f0d3c4c3, 0x3fbe0357c158b119),\n", "(0x3583cebeaacf2fa8, 0xb8efc7d3f760c89c),\n", "(0xbc410072ccb88630, 0xbfadffc2fc1a91f5),\n", "(0x3bd769e0c0dbfe1c, 0x3f3b9b82ae07da44),\n", "(0xbc02d8dbfa194096, 0x3f73f64e05320ac6),\n", "(0x3bafe44f6e4f7a6d, 0xbf05fe4b66cf19d9),\n", "(0xbbc540e88468d2a5, 0xbf2539518e1b00f5),\n", "(0xbb397c60f4bd9fcd, 0x3eb8f8d01c487905),\n", "(0xbb5e1765287d55c8, 0x3ec825045b97e2dc),\n", "(0xbad349d279137fbd, 0xbe5d565f3bb61dea),\n", "(0x3af6ef17211ae45b, 0xbe611186586f4f74),\n", "(0x3a9d5c753068eefb, 0x3df51a669158191b),\n", "(0xba9c8af441d79379, 0x3df06ef52f6715ac),\n", "(0x3a0be37a7ebfa57f, 0xbd848215e95caa77),\n", "(0xba12aea2c5547dd9, 0xbd76ec8422019b0d),\n", "(0xb995ce432bf4ea43, 0x3d0cbaf5fc139339),\n", "(0xb9937ae255b6301e, 0x3cf8393ffa4f5afd),\n", "(0xb92ae7fb140219c1, 0xbc8e6232fb7e093b),\n", "(0xb8f4f418e0ddb215, 0xbc740e69bcb200c8),\n", "(0x38ab0659f3e0af92, 0x3c091cd1de02ebf5),\n", "(0x388ccf22ef87b9fa, 0x3beab86d72560db8),\n", "(0xb82e0b1ad1c5038b, 0xbb80aa949dd60551),\n", "(0xb7d9ff00c88f4aa2, 0xbb5d41db239438ec),\n", "(0xb79bfe1d2d6ef829, 0x3af2270328ec903e),\n", "],\n", "[\n", "(0xb5ac5e4a2e275705, 0xb9005c1969d4e17b),\n", "(0xbc5cb1f28997ca39, 0xbfbd8293aa55d18f),\n", "(0xbbd0e0b711c0f01a, 0x3f53b6beb83f2596),\n", "(0x3c36c091c5e2bd3b, 0x3f93a5ccbc12a67b),\n", "(0x3bc80bb5066b1aa8, 0xbf2a3765d26aa42b),\n", "(0x3bc464654b3f4248, 0xbf4f5ab33748c215),\n", "(0xbb86c3ad1bc53ee0, 0x3ee4df6f1c257a5c),\n", "(0xbb9372510d6e3ed7, 0x3ef7cbd49c315be0),\n", "(0x3b1dfc7e29b94af4, 0xbe8f96098cf07175),\n", "(0x3b0aec3564d78716, 0xbe950b37dd43531f),\n", "(0x3aaa5efe8cd0d0ca, 0x3e2bd2e6405c605d),\n", "(0xbab9fdafce391124, 0x3e285530df0d4b70),\n", "(0x3a6ec037594c88d5, 0xbdc0029e21930f25),\n", "(0xba5f6bee6aa06bbf, 0xbdb3d11aeba731a1),\n", "(0xb9ee33d66b9efc78, 0x3d49ef077e065d17),\n", "(0xb9c765f6255cb3d1, 0x3d37f3d211d80ca6),\n", "(0xb95ffeb5c7b606b6, 0xbccf2617ced04ef7),\n", "(0xb95d433df855b01a, 0xbcb654785f90474d),\n", "(0x38a47f029dbdf48b, 0x3c4cd5d490baf361),\n", "(0x38d6ed83985660af, 0x3c308aa98d1885fa),\n", "(0xb81200c557f40391, 0xbbc53243b8f4a2ce),\n", "(0x384da8d1f6aaa7a2, 0xbba3f0a1e04e0f85),\n", "(0x37ce2a379bc1d480, 0x3b39568fa5547980),\n", "(0xb7a7c00b2c409082, 0x3b13efd3e10a8faf),\n", "],\n", "[\n", "(0xbc57ac02118ce034, 0xbfbd0b36e5737458),\n", "(0x355dad3277703540, 0x38d5fb77d2e0e26b),\n", "(0xbc494ec699987c67, 0x3fad082ce3c6b59b),\n", "(0x3bdbdb6b7d6d9ed8, 0xbf3905d00c5e6800),\n", "(0xbc14d8fddd68c49d, 0xbf7352b073fdac7b),\n", "(0x3ba8a390eb7c2b92, 0x3f03f1ccfec2fc88),\n", "(0xbb8f7492cb6fd0c1, 0x3f248d74583834bc),\n", "(0x3b536c4ae37b379a, 0xbeb6a9ef0d896bae),\n", "(0xbb686d0e0d1bf502, 0xbec764d9798d6a80),\n", "(0xbaf460a4621e034f, 0x3e5aa785d6736f5c),\n", "(0x3b035fd3f6a4b201, 0x3e608cae36118cdb),\n", "(0x3a9d857819eb2176, 0xbdf332ddfb39cd01),\n", "(0x3a737fa058aa2bf7, 0xbdefe502ff1a8f0d),\n", "(0xb9e58926244b72c2, 0x3d82afc83348eeb2),\n", "(0x3a12be94371e2b16, 0x3d764468c0a31511),\n", "(0x39a6e4a5223f4dab, 0xbd0a399e849c3f2a),\n", "(0x3993f30753f88192, 0xbcf78e09772ae1e8),\n", "(0xb90378dd4b889265, 0x3c8bc9dea67a7452),\n", "(0xb90f40c403d002cc, 0x3c738663e180417e),\n", "(0xb8a2c55a9de7b5bb, 0xbc07042a23846064),\n", "(0x3863528c0f407011, 0xbbea0b467e151132),\n", "(0x38083d5af6007837, 0x3b7e9e53f034f206),\n", "(0xb7fe52cf6cca2436, 0x3b5c8d6dc762abf9),\n", "(0x3781845e75790839, 0xbaf0b68e9fe150d5),\n", "],\n", "[\n", "(0x359b9f4f66331222, 0x3900369fa71bf644),\n", "(0xbc49df1f0f8d2108, 0x3fbc96700bf039e2),\n", "(0x3bd298b7ed2d16c5, 0xbf51ec0b5de4befe),\n", "(0xbc26397704521ddc, 0xbf93095734a24496),\n", "(0xbbbe43e747e8c9b8, 0x3f27d74e12285cb2),\n", "(0x3bbff97a4e7e808e, 0x3f4e636fe259352c),\n", "(0x3b74153b68748e94, 0xbee2fe11972bc0c6),\n", "(0x3b833d879080abe9, 0xbef712e4d44c4a74),\n", "(0xbb0f13d0520649e9, 0x3e8cc3adabae0452),\n", "(0x3b2bb2db97d7803d, 0x3e946ad2d9cbeb5c),\n", "(0x3aba423494626154, 0xbe295d81ae83f621),\n", "(0xbab425671ce4734d, 0xbe27a02aefea3d60),\n", "(0xba5a8cbe07596457, 0x3dbd3a949a72239d),\n", "(0xba589ce4399c7b23, 0x3db341e0bb193b49),\n", "(0x39c60f1c6ee12738, 0xbd47b550a4f77497),\n", "(0x39b9524731c89f4a, 0xbd374c654a2656ac),\n", "(0x396b773706300926, 0x3ccc861736a2cb66),\n", "(0x393ffcb4d6c5437c, 0x3cb5be2db467cb27),\n", "(0xb8d79e659806e4b3, 0xbc4a7433021b81a8),\n", "(0x38d24a44d0a8359e, 0xbc301fe901a012cf),\n", "(0x385ca56d7686e059, 0x3bc37bf8ae8852f8),\n", "(0x3823e08435643d0a, 0x3ba375bd0bad91a1),\n", "(0x37af4610bb7d3555, 0xbb37570ac69055a0),\n", "(0x37aa35e716b3a1f5, 0xbb137aed9b4389e6),\n", "],\n", "[\n", "(0x3c2c279ff462c3c0, 0x3fbc29ae8400a320),\n", "(0x356e0e33fd319cb9, 0xb8d9231986c55c3a),\n", "(0xbc47ac9bcf34430d, 0xbfac27138da31c2b),\n", "(0xbbbe5ab192b0135a, 0x3f36d141fcbea853),\n", "(0x3c12b724fd75b152, 0x3f72bdc71062acd6),\n", "(0x3baf5f2a5ef8fa68, 0xbf0231cf643ffc17),\n", "(0x3b6e53f54e3bf9fc, 0xbf23f0bf3b3fe8be),\n", "(0xbb4cfe2b683d9564, 0x3eb4b05e955de175),\n", "(0x3b6d19f537fcf89e, 0x3ec6b52b868fa5e2),\n", "(0x3afd6a6cb52830e5, 0xbe585a7aa3e84cc3),\n", "(0x3afd15d476513524, 0xbe6012d3384c9164),\n", "(0x3a5b65df2e4e4330, 0x3df18f8c4872544f),\n", "(0xba81d06080a51e9d, 0x3deeffc4029f2f06),\n", "(0x3a249fcb796b8760, 0xbd811d5a3daf70fa),\n", "(0x3a00e5fc84cbd7e0, 0xbd75a8d84ce12a33),\n", "(0x39aac0f727b50a5e, 0x3d080dfa27f213b4),\n", "(0xb98deba8bfe45bc0, 0x3cf6eec07f1e9fed),\n", "(0x3926f40f27003ad3, 0xbc8987d6f3b6b977),\n", "(0xb900c69dbdeb6cd7, 0xbc7307196963d259),\n", "(0xb8970cc24a5ffc69, 0x3c052f0ef3a48697),\n", "(0xb82c63f97263dd39, 0x3be968357fda6848),\n", "(0x38062270d5c769fc, 0xbb7c3bf907642446),\n", "(0xb7f7074e3e5184fa, 0xbb5be25cb690eabb),\n", "(0xb76e99e1fa5b8f27, 0x3aeee27d7ef3ffc0),\n", "],\n", "[\n", "(0x3538ee4168591cac, 0x38bef99392c87f53),\n", "(0x3c58fff4515190b5, 0xbfbbbf246914235f),\n", "(0xbbb59d638f727e96, 0x3f5062daee35411a),\n", "(0x3c1bef9e896a9a49, 0x3f927a96f174b6d1),\n", "(0x3bc79c688e785f3a, 0xbf25cdb5dea9c121),\n", "(0x3bd1f78082ebf798, 0xbf4d818348f98a0f),\n", "(0xbb8cf93ea6c33ca2, 0x3ee160aab829409d),\n", "(0xbb9dfe5ed028776c, 0x3ef6698d6ee99eb9),\n", "(0xbb0db3033371a004, 0xbe8a5633d8f0b3bf),\n", "(0x3b3148bb33e218be, 0xbe93d788d61154a7),\n", "(0xbabbfbbbe3dfb01e, 0x3e273ec2ae0084b9),\n", "(0x3a5bb0a12307343a, 0x3e26f958f6235deb),\n", "(0x3a36a5b33f99627e, 0xbdbad0939c43a9fe),\n", "(0xba4257e147ffea34, 0xbdb2bd56309cf195),\n", "(0xb9e2488ea9163776, 0x3d45c709d717f2e4),\n", "(0xb9d93a6f276892ca, 0x3d36b0b8fe737496),\n", "(0x3964c91263a6ad47, 0xbcca3cece6eae9d2),\n", "(0xb95aac081c12d91a, 0xbcb531b157cc8875),\n", "(0xb8e3db9a4bc40ecb, 0x3c485f3495a556d9),\n", "(0xb8cf57e3f8bac92a, 0x3c2f771622298662),\n", "(0xb86da2770d25e277, 0xbbc1fb1e956ae1b4),\n", "(0x3836de845e2a3207, 0xbba30179264b3e35),\n", "(0xb7dd698f3e703bcd, 0x3b3593d8b3319ae7),\n", "(0xb79dcfbbb66501cd, 0x3b130b99b87c3b97),\n", "],\n", "[\n", "(0xbc4b1bd5a08c4698, 0xbfbb5b8273b75055),\n", "(0xb579007ca42ecf31, 0xb8f30640d843b3e4),\n", "(0xbc19066393ec82d1, 0x3fab59418c36a684),\n", "(0x3bd4c6e4a4b62a0c, 0xbf34eafeaa92aa79),\n", "(0xbc1e8c2463f82477, 0xbf7235801af9be44),\n", "(0x3b9bcf2d21045067, 0x3f00af9747d0be92),\n", "(0xbbaf406893c94ac9, 0x3f23611db0e1566f),\n", "(0xbb5fa294e3a6cf5c, 0xbeb2fbe414da1250),\n", "(0xbb6579c1dd810ff1, 0xbec613ccbb9cbe59),\n", "(0xbafba31f9ef26cbe, 0x3e565cf274e84d31),\n", "(0xbae9213eec3645d6, 0x3e5f452996e3dc2b),\n", "(0x3a93719707a6b39b, 0xbdf023f5382da3ad),\n", "(0x3a83d3a0c57bd4cc, 0xbdee2be24fbad63f),\n", "(0x3a1e0d9a1a424f4e, 0x3d7f7ed3740f8cf5),\n", "(0xba195448240988be, 0x3d75187e998a1997),\n", "(0xb9a83d289fab0c82, 0xbd06293c9e781b76),\n", "(0x399920ae46c70e84, 0xbcf65a49786c4515),\n", "(0xb9223154eb869eba, 0x3c878dbf0233422a),\n", "(0xb8db7350f762522d, 0x3c728fde2c70ddb7),\n", "(0x389a86a79f193b5b, 0xbc0392b8f6167154),\n", "(0xb883a3fc81fa37b9, 0xbbe8cea59f44a3e2),\n", "(0x37d28560a2d0c913, 0x3b7a213dbaca9263),\n", "(0xb7672b5585eddf9a, 0x3b5b40576765c08e),\n", "(0xb78ee5530750cce7, 0xbaeca1b39264a34b),\n", "],\n", "[\n", "(0x359f12f74a1a873e, 0xb8fd67b1800cc2aa),\n", "(0xbc5024304247ada3, 0x3fbaf9cb49c4f935),\n", "(0x3bd43675d81a390c, 0xbf4e1d930b513228),\n", "(0xbc26b1ae600584f2, 0xbf91f7a8fec6eba8),\n", "(0xbbccaafb65ee566e, 0x3f240a55310866fc),\n", "(0xbbe93eb318fc691a, 0x3f4cb20c812fd3aa),\n", "(0x3b7bc11f6acb6aed, 0xbedff51953c6b6cc),\n", "(0x3b7ca6d60de07627, 0xbef5cdc48f5d75eb),\n", "(0xbb1e5c798f5702c3, 0x3e883b091952c721),\n", "(0x3b392f384e40f60f, 0x3e934fb685e58ab7),\n", "(0x3abc9afeb4201722, 0xbe2566fc4369ab71),\n", "(0x3ac8555b1f6751cc, 0xbe265f0f7de29720),\n", "(0x3a505976fb73241a, 0x3db8b61e5f9b7a00),\n", "(0xba04a898dd824080, 0x3db24253069b78a9),\n", "(0x39bb5929dac6aff0, 0xbd441732d722b422),\n", "(0xb9d662b0ae22d5ef, 0xbd361fa985a16926),\n", "(0xb92bfd8dca36b2a6, 0x3cc83c175673059f),\n", "(0xb956fcc071485aba, 0x3cb4ae32974df1c6),\n", "(0xb8d5a8f989475dc8, 0xbc468a7f73f5be7c),\n", "(0xb8c1d7200f0ee470, 0xbc2eba46ae458bcc),\n", "(0xb8686a635728619a, 0x3bc0a770636ddc81),\n", "(0x3846e16decd06b9b, 0x3ba29388d9fcba28),\n", "(0xb7da9125321029a4, 0xbb34040dedb7bebe),\n", "(0x37af7783c5802665, 0xbb12a1bc8335b315),\n", "],\n", "[\n", "(0x3c5ffacf3e2418f7, 0x3fba9e13a0db6429),\n", "(0xb583910dd6018bba, 0x38e353089e99116d),\n", "(0xbc305f5aef327444, 0xbfaa9c1ca2161b9b),\n", "(0xbbd5ab98ac97faea, 0x3f3344a09efdc635),\n", "(0x3be8bf0e556cf4b8, 0x3f71b82c430a2381),\n", "(0xbb93a99455084734, 0xbefebfb97bca01f2),\n", "(0xbb99136a1ed7b5f9, 0xbf22dcdb1bc1d038),\n", "(0x3b5ea30ecc612715, 0x3eb180047f0b79ae),\n", "(0x3b46ae074e2d9e22, 0x3ec57eeeee84d0d0),\n", "(0xbadb1941bb0e0bc1, 0xbe54a0c699c8318b),\n", "(0x3adc2d735741fddf, 0xbe5e7594e8a2c760),\n", "(0xba8de62221d00ec8, 0x3dedccbbb4c0ba7f),\n", "(0x3a8cf847ee673438, 0x3ded6766337b5c95),\n", "(0xba0200bd41d3e51f, 0xbd7d1a05cea18a02),\n", "(0xba1f3622c8b76f5f, 0xbd74922fb50a29f1),\n", "(0xb99416959af186e5, 0x3d047fa35bf627ce),\n", "(0x3983729747e80125, 0x3cf5cfa087122294),\n", "(0xb90144302fbdaa10, 0xbc85d009937bf5ab),\n", "(0x3907a8b2df9e5ac3, 0xbc72200b01fdbf9d),\n", "(0xb8a0a7e595a1fb47, 0x3c02265f004c1d49),\n", "(0x387e52805deaab21, 0x3be83df71ae8ab7a),\n", "(0x37bb19a9df1aa0a8, 0xbb7843800001ddf6),\n", "(0xb7eb3ebd0a11156f, 0xbb5aa6f0e2f25140),\n", "(0x37780a266a5c06bb, 0x3aeaa04878c515a9),\n", "],\n", "[\n", "(0x357a12f34662767b, 0x38ebd844c546d1fe),\n", "(0xbc55d35a88f1e0a3, 0xbfba4407e04298d1),\n", "(0x3bdf6dddc07add4c, 0x3f4bcc9df0cf00b2),\n", "(0xbc3c3cb8ccc39cf1, 0x3f917f0266db2149),\n", "(0x3ba3d974ad0c21fe, 0xbf2280a052234a05),\n", "(0x3bb902b669103937, 0xbf4bf2ada1f44071),\n", "(0xbb64ad3fa1509171, 0x3edd83d58032b48d),\n", "(0x3b3d6efd0446126a, 0x3ef53dd972d8f232),\n", "(0xbb230c11b6006891, 0xbe8663c1fe202028),\n", "(0xbb26dbba4ce8bd7d, 0xbe92d1fbf2203ff6),\n", "(0x3ac866e6e348b7b7, 0x3e23c9f0b759c5f9),\n", "(0x3ac489ff33dfce8f, 0x3e25cfe1b012696d),\n", "(0x3a4981337ac7965a, 0xbdb6ddc0795781e9),\n", "(0xba4b13e076398cc3, 0xbdb1cfd49504266a),\n", "(0x39edb765a45cfad5, 0x3d429b7af5214fbc),\n", "(0x39bd594b3ede144b, 0x3d3598302ab3ac8a),\n", "(0xb96436f0bc69940b, 0xbcc677f6a604ab42),\n", "(0xb95aaa7d20415d1b, 0xbcb432ecc122bbc3),\n", "(0x38b6c227de389245, 0x3c44ec114bfb6bf7),\n", "(0x38b8822ee44d55d6, 0x3c2e0887f8c2f57d),\n", "(0x38569ce3e7c211fb, 0xbbbef44a37f84f12),\n", "(0x384d44f14e9f294c, 0xbba22b91f5f4449b),\n", "(0xb7c6e331300713b4, 0x3b32a03f80301aa2),\n", "(0xb7bc71f13c4d9d35, 0x3b123d23f8f7ad2f),\n", "],\n", "[\n", "(0x3c423404089aea01, 0xbfb9ef3bb2213b0b),\n", "(0x3564b334f22dc8c4, 0x38ec7aef8237b6d2),\n", "(0x3c342c5cb51f2b57, 0x3fa9ed82007a9a45),\n", "(0xbbad41b75b8a8df3, 0xbf31d2fdeeb29f8a),\n", "(0x3c189945952fed1e, 0xbf71446866ff1b83),\n", "(0x3b94bf0ff761bace, 0x3efc73b684f93259),\n", "(0xbbc79edfb80bfc5d, 0x3f22628de594b6c9),\n", "(0xbb2bef93c666f4ba, 0xbeb03303c1427449),\n", "(0x3b69194ecd6aac53, 0xbec4f51007c51087),\n", "(0x3af53d1fa2147ee3, 0x3e531adfa36f2213),\n", "(0xbafbf005f05fcc98, 0x3e5db4f306b19095),\n", "(0x3a88f72949d1398a, 0xbdeb9e33598f899e),\n", "(0xba8457c3274ebd59, 0xbdecb09ed6ecb896),\n", "(0xba159f6f24f8986e, 0x3d7afe1183148a99),\n", "(0x3a11bfaf9fbcb95f, 0x3d7414e442aa8d57),\n", "(0x39ae38a755a019d9, 0xbd0307c129418397),\n", "(0xb99de6576700d7e4, 0xbcf54ddabca7b729),\n", "(0xb91f28f4f591d3f4, 0x3c84455c62381679),\n", "(0xb913f1c98ec45b97, 0x3c71b70264da382d),\n", "(0xb8a8129bcf1d63a0, 0xbc00e2cfa963d4c5),\n", "(0xb8879c81e5b960aa, 0xbbe7b5896de3457b),\n", "(0xb8030217c1f78b40, 0x3b7699efca5cd8c8),\n", "(0x37e0b0e37cbd943a, 0x3b5a15ae188cedc6),\n", "(0xb78b8997136a2cc2, 0xbae8d5720aed06a6),\n", "],\n", "[\n", "(0xb59a217cd5a5fc59, 0xb8f8cb0a4bb92b1c),\n", "(0x3c5728ab934a26a0, 0x3fb99be744018c90),\n", "(0xbbdb8852614fe858, 0xbf49c3f52a2af724),\n", "(0xbc2f281d89ca12e4, 0xbf910f5ca51f98b0),\n", "(0xbbc3c6681ac39db5, 0x3f2126c8e8ca2766),\n", "(0x3babb471b2b6cf3f, 0x3f4b416f7d4fc313),\n", "(0xbb677b33eb16cea4, 0xbedb5e2e5580e1ce),\n", "(0xbb988d4663776f74, 0xbef4b862279de756),\n", "(0xbb2b43c42f7f04bd, 0x3e84c5071b39dc13),\n", "(0xbb3de6264de806d7, 0x3e925d2fc3b19021),\n", "(0x3ac879393dd83f28, 0xbe225df322279972),\n", "(0xbac3ec23ad6e970a, 0xbe254a971eb6fe3b),\n", "(0x3a5048109b74bd8a, 0x3db53cc6c9922f2b),\n", "(0xba43610ec595546e, 0x3db164f95180d8c1),\n", "(0x39e236638a339577, 0xbd414b9ef404ed89),\n", "(0x39d5e32a69772db7, 0xbd3519623b4e50ac),\n", "(0x396ac2c256389163, 0x3cc4e7271a71f23c),\n", "(0x39593e237428a68a, 0x3cb3bf2a1b859197),\n", "(0xb8e5a9f4a410aefa, 0xbc437bc0d8e44b83),\n", "(0x38afa844b04c9f72, 0xbc2d6104b94c47d8),\n", "(0xb85bd976332a8ad4, 0x3bbcdb4b3544bc80),\n", "(0xb81ec0f06119d6f0, 0x3ba1c93567462aba),\n", "(0xb7dbdd21527e43db, 0xbb31623ef293806e),\n", "(0x37b58068411a8ada, 0xbb11dd917bc85327),\n", "],\n", "[\n", "(0xbc54096ec8637e04, 0x3fb94d3276914e51),\n", "(0xb599a52e7e447fba, 0xb8f7c4d3a1091c64),\n", "(0x3c4baee1d6c0d38b, 0xbfa94bac1950e319),\n", "(0x3bdbfe3ad50b1c19, 0x3f308d4ff8f2059e),\n", "(0xbc1cca1c2770b225, 0x3f70d90d29bfeecd),\n", "(0xbb987fee6225f412, 0xbefa6d56162f7fb4),\n", "(0xbbc7e723313bf860, 0xbf21f107da23807d),\n", "(0x3b42cbddeb0faca2, 0x3eae1a626277437b),\n", "(0x3b665fad37433b79, 0x3ec474eafd0cc642),\n", "(0x3acb91aaa2286db9, 0xbe51c27144f42d78),\n", "(0x3af7189d5fa17ee0, 0xbe5d01999b1a4fe9),\n", "(0x3a35f0e0348c776a, 0x3de9b014801da87a),\n", "(0x3a8958b840cda80a, 0x3dec061740bc8a45),\n", "(0x3a16875708b7d88b, 0xbd791f8c2972547e),\n", "(0x3a1c0289b9700b84, 0xbd739fb558b7aa4d),\n", "(0x39a9d6b95b5ce534, 0x3d01b9f74d47b35f),\n", "(0x3992cf3210e813d7, 0x3cf4d425557e1f1c),\n", "(0x392e1b1b93526a26, 0xbc82e617ae27952e),\n", "(0x3913ab3cd31920c7, 0xbc715432898c29d0),\n", "(0x3894feceefbf4d3a, 0x3bff843f6347963f),\n", "(0x388afc3194a2db07, 0x3be734c130fc648e),\n", "(0xb81e9da93ee8d83a, 0xbb751d395949afbc),\n", "(0x37d1fb7f6ae8afc8, 0xbb598c0f03028f01),\n", "(0x3751f15d40f7c19d, 0x3ae739cc4684a5bc),\n", "],\n", "[\n", "(0xb568e6ce9dddcc62, 0x38c846638d0f2565),\n", "(0x3c5e213a1a4b3671, 0xbfb8ffc9bd24fe08),\n", "(0x3be5e8a5d70cf555, 0x3f47f7d46ab33721),\n", "(0x3c2f532ddb23dab4, 0x3f90a7a725d3fbc4),\n", "(0xbbb3f089aa8f2adf, 0xbf1fea1728f216b4),\n", "(0xbbdf63ef3319327c, 0xbf4a9cac69f0ed64),\n", "(0x3b78f775cf86e9c6, 0x3ed977f48ff1056b),\n", "(0x3b8a77447ea6fe43, 0x3ef43c2d8e698c10),\n", "(0x3b293f5e91559672, 0xbe8355d1a6765ea6),\n", "(0x3b177401cf3aa17c, 0xbe91f0553501d121),\n", "(0xba823a3e8101b9d1, 0x3e211b47f6a44829),\n", "(0xbaa6a02fffa2b5eb, 0x3e24ce23303889a9),\n", "(0xba42b03ad2eec174, 0xbdb3ca98df62221f),\n", "(0xba50afdcc563be7a, 0xbdb100fc746529d7),\n", "(0xb9edcbe05d10e11a, 0x3d4020f11e2dca08),\n", "(0xb9da9e6748bc0bea, 0x3d34a26ef2219c2c),\n", "(0x3957914c29f9b911, 0xbcc38203ff52c747),\n", "(0xb94441377b47cfd9, 0xbcb35244c153aa29),\n", "(0xb8ef173859510b43, 0x3c4232dbbbea35fb),\n", "(0x38b7c43340294390, 0x3c2cc2f30d7e4a86),\n", "(0xb850cdea356a6de6, 0xbbbafaa22e04387a),\n", "(0x38455c9d49ba1463, 0xbba16c1420a026bc),\n", "(0x37ce36d7bd132716, 0x3b3044e17b70797e),\n", "(0x37bc48ba65be1620, 0x3b1182c036f66e44),\n", "],\n", "[\n", "(0x3c4123b2f0e7c9dd, 0xbfb8b67a2481077d),\n", "(0xb54bc05ff5d82c4f, 0xb8f3f299f5be57c2),\n", "(0xbc4b4ca91be60b3e, 0x3fa8b51f21068ea2),\n", "(0x3bb25eeb0c780d24, 0xbf2ed935c7aefa31),\n", "(0xbbf1e97629a4fbd3, 0xbf707522a5037f2d),\n", "(0x3b9aa02b2936e0d6, 0x3ef8a196061f8bbc),\n", "(0x3bc503ddcb9034df, 0x3f21874a47e3c1e3),\n", "(0x3b255f9307a25ea3, 0xbeac10cf34c04f17),\n", "(0xbb5b1d5a1969a1af, 0xbec3fd6c2d4fa2a4),\n", "(0xbaeb932c5947d65c, 0x3e50906d55522785),\n", "(0xbabb5acdea3816e2, 0x3e5c5a1c124dfa08),\n", "(0xba561fcb9b3ed156, 0xbde7f883b31a5f59),\n", "(0xba75531c808efbb8, 0xbdeb668cf53028e4),\n", "(0x3a104761ec9ef33f, 0x3d7775372d05b25d),\n", "(0xba0f2cfa85a363c5, 0x3d7331d871d677e0),\n", "(0xb9a6539a2342e3af, 0xbd009010248989d3),\n", "(0x398a668272dab0b6, 0xbcf461c4067c742d),\n", "(0xb92d7ef952991dfa, 0x3c81abf993696e78),\n", "(0x3913091355b7de99, 0x3c70f715fa383b8a),\n", "(0x3875a2bcb94003ab, 0xbbfd7ed2f30db038),\n", "(0x388cafff31b61f18, 0xbbe6bb0b4da7d6b8),\n", "(0xb7ea731441eedbfd, 0x3b73c73f0e157e5c),\n", "(0xb7f38c8cb3f130f8, 0x3b5909945c395947),\n", "(0x37892d92eac220fa, 0xbae5c71cc3e16dfe),\n", "],\n", "[\n", "(0x35720ba7b8040a50, 0xb8ee1da34bfeb8e0),\n", "(0x3c5b1c9821974148, 0x3fb86e51be0a9153),\n", "(0xbbeaa494385dab26, 0xbf465ed1b387e5da),\n", "(0x3c09cfc1363faa0e, 0xbf9046fc5a218a86),\n", "(0x3bbf17fc55a88b96, 0x3f1dca617fefa913),\n", "(0xbbe411ddd3f224d7, 0x3f4a0300221528a7),\n", "(0xbb35922d57d34f24, 0xbed7c7618906f1e2),\n", "(0x3b985c37a3fcd2ca, 0xbef3c838897d0a1e),\n", "(0xbb1cfc9e9ef07548, 0x3e820ede9f9dd7dd),\n", "(0x3b3d338a91461c93, 0x3e918a94165592bb),\n", "(0x3ab91bf2c08f3e78, 0xbe1ff76205118f09),\n", "(0x3ab5cfc207f32cd7, 0xbe24599dfeef01a1),\n", "(0x3a40b7bcb17c141b, 0x3db2803e59983134),\n", "(0xba1b8c9ffd59054b, 0x3db0a33202feb043),\n", "(0x39bbb27b9c04cfb6, 0xbd3e2bff738680f8),\n", "(0xb9daf156baca0aee, 0xbd34329cf32bcb6e),\n", "(0xb95aa99554b94956, 0x3cc2424890fb6cfb),\n", "(0xb94757efb61f4861, 0x3cb2eba657649d9b),\n", "(0x38e0a8b550a3fb8e, 0xbc410bda49bebe27),\n", "(0xb8b5e1a905ee61d3, 0xbc2c2d96d94f34d6),\n", "(0x38596b550a29ba35, 0x3bb94a9b8509dda4),\n", "(0xb8120159994b4d70, 0x3ba113d205a63be1),\n", "(0x37caf2ee39614a11, 0xbb2e87a2990f48e9),\n", "(0xb7a8109d37f955d6, 0xbb112c694684c14b),\n", "],\n", "[\n", "(0x3c48caabfef07d2c, 0x3fb829d06fee9266),\n", "(0xb57d95eabe44a5ef, 0xb8d5c95908041d40),\n", "(0xbc46f7f245223685, 0xbfa8289a526d7785),\n", "(0xbbbd55f593621103, 0x3f2cd680355c9eb6),\n", "(0x3c19dafafbc85033, 0x3f7017d70f512861),\n", "(0x3b94ef924915594e, 0xbef707978e2a0db8),\n", "(0xbbb84f6dd554027b, 0xbf21247ce15e7385),\n", "(0x3b3c1549321f5896, 0x3eaa3f6125485ec1),\n", "(0xbb6485c950af11e4, 0x3ec38da848401be9),\n", "(0xbae81c7e658ccb44, 0xbe4efe39d8db4cd8),\n", "(0xbaf106727152dad2, 0xbe5bbd40f1db0e94),\n", "(0x3a7e01f9c4e4c0e2, 0x3de66f7d49436f83),\n", "(0xba6a9de5073f8785, 0x3dead0e8148229b3),\n", "(0xb9edea6b298d9cb4, 0xbd75f78595133d0b),\n", "(0x3a0ffda12b15058b, 0xbd72ca9bb10321b3),\n", "(0xb995d841a594fd98, 0x3cff09e49c887e91),\n", "(0xb993b69afd44cfe7, 0x3cf3f60eeb66f747),\n", "(0xb910a7c26357cc61, 0xbc8091d689cc53d3),\n", "(0x3912aa74818ab310, 0xbc709f335e86201a),\n", "(0x389d74a5732f64e7, 0x3bfbad342a8e077c),\n", "(0xb889c873abcae58c, 0x3be647de871fcaea),\n", "(0x380999f107e74e72, 0xbb7292e087988121),\n", "(0xb7dd56a4a524a0b3, 0xbb588dc30bd642e2),\n", "(0x373e8c81645a59c4, 0x3ae4781fefecc3ab),\n", "],\n", "[\n", "(0x3590e3abb994f19d, 0xb8f3c9c05fc68dd7),\n", "(0x3c21907f595a082a, 0xbfb7e656efb009ae),\n", "(0x3bea53822a52d942, 0x3f44f15066f3d876),\n", "(0xbbef8f1c9736150f, 0x3f8fd932c26aad94),\n", "(0xbba4e6bbdf1f5013, 0xbf1be460dd86a0a4),\n", "(0x3bdda15b3eedcfa3, 0xbf49733b591879f8),\n", "(0x3b7b0e620a04314f, 0x3ed64488c56022e0),\n", "(0xbb74588b63a38eb3, 0x3ef35ba58bf2f993),\n", "(0xbb2d0149456492a2, 0xbe80ea47bceb9a8f),\n", "(0xbb1839787899a71b, 0xbe912b327055d0e9),\n", "(0xbaaeacb6c41bd108, 0x3e1df42fc4e2482c),\n", "(0xba6bbde5a22c7137, 0x3e23ec3e76876dba),\n", "(0xba4c4c84b112be57, 0xbdb1580393f473c3),\n", "(0x3a22a6076d63b081, 0xbdb04b0353c35935),\n", "(0xb9c9681ae93e12c5, 0x3d3c4ca30ffe2a12),\n", "(0xb9d1f206b8c5d3a1, 0x3d33c947b936c2fd),\n", "(0xb963c18fe06a22d6, 0xbcc122c73f770a60),\n", "(0x39590514d9616a4d, 0xbcb28ac7295026a0),\n", "(0x38e4da699d53ec4a, 0x3c4002243876b909),\n", "(0x38b0a1100a850e1a, 0x3c2ba04294d52584),\n", "(0xb85e4caf2a0c3dac, 0xbbb7c4c63a56cf5d),\n", "(0x383d5bda7bf4fb51, 0xbba0c0178f4adc58),\n", "(0x37ba459191582324, 0x3b2cb6cf025ab9d0),\n", "(0x37b2a1b95a167cc0, 0x3b10da465bbcd445),\n", "],\n", "[\n", "(0xbc2f952341a4610f, 0xbfb7a62320798175),\n", "(0x3588b8c77a52cc96, 0xb8e354421b948434),\n", "(0x3c4f5aadff868986, 0x3fa7a50ca4504bb8),\n", "(0xbbc425ed1e2ffb88, 0xbf2b095ccb50a68c),\n", "(0x3c0088e41711bdb7, 0xbf6f80ef11daa37a),\n", "(0xbb8b1b49cdffecd8, 0x3ef59822dc75b064),\n", "(0x3bc22455dc1dd149, 0x3f20c7e6a7c66630),\n", "(0x3b4cb7b87c0d2237, 0xbea89e00b5c358d0),\n", "(0x3b4c5e752b8da3c2, 0xbec324d5238b26d0),\n", "(0x3ae195d9c7c418a5, 0x3e4d13a888d5dd30),\n", "(0xbac402a4638ae535, 0x3e5b29f941a95b07),\n", "(0x3a831332fd181280, 0xbde50e6ebb3d1df6),\n", "(0xba87a4d1a4734618, 0xbdea4434c6b929dd),\n", "(0x3a1460d05df6e757, 0x3d74a03fe2c47842),\n", "(0x3a08550d3cb8e7ab, 0x3d7269628f2df98c),\n", "(0x398caf5ddb7a6639, 0xbcfd28cc08ef4278),\n", "(0xb9786d9d39f281e6, 0xbcf390706334abc3),\n", "(0xb90ccf6b842a2b18, 0x3c7f26c3ea443ebe),\n", "(0xb909111db3c1a608, 0x3c704c1cd3344483),\n", "(0xb89c3b1307b1967f, 0xbbfa08922dcea305),\n", "(0x38837f0ef471dbfb, 0xbbe5dabbff6c2bfb),\n", "(0xb80bcc939f982679, 0x3b717bccb6cd02d3),\n", "(0x37fb40b6199ccfa5, 0x3b5818261a2214e1),\n", "(0xb78fcd71326e756b, 0xbae3485ef660d33a),\n", "],\n", "];\n" ] } ], "source": [ "# from scipy.special import j1, jvp\n", "# from scipy.optimize import brentq\n", "from mpmath import mp, mpf, findroot, j1, besselj\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", " \n", "# Use Sage's RDF for high-precision floats\n", "R120 = RealField(120)\n", "\n", "# List of zeros\n", "zeros = []\n", "\n", "# Step size to detect sign changes\n", "# step = R120(0.001)\n", "# x = R120(0.0)\n", "\n", "mp.prec = 200\n", "\n", "step = mpf(\"0.01\")\n", "epsilon = mpf(\"1e-35\")\n", "x = mpf(\"0.0\")\n", "\n", "def j1_prime(x):\n", " return diff(lambda t: besselj(1, t), x)\n", "\n", "previous_zero = R120(0)\n", "# epsilon = 1e-12\n", "j1_zeros = []\n", "\n", "# while x < 77:\n", "# if j1(float(x)) * j1(float(x + step)) < 0: # Sign change => zero in interval\n", "# previous_zero = brentq(j1, x, x + step)\n", "# j1_zeros.append(R120(previous_zero))\n", "# if abs(x - round(x)) < epsilon:\n", "# zeros.append(R120(previous_zero))\n", "# x += step\n", "\n", "while x < mpf(\"76.0\"):\n", " f1 = besselj(1, x)\n", " f2 = besselj(1, x + step)\n", " if f1 * f2 < 0:\n", " zero = findroot(lambda t: j1(t), (x, x + step), solver='bisect', tol=mp.mpf(\"1e-41\"))\n", " previous_zero = zero\n", " j1_zeros.append(zero)\n", " if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon:\n", " zeros.append(previous_zero)\n", " x += step\n", "\n", "j1_extrema = []\n", "\n", "# x = R120(0.0)\n", "# while x < 77:\n", "# dfx = jvp(1, float(x), n=1) # Derivative of J1\n", "# dfx_next = jvp(1, float(x + step), n=1)\n", "# if dfx * dfx_next < 0:\n", "# extremum = brentq(lambda x: jvp(1, x, n=1), float(x), float(x + step))\n", "# j1_extrema.append(R120(extremum))\n", "# x += step\n", "\n", "x = mpf(\"0.0\")\n", "while x < mpf(\"76.0\"):\n", " d1 = mp.diff(lambda t: j1(t), x)\n", " d2 = mp.diff(lambda t: j1(t), x + step)\n", " if d1 * d2 < 0:\n", " extremum = findroot(lambda t: mp.diff(lambda u: j1(u), t), (x, x + step), solver='bisect', tol=mp.mpf(\"1e-41\"))\n", " j1_extrema.append(extremum)\n", " x += step\n", "\n", "# Print results\n", "for i, z in enumerate(j1_zeros):\n", " print(f\"Zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"Extrema (peaks/valleys) of J1(x):\")\n", "for e in j1_extrema:\n", " print(f\"nExtrema: {e}\")\n", "\n", "j1_zeros.extend(j1_extrema)\n", "\n", "j1_zeros = sorted(j1_zeros)\n", "\n", "# Print results\n", "for i, z in enumerate(j1_zeros):\n", " print(f\"Peak or zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"\")\n", "\n", "print(\"pub(crate) static J1_ZEROS: [(u64, u64); 48] = [\")\n", "print(f\"(0x0, 0x0),\")\n", "for z in j1_zeros:\n", " k = split_double_double(z)\n", " # print_dyadic(z)\n", " hi = double_to_hex(k[1])\n", " lo = double_to_hex(k[0])\n", " print(f\"({lo}, {hi}),\")\n", " \n", "print(\"];\")\n", "\n", "from mpmath import *\n", "from sage.all import *\n", "\n", "from mpmath import mp, j1, taylor, expm1\n", "\n", "prev_zero = 0\n", "\n", "CDR = RealField(120)\n", "\n", "var('x')\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffs(poly, x0):\n", " print(\"[\")\n", " for i in range(0, 24):\n", " coeff = poly[i]\n", " print_double_double(\"\", coeff)\n", " # print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "def print_taylor_coeffs_dyad(poly):\n", " print(\"[\")\n", " for i in range(0, 24):\n", " coeff = poly[i]\n", " print_dyadic(coeff)\n", " print(\"],\")\n", "\n", "print(f\"pub(crate) static J1_COEFFS_TAYLOR: [J1TaylorExtendedSeries; {len(j1_zeros)}] = [\")\n", "\n", "for i in range(0, len(j1_zeros)):\n", " k_range = j1_zeros[i]\n", " range_diff = k_range - prev_zero\n", " g_c = 1\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, j1, taylor\n", " poly = taylor(lambda val: j1(val), x0, 25)\n", " print_taylor_coeffs(poly, CDR(k_range))\n", " prev_zero = j1_zeros[i]\n", "\n", "print(\"];\")\n", "\n", "# print(f\"pub(crate) static J1_COEFFS_RATIONAL128: [DyadicFloat128; {len(j1_zeros)}] = [\")\n", "\n", "# for i in range(0, len(j1_zeros)):\n", "# k_range = j1_zeros[i]\n", "# range_diff = k_range - prev_zero\n", "# g_c = 1\n", "\n", "# x0 = mp.mpf(k_range)\n", "# from mpmath import mp, j1, taylor\n", "# poly = taylor(lambda val: j1(val), x0, 25)\n", "# print_taylor_coeffs_dyad(poly)\n", "# prev_zero = j1_zeros[i]\n", "\n", "# print(\"];\")\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "0b9e8b75-c4f7-475c-8f8e-6ab787ed8519", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static C: DyadicFloat128 = [\n", "[\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -131,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -136,\n", " mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -142,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -148,\n", " mantissa: 0xb60b60b6_0b60b60b_60b60b60_b60b60b6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -155,\n", " mantissa: 0xc22e4506_72894ab6_cd8efb11_d33f5618_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -162,\n", " mantissa: 0x93f27dbb_c4fae397_780b69f5_333c725b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -170,\n", " mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -178,\n", " mantissa: 0x964bac6d_7ae67d8d_aec68405_485dea03_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -187,\n", " mantissa: 0xd5c0f53a_fe6fa17f_8c7b0b68_39691f4e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -196,\n", " mantissa: 0xf8bb4be7_8e7896b0_58fee362_01a4370c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -205,\n", " mantissa: 0xf131bdf7_cff8d02e_e1ef6820_f9d58ab6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -214,\n", " mantissa: 0xc5e72c48_0d1aec75_3caa2e0d_edd008ca_u128,\n", "},\n", "],\n", "[;\n" ] } ], "source": [ "def print_expansion_at_0():\n", " print(f\"static C: [DyadicFloat128; 13] = \")\n", " from mpmath import mp, j1, taylor, expm1\n", " poly = taylor(lambda val: j1(val), 0, 26)\n", " # print(poly)\n", " real_i = 0\n", " print(\"[\")\n", " for i in range(1, len(poly), 2):\n", " print_dyadic(poly[i])\n", " real_i = real_i + 1\n", " print(\"],\")\n", "\n", " print(\"];\")\n", "\n", "mp.prec = 180\n", "\n", "print_expansion_at_0()" ] }, { "cell_type": "code", "execution_count": 3, "id": "a558bfc9-9980-42d7-bf1a-6d134b7872c2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(-0.97059, 1.0453, 1.8411837813406593026436295136444), (-1.0453, 0.79987, 3.8317059702075123156144358863082), (-0.79987, 0.89207, 5.3314427735250326368840161834339), (-0.89207, 0.81036, 7.0155866698156187535370499814765), (-0.81036, 0.86858, 8.5363163663462858343589608864121), (-0.86858, 0.81627, 10.173468135062722077185711776776), (-0.81627, 0.85884, 11.706004902592064100192670477240), (-0.85884, 0.81995, 13.323691936314223032393684126948), (-0.81995, 0.85352, 14.863588633909033105004905304986), (-0.85352, 0.82245, 16.470630050877632812552460470990), (-0.82245, 0.85017, 18.015527862681803727025625542010), (-0.85017, 0.82426, 19.615858510468242021125065884137), (-0.82426, 0.84786, 21.164369859188790027767973293705), (-0.84786, 0.82562, 22.760084380592771898053005152182), (-0.82562, 0.84617, 24.311326857210776091733221673754), (-0.84617, 0.82669, 25.903672087618382625495855445980), (-0.82669, 0.84489, 27.457050571059245888223275587902), (-0.84489, 0.82755, 29.046828534916855066647819883532), (-0.82755, 0.84388, 30.601922972669094192330163628525), (-0.84388, 0.82825, 32.189679910974403626622984104460), (-0.82825, 0.84306, 33.746182898667382556147730594291), (-0.84306, 0.82884, 35.332307550083865102634479022519), (-0.82884, 0.84239, 36.889987409236810736184291115055), (-0.84239, 0.82934, 38.474766234771615112052197557717), (-0.82934, 0.84182, 40.033444053350675483595577824821), (-0.84182, 0.82977, 41.617094212814450885863516805060), (-0.82977, 0.84135, 43.176628965448822065171326670935), (-0.84135, 0.83014, 44.759318997652821732779352713212), (-0.83014, 0.84093, 46.319597561173912431514896922521), (-0.84093, 0.83046, 47.901460887185447121274008722507), (-0.83046, 0.84057, 49.462391139702755522817961514251), (-0.84057, 0.83075, 51.043535183571509468733034633224), (-0.83075, 0.84026, 52.605041111556684816016445795619), (-0.84026, 0.83101, 54.185553641061320532099966214534), (-0.83101, 0.83998, 55.747571792251006871041271951261), (-0.83998, 0.83124, 57.327525437901010745090504243751), (-0.83124, 0.83973, 58.890002299185703524557516663956), (-0.83973, 0.83144, 60.469457845347491559398749808383), (-0.83144, 0.83950, 62.032347870661986904980183177973), (-0.83950, 0.83163, 63.611356698481232631039762417874), (-0.83163, 0.83930, 65.174620802544453140913079699161), (-0.83930, 0.83180, 66.753226734098493415305259750042), (-0.83180, 0.83912, 68.316831125951808310075532836204), (-0.83912, 0.83196, 69.895071837495773969730536435500), (-0.83196, 0.83895, 71.458987105851000181223748893952), (-0.83895, 0.83210, 73.036895225573834826506117569092), (-0.83210, 0.88000, 74.601095613456402477925006047823)]\n", "pub(crate) static J1F_COEFFS: [[u64;14]; 47] = [\n", "[\n", "0x3fe29ea3d19f035d,\n", "0xbce22d3695a081b6,\n", "0xbfca41115c5deeab,\n", "0x3f78d1448e710c46,\n", "0x3f8c441a2f9a4f69,\n", "0xbf386671c22a634e,\n", "0xbf39e2504b2e7b5b,\n", "0x3ee34ccc14eef789,\n", "0x3eda49718b72405e,\n", "0xbe810474efe3c9c6,\n", "0xbe70fa29fb791201,\n", "0x3e1362d76c062ab0,\n", "0x3dfdd76f07295520,\n", "0xbda1a753bf39cb58,\n", "],\n" ] }, { "ename": "KeyboardInterrupt", "evalue": "", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mKeyboardInterrupt\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 60\u001b[39m\n\u001b[32m 58\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[32m0\u001b[39m, \u001b[38;5;28mlen\u001b[39m(intervals)):\n\u001b[32m 59\u001b[39m interval = intervals[i]\n\u001b[32m---> \u001b[39m\u001b[32m60\u001b[39m \u001b[43mcall_sollya_on_interval\u001b[49m\u001b[43m(\u001b[49m\u001b[43minterval\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minterval\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minterval\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdegree\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 61\u001b[39m coeffs = load_coefficients(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mcoefficients.txt\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 62\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m[\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 46\u001b[39m, in \u001b[36mcall_sollya_on_interval\u001b[39m\u001b[34m(a, b, zero, degree)\u001b[39m\n\u001b[32m 44\u001b[39m os.remove(\u001b[33m\"\u001b[39m\u001b[33mcoefficients.txt\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 45\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m46\u001b[39m result = \u001b[43msubprocess\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 47\u001b[39m \u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43msollya\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtmp_interval.sollya\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 48\u001b[39m \u001b[43m \u001b[49m\u001b[43mcheck\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 49\u001b[39m \u001b[43m \u001b[49m\u001b[43mcapture_output\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 50\u001b[39m \u001b[43m \u001b[49m\u001b[43mtext\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\n\u001b[32m 51\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 52\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess.CalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m 53\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/subprocess.py:550\u001b[39m, in \u001b[36mrun\u001b[39m\u001b[34m(input, capture_output, timeout, check, *popenargs, **kwargs)\u001b[39m\n\u001b[32m 548\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m Popen(*popenargs, **kwargs) \u001b[38;5;28;01mas\u001b[39;00m process:\n\u001b[32m 549\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m550\u001b[39m stdout, stderr = \u001b[43mprocess\u001b[49m\u001b[43m.\u001b[49m\u001b[43mcommunicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 551\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m TimeoutExpired \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[32m 552\u001b[39m process.kill()\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/subprocess.py:1209\u001b[39m, in \u001b[36mPopen.communicate\u001b[39m\u001b[34m(self, input, timeout)\u001b[39m\n\u001b[32m 1206\u001b[39m endtime = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 1208\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1209\u001b[39m stdout, stderr = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_communicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mendtime\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1210\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[32m 1211\u001b[39m \u001b[38;5;66;03m# https://bugs.python.org/issue25942\u001b[39;00m\n\u001b[32m 1212\u001b[39m \u001b[38;5;66;03m# See the detailed comment in .wait().\u001b[39;00m\n\u001b[32m 1213\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m timeout \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/subprocess.py:2115\u001b[39m, in \u001b[36mPopen._communicate\u001b[39m\u001b[34m(self, input, endtime, orig_timeout)\u001b[39m\n\u001b[32m 2108\u001b[39m \u001b[38;5;28mself\u001b[39m._check_timeout(endtime, orig_timeout,\n\u001b[32m 2109\u001b[39m stdout, stderr,\n\u001b[32m 2110\u001b[39m skip_check_and_raise=\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[32m 2111\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m( \u001b[38;5;66;03m# Impossible :)\u001b[39;00m\n\u001b[32m 2112\u001b[39m \u001b[33m'\u001b[39m\u001b[33m_check_timeout(..., skip_check_and_raise=True) \u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 2113\u001b[39m \u001b[33m'\u001b[39m\u001b[33mfailed to raise TimeoutExpired.\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m-> \u001b[39m\u001b[32m2115\u001b[39m ready = \u001b[43mselector\u001b[49m\u001b[43m.\u001b[49m\u001b[43mselect\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 2116\u001b[39m \u001b[38;5;28mself\u001b[39m._check_timeout(endtime, orig_timeout, stdout, stderr)\n\u001b[32m 2118\u001b[39m \u001b[38;5;66;03m# XXX Rewrite these to use non-blocking I/O on the file\u001b[39;00m\n\u001b[32m 2119\u001b[39m \u001b[38;5;66;03m# objects; they are no longer using C stdio!\u001b[39;00m\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/selectors.py:415\u001b[39m, in \u001b[36m_PollLikeSelector.select\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 413\u001b[39m ready = []\n\u001b[32m 414\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m415\u001b[39m fd_event_list = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_selector\u001b[49m\u001b[43m.\u001b[49m\u001b[43mpoll\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 416\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mInterruptedError\u001b[39;00m:\n\u001b[32m 417\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m ready\n", "\u001b[31mKeyboardInterrupt\u001b[39m: " ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = (zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(j1_zeros)\n", "print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 500;\n", "bessel_j1 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_j1(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d, 1, 1e-25);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RR(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "degree = 13\n", "\n", "print(f\"pub(crate) static J1F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print(\"[\")\n", " for c in coeffs:\n", " print(double_to_hex(c) + \",\")\n", " print(\"],\")\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "b835298a-6361-4953-ae3e-fc5149f6361d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "];\n" ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = (zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(j1_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 500;\n", "bessel_j1 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_j1(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "def print_remez_coeffs(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " print_dyadic(coeff)\n", " # print_double_double(\"\", coeff)\n", " print(\"],\")\n", "\n", "degree = 23\n", "\n", "print(f\"pub(crate) static J1_COEFFS_RATIONAL128: [[(u64, u64); {degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_remez_coeffs(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "f17e1fb4-540b-444f-b7c2-d06c43d0f70e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) const J1_MACLAURIN_SERIES: [u64; 9] = [\n", "0x3fe0000000000000,\n", "0xbfb0000000000000,\n", "0x3f65555555555555,\n", "0xbf0c71c71c71c71c,\n", "0x3ea6c16c16c16c17,\n", "0xbe3845c8a0ce5129,\n", "0x3dc27e4fb7789f5c,\n", "0xbd4522a43f65486a,\n", "0x3cc2c9758daf5cd0,\n", "];\n", "poly [mpf('0.0'), mpf('0.5'), mpf('0.0'), mpf('-0.0625'), mpf('0.0'), mpf('0.0026041666666666666678'), mpf('0.0'), mpf('-0.000054253472222222222228'), mpf('0.0'), mpf('6.7816840277777777802e-7'), mpf('0.0'), mpf('-5.6514033564814814787e-9'), mpf('0.0'), mpf('3.3639305693342151652e-11'), mpf('0.0'), mpf('-1.5017547184527746284e-13'), mpf('0.0'), mpf('5.2144261057388007941e-16'), mpf('0.0')]\n" ] } ], "source": [ "def print_expansion_at_0_f():\n", " print(f\"pub(crate) const J1_MACLAURIN_SERIES: [u64; 9] = [\")\n", " from mpmath import mp, j1, taylor, expm1\n", " mp.prec = 60\n", " poly = taylor(lambda val: j1(val), 0, 18)\n", " z = 0\n", " for i in range(1, 18, 2):\n", " print(f\"{double_to_hex(poly[i])},\")\n", " print(\"];\")\n", "\n", " print(f\"poly {poly}\")\n", "\n", "print_expansion_at_0_f()" ] }, { "cell_type": "code", "execution_count": 9, "id": "8bccb7eb-61b8-44d5-9d3b-9ac408545c49", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static J1F_COEFFS: [[u64; 15]; 47] = [\n", "[mpf('0.58186522428159637935'), mpf('0.0'), mpf('-0.20511071214777319618'), mpf('0.0060589483246034702712'), mpf('0.013801769807956073966'), mpf('-0.00037231709715624585667'), mpf('-0.00039495907354755762771'), mpf('9.2029497991652741433e-6'), mpf('6.2672896817308790948e-6'), mpf('-1.2678573687215959376e-7'), mpf('-6.3255405008454650371e-8'), mpf('1.1251416998452125018e-9'), mpf('4.4195229281806885938e-10'), mpf('-6.9988903007532951552e-12'), mpf('-2.2644917176837842057e-12'), mpf('3.2279649218764984938e-14')]\n", "[\n", "0x3fe29ea3d19f035f,\n", "0x0000000000000000,\n", "0xbfca41115c5df243,\n", "0x3f78d1448e6fed48,\n", "0x3f8c441a2f9de22b,\n", "0xbf386671c18b088a,\n", "0xbf39e2504ddc7608,\n", "0x3ee34ccbca0c75d1,\n", "0x3eda4973784d1087,\n", "0xbe81045322aaab45,\n", "0xbe70fae0da6cdcef,\n", "0x3e13546cef5ed00a,\n", "0x3dfe5ee82e667708,\n", "0xbd9ec80cc8b63c39,\n", "0xbd83eb2e99629b44,\n", "],\n", "[mpf('0.0'), mpf('-0.40275939570255297204'), mpf('0.05255614585697723529'), mpf('0.053410444132724809124'), mpf('-0.0051797192456385702015'), mpf('-0.0022331253391474781904'), mpf('0.00017466429072012055577'), mpf('0.000046208701297458375041'), mpf('-3.0368633802997825054e-6'), mpf('-5.7278057351403828758e-7'), mpf('3.248286298212016063e-8'), mpf('4.7353805694230912062e-9'), mpf('-2.3621961879300647998e-10'), mpf('-2.798876498866189761e-11'), mpf('1.24622958871638405e-12'), mpf('1.2418546943452456094e-13')]\n", "[\n", "0x0000000000000000,\n", "0xbfd9c6cf582cbf7f,\n", "0x3faae8a39f51ad04,\n", "0x3fab589d1da13905,\n", "0xbf7537544c331da7,\n", "0xbf624b3409959064,\n", "0x3f26e4c2d5354224,\n", "0x3f083a06e30c4109,\n", "0xbec9799d4c9f2549,\n", "0xbea33825cd2e2c16,\n", "0x3e617069233e916c,\n", "0x3e34569b22afc3c8,\n", "0xbdf03b9e9651056a,\n", "0xbdbec62310af5f52,\n", "0x3d75ec84e47b6f4f,\n", "],\n", "[mpf('-0.34612620185379152499'), mpf('0.0'), mpf('0.16697453550109304715'), mpf('-0.0096782685428781834634'), mpf('-0.012099225779142165017'), mpf('0.00066540090064248448297'), mpf('0.00035413890079969189734'), mpf('-0.000017427203138287973507'), mpf('-5.6552936118188389545e-6'), mpf('2.4842947979085213322e-7'), mpf('5.7099041733534499266e-8'), mpf('-2.253735114333317759e-9'), mpf('-3.9815202626737523496e-10'), mpf('1.423282431012698274e-11'), mpf('2.0342689365206355806e-12'), mpf('-6.6361791580308299188e-14')]\n", "[\n", "0xbfd626ee83500bf2,\n", "0x0000000000000000,\n", "0x3fc55f6bec9ef962,\n", "0xbf83d23336fd10e4,\n", "0xbf88c77a983a0814,\n", "0x3f45cdc98db1cbe2,\n", "0x3f373576ff46ee3b,\n", "0xbef2461447d7b423,\n", "0xbed7b853456b6eaa,\n", "0x3e90abfc68274a98,\n", "0x3e6ea7a1ee26124d,\n", "0xbe235c0413e01418,\n", "0xbdfb5c5d512fbb00,\n", "0x3daf4c5e26fd6e90,\n", "0x3d81e4c43397be51,\n", "],\n", "[mpf('0.0'), mpf('0.30011575252613256325'), mpf('-0.021389212809341581604'), mpf('-0.046970478949741492397'), mpf('0.0031302917260480910314'), mpf('0.0021055871432482764524'), mpf('-0.00012550790955145584594'), mpf('-0.000044991475302930677458'), mpf('2.4015807963093220637e-6'), mpf('5.6652700115483305252e-7'), mpf('-2.7273427677991571622e-8'), mpf('-4.7204830035449803097e-9'), mpf('2.0653486761001609926e-10'), mpf('2.8005725262750139892e-11'), mpf('-1.1216380229417615937e-12'), mpf('-1.2445402051043784197e-13')]\n", "[\n", "0x0000000000000000,\n", "0x3fd33518b3874e8a,\n", "0xbf95e70dc60362bf,\n", "0xbfa80c83bdeee5b0,\n", "0x3f69a4b292e3de42,\n", "0x3f613fbc7d698217,\n", "0xbf207358bbdbff91,\n", "0xbf0796a751f89051,\n", "0x3ec4255b015aded4,\n", "0x3ea3026e0ce97ab9,\n", "0xbe5d48dcdae92f2c,\n", "0xbe344639d7eeb0a6,\n", "0x3dec62ccb4a32eb4,\n", "0x3dbecae92e854457,\n", "0xbd73bb6898d73cd2,\n", "],\n", "[mpf('0.27329994163319984652'), mpf('0.0'), mpf('-0.13477468037992366371'), mpf('0.0051163403464880437583'), mpf('0.010631861751984684542'), mpf('-0.0004487436837355104409'), mpf('-0.00032680001852314866825'), mpf('0.000013382555976264054131'), mpf('5.3631771590310306119e-6'), mpf('-2.0647201477005368657e-7'), mpf('-5.4999876460932523786e-8'), mpf('1.9738246864962383629e-9'), mpf('3.8700134714235867337e-10'), mpf('-1.2932330828461372144e-11'), mpf('-1.9877528061462670066e-12'), mpf('6.1949256560561771715e-14')]\n", "[\n", "0x3fd17dbf09d40d25,\n", "0x0000000000000000,\n", "0xbfc1404bf647c28f,\n", "0x3f74f4df2769f830,\n", "0x3f85c6285429b66d,\n", "0xbf3d68ab722881bd,\n", "0xbf356acb6452d860,\n", "0x3eec10b47cf7ef69,\n", "0x3ed67eaae97bbc86,\n", "0xbe8bb6530c63f2df,\n", "0xbe6d87201e450edd,\n", "0x3e20f47c83ec550b,\n", "0x3dfa98331f6ea799,\n", "0xbdac70414a236a67,\n", "0xbd817c057a5fcd3d,\n", "],\n", "[mpf('0.0'), mpf('-0.24970487705784319768'), mpf('0.012272357555101523016'), mpf('0.040411169390792762014'), mpf('-0.0019268187972607869614'), mpf('-0.0019115826893826532914'), mpf('0.000086617294541704344343'), mpf('0.000042411162810834605721'), mpf('-1.8009794578804266187e-6'), mpf('-5.4716029875821084779e-7'), mpf('2.1683937068370021148e-8'), mpf('4.6309166017117001797e-9'), mpf('-1.7127551080711048348e-10'), mpf('-2.7754891630185889922e-11'), mpf('9.5974160168809293401e-13'), mpf('1.2416439077261460564e-13')]\n", "[\n", "0x0000000000000000,\n", "0xbfcff654544ebcd1,\n", "0x3f89223ff2c0785b,\n", "0x3fa4b0c5d5da6789,\n", "0xbf5f91a9ee0d2897,\n", "0xbf5f51c2489b9e6f,\n", "0x3f16b4c9ca0f770d,\n", "0x3f063c5475439cb2,\n", "0xbebe3725daf69867,\n", "0xbea25c1238b32e59,\n", "0x3e57486f6b9aa951,\n", "0x3e33e3bf248277ee,\n", "0xbde78a38a73e7c0a,\n", "0xbdbe844eb6b211b0,\n", "0x3d70e24abb40708e,\n", "],\n", "[mpf('-0.23330441717143407163'), mpf('0.0'), mpf('0.11580092244607787173'), mpf('-0.0032489977328227131391'), mpf('-0.0093725272060515148708'), mpf('0.00030361382116848387787'), mpf('0.00029804555532438402212'), mpf('-9.8138185844927528334e-6'), mpf('-5.0242299986728071413e-6'), mpf('1.6136266730440164581e-7'), mpf('5.2519642038231082736e-8'), mpf('-1.6181244659556868191e-9'), mpf('-3.7451750290225519442e-10'), mpf('1.0991700523364741105e-11'), mpf('1.9416081678963447356e-12'), mpf('-5.4135859571506795954e-14')]\n", "[\n", "0xbfcddceb4ce1bf4a,\n", "0x0000000000000000,\n", "0x3fbda52116c0a640,\n", "0xbf6a9da4603b67ea,\n", "0xbf8331e74ea59ab8,\n", "0x3f33e5cb6eba6eaa,\n", "0x3f33885fe9afa541,\n", "0xbee494c0f4b0680b,\n", "0xbed512b9d37762d7,\n", "0x3e85a861082bfb7f,\n", "0x3e6c323ea0a042c3,\n", "0xbe1bcc962f7b91eb,\n", "0xbdf9bc94e2f29a52,\n", "0x3da82bc6fcfa8e89,\n", "0x3d81141ce7b78460,\n", "],\n", "[mpf('0.0'), mpf('0.21835940724787296211'), mpf('-0.008194403183877517927'), mpf('-0.035778209575030602615'), mpf('0.0013195736128103676684'), mpf('0.0017308725061749555204'), mpf('-0.000062007351614213552148'), mpf('-0.000039387037420757643546'), mpf('1.3569942254160055383e-6'), mpf('5.1906566526836006101e-7'), mpf('-1.7083741497242886404e-8'), mpf('-4.4653408290297706985e-9'), mpf('1.3991439234814039386e-10'), mpf('2.708929479095925876e-11'), mpf('-8.0702945212994599312e-13'), mpf('-1.2227780235323198076e-13')]\n", "[\n", "0x0000000000000000,\n", "0x3fcbf3337873a7d8,\n", "0xbf80c83a2d7add33,\n", "0xbfa251858011816b,\n", "0x3f559eb160bf72d8,\n", "0x3f5c5bce33af2d77,\n", "0xbf10413e306e0039,\n", "0xbf04a6704d05ad0b,\n", "0x3eb6c43eedfed6c9,\n", "0x3ea16abd7815de74,\n", "0xbe5257f16f5d4346,\n", "0xbe332db1b4b2ff8b,\n", "0x3de33acccf7bfdce,\n", "0x3dbdc8f5682566ba,\n", "0xbd6c6513386daae2,\n", "],\n", "[mpf('0.20701265272531904561'), mpf('0.0'), mpf('-0.10303781563402768034'), mpf('0.0022897295462872819796'), mpf('0.0084324350588640949335'), mpf('-0.00021965941962538873663'), mpf('-0.0002727215439833826185'), mpf('7.3690946296541228767e-6'), mpf('4.6821283504536998329e-6'), mpf('-1.2611231003634097541e-7'), mpf('-4.9736271581451709565e-8'), mpf('1.3107727339970544703e-9'), mpf('3.5930850401806135325e-10'), mpf('-9.1762541875983448868e-12'), mpf('-1.8817794951369846518e-12'), mpf('4.6331867400008658346e-14')]\n", "[\n", "0x3fca7f63fea81f26,\n", "0x0000000000000000,\n", "0xbfba60afb06640cf,\n", "0x3f62c1e930935d3c,\n", "0x3f814506466d7f1f,\n", "0xbf2cca8c0c0eaa3f,\n", "0xbf31df821cc1377e,\n", "0x3edee8814ed0ac45,\n", "0x3ed3a365a4199dd1,\n", "0xbe80ed2f9c3e458e,\n", "0xbe6ab3b37c5271b3,\n", "0x3e1684d6e62b5c66,\n", "0x3df8b105a5120ed2,\n", "0xbda42dc5991b9d01,\n", "0xbd808d6405ffe3dc,\n", "],\n", "[mpf('0.0'), mpf('-0.19646537146865718291'), mpf('0.0059641122064480035393'), mpf('0.032382122684890818592'), mpf('-0.00097203375623040993631'), mpf('-0.001584230341756570203'), mpf('0.000046667442231393631168'), mpf('0.000036572573538843407202'), mpf('-1.0499615284344570279e-6'), mpf('-4.8917908609698244358e-7'), mpf('1.3610422078373997128e-8'), mpf('4.264651809545571522e-9'), mpf('-1.1453319428019084657e-10'), mpf('-2.6162364234398161592e-11'), mpf('6.7651044753415446295e-13'), mpf('1.1916937033915236338e-13')]\n", "[\n", "0x0000000000000000,\n", "0xbfc925c6fca08f55,\n", "0x3f786dd32e059b0e,\n", "0x3fa09463bbd0367f,\n", "0xbf4fda0298c8768b,\n", "0xbf59f4be60758fb1,\n", "0x3f0877991af9d1bb,\n", "0x3f032cb00ee8c1f3,\n", "0xbeb19d8ce8c35f58,\n", "0xbea06a042fbba455,\n", "0x3e4d3a689e677731,\n", "0x3e325108c4ce2b63,\n", "0xbddf7b8e9ab53152,\n", "0xbdbcc40d05652642,\n", "0x3d67cd76e2d7e2cb,\n", "],\n", "[mpf('-0.18801748852581776019'), mpf('0.0'), mpf('0.093719093772432139904'), mpf('-0.0017233243363060656687'), mpf('-0.0077142667601276035727'), mpf('0.00016755862376976238962'), mpf('0.00025182717468682616633'), mpf('-5.7335172626499247136e-6'), mpf('-4.3724260796916482492e-6'), mpf('1.0045696055698888501e-7'), mpf('4.6984557443518690411e-8'), mpf('-1.0697010970466780361e-9'), mpf('-3.4303476631796167721e-10'), mpf('7.6603335590907537838e-12'), mpf('1.8130313743728005892e-12'), mpf('-3.9468461501640107271e-14')]\n", "[\n", "0xbfc810f50225b04b,\n", "0x0000000000000000,\n", "0x3fb7fdf97ac36b1f,\n", "0xbf5c3c256a8caa05,\n", "0xbf7f98feb7286b47,\n", "0x3f25f6559e5686e2,\n", "0x3f3080f57ac215af,\n", "0xbed80c51397e5eba,\n", "0xbed256db543cd140,\n", "0x3e7af7598a219824,\n", "0x3e69398226ca2305,\n", "0xbe1260985d92587d,\n", "0xbdf792bb3eea6f6a,\n", "0x3da0d862695e1a7a,\n", "0x3d7fe52adc2baacf,\n", "],\n", "[mpf('0.0'), mpf('0.18006337534431555427'), mpf('-0.004589739858906061618'), mpf('-0.029776581472313524138'), mpf('0.00075302848385339223811'), mpf('0.0014660390526561338733'), mpf('-0.000036589009383100233434'), mpf('-0.00003413723646008697731'), mpf('8.3663282076993441633e-7'), mpf('4.6108501645071014599e-7'), mpf('-1.1048051583135713088e-8'), mpf('-4.0592781268151169221e-9'), mpf('9.4754892811648019785e-11'), mpf('2.5129092903968349706e-11'), mpf('-5.6991401136718529955e-13'), mpf('-1.1538053180898008511e-13')]\n", "[\n", "0x0000000000000000,\n", "0x3fc70c511227d5aa,\n", "0xbf72ccb0e97558da,\n", "0xbf9e7dc08e70e99a,\n", "0x3f48acdc5b058c0e,\n", "0x3f580503724ad30a,\n", "0xbf032ee4ca1fcafb,\n", "0xbf01e5d2836c8d99,\n", "0x3eac129f077bb163,\n", "0x3e9ef161591181a2,\n", "0xbe47b9bb07f19f82,\n", "0xbe316f3937595d96,\n", "0x3dda0bc8665b687b,\n", "0x3dbba135f99a9e19,\n", "0xbd640d543d2cbdf0,\n", "],\n", "[mpf('0.17345904928574641885'), mpf('0.0'), mpf('-0.086535901938761234037'), mpf('0.0013568189856143958374'), mpf('0.0071472165207372924636'), mpf('-0.00013295776592377230269'), mpf('-0.00023462959312285641247'), mpf('4.6031433817449970156e-6'), mpf('4.1031973660369767959e-6'), mpf('-8.1836132695052081749e-8'), mpf('-4.4443075049241166797e-8'), mpf('8.8555360853740138601e-10'), mpf('3.2707069022519079013e-10'), mpf('-6.4458409250944729908e-12'), mpf('-1.7415885876852885479e-12'), mpf('3.3732747135854115034e-14')]\n", "[\n", "0x3fc633e7f7f05301,\n", "0x0000000000000000,\n", "0xbfb6273784c1c06e,\n", "0x3f563ae94ade18d4,\n", "0x3f7d4666536c88b9,\n", "0xbf216d528345ca11,\n", "0xbf2ec0dcdbb7c5fe,\n", "0x3ed34e966b0b09f8,\n", "0x3ed135c64dc2d8d0,\n", "0xbe75f7bc78b5fc2b,\n", "0xbe67dc35b0764096,\n", "0x3e0e6d697361ea54,\n", "0x3df679e3704987b4,\n", "0xbd9c595f278a4d6c,\n", "0xbd7ea36aef56eec0,\n", "],\n", "[mpf('0.0'), mpf('-0.16718460047381804539'), mpf('0.0036727588017286566178'), mpf('0.027702731661334967662'), mpf('-0.00060503649246538873817'), mpf('-0.0013693112504510835584'), mpf('0.000029615596937998213397'), mpf('0.000032060961900116606979'), mpf('-6.8410614399343638744e-7'), mpf('-4.3588795163776394705e-7'), mpf('9.144492104447539661e-9'), mpf('3.8644489921496516588e-9'), mpf('-7.947190941712038235e-11'), mpf('-2.4090019529127878926e-11'), mpf('4.844331366939744486e-13'), mpf('1.1133632079140188325e-13')]\n", "[\n", "0x0000000000000000,\n", "0xbfc5664e13b70622,\n", "0x3f6e16555e108dc6,\n", "0x3f9c5e1ad9fb2f40,\n", "0xbf43d369f958e56a,\n", "0xbf566f4ec27a96e9,\n", "0x3eff0de0532652d5,\n", "0x3f00cf264341409e,\n", "0xbea6f46d51e5766f,\n", "0xbe9d407f7c248d45,\n", "0x3e43a33cd9df6696,\n", "0x3e309901b0a816e5,\n", "0xbdd5d856a58443f5,\n", "0xbdba7cbcd8fc0758,\n", "0x3d610b62c2fd47f6,\n", "],\n", "[mpf('-0.1618382095526585164'), mpf('0.0'), mpf('0.080782195225750007446'), mpf('-0.0011038527651115924277'), mpf('-0.0066864447268136515803'), mpf('0.00010870535077588026585'), mpf('0.00022030197370284177491'), mpf('-3.7918054763244086637e-6'), mpf('-3.8711490352810117618e-6'), mpf('6.8059764283039660805e-8'), mpf('4.2162867094338606536e-8'), mpf('-7.4460684763210260148e-10'), mpf('-3.1211691604242614993e-10'), mpf('5.4835588665561701385e-12'), mpf('1.6716817971649224399e-12'), mpf('-2.9036016761662095926e-14')]\n", "[\n", "0xbfc4b71d4ca2cc69,\n", "0x0000000000000000,\n", "0x3fb4ae245697fba6,\n", "0xbf5215e4e1a5f1d6,\n", "0xbf7b633ed6d9cf61,\n", "0x3f1c7f17b4b7dbbd,\n", "0x3f2ce01b8b6aa34c,\n", "0xbecfced71b11e35b,\n", "0xbed03c9d5823261d,\n", "0x3e724508091063b2,\n", "0x3e66a2d20111e303,\n", "0xbe0995a18f8e6888,\n", "0xbdf572d1a074f647,\n", "0x3d981df03c1911f1,\n", "0x3d7d6895e48f475d,\n", "],\n", "[mpf('0.0'), mpf('0.1567249862528522302'), mpf('-0.0030251499811056658906'), mpf('-0.026004046442226119582'), mpf('0.00049968324480690083845'), mpf('0.0012886979076641241942'), mpf('-0.000024577609477776825142'), mpf('-0.000030285619999010918203'), mpf('5.7159860901122563806e-7'), mpf('4.1362773860810494807e-7'), mpf('-7.7044747635491453928e-9'), mpf('-3.6857163491591207957e-9'), mpf('6.7586718488333867274e-11'), mpf('2.3097146345017692933e-11'), mpf('-4.1607352443927805465e-13'), mpf('-1.0730436022610238832e-13')]\n", "[\n", "0x0000000000000000,\n", "0x3fc40f90793605bb,\n", "0xbf68c833077fbeae,\n", "0xbf9aa0ce0421d1a8,\n", "0x3f405fa598ef5d1d,\n", "0x3f551d30d78ab526,\n", "0xbef9c5807675c5f6,\n", "0xbeffc1bbf57e3ae2,\n", "0x3ea32dfea2518ce6,\n", "0x3e9bc212085dcbc6,\n", "0xbe408b946d64c5c2,\n", "0xbe2fa8f9d8da736a,\n", "0x3dd293fe14af1d0f,\n", "0x3db96544cb75a58d,\n", "0xbd5d4750748e2ce8,\n", "],\n", "[mpf('0.15228206634189006899'), mpf('0.0'), mpf('-0.076040035583846372143'), mpf('0.0009206869010854983218'), mpf('0.0063031377382864250006'), mpf('-0.000090970053990075185986'), mpf('-0.00020818857704001538427'), mpf('3.1893311520043682698e-6'), mpf('3.6705205791972406023e-6'), mpf('-5.7623989978039676433e-8'), mpf('-4.0136830087665377774e-8'), mpf('6.3533272959999965554e-10'), mpf('2.9841687721674000928e-10'), mpf('-4.7187363556971390774e-12'), mpf('-1.6055273678339172038e-12'), mpf('2.5208428185615752596e-14')]\n", "[\n", "0x3fc37dfa8f5a550a,\n", "0x0000000000000000,\n", "0xbfb3775c1a04f09c,\n", "0x3f4e2b4810a46c60,\n", "0x3f79d151a72b83a8,\n", "0xbf17d8e5a090e4e6,\n", "0xbf2b49a6427386a0,\n", "0x3ecac10957ddd2eb,\n", "0x3ececa620745d3d3,\n", "0xbe6eefc7e795dcdd,\n", "0xbe658c5d2a0da41d,\n", "0x3e05d4721f44a8f9,\n", "0x3df481ce2314af59,\n", "0xbd94c0d3279e920c,\n", "0xbd7c3ea707530563,\n", "],\n", "[mpf('0.0'), mpf('-0.14801110997277754414'), mpf('0.0025478015576615379632'), mpf('0.02458080474056066546'), mpf('-0.00042161386264394085718'), mpf('-0.0012203728389620493503'), mpf('0.00002080746359569829308'), mpf('0.0000287548675998798571'), mpf('-4.8621923672992888475e-7'), mpf('-3.9400451865642030503e-7'), mpf('6.5925374446715391421e-9'), mpf('3.523979205857853173e-9'), mpf('-5.822692462094286559e-11'), mpf('-2.217217180651544635e-11'), mpf('3.6110666676518030368e-13'), mpf('1.0342982977987302316e-13')]\n", "[\n", "0x0000000000000000,\n", "0xbfc2f2072e638cf4,\n", "0x3f64df208bbd44f1,\n", "0x3f992bb5e1e159fc,\n", "0xbf3ba181c06897cd,\n", "0xbf53fe9d5baa4a3d,\n", "0x3ef5d17602b01cac,\n", "0x3efe26d3747fe829,\n", "0xbea0509768ab6ecb,\n", "0xbe9a70f232d9d06c,\n", "0x3e3c509252de33f9,\n", "0x3e2e454fee07116e,\n", "0xbdd0015b062ba125,\n", "0xbdb860e95adf840f,\n", "0x3d59691e90f7d9c0,\n", "],\n", "[mpf('-0.14424290218193798279'), mpf('0.0'), mpf('0.072044437562627664092'), mpf('-0.00078307073022993910608'), mpf('-0.0059781141915457615681'), mpf('0.000077554773205678707992'), mpf('0.00019780236837872788842'), mpf('-2.7288104932140985886e-6'), mpf('-3.4958120742280083257e-6'), mpf('4.9536406033915099305e-8'), mpf('3.8338261429071824386e-8'), mpf('-5.4924724311985451484e-10'), mpf('-2.859827049984700689e-10'), mpf('4.1051898763709794572e-12'), mpf('1.5440195398890325414e-12'), mpf('-2.2079134307152385546e-14')]\n", "[\n", "0xbfc2768d29c69936,\n", "0x0000000000000000,\n", "0x3fb271811730b0ef,\n", "0xbf49a8df96a1225e,\n", "0xbf787c81cf1c6fc4,\n", "0x3f14549cdbb77978,\n", "0x3f29ed2568116e19,\n", "0xbec6e4136f033ace,\n", "0xbecd53330316cde7,\n", "0x3e6a983b5782dfca,\n", "0x3e64952ba7c5a1dc,\n", "0xbe02df3ad6f82e0d,\n", "0xbdf3a70f9a89d2c2,\n", "0x3d920e086c17f5dc,\n", "0x3d7b29a554c1159f,\n", "],\n", "[mpf('0.0'), mpf('0.14060579818398225406'), mpf('-0.0021840198251869790085'), mpf('-0.023366451249280341401'), mpf('0.00036189553399826029025'), mpf('0.0011616031973470813372'), mpf('-0.000017903598614259314602'), mpf('-0.000027422245345846301253'), mpf('4.1980686260628888719e-7'), mpf('3.7665128146866751195e-7'), mpf('-5.7168211453121149255e-9'), mpf('-3.3782385492932150376e-9'), mpf('5.0748836429127423531e-11'), mpf('2.1320762911883112676e-11'), mpf('-3.164977963993869816e-13'), mpf('-9.9780070194985945396e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fc1ff5eec6a01cd,\n", "0xbf61e438b722c3b5,\n", "0xbf97ed5fffc1c774,\n", "0x3f37b7997babd9ca,\n", "0x3f53081def9612c5,\n", "0xbef2c5f5edafc4e9,\n", "0xbefcc11a59e13739,\n", "0x3e9c2c3a1b8014a3,\n", "0x3e9946d1dab7bd01,\n", "0xbe388db61946be64,\n", "0xbe2d04d33be580e8,\n", "0x3dcbe64386d2c5d0,\n", "0x3db77142e0e4497b,\n", "0xbd56458476679697,\n", "],\n", "[mpf('0.13735719367686963677'), mpf('0.0'), mpf('-0.068618289230663856351'), mpf('0.00067659675980545606419'), mpf('0.0056981411902270204405'), mpf('-0.000067125116991851375395'), mpf('-0.00018878432147593585483'), mpf('2.3680904387636439188e-6'), mpf('3.3424149628029455411e-6'), mpf('-4.3138368684968676721e-8'), mpf('-3.6736795307417882556e-8'), mpf('4.8032593672720015895e-10'), mpf('2.7472821982052313852e-10'), mpf('-3.6072959659380978455e-12'), mpf('-1.4873239313390727629e-12'), mpf('1.9502641038116447443e-14')]\n", "[\n", "0x3fc194eba75b32f9,\n", "0x0000000000000000,\n", "0xbfb190f7dc27362b,\n", "0x3f462bb47a5c5f7f,\n", "0x3f7756ef20f5d2e2,\n", "0xbf1198b0ba97ecfb,\n", "0xbf28be8cf9358d55,\n", "0x3ec3dd6f7c8cc3c0,\n", "0x3ecc09c80ee7f9af,\n", "0xbe6728e46a451e32,\n", "0xbe63b91113508622,\n", "0x3e0080fddad62bf8,\n", "0x3df2e111e88dae1f,\n", "0xbd8fbae88bdab215,\n", "0xbd7a2a4fbea868a8,\n", "],\n", "[mpf('0.0'), mpf('-0.13421124031000068798'), mpf('0.0018992708036370826122'), mpf('0.02231478554381458829'), mpf('-0.00031502373577507190387'), mpf('-0.0011104068860942181078'), mpf('0.000015612943996162537742'), mpf('0.000026251114160604394424'), mpf('-3.67040152858382818e-7'), mpf('-3.6122468214170927615e-7'), mpf('5.0146404025683968102e-9'), mpf('3.2468644619907708949e-9'), mpf('-4.4687784404154502775e-11'), mpf('-2.0540951231528793857e-11'), mpf('2.7990743664438689948e-13'), mpf('9.6377993542495655026e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfc12dd57bf18ada,\n", "0x3f5f1e1e7f393e83,\n", "0x3f96d9afe88301fa,\n", "0xbf34a538a482979b,\n", "0xbf52316250b4ae37,\n", "0x3ef05f11577b4627,\n", "0x3efb86bad42fc220,\n", "0xbe98a1b3a9e92749,\n", "0xbe983dcaf3f8fcc5,\n", "0x3e3589a7ca5fdcf1,\n", "0x3e2be3ee3298bb99,\n", "0xbdc8913f1d0ff12a,\n", "0xbdb695c386660813,\n", "0x3d53b25d364762e7,\n", "],\n", "[mpf('-0.13137285618706717803'), mpf('0.0'), mpf('0.06563816016818494923'), mpf('-0.0005922259572351858309'), mpf('-0.0054537928406342264581'), mpf('0.000058831028520129374116'), mpf('0.00018086723514251230378'), mpf('-2.0796379637933189105e-6'), mpf('-3.2066223725228292883e-6'), mpf('3.7984267026736048842e-8'), mpf('3.530414976385124442e-8'), mpf('-4.2430381399132635892e-10'), mpf('-2.6453433841309821168e-10'), mpf('3.1984047351879080478e-12'), mpf('1.4352477227546607395e-12'), mpf('-1.7362821828332264282e-14')]\n", "[\n", "0xbfc0d0d36473e98c,\n", "0x0000000000000000,\n", "0x3fb0cda9974abe2b,\n", "0xbf4367f38f201c25,\n", "0xbf7656b75e3c242e,\n", "0x3f0ed82abf7489f1,\n", "0x3f27b4e5b83eeb36,\n", "0xbec171fd0fb670e7,\n", "0xbecae62b4ad017fb,\n", "0x3e64648495a7b49e,\n", "0x3e62f42a577135ad,\n", "0xbdfd286e7fa32656,\n", "0xbdf22dbcbf76a1c7,\n", "0x3d8c222accc0d2d2,\n", "0x3d793fc7f6c8d355,\n", "],\n", "[mpf('0.0'), mpf('0.12861662207206995471'), mpf('-0.0016714412413483688902'), mpf('-0.021392661147250082777'), mpf('0.00027744442273605626775'), mpf('0.0010653181511813165137'), mpf('-0.000013769481459014210127'), mpf('-0.000025212865164017827834'), mpf('3.2434377566741388442e-7'), mpf('3.4742933337009585248e-7'), mpf('-4.4425127738781929125e-9'), mpf('-3.1281347722274219089e-9'), mpf('3.970846653305358902e-11'), mpf('1.9827532690681618295e-11'), mpf('-2.495673464433207663e-13'), mpf('-9.3222944134563171038e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fc076826cc2c191,\n", "0xbf5b62885e0070c6,\n", "0xbf95e7f53001e4b1,\n", "0x3f322ebeb8dc2202,\n", "0x3f517444a7a04cd0,\n", "0xbeece06f1f1fcd7e,\n", "0xbefa7006e6ad9cfe,\n", "0x3e95c42f02cf15ca,\n", "0x3e9750ca5e1366b4,\n", "0xbe3314982df7eaa2,\n", "0xbe2aded75306b3b3,\n", "0x3dc5d47847d8ebf1,\n", "0x3db5ccf44d287a21,\n", "0xbd518fce3e04028a,\n", "],\n", "[mpf('0.12610881373023247946'), mpf('0.0'), mpf('-0.063015063678111263496'), mpf('0.00052403166729155237061'), mpf('0.0052381654592657222777'), mpf('-0.000052108952530121534115'), mpf('-0.00017384929009660832777'), mpf('1.8448696857641598153e-6'), mpf('3.0854858035018361065e-6'), mpf('-3.3765713662376143148e-8'), mpf('-3.4015778101107583915e-8'), mpf('3.7813289723926428058e-10'), mpf('2.5527851056481057277e-10'), mpf('-2.8587137150130485859e-12'), mpf('-1.3874438089351992559e-12'), mpf('1.5569367714354429436e-14')]\n", "[\n", "0x3fc02455675ab6d2,\n", "0x0000000000000000,\n", "0xbfb021c155a720df,\n", "0x3f412be56fc1449a,\n", "0x3f75749d556ad61c,\n", "0xbf0b51f1f9bea93e,\n", "0xbf26c96a07e236bd,\n", "0x3ebef3a7abd5ac6b,\n", "0x3ec9e207c257433a,\n", "0xbe6220b96eef8058,\n", "0xbe624317cb296737,\n", "0x3df9fc2f2cd3917f,\n", "0x3df18ae8347e8256,\n", "0xbd892540423f2dda,\n", "0xbd78687dcdc2e3a9,\n", "],\n", "[mpf('0.0'), mpf('-0.12366796076983712553'), mpf('0.0014857832233245892167'), mpf('0.020575625522420598617'), mpf('-0.0002467726860606215756'), mpf('-0.0010252317618176783395'), mpf('0.000012260493246807405047'), mpf('0.00002428509482378614297'), mpf('-2.892474248649144559e-7'), mpf('-3.3501900411905544966e-7'), mpf('3.9696871646433667259e-9'), mpf('3.0204454462249066396e-9'), mpf('-3.5566813238643349943e-11'), mpf('-1.9174244290466465183e-11'), mpf('2.2414588098737333594e-13'), mpf('9.0302684391464567514e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfbfa8b41711c83a,\n", "0x3f5857d3969997d1,\n", "0x3f9511c6dadaaa12,\n", "0xbf302c289dbdbd4f,\n", "0xbf50cc2238d229f9,\n", "0x3ee9b64d5c63668f,\n", "0x3ef976fb023f0f79,\n", "0xbe93693ba0b5ba70,\n", "0xbe967b952987350c,\n", "0x3e310cb79a2addac,\n", "0x3e29f2079f8e397f,\n", "0xbdc38d957eaa53ad,\n", "0xbdb51511e93ba74c,\n", "0x3d4f8bb4d9d2f3a4,\n", "],\n", "[mpf('-0.12143117472506242591'), mpf('0.0'), mpf('0.06068301848901461377'), mpf('-0.00046798373869105269614'), mpf('-0.0050460793867432656603'), mpf('0.00004657248334010626799'), mpf('0.00016757561346322504388'), mpf('-1.6508729078842472609e-6'), mpf('-2.9766582142050264065e-6'), mpf('3.026442193985882438e-8'), mpf('3.2850977324541320745e-8'), mpf('-3.3960401211034057052e-10'), mpf('-2.4684678559501814245e-10'), mpf('2.5734519929705973743e-12'), mpf('1.3435163361599110044e-12'), mpf('-1.4052621438068119981e-14')]\n", "[\n", "0xbfbf161d0c28b48c,\n", "0x0000000000000000,\n", "0x3faf11d837aa6f64,\n", "0xbf3eab76da4d07a0,\n", "0xbf74ab329f067aea,\n", "0x3f086ada57bc1c51,\n", "0x3f25f6e78f11ab9a,\n", "0xbebbb271f54c8965,\n", "0xbec8f85328c26cb7,\n", "0x3e603f82aebdeac1,\n", "0x3e61a3010279a195,\n", "0xbdf75660809cdedf,\n", "0xbdf0f6931774a05f,\n", "0x3d86a2e61267070b,\n", "0x3d77a2a8e0311c3a,\n", "],\n", "[mpf('0.0'), mpf('0.11924981201068947389'), mpf('-0.0013321227252914966475'), mpf('-0.019845206760646177583'), mpf('0.00022135552211912821184'), mpf('0.00098929900297625096204'), mpf('-0.000011007155899517397606'), mpf('-0.000023450118334627794185'), mpf('2.6000062802475015804e-7'), mpf('3.2379070001649506525e-7'), mpf('-3.5739871846906196357e-9'), mpf('-2.9223781669901756779e-9'), mpf('3.2082938047881017166e-11'), mpf('1.8574790148799141929e-11'), mpf('-2.0263600003929869535e-13'), mpf('-8.7599981026004179116e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fbe8727daa3daed,\n", "0xbf55d353e2854a37,\n", "0xbf94524d4813cc25,\n", "0x3f2d037574e28370,\n", "0x3f50356bb747a763,\n", "0xbee7156bfccef376,\n", "0xbef896d7dc819faf,\n", "0x3e9172c6dadf4149,\n", "0x3e95baae8efc2e31,\n", "0xbe2eb347eb4d6941,\n", "0xbe291a60a72a20e0,\n", "0x3dc1a345a9a6a5f7,\n", "0x3db46c56b01906be,\n", "0xbd4c84bb37677838,\n", "],\n", "[mpf('0.11723850698826188924'), mpf('0.0'), mpf('-0.058591931604755768015'), mpf('0.0004212564508913367181'), mpf('0.0048735664050833566691'), mpf('-0.000041948963235994156563'), mpf('-0.00016192551179550872492'), mpf('1.488442749615247626e-6'), mpf('2.8782603436163280391e-6'), mpf('-2.7322574187104928635e-8'), mpf('-3.1792477143666852709e-8'), mpf('3.0709092330172714681e-10'), mpf('2.3913786177203120479e-10'), mpf('-2.3315063622280832608e-12'), mpf('-1.3030723486672298974e-12'), mpf('1.275882329931853387e-14')]\n", "[\n", "0x3fbe0357c158b119,\n", "0x0000000000000000,\n", "0xbfadffc2fc1a91f5,\n", "0x3f3b9b82ae07da44,\n", "0x3f73f64e05320ac6,\n", "0xbf05fe4b66cf19d8,\n", "0xbf2539518e1b00f5,\n", "0x3eb8f8d01c487905,\n", "0x3ec825045b97e2dc,\n", "0xbe5d565f3bb61dea,\n", "0xbe611186586f4f74,\n", "0x3df51a669158191b,\n", "0x3df06ef52f6715ac,\n", "0xbd848215e95caa77,\n", "0xbd76ec8422019b0d,\n", "],\n", "[mpf('0.0'), mpf('-0.11527369412016796109'), mpf('0.0012032377717211320913'), mpf('0.019187163332992513391'), mpf('-0.00020001523917770440769'), mpf('-0.00095685721186639321177'), mpf('9.9529214636049313319e-6'), mpf('0.000022693837092493148082'), mpf('-2.3533465884428004375e-7'), mpf('-3.1357737141400849799e-7'), mpf('3.2391196416795372609e-9'), mpf('2.8327080615337696584e-9'), mpf('-2.9122430332545317206e-11'), mpf('-1.8023290089818150302e-11'), mpf('1.842700788272845082e-13'), mpf('8.5096104951123437343e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfbd8293aa55d18f,\n", "0x3f53b6beb83f2596,\n", "0x3f93a5ccbc12a67b,\n", "0xbf2a3765d26aa42b,\n", "0xbf4f5ab33748c215,\n", "0x3ee4df6f1c257a5c,\n", "0x3ef7cbd49c315be0,\n", "0xbe8f96098cf07175,\n", "0xbe950b37dd43531f,\n", "0x3e2bd2e6405c605d,\n", "0x3e285530df0d4b70,\n", "0xbdc0029e21930f25,\n", "0xbdb3d11aeba731a1,\n", "0x3d49ef077e065d17,\n", "],\n", "[mpf('-0.11345236875372799966'), mpf('0.0'), mpf('0.056702997975075682135'), mpf('-0.00038181618980959173131'), mpf('-0.004717530507927776673'), mpf('0.000038041180091757478737'), mpf('0.0001568035623766057419'), mpf('-1.3508679811621934642e-6'), mpf('-2.7887753727811054734e-6'), mpf('2.4823831348881216792e-8'), mpf('3.0825907833937410634e-8'), mpf('-2.7937785004333194433e-10'), mpf('-2.3206359017746757914e-10'), mpf('2.124425982927991973e-12'), mpf('1.2657451063731089465e-12'), mpf('-1.1646272854044076024e-14')]\n", "[\n", "0xbfbd0b36e5737458,\n", "0x0000000000000000,\n", "0x3fad082ce3c6b59b,\n", "0xbf3905d00c5e6800,\n", "0xbf7352b073fdac7b,\n", "0x3f03f1ccfec2fc88,\n", "0x3f248d74583834bc,\n", "0xbeb6a9ef0d896bae,\n", "0xbec764d9798d6a80,\n", "0x3e5aa785d6736f5c,\n", "0x3e608cae36118cdb,\n", "0xbdf332ddfb39cd01,\n", "0xbdefe502ff1a8f0d,\n", "0x3d82afc83348eeb2,\n", "0x3d764468c0a31511,\n", "],\n", "[mpf('0.0'), mpf('0.11167049685921129061'), mpf('-0.0010938750270489956341'), mpf('-0.018590319240108309814'), mpf('0.00018189266218435677901'), mpf('0.00092738116354388256092'), mpf('-9.0563087033760390883e-6'), mpf('-0.000022004894407132897823'), mpf('2.1431124771698214093e-7'), mpf('3.0424117784782828097e-7'), mpf('-2.952904910282455379e-9'), mpf('-2.7503882498933139404e-9'), mpf('2.6583466029907528906e-11'), mpf('1.7514444489909926449e-11'), mpf('-1.6845733189471409962e-13'), mpf('-8.2772617408598910116e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fbc96700bf039e2,\n", "0xbf51ec0b5de4befe,\n", "0xbf93095734a24496,\n", "0x3f27d74e12285cb2,\n", "0x3f4e636fe259352c,\n", "0xbee2fe11972bc0c6,\n", "0xbef712e4d44c4a74,\n", "0x3e8cc3adabae0452,\n", "0x3e946ad2d9cbeb5c,\n", "0xbe295d81ae83f621,\n", "0xbe27a02aefea3d60,\n", "0x3dbd3a949a72239d,\n", "0x3db341e0bb193b49,\n", "0xbd47b550a4f77497,\n", "],\n", "[mpf('0.11001101229397791746'), mpf('0.0'), mpf('-0.054985629119578350915'), mpf('0.00034816609399491054892'), mpf('0.0045755172670098514113'), mpf('-0.000034703389729877506672'), mpf('-0.00015213331573688497587'), mpf('1.2331571119500546195e-6'), mpf('2.7069682357785392548e-6'), mpf('-2.2680902706374642863e-8'), mpf('-2.9939292855895413156e-8'), mpf('2.5554231686142950649e-10'), mpf('2.2554802583856783502e-10'), mpf('-1.9457113714619332979e-12'), mpf('-1.2312029003178268593e-12'), mpf('1.0682387564835286559e-14')]\n", "[\n", "0x3fbc29ae8400a320,\n", "0x0000000000000000,\n", "0xbfac27138da31c2b,\n", "0x3f36d141fcbea853,\n", "0x3f72bdc71062acd6,\n", "0xbf0231cf643ffc17,\n", "0xbf23f0bf3b3fe8be,\n", "0x3eb4b05e955de175,\n", "0x3ec6b52b868fa5e2,\n", "0xbe585a7aa3e84cc3,\n", "0xbe6012d3384c9164,\n", "0x3df18f8c4872544f,\n", "0x3deeffc4029f2f06,\n", "0xbd811d5a3daf70fa,\n", "0xbd75a8d84ce12a33,\n", "],\n", "[mpf('0.0'), mpf('-0.1083853489436825497'), mpf('0.0010001314156689645446'), mpf('0.018045767295169327612'), mpf('-0.00016634793367443450774'), mpf('-0.00090044889834600844293'), mpf('8.286287770748178429e-6'), mpf('0.00002137404856697333671'), mpf('-1.9622391930884340383e-7'), mpf('-2.9566782272967089359e-7'), mpf('2.7060925583828969036e-9'), mpf('2.6745271978916839195e-9'), mpf('-2.4387875197199748322e-11'), mpf('-1.7043563642276806337e-11'), mpf('1.5473840093474820457e-13'), mpf('8.0612220129867857019e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfbbbf246914235f,\n", "0x3f5062daee35411a,\n", "0x3f927a96f174b6d1,\n", "0xbf25cdb5dea9c121,\n", "0xbf4d818348f98a0f,\n", "0x3ee160aab829409d,\n", "0x3ef6698d6ee99eb9,\n", "0xbe8a5633d8f0b3bf,\n", "0xbe93d788d61154a7,\n", "0x3e273ec2ae0084b9,\n", "0x3e26f958f6235deb,\n", "0xbdbad0939c43a9fe,\n", "0xbdb2bd56309cf195,\n", "0x3d45c709d717f2e4,\n", "],\n", "[mpf('-0.10686507535075525103'), mpf('0.0'), mpf('0.053415344587233653758'), mpf('-0.0003191825622460907532'), mpf('-0.0044455532184737894778'), mpf('0.000031825832572327258872'), mpf('0.00014785277784550322145'), mpf('-1.1315315363867808994e-6'), mpf('-2.6318243414797812446e-6'), mpf('2.0827236208299949692e-8'), mpf('2.9122611371894437657e-8'), mpf('-2.3487461296909401513e-10'), mpf('-2.1952598754866933852e-10'), mpf('1.7903070114614162343e-12'), mpf('1.1991506743860569981e-12'), mpf('-9.8414970496750869555e-15')]\n", "[\n", "0xbfbb5b8273b75055,\n", "0x0000000000000000,\n", "0x3fab59418c36a684,\n", "0xbf34eafeaa92aa79,\n", "0xbf7235801af9be44,\n", "0x3f00af9747d0be92,\n", "0x3f23611db0e1566f,\n", "0xbeb2fbe414da1250,\n", "0xbec613ccbb9cbe59,\n", "0x3e565cf274e84d31,\n", "0x3e5f452996e3dc2b,\n", "0xbdf023f5382da3ad,\n", "0xbdee2be24fbad63f,\n", "0x3d7f7ed3740f8cf5,\n", "0x3d75187e998a1997,\n", "],\n", "[mpf('0.0'), mpf('0.10537405539523521034'), mpf('-0.00091905288594202204669'), mpf('-0.017546310949665106584'), mpf('0.00015289583144877787632'), mpf('0.00087571726396494971413'), mpf('-7.6192421229311937245e-6'), mpf('-0.000020793705480462024803'), mpf('1.8053209475048557309e-7'), mpf('2.8776196882831319164e-7'), mpf('-2.4915540978496535426e-9'), mpf('-2.6043655973828521026e-9'), mpf('2.2474888248609966193e-11'), mpf('1.6606535949284576112e-11'), mpf('-1.4275243751549612083e-13'), mpf('-7.8599102161372103307e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fbaf9cb49c4f935,\n", "0xbf4e1d930b513228,\n", "0xbf91f7a8fec6eba8,\n", "0x3f240a55310866fc,\n", "0x3f4cb20c812fd3aa,\n", "0xbedff51953c6b6cc,\n", "0xbef5cdc48f5d75eb,\n", "0x3e883b091952c721,\n", "0x3e934fb685e58ab7,\n", "0xbe2566fc4369ab71,\n", "0xbe265f0f7de29720,\n", "0x3db8b61e5f9b7a00,\n", "0x3db24253069b78a9,\n", "0xbd441732d722b422,\n", "],\n", "[mpf('0.10397455861256390403'), mpf('0.0'), mpf('-0.051972288881237471182'), mpf('0.00029400750553696127899'), mpf('0.0043260315875465203049'), mpf('-0.00002932445908010619185'), mpf('-0.0001439111200657332205'), mpf('1.0430853729020322728e-6'), mpf('2.5625030170233119336e-6'), mpf('-1.9211350387294044552e-8'), mpf('-2.8367436879276048653e-8'), mpf('2.1682163909473344535e-10'), mpf('2.1394155348420923249e-10'), mpf('-1.6542373435932738478e-12'), mpf('-1.1693282689232714527e-12'), mpf('9.1032010436153507612e-15')]\n", "[\n", "0x3fba9e13a0db642a,\n", "0x0000000000000000,\n", "0xbfaa9c1ca2161b9b,\n", "0x3f3344a09efdc635,\n", "0x3f71b82c430a2381,\n", "0xbefebfb97bca01f2,\n", "0xbf22dcdb1bc1d038,\n", "0x3eb180047f0b79ae,\n", "0x3ec57eeeee84d0d0,\n", "0xbe54a0c699c8318b,\n", "0xbe5e7594e8a2c760,\n", "0x3dedccbbb4c0ba7f,\n", "0x3ded6766337b5c95,\n", "0xbd7d1a05cea18a02,\n", "0xbd74922fb50a29f1,\n", "],\n", "[mpf('0.0'), mpf('-0.10260056710339717423'), mpf('0.00084836685129376632915'), mpf('0.017086064842062572404'), mpf('-0.0001411624626315861832'), mpf('-0.00085290411144180015077'), mpf('7.0369187625099623987e-6'), mpf('0.000020257567646663438134'), mpf('-1.6681610676160948753e-7'), mpf('-2.8044358846377546361e-7'), mpf('2.3037229301322924001e-9'), mpf('2.539255362032374819e-9'), mpf('-2.0796704275232000962e-11'), mpf('-1.6199771830851734415e-11'), mpf('1.3221313774039008044e-13'), mpf('7.6719022129281063229e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfba4407e04298d1,\n", "0x3f4bcc9df0cf00b2,\n", "0x3f917f0266db2149,\n", "0xbf2280a052234a05,\n", "0xbf4bf2ada1f44071,\n", "0x3edd83d58032b48d,\n", "0x3ef53dd972d8f232,\n", "0xbe8663c1fe202028,\n", "0xbe92d1fbf2203ff6,\n", "0x3e23c9f0b759c5f9,\n", "0x3e25cfe1b012696d,\n", "0xbdb6ddc0795781e9,\n", "0xbdb1cfd49504266a,\n", "0x3d429b7af5214fbc,\n", "],\n", "[mpf('-0.10130665873405690441'), mpf('0.0'), mpf('0.05064016586156986602'), mpf('-0.00027197551271251256927'), mpf('-0.0042156294075031986387'), mpf('0.00002713394525093374988'), mpf('0.00014026624811818422052'), mpf('-9.655520943126805162e-7'), mpf('-2.4983019654441094841e-6'), mpf('1.7792894459695768376e-8'), mpf('2.7666644458391307961e-8'), mpf('-2.0094718665114134832e-10'), mpf('-2.0874666878940311929e-10'), mpf('1.534343409298639562e-12'), mpf('1.1415072536648587747e-12'), mpf('-8.4511469623885421182e-15')]\n", "[\n", "0xbfb9ef3bb2213b0b,\n", "0x0000000000000000,\n", "0x3fa9ed82007a9a45,\n", "0xbf31d2fdeeb29f8a,\n", "0xbf71446866ff1b83,\n", "0x3efc73b684f93259,\n", "0x3f22628de594b6c9,\n", "0xbeb03303c1427449,\n", "0xbec4f51007c51087,\n", "0x3e531adfa36f2213,\n", "0x3e5db4f306b19095,\n", "0xbdeb9e33598f899e,\n", "0xbdecb09ed6ecb896,\n", "0x3d7afe1183148a99,\n", "0x3d7414e442aa8d57,\n", "],\n", "[mpf('0.0'), mpf('0.1000351468115232617'), mpf('-0.00078629942830563519099'), mpf('-0.016660163477262458228'), mpf('0.00013085558420683066916'), mpf('0.00083177512953911054456'), mpf('-6.5250145198582105878e-6'), mpf('-0.000019760368082689363922'), mpf('1.5474587443709632705e-7'), mpf('2.736450743277933514e-7'), mpf('-2.1381991882249784312e-9'), mpf('-2.4786415053408337153e-9'), mpf('1.9315310287133023631e-11'), mpf('1.5820141285487122965e-11'), mpf('-1.2289116699088650868e-13'), mpf('-7.4959257099167780235e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fb99be744018c90,\n", "0xbf49c3f52a2af724,\n", "0xbf910f5ca51f98b0,\n", "0x3f2126c8e8ca2766,\n", "0x3f4b416f7d4fc313,\n", "0xbedb5e2e5580e1ce,\n", "0xbef4b862279de756,\n", "0x3e84c5071b39dc13,\n", "0x3e925d2fc3b19021,\n", "0xbe225df322279972,\n", "0xbe254a971eb6fe3b,\n", "0x3db53cc6c9922f2b,\n", "0x3db164f95180d8c1,\n", "0xbd414b9ef404ed89,\n", "],\n", "[mpf('0.098834184596222183876'), mpf('0.0'), mpf('-0.049405458536460670831'), mpf('0.00025256349994869946121'), mpf('0.0041132463629726776592'), mpf('-0.000025202841594906565653'), mpf('-0.0001368829808319239182'), mpf('8.9714121014927428183e-7'), mpf('2.4386299418914361688e-6'), mpf('-1.6539861311327607996e-8'), mpf('-2.7014175513361372061e-8'), mpf('1.8690343722178003018e-10'), mpf('2.038999250416499923e-10'), mpf('-1.4280904253427435801e-12'), mpf('-1.1154873435993946843e-12'), mpf('7.8721161931972536006e-15')]\n", "[\n", "0x3fb94d3276914e51,\n", "0x0000000000000000,\n", "0xbfa94bac1950e319,\n", "0x3f308d4ff8f2059e,\n", "0x3f70d90d29bfeecd,\n", "0xbefa6d56162f7fb4,\n", "0xbf21f107da23807d,\n", "0x3eae1a626277437b,\n", "0x3ec474eafd0cc642,\n", "0xbe51c27144f42d78,\n", "0xbe5d01999b1a4fe9,\n", "0x3de9b014801da87a,\n", "0x3dec061740bc8a45,\n", "0xbd791f8c2972547e,\n", "0xbd739fb558b7aa4d,\n", "],\n", "[mpf('0.0'), mpf('-0.097653015783173307152'), mpf('0.00073144790567323065329'), mpf('0.016264545139161660511'), mpf('-0.00012174383503990132813'), mpf('-0.00081213396686711768399'), mpf('6.0721815762788217075e-6'), mpf('0.000019297666677419638672'), mpf('-1.4405869140360647463e-7'), mpf('-2.6730895275681491999e-7'), mpf('1.9914664822881933103e-9'), mpf('2.4220468979100526358e-9'), mpf('-1.8000169030184880714e-11'), mpf('-1.5464913442462141562e-11'), mpf('1.1460115819491910409e-13'), mpf('7.3308489586119513174e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfb8ffc9bd24fe08,\n", "0x3f47f7d46ab33721,\n", "0x3f90a7a725d3fbc4,\n", "0xbf1fea1728f216b4,\n", "0xbf4a9cac69f0ed64,\n", "0x3ed977f48ff1056b,\n", "0x3ef43c2d8e698c10,\n", "0xbe8355d1a6765ea6,\n", "0xbe91f0553501d121,\n", "0x3e211b47f6a44829,\n", "0x3e24ce23303889a9,\n", "0xbdb3ca98df62221f,\n", "0xbdb100fc746529d7,\n", "0x3d4020f11e2dca08,\n", "],\n", "[mpf('-0.0965343798752921876'), mpf('0.0'), mpf('0.048256848126837736739'), mpf('-0.00023535520071323167442'), mpf('-0.0040179589561544606493'), mpf('0.000023490138467151720763'), mpf('0.00013373166797904434411'), mpf('-8.3642189841130020971e-7'), mpf('-2.3829855799638399216e-6'), mpf('1.5426583861495063866e-8'), mpf('2.6404849101912898507e-8'), mpf('-1.7441023066013380126e-10'), mpf('-1.9936551940059712276e-10'), mpf('1.3334257100117285396e-12'), mpf('1.0910928798294402314e-12'), mpf('-7.3553369254921115951e-15')]\n", "[\n", "0xbfb8b67a2481077d,\n", "0x0000000000000000,\n", "0x3fa8b51f21068ea2,\n", "0xbf2ed935c7aefa31,\n", "0xbf707522a5037f2d,\n", "0x3ef8a196061f8bbc,\n", "0x3f21874a47e3c1e3,\n", "0xbeac10cf34c04f17,\n", "0xbec3fd6c2d4fa2a4,\n", "0x3e50906d55522785,\n", "0x3e5c5a1c124dfa08,\n", "0xbde7f883b31a5f59,\n", "0xbdeb668cf53028e4,\n", "0x3d7775372d05b25d,\n", "0x3d7331d871d677e0,\n", "],\n", "[mpf('0.0'), mpf('0.095433339020535349088'), mpf('-0.00068269004174153639031'), mpf('-0.015895789147530446449'), mpf('0.00011364193049670885699'), mpf('0.00079381472111463433329'), mpf('-5.6693153429013185048e-6'), mpf('-0.000018865692793976654867'), mpf('1.3454321373299606924e-7'), mpf('2.6138606864225107376e-7'), mpf('-1.8606858452222984138e-9'), mpf('-2.3690596077487094041e-9'), mpf('1.6826517262570876729e-11'), mpf('1.5131701609754333781e-11'), mpf('-1.0719200328090639457e-13'), mpf('-7.1756671236823762396e-14')]\n", "[\n", "0x0000000000000000,\n", "0x3fb86e51be0a9153,\n", "0xbf465ed1b387e5da,\n", "0xbf9046fc5a218a86,\n", "0x3f1dca617fefa913,\n", "0x3f4a0300221528a7,\n", "0xbed7c7618906f1e2,\n", "0xbef3c838897d0a1e,\n", "0x3e820ede9f9dd7dd,\n", "0x3e918a94165592bb,\n", "0xbe1ff76205118f09,\n", "0xbe24599dfeef01a1,\n", "0x3db2803e59983134,\n", "0x3db0a33202feb043,\n", "0xbd3e2bff738680f8,\n", "],\n", "[mpf('0.094388034178857080293'), mpf('0.0'), mpf('-0.047184774934733867964'), mpf('0.00022001566929329634253'), mpf('0.0039289856695835246854'), mpf('-0.000021962791729735716415'), mpf('-0.00013078712862304664638'), mpf('7.8223872407558275716e-7'), mpf('2.3309408465651831655e-6'), mpf('-1.4432272956073114317e-8'), mpf('-2.5834210429547877517e-8'), mpf('1.6323978681956180938e-10'), mpf('1.9511237959858629649e-10'), mpf('-1.2486726776908588314e-12'), mpf('-1.0681695904995622782e-12'), mpf('6.8919635740651658607e-15')]\n", "[\n", "0x3fb829d06fee9266,\n", "0x0000000000000000,\n", "0xbfa8289a526d7785,\n", "0x3f2cd680355c9eb6,\n", "0x3f7017d70f512861,\n", "0xbef707978e2a0db8,\n", "0xbf21247ce15e7385,\n", "0x3eaa3f6125485ec1,\n", "0x3ec38da848401be9,\n", "0xbe4efe39d8db4cd8,\n", "0xbe5bbd40f1db0e94,\n", "0x3de66f7d49436f83,\n", "0x3dead0e8148229b3,\n", "0xbd75f78595133d0b,\n", "0xbd72ca9bb10321b3,\n", "],\n", "[mpf('0.0'), mpf('-0.093358453290454973105'), mpf('0.00063911844145426895193'), mpf('0.015550991590621156214'), mpf('-0.00010639992922867547593'), mpf('-0.00077667615750326345998'), mpf('5.3090362453010040925e-6'), mpf('0.000018461222450077951618'), mpf('-1.2602774154061398181e-7'), mpf('-2.5583413817217867922e-7'), mpf('1.7435437707627237553e-9'), mpf('2.3193224461052905671e-9'), mpf('-1.5774098387888381677e-11'), mpf('-1.4818414928445975014e-11'), mpf('1.0053953451412704343e-13'), mpf('7.0294883384864148163e-14')]\n", "[\n", "0x0000000000000000,\n", "0xbfb7e656efb009ae,\n", "0x3f44f15066f3d876,\n", "0x3f8fd932c26aad94,\n", "0xbf1be460dd86a0a4,\n", "0xbf49733b591879f8,\n", "0x3ed64488c56022e0,\n", "0x3ef35ba58bf2f993,\n", "0xbe80ea47bceb9a8f,\n", "0xbe912b327055d0e9,\n", "0x3e1df42fc4e2482c,\n", "0x3e23ec3e76876dba,\n", "0xbdb1580393f473c3,\n", "0xbdb04b0353c35935,\n", "0x3d3c4ca30ffe2a12,\n", "],\n", "[mpf('-0.092378802708031519143'), mpf('0.0'), mpf('0.046181101854151976967'), mpf('-0.00020627267591182377249'), mpf('-0.0038456601458460277282'), mpf('0.000020593912066699587302'), mpf('0.00012802782647440689028'), mpf('-7.3364968102942266305e-7'), mpf('-2.2821280051030681707e-6'), mpf('1.353993564033335372e-8'), mpf('2.5298408793480731944e-8'), mpf('-1.5320530748500725546e-10'), mpf('-1.9111343355225588559e-10'), mpf('1.1724509261116985428e-12'), mpf('1.046581709573312598e-12'), mpf('-6.4746793094789554707e-15')]\n", "[\n", "0xbfb7a62320798175,\n", "0x0000000000000000,\n", "0x3fa7a50ca4504bb8,\n", "0xbf2b095ccb50a68c,\n", "0xbf6f80ef11daa37a,\n", "0x3ef59822dc75b064,\n", "0x3f20c7e6a7c66630,\n", "0xbea89e00b5c358d0,\n", "0xbec324d5238b26d0,\n", "0x3e4d13a888d5dd30,\n", "0x3e5b29f941a95b07,\n", "0xbde50e6ebb3d1df6,\n", "0xbdea4434c6b929dd,\n", "0x3d74a03fe2c47842,\n", "0x3d7269628f2df98c,\n", "],\n", "];\n" ] } ], "source": [ "# Taylor series for f32\n", "mp.prec = 60\n", "print(f\"pub(crate) static J1F_COEFFS: [[u64; 15]; {len(j1_zeros)}] = [\")\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffsf(poly, x0):\n", " print(\"[\")\n", " for i in range(0, 15):\n", " coeff = poly[i]\n", " print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(j1_zeros)):\n", " k_range = j1_zeros[i]\n", " range_diff = k_range - prev_zero\n", " g_c = 1\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, j1, taylor, expm1\n", " # The j1 (Bessel J_1) function from mpmath will compute with mp.dps precision\n", " # The Taylor series computation will also respect mp.dps\n", " poly = taylor(lambda val: j1(val), x0, 16)\n", " # print(poly)\n", " print_taylor_coeffsf(poly, CDR(k_range))\n", " prev_zero = j1_zeros[i]\n", "\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 22, "id": "c0306fe2-d820-4000-a14e-82293f2dd219", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Max relative error over [0, 1]: 1.224074717441528028996975552824e-29\n", "Occurs at x = 0.9909999999999999920063942226989\n", "Max abs error over [0, 1]: 1.224074717441528028996975552824e-29\n", "Occurs at x = 0.9909999999999999920063942226989\n", "0x39ef08b2faac819b\n", "0.4318209025803349383680360368051\n", "0x3c800000003b1143\n", "0.4136748745759469052209620580648\n" ] } ], "source": [ "from mpmath import mp, j1, taylor, linspace, chebyfit\n", "\n", "# Set precision (decimal places)\n", "mp.prec = 107\n", "\n", "# Generate degree-46 Taylor series of J1(x) at x = 0\n", "poly = taylor(lambda val: j1(val), mp.mpf('1.8411837813407134767373918293742463'), 25)\n", "\n", "def polyeval(coeffs, x, center):\n", " \"\"\"Evaluate Taylor polynomial centered at `center` using Horner's method.\"\"\"\n", " u = x - center\n", " # result = mpf(0)\n", " # for c in reversed(coeffs):\n", " # result = result * u + c\n", " # return result\n", " result = RealField(53)(0)\n", " for (index, c) in enumerate(reversed(coeffs)):\n", " if index < 8:\n", " result = RealField(53)(result) * RealField(53)(u) + RealField(53)(c)\n", " else:\n", " result = RealField(107)(result) * RealField(107)(u) + RealField(107)(c)\n", " return result\n", "\n", "xs = linspace(0.991, 2, 1000) # 1000 evenly spaced points\n", "max_rel_error = 0\n", "max_abs_error = 0\n", "worst_x = None\n", "\n", "for x in xs:\n", " true_val = j1(x)\n", " approx_val = polyeval(poly, x, DD('1.8411837813407134767373918293742463'))\n", " if true_val != 0:\n", " rel_error = abs((approx_val - true_val) / true_val)\n", " if rel_error > max_rel_error:\n", " max_rel_error = rel_error\n", " worst_x = x\n", "\n", "print(f\"Max relative error over [0, 1]: {max_rel_error}\")\n", "print(f\"Occurs at x = {worst_x}\")\n", "worst_x = None\n", "\n", "for x in xs:\n", " true_val = j1(x)\n", " approx_val = polyeval(poly, x, DD('1.8411837813407134767373918293742463'))\n", " abs_error = abs(approx_val - true_val)\n", " if abs_error > max_abs_error:\n", " max_abs_error = abs_error\n", " worst_x = x\n", "\n", "print(f\"Max abs error over [0, 1]: {max_rel_error}\")\n", "print(f\"Occurs at x = {worst_x}\")\n", "\n", "print(double_to_hex(DD(max_rel_error)))\n", "print(polyeval(poly, mp.mpf('0.9750000000213042'), mp.mpf('1.8411837813407134767373918293742463')))\n", "def make_e(eps, p):\n", " return float((DD(1) + DD(2)**DD(-p)) / (DD(1) - eps - DD(2) ** DD(p + 1)*eps)) * 2**(-p)\n", "print(double_to_hex(make_e(DD('1.192857060732688978535982892962e-26'), 55)))\n", "print(polyeval(poly, DD('0.9218750000227204'), DD('1.8411837813407134767373918293742463')))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Compound.ipynb000064400000000000000000000274741046102023000146560ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 27, "id": "38d0650c-7644-42b4-8b35-1ad821557646", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LOG 43.16211491037066979311498440337232740\n", "5.559917313492231480000000000000000002e18\n" ] } ], "source": [ "from sage.all import *\n", "\n", "D = RealField(127)\n", "\n", "x = '10'\n", "y = '18'\n", "\n", "x0 = D(x)\n", "y0 = D(y)\n", "x0p1 = x0 + D(1)\n", "x0p1ln = x0p1.log()\n", "\n", "x0p1ln_y0 = x0p1ln * y0\n", "\n", "print(f\"LOG {x0p1ln_y0}\")\n", "\n", "z = x0p1ln_y0.exp() - D(1)\n", "\n", "print(z)\n" ] }, { "cell_type": "code", "execution_count": 28, "id": "10b712ae-2146-40ef-996f-862dbc4d3a86", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555555555, 0x3fa5555555555555, 0x3f81111125f3a235, 0x3f56c16c3fea7746\n" ] } ], "source": [ "import struct\n", "\n", "# Example array of big floats in SageMath\n", "bigfloats = [1,\n", "0.5,\n", "0.166666666666666657414808128123695496469736099243164,\n", "4.1666666666666664353702032030923874117434024810791e-2,\n", "8.333333941167623062917790832671016687527298927307e-3,\n", "1.38888903862928589014180680294430203502997756004333e-3]\n", "\n", "def double_to_hex(f):\n", " # Convert float to IEEE 754 double hex representation\n", " packed = struct.pack('>d', float(f)) # big-endian double\n", " return '0x' + packed.hex()\n", "\n", "hex_array = [double_to_hex(RR(x)) for x in bigfloats]\n", "\n", "print(\", \".join(hex_array))\n" ] }, { "cell_type": "code", "execution_count": 29, "id": "1ef374e7-9c2e-462c-863d-9516fd2549fe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x0000000000000000, 0x3ff0000000000000, 0x3a20e40000000000, 0x3ff0000000000000, 0x3a04820000000000, 0x3fe0000000000000, 0xbc756423c5338a66, 0x3fc5555555555556, 0xbc5560f74db5556c, 0x3fa5555555555556, 0x3c3648eca89bc6ac, 0x3f8111111144fbee, 0xbbd53d924ae90c8c, 0x3f56c16c16ffeecc\n", "0x400921fb54442d18\n", "0x3ca1a62633145c07\n" ] } ], "source": [ "import struct\n", "from sage.all import *\n", "\n", "R = RealField(52)\n", "\n", "def double_to_hex(f):\n", " # Converts Python float (f64) to hex string\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = R(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "DD = RealField(120)\n", "\n", "# Input RR array (high precision)\n", "bigfloats = [\n", "'1',\n", "'1.00000000000000000000000000010659482981798922020626',\n", "'0.50000000000000000000000000003235562306570556233134',\n", "'0.16666666666666666661650065088154907094781865583483',\n", "'4.1666666666666666656813389760732706689332161864754e-2',\n", "'8.333333339235663398545366857448291597622040747153e-3',\n", "'1.38888888977721761402414540629642690134205558400704e-3',\n", "]\n", "\n", "# Split first 4 as DD pairs\n", "dd_pairs = [split_double_double(DD(x)) for x in bigfloats]\n", "\n", "# Convert to hex\n", "hex_pairs = [(double_to_hex(hi), double_to_hex(lo)) for hi, lo in dd_pairs]\n", "\n", "# Print as flat list\n", "flat_hex = [x for pair in hex_pairs for x in pair]\n", "print(\", \".join(flat_hex))\n", "\n", "d_pi = split_double_double(DD.pi())\n", "pi_hi = double_to_hex(d_pi[1])\n", "pi_lo = double_to_hex(d_pi[0])\n", "print(pi_hi)\n", "print(pi_lo)" ] }, { "cell_type": "code", "execution_count": 47, "id": "e1149a60-2bf0-46c9-91c0-3407d2ea403b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1*x + (-1/2)*x^2 + 1/3*x^3 + (-1/4)*x^4 + 1/5*x^5 + (-1/6)*x^6 + 1/7*x^7 + (-1/8)*x^8 + 1/9*x^9 + Order(x^10)\n", "\n", "Coefficients:\n", "(0x0000000000000000, 0x3ff0000000000000),\n", "(0x0000000000000000, 0xbfe0000000000000),\n", "(0xbe25555558000000, 0x3fd5555558000000),\n", "(0x0000000000000000, 0xbfd0000000000000),\n", "(0x3e099999a0000000, 0x3fc9999998000000),\n", "(0x3e15555558000000, 0xbfc5555558000000),\n", "(0x3e12492490000000, 0x3fc2492490000000),\n", "(0x0000000000000000, 0xbfc0000000000000),\n", "(0xbe0c71c720000000, 0x3fbc71c720000000),\n", "\n", "Coefficients double:\n", "(0x3ff0000000000000),\n", "(0xbfe0000000000000),\n", "(0x3fd5555555555556),\n", "(0xbfd0000000000000),\n", "(0x3fc999999999999a),\n", "(0xbfc5555555555556),\n", "(0x3fc2492492492492),\n", "(0xbfc0000000000000),\n", "(0x3fbc71c71c71c71c),\n" ] } ], "source": [ "import struct\n", "from sage.all import *\n", "\n", "terms = 10\n", "\n", "var('x')\n", "f = log(1 + x)\n", "t = f.series(x == 0, terms) # up to x^9 (9 terms)\n", "print(t)\n", "\n", "R = RealField(52)\n", "\n", "DD = RealField(120)\n", "\n", "def double_to_hex(f):\n", " # Converts Python float (f64) to hex string\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = R(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def vetkamp_split(a):\n", " \"\"\"\n", " Split a double-precision float into two parts using the Dekker/Vetkamp trick.\n", " Returns (hi, lo) such that a = hi + lo and hi contains the leading bits.\n", " \"\"\"\n", " # Use 2^27 + 1 as the constant for f64 splitting (Dekker's method)\n", " C = float(2**27 + 1)\n", " t1 = C * a\n", " t2 = a - t1\n", " r_hi = t1 + t2\n", " r_lo = a - r_hi\n", " return r_lo, r_hi\n", "\n", "print(\"\\nCoefficients:\")\n", "for i in range(1, terms): # log(1+x) has no constant term\n", " coeff = t.coefficient(x**i)\n", " k = split_double_double(DD(coeff))\n", " hi = double_to_hex(k[1])\n", " lo = double_to_hex(k[0])\n", " print(f\"({lo}, {hi}),\")\n", " # print(f\"x^{i}: {coeff}\")\n", "\n", "print(\"\\nCoefficients double:\")\n", "for i in range(1, terms): \n", " coeff = t.coefficient(x**i)\n", " k = split_double_double(DD(coeff))\n", " hi = double_to_hex(k[1])\n", " print(f\"({hi}),\")\n", " # print(f\"x^{i}: {coeff}\")" ] }, { "cell_type": "code", "execution_count": 55, "id": "8c1dbf7c-c181-4184-9a6d-2ba3fac152e6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x0000000000000000, 0x3ff0000000000000, 0x0000000000000000, 0xbfe0000000000000, 0xbc85555555555556, 0x3fd5555555555556, 0x3999c00000000000, 0xbfd0000000000000, 0xbc6999999981f36e, 0x3fc999999999999a, 0x3c7555554743d27d, 0xbfc5555555555556, 0x3c6247f02d51c658, 0x3fc2492492492492, 0x3c26ef9953cc6840, 0xbfc0000000000000, 0xbc60a66163a63ed2, 0x3fbc71c71c71c758, 0x3c69d1ae7ae4abd1, 0xbfb999999999e040, 0x3c67d7eee3debe26, 0x3fb745d173affb86, 0xbc3ef276254f5c00, 0xbfb5555485be87b6, 0x3c51f94d5ec7053e, 0x3fb3b2041e0a9ef8, 0x3c3d1e0180b9b780, 0xbfb333afb6247696\n" ] } ], "source": [ "bigfloats = [\n", "'1',\n", "'-0.5',\n", "'0.333333333333333333333333333333332306170696326807545036811763954705430113012454285126295872032642364501953125',\n", "'-0.249999999999999999999999999999682606745164983531416374835062003977904920848374104025424458086490631103515625',\n", "'0.200000000000000000000000002387949136540462961767856959621631279485666488060502388179884292185306549072265625',\n", "'-0.166666666666666666666667393986043856317874326241244099980138147656764935344853029164369218051433563232421875',\n", "'0.1428571428571428571408163599106053233656149391100956916031132384707624805031400683219544589519500732421875',\n", "'-0.12499999999999999937832028113316696072215483698725704640401028516598358475420127433608286082744598388671875',\n", "'0.11111111111111193038972057718902279427957977404456151551405321587537126937217379918365622870624065399169921875',\n", "'-0.1000000000002509880241711464546716390478971261945224395226512311622528439425394708450767211616039276123046875',\n", "'9.0909090751649750743304935100388324903899779563569833378440453413964206230701847744057886302471160888671875e-2',\n", "'-8.3333285000235375895682579496227015767268553492735970464138327284953078333273879252374172210693359375e-2',\n", "'7.69350598662831325463995536139570999801209091083709001164372138083062668822975638249772600829601287841796875e-2',\n", "'-7.5007421463363447931295368457235624520969053746502721052817207365859264456275923294015228748321533203125e-2',\n", "]\n", "\n", "# Split first 4 as DD pairs\n", "dd_pairs = [split_double_double(DD(x)) for x in bigfloats]\n", "\n", "# Convert to hex\n", "hex_pairs = [(double_to_hex(hi), double_to_hex(lo)) for hi, lo in dd_pairs]\n", "\n", "# Print as flat list\n", "flat_hex = [x for pair in hex_pairs for x in pair]\n", "print(\", \".join(flat_hex))" ] }, { "cell_type": "code", "execution_count": 57, "id": "27e53241-55b6-4b7f-9892-56bd8b29ac3e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = 0.001960754394531250000000000000000\n", "Approximation: 0.001958834624688574780016617412059\n", "True log(1 + x): 0.001958834624688574780016617412059\n", "Absolute error (ULPs): -0.0000000000000000000000000000000\n", "Relative error (ULPs): -0.0000000000000000000000000000000\n" ] } ], "source": [ "R = RealField(106) # ~106 bits = double-double\n", "coeffs = [R(s) for s in bigfloats]\n", "\n", "# Polynomial evaluation function (Horner's method)\n", "def dd_polyval(x, coeffs):\n", " acc = R(0)\n", " for c in reversed(coeffs):\n", " acc = acc * x + c\n", " return acc * x\n", "\n", "# Interval and test point\n", "x = R('0.00196075439453125') # small x near 0 for log(1 + x)\n", "true_val = log(1 + x)\n", "approx = dd_polyval(x, coeffs)\n", "\n", "# Compute error\n", "abs_err = abs(approx - true_val)\n", "rel_err = abs_err / abs(true_val)\n", "\n", "# Convert to ULPs of 53-bit double precision\n", "ulp = 2^(-53)\n", "abs_ulp = abs_err / ulp\n", "rel_ulp = rel_err / ulp\n", "\n", "# Display\n", "print(\"x =\", x)\n", "print(\"Approximation:\", approx)\n", "print(\"True log(1 + x):\", true_val)\n", "print(\"Absolute error (ULPs):\", abs_ulp)\n", "print(\"Relative error (ULPs):\", rel_ulp)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3780b1ab-9a35-430f-bafa-f50029ccf60e", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Erff.ipynb000064400000000000000000006150451046102023000137510ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 7, "id": "faa0eee1-e8a0-43bc-ab88-05ae5c4c4d0f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0x3ff20dd750429b6d, 0xbfd812746b037753, 0x3fbce2f219e8596a, 0xbf9b82cdacb78fda, 0x3f756479297dfda5, 0xbf48b3ac5455ef02, 0xbf7126fcac367e3b, 0x3fb2d0bdb3ba4984 ],\n", "[ 0x3ff20dd750429b6d, 0xbfd812746b0379a8, 0x3fbce2f21a03cf2a, 0xbf9b82ce30de083e, 0x3f7565bcad3eb60f, 0xbf4c02c66f659256, 0x3f1f92f673385229, 0xbeedef402648ae90 ],\n", "[ 0x3ff20dd750429b34, 0xbfd812746b032dce, 0x3fbce2f219d84aae, 0xbf9b82ce22dcf139, 0x3f7565b9efcd4af1, 0xbf4c021f1af414bc, 0x3f1f7c6d177eff82, 0xbeec9e4410dcf865 ],\n", "[ 0x3ff20dd750426eab, 0xbfd812746ae592c7, 0x3fbce2f211525f14, 0xbf9b82ccc125e63f, 0x3f756596f261cfd3, 0xbf4bfde1ff8eeecf, 0x3f1f31a9d15dc5d8, 0xbeea5a4362844b3c ],\n", "[ 0x3ff20dd75039c705, 0xbfd812746777e74d, 0x3fbce2f17af98a1b, 0xbf9b82be4b817cbe, 0x3f7564bec2e2962e, 0xbf4bee86f9da3558, 0x3f1e9443689dc0cc, 0xbee79c0f230805d8 ],\n", "[ 0x3ff20dd74f811211, 0xbfd81274371a3e8f, 0x3fbce2ec038262e5, 0xbf9b8265b82c5e1f, 0x3f75615a2e239267, 0xbf4bc63ae023dceb, 0x3f1d87c2102f7e06, 0xbee49584bea41d62 ],\n", "[ 0x3ff20dd746d063e3, 0xbfd812729a8a950f, 0x3fbce2cb0a2df232, 0xbf9b80eca1f51278, 0x3f75572e26c46815, 0xbf4b715e5638b65e, 0x3f1bfbb195484968, 0xbee177a565c15c52 ],\n", "[ 0x3ff20dd701b44486, 0xbfd812691145f237, 0x3fbce23a06b8cfd9, 0xbf9b7c1dc7245288, 0x3f753e92f7f397dd, 0xbf4ad97cc4acf0b2, 0x3f19f028b2b09b71, 0xbedcdc4da08da8c1 ],\n", "[ 0x3ff20dd5715ac332, 0xbfd8123e680bd0eb, 0x3fbce0457aded691, 0xbf9b6f52d52bed40, 0x3f750c291b84414c, 0xbf49ea246b1ad4a9, 0x3f177654674e0ca0, 0xbed737c11a1bcebb ],\n", "[ 0x3ff20dce6593e114, 0xbfd811a59c02eadc, 0x3fbcdab53c7cd7d5, 0xbf9b526d2e321eed, 0x3f74b1d32cd8b994, 0xbf48963143ec0a1e, 0x3f14ad5700e4db91, 0xbed231e100e43ef2 ],\n", "[ 0x3ff20db48bfd5a62, 0xbfd80fdd84f9e308, 0x3fbccd340d462983, 0xbf9b196a29287680, 0x3f74210c2c13a0f7, 0xbf46dbdfb4ff71ae, 0x3f11bca2d17fbd71, 0xbecbca36f90c7cf5 ],\n", "[ 0x3ff20d64b2f8f508, 0xbfd80b4d4f19fa8b, 0x3fbcb088197262e3, 0xbf9ab51fd02e5b99, 0x3f734e1e5e81a632, 0xbf44c66377b502ce, 0x3f0d9ad25066213c, 0xbec4b0df7dd0cfa1 ],\n", "[ 0x3ff20c8fc1243576, 0xbfd8010cb2009e27, 0x3fbc7a47e9299315, 0xbf9a155be5683654, 0x3f7233502694997b, 0xbf426c94b7d81300, 0x3f08094f1de25fb9, 0xbebe0e3d776c6eef ],\n", "[ 0x3ff20a9bd1611bc1, 0xbfd7ec7fbce83f90, 0x3fbc1d757d7317b7, 0xbf992c160cd589f0, 0x3f70d307269cc5c2, 0xbf3fda5b0d2d1879, 0x3f02fdd7b3b14a7f, 0xbeb54eed4a26af5a ],\n", "[ 0x3ff20682834f943d, 0xbfd7c73f747bf5a9, 0x3fbb8c2db4a9ffd1, 0xbf97f0e4ffe989ec, 0x3f6e7061eae4166e, 0xbf3ad36e873fff2d, 0x3efd39222396128e, 0xbead83dacec5ea6b ],\n", "[ 0x3ff1feb8d12676d7, 0xbfd7898347284afe, 0x3fbaba3466b34451, 0xbf9663adc573e2f9, 0x3f6ae99fb17c3e08, 0xbf3602f950ad5535, 0x3ef5e9717490609d, 0xbea3fca107bbc8d5 ],\n", "[ 0x3ff1f12fe3c536fa, 0xbfd72b1d1f22e6d3, 0x3fb99fc0eed4a896, 0xbf948db0a87bd8c6, 0x3f673e368895aa61, 0xbf319b35d5301fc8, 0x3ef007987e4bb033, 0xbe9a7edcd4c2dc70 ],\n", "[ 0x3ff1db7b0df84d5d, 0xbfd6a4e4a41cde02, 0x3fb83bbded16455d, 0xbf92809b3b36977e, 0x3f639c08bab44679, 0xbf2b7b45a70ed119, 0x3ee6e99b36410e7b, 0xbe913619bb7ebc0c ],\n", "[ 0x3ff1bb1c85c4a527, 0xbfd5f23b99a249a3, 0x3fb694c91fa0d12c, 0xbf9053e1ce11c72d, 0x3f602bf72c50ea78, 0xbf24f478fb56cb02, 0x3ee005f80ecbe213, 0xbe85f2446bde7f5b ],\n", "[ 0x3ff18dec3bd51f9d, 0xbfd5123f58346186, 0x3fb4b8a1ca536ab4, 0xbf8c4243015cc723, 0x3f5a1a8a01d351ef, 0xbf1f466b34f1d86b, 0x3ed5f835eea0bf6a, 0xbe7b83165b939234 ],\n", "[ 0x3ff152804c3369f4, 0xbfd4084cd4afd4bc, 0x3fb2ba2e836e47aa, 0xbf8800f2dfc6904b, 0x3f54a6daf0669c59, 0xbf16e326ab872317, 0x3ecd9761a6a755a5, 0xbe70fca33f9dd4b5 ],\n", "[ 0x3ff1087ad68356aa, 0xbfd2dbb044707459, 0x3fb0aea8ceaa0384, 0xbf840b516d52b3d2, 0x3f500c9e05f01d22, 0xbf1076afb0dc0ff7, 0x3ec39fadec400657, 0xbe64b5761352e7e3 ],\n", "[ 0x3ff0b0a7a8ba4a22, 0xbfd196990d22d4a1, 0x3fad5551e6ac0c4d, 0xbf807cce1770bd1a, 0x3f4890347b8848bf, 0xbf0757ec96750b6a, 0x3eb9b258a1e06bce, 0xbe58fc6d22da7572 ],\n", "[ 0x3ff04ce2be70fb47, 0xbfd0449e4b0b9cac, 0x3fa97f7424f4b0e7, 0xbf7ac825439c42f4, 0x3f428f5f65426dfb, 0xbf005b699a90f90f, 0x3eb0a888eecf4593, 0xbe4deace2b32bb31 ],\n", "[ 0x3fefbf9fb0e11cc8, 0xbfcde2640856545a, 0x3fa5f5b1f47f8510, 0xbf7588bc71eb41b9, 0x3f3bc6a0a772f56d, 0xbef6b9fad1f1657a, 0x3ea573204ba66504, 0xbe41d38065c94e44 ],\n", "[ 0x3feed8f18c99e031, 0xbfcb4cb6acd903b4, 0x3fa2c7f3dddd6fc1, 0xbf713052067df4e0, 0x3f34a5027444082f, 0xbeef672bab0e2554, 0x3e9b83c756348cc9, 0xbe3534f1a1079499 ],\n", "[ 0x3fedebd33044166d, 0xbfc8d7cd9053f7d8, 0x3f9ff9957fb3d6e7, 0xbf6b50be55de0f36, 0x3f2e92c8ec53a628, 0xbee5a4b88d508007, 0x3e91a27737559e26, 0xbe2942ae62cb2c14 ],\n", "[ 0x3fecfdbf0386f3bd, 0xbfc68e33d93b0dc4, 0x3f9b2683d58f53de, 0xbf65a9174e70d26f, 0x3f269ddd326d49cd, 0xbeddd8f397a8219c, 0x3e86a755016ad4dd, 0xbe1e366e0139187d ],\n", "[ 0x3fec132adb8d7464, 0xbfc475a899f61b46, 0x3f970a431397a77c, 0xbf612e3d35beeee2, 0x3f20c16b05738333, 0xbed4a47f873e144e, 0x3e7d3d494c698c02, 0xbe12302c59547fe5 ],\n", "[ 0x3feb2f5fd05555e7, 0xbfc28feefbe03ec7, 0x3f93923acbb3a676, 0xbf5b4ff793cd6358, 0x3f18ea0eb8c913bc, 0xbeccb31ec2baceb1, 0x3e730011e7e80c04, 0xbe0617710635cb1d ],\n", "[ 0x3fea54853cd9593e, 0xbfc0dbdbaea4dc8e, 0x3f90a93e2c20a0fd, 0xbf55c969ff401ea8, 0x3f129e0cc64fe627, 0xbec4160d8e9d3c2a, 0x3e68e7b67594624a, 0xbdfb1cf2c975b09b ],\n", "[ 0x3fe983ceece09ff8, 0xbfbeacc78f7a2d00, 0x3f8c74418410655f, 0xbf51756a050e441e, 0x3f0bff3650f7f548, 0xbebc56c0217d3ada, 0x3e607b4918d0b489, 0xbdf0d4be8c1c50f8 ],\n" ] } ], "source": [ "import struct\n", "\n", "data = \"\"\"\n", " {0x1.20dd750429b6dp0, -0x1.812746b037753p-2, 0x1.ce2f219e8596ap-4, -0x1.b82cdacb78fdap-6, 0x1.56479297dfda5p-8, -0x1.8b3ac5455ef02p-11, -0x1.126fcac367e3bp-8, 0x1.2d0bdb3ba4984p-4},\n", " {0x1.20dd750429b6dp0, -0x1.812746b0379a8p-2, 0x1.ce2f21a03cf2ap-4,-0x1.b82ce30de083ep-6, 0x1.565bcad3eb60fp-8, -0x1.c02c66f659256p-11, 0x1.f92f673385229p-14, -0x1.def402648ae9p-17},\n", " {0x1.20dd750429b34p0, -0x1.812746b032dcep-2, 0x1.ce2f219d84aaep-4,-0x1.b82ce22dcf139p-6, 0x1.565b9efcd4af1p-8, -0x1.c021f1af414bcp-11, 0x1.f7c6d177eff82p-14, -0x1.c9e4410dcf865p-17},\n", " {0x1.20dd750426eabp0, -0x1.812746ae592c7p-2, 0x1.ce2f211525f14p-4,-0x1.b82ccc125e63fp-6, 0x1.56596f261cfd3p-8, -0x1.bfde1ff8eeecfp-11, 0x1.f31a9d15dc5d8p-14, -0x1.a5a4362844b3cp-17},\n", " {0x1.20dd75039c705p0, -0x1.812746777e74dp-2, 0x1.ce2f17af98a1bp-4, -0x1.b82be4b817cbep-6, 0x1.564bec2e2962ep-8, -0x1.bee86f9da3558p-11, 0x1.e9443689dc0ccp-14, -0x1.79c0f230805d8p-17},\n", " {0x1.20dd74f811211p0, -0x1.81274371a3e8fp-2, 0x1.ce2ec038262e5p-4,-0x1.b8265b82c5e1fp-6, 0x1.5615a2e239267p-8, -0x1.bc63ae023dcebp-11, 0x1.d87c2102f7e06p-14, -0x1.49584bea41d62p-17},\n", " {0x1.20dd746d063e3p0, -0x1.812729a8a950fp-2, 0x1.ce2cb0a2df232p-4, -0x1.b80eca1f51278p-6, 0x1.5572e26c46815p-8, -0x1.b715e5638b65ep-11, 0x1.bfbb195484968p-14, -0x1.177a565c15c52p-17},\n", " {0x1.20dd701b44486p0, -0x1.812691145f237p-2, 0x1.ce23a06b8cfd9p-4, -0x1.b7c1dc7245288p-6, 0x1.53e92f7f397ddp-8, -0x1.ad97cc4acf0b2p-11, 0x1.9f028b2b09b71p-14, -0x1.cdc4da08da8c1p-18},\n", " {0x1.20dd5715ac332p0, -0x1.8123e680bd0ebp-2, 0x1.ce0457aded691p-4, -0x1.b6f52d52bed4p-6, 0x1.50c291b84414cp-8, -0x1.9ea246b1ad4a9p-11, 0x1.77654674e0cap-14, -0x1.737c11a1bcebbp-18},\n", " {0x1.20dce6593e114p0, -0x1.811a59c02eadcp-2, 0x1.cdab53c7cd7d5p-4, -0x1.b526d2e321eedp-6, 0x1.4b1d32cd8b994p-8, -0x1.8963143ec0a1ep-11, 0x1.4ad5700e4db91p-14, -0x1.231e100e43ef2p-18},\n", " {0x1.20db48bfd5a62p0, -0x1.80fdd84f9e308p-2, 0x1.ccd340d462983p-4, -0x1.b196a2928768p-6, 0x1.4210c2c13a0f7p-8, -0x1.6dbdfb4ff71aep-11, 0x1.1bca2d17fbd71p-14, -0x1.bca36f90c7cf5p-19},\n", " {0x1.20d64b2f8f508p0, -0x1.80b4d4f19fa8bp-2, 0x1.cb088197262e3p-4,-0x1.ab51fd02e5b99p-6, 0x1.34e1e5e81a632p-8, -0x1.4c66377b502cep-11, 0x1.d9ad25066213cp-15, -0x1.4b0df7dd0cfa1p-19},\n", " {0x1.20c8fc1243576p0, -0x1.8010cb2009e27p-2, 0x1.c7a47e9299315p-4, -0x1.a155be5683654p-6, 0x1.233502694997bp-8, -0x1.26c94b7d813p-11, 0x1.8094f1de25fb9p-15, -0x1.e0e3d776c6eefp-20},\n", " {0x1.20a9bd1611bc1p0, -0x1.7ec7fbce83f9p-2, 0x1.c1d757d7317b7p-4, -0x1.92c160cd589fp-6, 0x1.0d307269cc5c2p-8, -0x1.fda5b0d2d1879p-12, 0x1.2fdd7b3b14a7fp-15, -0x1.54eed4a26af5ap-20},\n", " {0x1.20682834f943dp0, -0x1.7c73f747bf5a9p-2, 0x1.b8c2db4a9ffd1p-4, -0x1.7f0e4ffe989ecp-6, 0x1.e7061eae4166ep-9, -0x1.ad36e873fff2dp-12, 0x1.d39222396128ep-16, -0x1.d83dacec5ea6bp-21},\n", " {0x1.1feb8d12676d7p0, -0x1.7898347284afep-2, 0x1.aba3466b34451p-4, -0x1.663adc573e2f9p-6, 0x1.ae99fb17c3e08p-9, -0x1.602f950ad5535p-12, 0x1.5e9717490609dp-16, -0x1.3fca107bbc8d5p-21},\n", " {0x1.1f12fe3c536fap0, -0x1.72b1d1f22e6d3p-2, 0x1.99fc0eed4a896p-4, -0x1.48db0a87bd8c6p-6, 0x1.73e368895aa61p-9, -0x1.19b35d5301fc8p-12, 0x1.007987e4bb033p-16, -0x1.a7edcd4c2dc7p-22},\n", " {0x1.1db7b0df84d5dp0, -0x1.6a4e4a41cde02p-2, 0x1.83bbded16455dp-4, -0x1.2809b3b36977ep-6, 0x1.39c08bab44679p-9, -0x1.b7b45a70ed119p-13, 0x1.6e99b36410e7bp-17, -0x1.13619bb7ebc0cp-22},\n", " {0x1.1bb1c85c4a527p0, -0x1.5f23b99a249a3p-2, 0x1.694c91fa0d12cp-4, -0x1.053e1ce11c72dp-6, 0x1.02bf72c50ea78p-9, -0x1.4f478fb56cb02p-13, 0x1.005f80ecbe213p-17, -0x1.5f2446bde7f5bp-23},\n", " {0x1.18dec3bd51f9dp0, -0x1.5123f58346186p-2, 0x1.4b8a1ca536ab4p-4, -0x1.c4243015cc723p-7, 0x1.a1a8a01d351efp-10, -0x1.f466b34f1d86bp-14, 0x1.5f835eea0bf6ap-18, -0x1.b83165b939234p-24},\n", " {0x1.152804c3369f4p0, -0x1.4084cd4afd4bcp-2, 0x1.2ba2e836e47aap-4,-0x1.800f2dfc6904bp-7, 0x1.4a6daf0669c59p-10, -0x1.6e326ab872317p-14, 0x1.d9761a6a755a5p-19, -0x1.0fca33f9dd4b5p-24},\n", " {0x1.1087ad68356aap0, -0x1.2dbb044707459p-2, 0x1.0aea8ceaa0384p-4, -0x1.40b516d52b3d2p-7, 0x1.00c9e05f01d22p-10, -0x1.076afb0dc0ff7p-14, 0x1.39fadec400657p-19, -0x1.4b5761352e7e3p-25},\n", " {0x1.0b0a7a8ba4a22p0, -0x1.196990d22d4a1p-2, 0x1.d5551e6ac0c4dp-5, -0x1.07cce1770bd1ap-7, 0x1.890347b8848bfp-11, -0x1.757ec96750b6ap-15, 0x1.9b258a1e06bcep-20, -0x1.8fc6d22da7572p-26},\n", " {0x1.04ce2be70fb47p0, -0x1.0449e4b0b9cacp-2, 0x1.97f7424f4b0e7p-5,-0x1.ac825439c42f4p-8, 0x1.28f5f65426dfbp-11, -0x1.05b699a90f90fp-15, 0x1.0a888eecf4593p-20, -0x1.deace2b32bb31p-27},\n", " {0x1.fbf9fb0e11cc8p-1, -0x1.de2640856545ap-3, 0x1.5f5b1f47f851p-5, -0x1.588bc71eb41b9p-8, 0x1.bc6a0a772f56dp-12, -0x1.6b9fad1f1657ap-16, 0x1.573204ba66504p-21, -0x1.1d38065c94e44p-27},\n", " {0x1.ed8f18c99e031p-1, -0x1.b4cb6acd903b4p-3, 0x1.2c7f3dddd6fc1p-5, -0x1.13052067df4ep-8, 0x1.4a5027444082fp-12, -0x1.f672bab0e2554p-17, 0x1.b83c756348cc9p-22, -0x1.534f1a1079499p-28},\n", " {0x1.debd33044166dp-1, -0x1.8d7cd9053f7d8p-3, 0x1.ff9957fb3d6e7p-6,-0x1.b50be55de0f36p-9, 0x1.e92c8ec53a628p-13, -0x1.5a4b88d508007p-17, 0x1.1a27737559e26p-22, -0x1.942ae62cb2c14p-29},\n", " {0x1.cfdbf0386f3bdp-1, -0x1.68e33d93b0dc4p-3, 0x1.b2683d58f53dep-6,-0x1.5a9174e70d26fp-9, 0x1.69ddd326d49cdp-13, -0x1.dd8f397a8219cp-18, 0x1.6a755016ad4ddp-23, -0x1.e366e0139187dp-30},\n", " {0x1.c132adb8d7464p-1, -0x1.475a899f61b46p-3, 0x1.70a431397a77cp-6, -0x1.12e3d35beeee2p-9, 0x1.0c16b05738333p-13, -0x1.4a47f873e144ep-18, 0x1.d3d494c698c02p-24, -0x1.2302c59547fe5p-30},\n", " {0x1.b2f5fd05555e7p-1, -0x1.28feefbe03ec7p-3, 0x1.3923acbb3a676p-6, -0x1.b4ff793cd6358p-10, 0x1.8ea0eb8c913bcp-14, -0x1.cb31ec2baceb1p-19, 0x1.30011e7e80c04p-24, -0x1.617710635cb1dp-31},\n", " {0x1.a54853cd9593ep-1, -0x1.0dbdbaea4dc8ep-3, 0x1.0a93e2c20a0fdp-6,-0x1.5c969ff401ea8p-10, 0x1.29e0cc64fe627p-14, -0x1.4160d8e9d3c2ap-19, 0x1.8e7b67594624ap-25, -0x1.b1cf2c975b09bp-32},\n", " {0x1.983ceece09ff8p-1, -0x1.eacc78f7a2dp-4, 0x1.c74418410655fp-7, -0x1.1756a050e441ep-10, 0x1.bff3650f7f548p-15, -0x1.c56c0217d3adap-20, 0x1.07b4918d0b489p-25, -0x1.0d4be8c1c50f8p-32},\n", "\"\"\"\n", "\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in data.strip().splitlines():\n", " floats = line.strip(\"{}, \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"[ {', '.join(encoded)} ],\")" ] }, { "cell_type": "code", "execution_count": 3, "id": "a0e30250-4d25-4955-b788-e7455f50056e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0x3fbb0081148a873a, 0xbc2f0295f16ba5d8, 0x3ff1e565bca400d4, 0xbc962d0ac26c78d3, 0xbfbad8189af6013d, 0xbfd7712743c42914, 0x3faaafd4760d7634, 0x3fbba14988b4127e, 0xbf91afcdb244078a, 0xbf99d72ee25cf211, 0x3f719502f7beca8f, 0x3f73b955bfd46624, 0xbf4a4e2d4d32228b ],\n", "[ 0x3fc662a0bdf7a89f, 0xbc4ef7bc5856c2d4, 0x3ff19e5e92b964ab, 0x3c6cca4dec08a640, 0xbfc605f63767bdd6, 0xbfd6582e9b69c9a9, 0x3fb5aa32b580ec64, 0x3fb97594c2593d3e, 0xbf9c69c62749fb7f, 0xbf96fa7f611aacdc, 0x3f7bf1e628a4606e, 0x3f70e50e4329e8a9, 0xbf568ca9c1954b4c ],\n", "[ 0x3fcf190aa85540e2, 0xbc6e522ac9f718e6, 0x3ff135e3075d076b, 0xbc6e2d8ed30e4a48, 0xbfce1e4d4ce2ccfb, 0xbfd4c04e66e0d59b, 0x3fbd2855d59988e8, 0x3fb659a35f29781a, 0xbfa2cf6266a634c8, 0xbf92ef4180b1f3fa, 0x3f823199a6da60e3, 0x3f69e80d13a3368c, 0xbf5ba4e4eff641dd ],\n", "[ 0x3fd3c9aa8b84beda, 0x3c538ec27d3e5820, 0x3ff0ae54fa490723, 0xbc9d016b7bc67433, 0xbfd2c41f99922807, 0xbfd2b900b640a201, 0x3fc1c6c7eef8fa14, 0x3fb277ad7822021e, 0xbfa66c9b2023b9df, 0xbf8bf7e7b4e8559e, 0x3f853005de4b5751, 0x3f60737c6ba405f0, 0xbf606ccc916b15dc ],\n", "[ 0x3fd7e15944d9d3e4, 0xbc695f819cf77862, 0x3ff00abcf3e187a9, 0x3c85860d868dc542, 0xbfd60ec3cf561a89, 0xbfd05599bafe4ecc, 0x3fc451ef6280e70f, 0x3fac06c6e434be6f, 0xbfa8e2d73679096f, 0xbf80ea4a60550d9c, 0x3f86c911882cc99c, 0x3f48c65a9990353b, 0xbf61e8a88301a7b5 ],\n", "[ 0x3fdbccfec24855b8, 0xbc7472ab1c2b898c, 0x3fee9d5a8e4c934e, 0xbc79a002a2814a72, 0xbfd8dfd9939e37af, 0xbfcb588d8dc5bb96, 0x3fc62338788aee97, 0x3fa26cf85bc6dff9, 0xbfaa1bcaa91da902, 0xbf65b4a7d42d0f64, 0x3f86edef7de2b68d, 0xbf4037b458e2da8c, 0xbf5e8d6001a54334 ],\n", "[ 0x3fdf86faa9428f9d, 0x3c79996c0c376e32, 0x3fecfc41e36c7df9, 0xbc79be994724ea34, 0xbfdb2c7dc535b619, 0xbfc5a9de93f9c0d5, 0x3fc7317958d24aae, 0x3f9133e02ab7d777, 0xbfaa155bbde32db8, 0x3f672049c0cc8525, 0x3f85adde5c722d85, 0xbf5b0a7ec5dc80fc, 0xbf5aa9393b806535 ],\n", "[ 0x3fe1855a5fd3dd50, 0x3c88f6964e67d61a, 0x3feb3aafcc27502e, 0xbc7a9dd26edea8a2, 0xbfdcee5ac8e9c531, 0xbfbfa02983c853d1, 0x3fc77cd75ec73100, 0xbf5fa6f82f9333b7, 0xbfa8e0db5528e559, 0x3f800bf7062212bc, 0x3f83319e670adc9f, 0xbf658833e091aa36, 0xbf58f99b6e81e8f5 ],\n", "[ 0x3fe32a54cb8db67b, 0xbc696221f7e18978, 0x3fe96164fafd8de3, 0x3c70887f82841acc, 0xbfde23a7ea0d187e, 0xbfb3f5ee1564be49, 0x3fc70e469de06907, 0xbf93da6878ae6fd8, 0xbfa6a0d076468415, 0x3f88cf081f1fc304, 0x3f7f6d62866525e6, 0xbf6b93149d5701a4, 0xbf51a6c1a9f7ea73 ],\n", "[ 0x3fe4b13713ad3513, 0x3c6e944ee1b212e4, 0x3fe7791b886e7403, 0xbc6da43cb53d911c, 0xbfdecef42310f844, 0xbfa15c3c5ce705df, 0x3fc5f6890affa468, 0xbfa1da642fabd4da, 0xbfa385991202c7eb, 0x3f8fa4f37fc7c6d4, 0x3f77156b4e430998, 0xbf6f546a4377d648, 0xbf432e4e5abb1e1a ],\n", "[ 0x3fe61955607dd15d, 0x3c898ff39319ab83, 0x3fe58a445da7c74c, 0x3c808ec8e156809b, 0xbfdef6c246a12e7e, 0x3f7e83e0da030480, 0x3fc44cc65df8bfc7, 0xbfa87d3c8dd62c82, 0xbf9f9271a8a1d4e2, 0x3f9225234c1c0a0e, 0x3f6c0b0e055a0c48, 0xbf70585251f84919, 0xbf285bfb02436e0f ],\n", "[ 0x3fe762870f720c6f, 0x3c8118b1ba6da9a7, 0x3fe39ccc1b136d5a, 0x3c5faa9371c0dd80, 0xbfdea4feea4e5add, 0x3fa715e595343353, 0x3fc22cdbdb4cdd0c, 0xbfada50ae547e69e, 0xbf975578f87f217d, 0x3f9353319c65f251, 0x3f539db53a2d03d5, 0xbf6fc0364ce17870, 0x3f3272bc18b0f2ce ],\n", "[ 0x3fe88d1cd474a2e0, 0x3c86f571ada77d52, 0x3fe1b7e98fe26217, 0x3c7952bd607eb12e, 0xbfdde65a22ce0587, 0x3fb40686a3f3dc2b, 0x3fbf6b0cb6926c42, 0xbfb09c7caecd317d, 0xbf8da668f759eaea, 0x3f9364e72035e80a, 0xbf4d421975736447, 0xbf6cc98454e96141, 0x3f4a8860fdf17259 ],\n", "[ 0x3fe999d4192a5715, 0xbc8c888a5759a92c, 0x3fdfc3ee5d1524b0, 0xbc527e60faac0278, 0xbfdcc990045b293f, 0x3fbb37338e6ac814, 0x3fba0d11fe9ba61a, 0xbfb19bb2ca3816ba, 0xbf7a0b7d94791f03, 0x3f9274a59774d5e6, 0xbf664adea7b36f57, 0xbf683684bd8ef173, 0x3f538905afd229ff ],\n", "[ 0x3fea89c850b7d54d, 0xbc8e2752ebf0cd02, 0x3fdc40b0729ed548, 0xbc7c4c1c4927306d, 0xbfdb5eaaef09de9d, 0x3fc0847c7dad86af, 0x3fb47de0a4f796ca, 0xbfb1d9de8b54a3ec, 0x3f533252fb810c7c, 0x3f90ab3e329ded2f, 0xbf712d82076274ed, 0xbf6287bb4a78d728, 0x3f557d31bd574da0 ],\n", "[ 0x3feb5e62fce16095, 0x3c7bc3cff4400364, 0x3fd8eed36b886d93, 0x3c7ea7e17b96436d, 0xbfd9b64a06e4b100, 0x3fc2bb6e2c74d4fe, 0x3fadee322c062364, 0xbfb169960d5a983d, 0x3f7feab4ad0bfc14, 0x3f8c76eb94b07a5f, 0xbf7584474ae8f994, 0xbf588df75be9251f, 0x3f54edef50317090 ],\n", "[ 0x3fec194b1d49a184, 0xbc66770a58b27668, 0x3fd5d4fd33729015, 0xbc76db7d76e9e97b, 0xbfd7e0f4f0454d97, 0x3fc444bc66c35bc4, 0x3fa356dbb5432550, 0xbfb0643de6e8c574, 0x3f8b2e1f789415e4, 0x3f86ba6d9f4af32f, 0xbf78138bf4573a6a, 0xbf47e6e52a583322, 0x3f50f87322fa18a3 ],\n", "[ 0x3fecbc54b476248d, 0x3c81a5083b01ec0d, 0x3fd2f7cc3fe6f423, 0x3c79fbb4b774e85d, 0xbfd5ee8429e30a49, 0x3fc52a8395f96270, 0x3f9313759f199499, 0xbfadcf844d90282c, 0x3f91e45f25ab54a1, 0x3f8091cb68a58665, 0xbf78ea40b0ac8b7b, 0xbee6b91b1bf985f2, 0x3f5158d9c0e1c327 ],\n", "[ 0x3fed4970f9ce00d9, 0xbc756704209fca70, 0x3fd059f59af7a906, 0xbc70ce27da57f153, 0xbfd3eda354ddd5ff, 0x3fc57b85ad436067, 0x3f58e90c2a157e8d, 0xbfaa2893b28f4033, 0x3f94d6af4484a1cb, 0x3f74ccee8c8b1f57, 0xbf783304b9e2e312, 0x3f440cb679d0a832, 0x3f4d6b5f4bdef24b ],\n", "[ 0x3fedc29fb60715af, 0x3c8ab029f047a087, 0x3fcbf8e1b1ca2279, 0x3be0426e10a38000, 0xbfd1eb7095e57e16, 0x3fc549ea6f7a013f, 0xbf8b10f20d110552, 0xbfa61420b5b34a55, 0x3f9677b7ea46c6f2, 0x3f624f9940ffd840, 0xbf76304445e5f6ca, 0x3f5222fabfa75bb0, 0x3f3fdcf55be3c03e ],\n", "[ 0x3fee29e22a89d766, 0x3c8bcc9d569ed217, 0x3fc7bd5c7df3fe9c, 0x3c6488f3b06e1394, 0xbfcfe674493fde22, 0x3fc4a9feacf7e222, 0xbf9a0082c90a1b0d, 0xbfa1cf0e7655f99a, 0x3f96e3396f042620, 0xbf33a2d2cdd5650d, 0xbf7334add14b9a31, 0x3f57e12864580191, 0x3f3dae75c3e2be46 ],\n", "[ 0x3fee812fc64db369, 0x3c83c66a6a23d9a5, 0x3fc3fda6bc016994, 0x3c6586ddaff31a18, 0xbfcc1cb27861fc79, 0x3fc3b1051230b982, 0xbfa1e645a2a638ff, 0xbf9b1f643b14fd89, 0x3f964297d7a66c20, 0xbf63e365adfbccae, 0xbf6f2aa2b3ef5ec2, 0x3f5b3339ee2c8c49, 0x3f20ef5710223110 ],\n", "[ 0x3feeca6ccd709544, 0x3c6f3de8f1953470, 0x3fc0b3f52ce8c383, 0x3c6d1234b508bcfb, 0xbfc8885019f5df29, 0x3fc274275fc87eae, 0xbfa57f7386bfd263, 0xbf930769f45aaa8b, 0x3f94c8231709cfee, 0xbf70c2c99c75913f, 0xbf67514483efc090, 0x3f5c3ebcf121a533, 0x3eede2f1801b8480 ],\n", "[ 0x3fef0762fde45ee6, 0x3c89c3612a14fb77, 0x3fbbb1c972f23e50, 0x3c5ba69c564971e1, 0xbfc5341e3c0177b6, 0x3fc107929f6e7528, 0xbfa7e1b362eacfe6, 0xbf873b61e487b8a9, 0x3f92aa763e0343a9, 0xbf759a388fd2272d, 0xbf5eea3c7f50e8de, 0x3f5b5026fd87d0ca, 0xbf30f2c660125dc6 ],\n", "[ 0x3fef39bc242e43e6, 0xbc8dbae0fd9b967d, 0x3fb6c7e64e7281cb, 0x3c5aa87392dc4c20, 0xbfc2274b86833f6e, 0x3fbefb890e5b6633, 0xbfa92c7dbb880b5c, 0xbf74547708842f2b, 0x3f902047ab6c08c4, 0xbf7888355239e9ec, 0xbf50313bb85e86e1, 0x3f58ced9ddf3d834, 0xbf32d520499bd799 ],\n", "[ 0x3fef62fe80272419, 0xbc8b7c2d17fc31d3, 0x3fb297db960e4f63, 0xbc522bea9385fad9, 0xbfbecb83b087b37b, 0x3fbbce18363bbbb9, 0xbfa985aaf97891cb, 0x3f3cd95f2aa8601a, 0x3f8ab9d43270d20f, 0xbf79b93410d46789, 0xbf29b530b472cadf, 0x3f552f54de527458, 0xbf36844d43c7d693 ],\n", "[ 0x3fef848acb544e95, 0xbc8b27aa2c376c3c, 0x3fae1d4cf1e2450a, 0xbc4783e14555c1e9, 0xbfb9e12e1fde7354, 0x3fb8a27806de834f, 0xbfa91674e13a339a, 0x3f73bc75e8f9d448, 0x3f851b4d09ac47b8, 0xbf796dc7b5f9bd66, 0x3f3e16520532bde9, 0x3f50e742b323f434, 0xbf3ac319bfed91d4 ],\n", "[ 0x3fef9f9ba8d3c733, 0x3c8cd5790ff03ab3, 0x3fa83298d717210e, 0x3c4740e2b04276bf, 0xbfb58d101f909971, 0x3fb58f1456f7db5e, 0xbfa808d17b33b814, 0x3f80c1bdce673b10, 0x3f7f5ff1c06e9df2, 0xbf77f26b8865f398, 0x3f4f87060e6f6460, 0x3f48c6056bea9223, 0xbf3e3499a90b84f5 ],\n", "[ 0x3fefb54641aebbc9, 0xbc879975513f67e7, 0x3fa34ac36ad8dafe, 0x3c0902fb5363d360, 0xbfb1c8ec267fe9e2, 0x3fb2a52c5d83c050, 0xbfa68541b2c0582c, 0x3f85afe422155ad5, 0x3f756303c111cd8a, 0xbf7597ead749c06a, 0x3f557b0870a7b4cf, 0x3f3ffc0efb0ac024, 0xbf39e3ea349ab39e ],\n", "[ 0x3fefc67bcf2d7b8f, 0xbc80d2748f976e8c, 0x3f9e85c449e377f3, 0xbc3cb7ccd2616394, 0xbfad177f166cce53, 0x3fafe23b75845cdf, 0xbfa4b120f9dde895, 0x3f88d9906d138bd5, 0x3f69201b7e469e83, 0xbf72aceacb2954f0, 0x3f58d4e8140dc518, 0x3f300a33f7e93047, 0xbf372b7adfeee575 ],\n", "[ 0x3fefd40bd6d7a785, 0x3c860d45e630998f, 0x3f97f5188610ddc8, 0xbc360e8565137ecb, 0xbfa7954423f89a51, 0x3faaf5baae337ae6, 0xbfa2ad77b77d17dc, 0x3f8a7b8c4a8d53fe, 0x3f54593adc5d737a, 0xbf6ef1cf14455c9c, 0x3f5a1a04ce289b4b, 0x3f03d14f37840954, 0xbf350b861df174ee ],\n", "[ 0x3fefdea6e062d0c9, 0xbc764c70f379f670, 0x3f92a875b5ffab56, 0x3c0531231987c3b8, 0xbfa2f3178cd7aa03, 0x3fa68d1c45b96efe, 0xbfa09648dd332653, 0x3f8ad8b148089c02, 0xbf2f00fa01e6ca19, 0xbf68718785b34600, 0x3f59a7b0da775387, 0xbf2090258ede6532, 0xbf2b3980b454d442 ],\n", "[ 0x3fefe6e1742f7cf6, 0xbc8cebced8a49e04, 0x3f8cd5ec93c12432, 0xbc2bb85326a5eff3, 0xbf9e2ff3aaae31e4, 0x3fa2aa4e58242520, 0xbf9d049824fc44db, 0x3f8a34eda0fc336e, 0xbf5682d8d1801582, 0xbf6239bf51e17ea8, 0x3f57e761274bf059, 0xbf301e715d70d49f, 0xbf24d89f3d9c30d5 ],\n", "[ 0x3fefed37386190fb, 0x3c872b1549ea44ee, 0x3f861beae53b72b7, 0x3bf401790f84b248, 0xbf97d6193f2417ad, 0x3f9e947279e4a43b, 0xbf99060301092cdc, 0x3f88d14d4bdaa7f4, 0xbf61f795ac880380, 0xbf59222edb6bd145, 0x3f553f95c7b01615, 0xbf3529b07d094e1d, 0xbf15b533d0382e20 ],\n", "[ 0x3feff20e0a7ba8c2, 0xbc603f86c5a13f78, 0x3f80d1d69569b82d, 0xbc1a5e866bd1366e, 0xbf92a8ca0dc14852, 0x3f98cc071b719c43, 0xbf954a148886e917, 0x3f86e91361df3c9e, 0xbf665c02e0d08291, 0xbf4e94b0adc3b1ca, 0x3f5210781b57b089, 0xbf37b88f8c82fbff, 0xbf068df27e9a1688 ],\n", "[ 0x3feff5b8fb26f5f6, 0xbc87e917ec20b615, 0x3f79646f35a76624, 0xbc1f771f32fd191b, 0xbf8cf68ed932f081, 0x3f93e8735b5b73b1, 0xbf91e1611aabcbea, 0x3f84afd8cd100d70, 0xbf68c72005b1cfcf, 0xbf3c6a7216b336aa, 0x3f4d577412afc2e2, 0xbf3836a0c0e10a99, 0x3eca8f39f410252a ],\n", "[ 0x3feff87b1913e853, 0xbc73ca98afc58454, 0x3f730499b503957f, 0xbbfd1eabb1c04f50, 0xbf86496420203331, 0x3f8fa73d7eb1b70d, 0xbf8daa3005c2d3fe, 0x3f8250942c31c3ad, 0xbf6997578dc240a8, 0xbf03904177639e63, 0x3f46a6ed488a1f54, 0xbf371cf0c5789c7d, 0x3f043cb84231ab1c ],\n", "[ 0x3feffa89fe5b3625, 0x3c8934b2bcb7f9a3, 0x3f6c4412bf4b8f0b, 0xbbcbbcc9dca4ec60, 0xbf8100f34713740d, 0x3f88ebda0768e8e6, 0xbf8850c68e8e5c3c, 0x3f7fdac8346071b3, 0xbf6929de70d00321, 0x3f310c7101bc52d8, 0x3f4070f7e89ec1e2, 0xbf34e4b3dcf4f08d, 0x3f0f0d43b9869b19 ],\n", "[ 0x3feffc10194fcb64, 0x3c8ea14750ac9b59, 0x3f64d78bba8ca5fd, 0x3be4d9a93566b5b4, 0xbf79ba107a459ce4, 0x3f836f273fbd909b, 0xbf83b38708f7bef7, 0x3f7b3fdff1de2112, 0xbf67d55d55d262d8, 0x3f3eae5e05e74fcc, 0x3f35ebc1e53214a9, 0xbf31fd7c1cd5d63e, 0x3f149559a04c8568 ],\n", "[ 0x3feffd2eae369a07, 0xbc683b09df7f7db4, 0x3f5e7f232d9e2630, 0x3bfa26ac725599e5, 0xbf734c7442de142b, 0x3f7e066bed09942f, 0xbf7f914f2c60b9bb, 0x3f76f4662f6be13b, 0xbf65e664591d6604, 0x3f43a1598d880f36, 0x3f2965b2e78a4544, 0xbf2d8db42b193729, 0x3f1449172919598e ],\n", "[ 0x3feffdff92db56e5, 0xbc78aeef4ee0690a, 0x3f56235fbd7a4345, 0xbbe11380fe434056, 0xbf6cb5e029ba8f3d, 0x3f76fa4c7ef470e9, 0xbf7903a08305eeb0, 0x3f730f12c83fdb23, 0xbf639d769a774af1, 0x3f45d79439ceaefd, 0x3f15326883e7dfeb, 0xbf27199782285958, 0x3f147181c8911603 ],\n", "[ 0x3feffe96a78a04a9, 0xbc82816fe4528f9b, 0x3f4fe41cd9bb4eee, 0x3bde3be508cae7ec, 0xbf652d7b2896626a, 0x3f716c192d8803dc, 0xbf739bfce9b4ecc2, 0x3f6f376a554e5dec, 0xbf612e67cb7aa486, 0x3f466d6e460b1614, 0xbed54f70e4bde32b, 0xbf210e125571fe1e, 0x3f12842d46eb9f29 ],\n", "[ 0x3fefff0312b010b5, 0x3c8155dec9cdc96b, 0x3f46caa0d3582fe9, 0xbbc97d95851163fc, 0xbf5efb729f4be121, 0x3f6a2da7cec01564, 0xbf6e6c27ad2b1ce0, 0x3f693b1f34b17723, 0xbf5d8179cd2ad34f, 0x3f45cf51e0add9bb, 0xbf116d8f4b5119c7, 0xbf1768557564f5f5, 0x3f0f4fc9dde73f24 ],\n", "[ 0x3fefff50456dab8c, 0xbc5a197a986f0de0, 0x3f40295ef6591848, 0xbbd262bd83520706, 0xbf5679880e93e5c4, 0x3f637d38e3a705af, 0xbf675b371a264745, 0x3f64231c3bfe3e65, 0xbf58e184d4921105, 0x3f445d5b5a7f77fa, 0xbf1bf8ece4afedd2, 0xbf0ccd677aaa82f7, 0x3f09e5241d5b6b15 ],\n", "[ 0x3fefff86cfd3e657, 0xbc72e06adb26f84e, 0x3f36be02102b3520, 0x3bb448bcfd3cfe0c, 0xbf502b15777eb7c5, 0x3f5cc1d886874d5b, 0xbf61bff70664651d, 0x3f5fc0f76c943696, 0xbf54a22286622d3e, 0x3f4268887688a6e6, 0xbf20fa2692fd7da2, 0xbefcc13d1a82f742, 0x3f04153e6537aae5 ],\n", "[ 0x3fefffad0b901755, 0x3c670d5c9a92b65c, 0x3f2fc0d55470cf51, 0xbbc6f2b03553d4c8, 0xbf47121aff59f6a1, 0x3f5506d6992fc8ff, 0xbf5ab596015fc183, 0x3f58bdd79a098723, 0xbf50d88da9deb868, 0x3f4031cdd07e4507, 0xbf222fc41430a37d, 0xbedb5cc9546afcec, 0x3efd7ea1c7b8fdb6 ],\n", "[ 0x3fefffc7a37857d2, 0xbc797b30fd4b6b48, 0x3f25feada379d8b7, 0xbbc0546c4da57036, 0xbf405304df546ed8, 0x3f4e79c081b79ebc, 0xbf53e5dc1062db15, 0x3f530eb20ccc1f98, 0xbf4b1b06c20a060d, 0x3f3bd52fbd55e0ef, 0xbf2214afb8835b23, 0x3ee19ae9d16650a0, 0x3ef42d933ee154fd ],\n", "[ 0x3fefffd9fdeabcce, 0x3c80c43c3bc59762, 0x3f1e3bcf436a1a95, 0xbba6458a28a3f9b6, 0xbf36e95311166825, 0x3f45e3edf674e2db, 0xbf4d5be6d15abe3a, 0x3f4d07da13e640c2, 0xbf458106cc648748, 0x3f376c840985e5eb, 0xbf2111de112b1a2e, 0x3ef315fc34053fbd, 0x3ee939439a75a553 ],\n", "[ 0x3fefffe68f4fa777, 0x3c32f21786b76440, 0x3f149e17724f4d41, 0x3ba747684f0023e4, 0xbf2fe48c44d2ab81, 0x3f3f2bd95d72a532, 0xbf457389188a71a9, 0x3f45decc4058f7a1, 0xbf40d559cf0f2957, 0x3f33583904af6f83, 0xbf1efd7979333337, 0x3ef904cf9fa5c1f6, 0x3eda13a094bd56a2 ],\n", "[ 0x3fefffef1960d85d, 0xbc8f7cc78053f6ad, 0x3f0be6abbb10a5aa, 0xbb9e50b219d40126, 0xbf260403819b22b8, 0x3f35fff1dde5305e, 0xbf3f0c93c73e7f42, 0x3f404cbf67af6c26, 0xbf3a04893510426c, 0x3f2f66b51a7bc4a0, 0xbf1b410d7f2fd319, 0x3efb99f9eb427956, 0x3ebf26fcffb14441 ],\n", "[ 0x3feffff4db27f146, 0x3c8ddecdd5e1d408, 0x3f02bb5cc22e5db6, 0x3b9c5112eca8acde, 0xbf1e258948829ed1, 0x3f2ec8a8e59d9d5b, 0xbf36425722b9f3cd, 0x3f380a83a7103b4b, 0xbf33dbb9374004f9, 0x3f2913b301d37bde, 0xbf17563b0d94459f, 0x3efbc01eea9a10be, 0xbeb3df26463df6a5 ],\n", "[ 0x3feffff8b500e77c, 0xbc71014e1f83ed4c, 0x3ef8f4ccca7fc90d, 0x3b9a5d4ec8b9de43, 0xbf1478cffe1cd2ed, 0x3f2559f04ad4de62, 0xbf2f9e163b15c466, 0x3f318bda8b8c1315, 0xbf2df381bd3c058e, 0x3f23b94f531bb6be, 0xbf1385f32481ed94, 0x3efa414bd2b7cb3c, 0xbecac2bbe30f8767 ],\n", "[ 0x3feffffb43555b5f, 0x3c8c17f83b8d73a2, 0x3ef07ebd2a2d2844, 0x3b9d1bbdc704f49b, 0xbf0b93e442837f52, 0x3f1d5cf1514977f3, 0xbf263f5eb46877fd, 0x3f295a0411e668b1, 0xbf2652e5f2a88269, 0x3f1e950ddb7f5444, 0xbf0ffeb9383bdb3d, 0x3ef7c24392346fdd, 0xbed1f3b3254d7230 ],\n", "[ 0x3feffffcf23ff5fc, 0xbc8b18a8b25039c4, 0x3ee5a2adfa0b4bc4, 0x3b8eb6d61aaaf95c, 0xbf026c8826ed9e85, 0x3f140473571d5383, 0xbf1f057dbf365c0a, 0x3f22217929fed933, 0xbf207324014ddb42, 0x3f1762758a56d654, 0xbf09ba250c662e90, 0x3ef4c25759179e3d, 0xbed3e800358f1a7b ],\n", "[ 0x3feffffe0bd3e852, 0xbc5d7ece4ab53150, 0x3edc282cd3957eda, 0x3b6eb3cf4fd14280, 0xbef86ad6df7ba401, 0x3f0b0f313eeb65a6, 0xbf156e457745d637, 0x3f19ad1f65a78253, 0xbf17f92ad8542929, 0x3f11a5578c0d30b3, 0xbf04548d876bb0a3, 0x3ef19e60bf53b25a, 0xbed3f1745170e2d3 ],\n", "[ 0x3feffffec2641a9e, 0xbc8e7ba4fdaaa8c8, 0x3ed22df298214423, 0xbb5a9d49552152a4, 0xbef00c902a4d5e27, 0x3f022234eb745941, 0xbf0d57a2be01db67, 0x3f1200c2ffad65f1, 0xbf1147585d43f49a, 0x3f0a4b07aec797e9, 0xbeff9d088bbeff64, 0x3eed2b2be4e42422, 0xbed2bb57c0cf2941 ],\n", "[ 0x3fefffff37d63a36, 0xbc6753e3241c01b0, 0x3ec74adc8f4064d3, 0x3b6de8a904d5c372, 0xbee4ed4228b3da96, 0x3ef81918baca1979, 0xbf03e81c09c29601, 0x3f09004afed1bde9, 0xbf08a40e183ee3fc, 0x3f0359242a8b8c58, 0xbef834b953bcb845, 0x3ee79e345fb0b20d, 0xbed0bb2d323900ce ],\n", "[ 0x3fefffff82cdcf1b, 0x3c8046bbe9897fd5, 0x3ebd9c73698fb1dc, 0x3b588de36481dfb5, 0xbedb11017e7d5893, 0x3eefc0dfadc2c6d6, 0xbefac4e1aa499ac6, 0x3f0131810ab2e2e3, 0xbf01629d94abc864, 0x3efc22a71036c259, 0xbef244452f74de31, 0x3ee2bf17664310c1, 0xbeccd1b31a8349be ],\n", "[ 0x3fefffffb248c39d, 0x3c89b9a41713558c, 0x3eb2acee2f5ecdb8, 0xbb32d1692a9a105c, 0xbed15cc5700a2341, 0x3ee4be757b934819, 0xbef1d6ab6f8cbf7c, 0x3ef76c5a3035bdab, 0xbef847332578dfac, 0x3ef437f23f8d25ff, 0xbeeb305e625a092d, 0x3edd3886ff986fef, 0xbec81f2189b385a2 ],\n", "[ 0x3fefffffd01f36af, 0xbc8d41915db812ef, 0x3ea75fa8dbc84bec, 0x3b3a5cd79572a1a6, 0xbec6186d9fc357c5, 0x3edae02322e08822, 0xbee79082befd50ca, 0x3eef9c26e211b174, 0xbef0c768235c378b, 0x3eecba7164e1064f, 0xbee3f75c28c31ac8, 0x3ed663fcfff77e44, 0xbec3a6da35f36ee6 ],\n", "[ 0x3fefffffe2ba0ea5, 0xbc826cd7908cba2b, 0x3e9d06ad6ecdf971, 0xbb3020b74d9d30fb, 0xbebbe46aa879edb2, 0x3ed143860c49d129, 0xbededabcbc3e620d, 0x3ee52139c87e9c82, 0xbee6f567cd982028, 0x3ee42ebd266abd62, 0xbedcf2f0c6adfb3e, 0x3ed0e2c0ed67786c, 0xbebf50cb81b9b190 ],\n", "[ 0x3fefffffee3cc32c, 0x3c7e429188c949b8, 0x3e91e1e857adc568, 0x3b32439f8a1649bb, 0xbeb1769ce59fb2c8, 0x3ec5fe5d47560794, 0xbed405da04875e51, 0x3edbfc96a938083d, 0xbedf19ff5e59cbe9, 0x3edc0c4d50d275bf, 0xbed4b9df120462ae, 0x3ec916640ee35de4, 0xbeb874483d99c37e ],\n", "[ 0x3feffffff54dab72, 0xbc8a443df643729a, 0x3e85dcd669f2cd34, 0xbb1ceb1ec59e0c28, 0xbea5b11cbd1ee799, 0x3ebbc91a6b1c1839, 0xbec9c2c5d12dfa2c, 0x3ed25d1e3c70364f, 0xbed4dbe26c88e4f7, 0x3ed347bb8350b422, 0xbecd51d3280da8a0, 0x3ec25ed8e5b466b5, 0xbeb2b9c5d3390919 ],\n", "[ 0x3feffffff99b79d2, 0xbc758ff1c425f8de, 0x3e7a854ea14102a9, 0xbb121745e4b4fcb3, 0xbe9aba593e8384ae, 0x3eb167c252a45678, 0xbec06d78ca0424a3, 0x3ec7e0f59fcfa53d, 0xbecbb4d48383b847, 0x3eca39f3ad9a397f, 0xbec47e836879c374, 0x3eba89244d14b829, 0xbeac33e15a6dbe37 ],\n", "[ 0x3feffffffc355dfd, 0x3c688cb60fd4511c, 0x3e6febc107d5efab, 0xbaed9ed10902067c, 0xbe9055a3c70279a4, 0x3ea59ff37766e9a7, 0xbeb4c53adb9dcc4d, 0x3ebec49242997849, 0xbec23927ad6ac54f, 0x3ec1a6e0676c7463, 0xbebc5239f6a88a96, 0x3eb2e991308bf6fa, 0xbea4e276c09fe81b ],\n", "[ 0x3feffffffdc4ad7a, 0xbc8d75de787812d4, 0x3e630f93c3699079, 0xbaf8f941ab38e9da, 0xbe83ce2f890bb01d, 0x3e9aa5010863c83b, 0xbeaa08ef1ca16360, 0x3eb3a4a6af3cafac, 0xbeb7be1e832218f0, 0x3eb784775c30c386, 0xbeb3593046482ce3, 0x3eaa9d448178fbfd, 0xbe9e77bb85451c65 ],\n", "[ 0x3feffffffeb24467, 0x3c8bff89ef33d6dd, 0x3e56961b8d641d07, 0xbaf74a7fc97b1544, 0xbe77d2510f1f969d, 0x3e90476b165ac852, 0xbea02d3a3b9d195e, 0x3ea8db3567bef1df, 0xbeaea3ef4e3a126b, 0x3eaf03b0861a59ac, 0xbeaa250ca467705a, 0x3ea27e9995f6dfcd, 0xbe95e77b673c6d74 ],\n", "[ 0x3fefffffff3e8892, 0x3c5befbf8d294678, 0x3e4a8e405e651ab7, 0x3ab167a2d8cf6b18, 0xbe6c6c40e5083698, 0x3e83ba47a17512fd, 0xbe93ee334beef6ec, 0x3e9f2bf9e6c43e99, 0xbea395c08ac8e281, 0x3ea43ee4b521ccad, 0xbea178f0deeb9b20, 0x3e9964e51b0f0532, 0xbe8f0cc4ecca5c2f ],\n", "[ 0x3fefffffff90b2e3, 0xbc7d82d94a90f1e4, 0x3e3efac5187b2864, 0x3acf1301ae680614, 0xbe60d229044adeee, 0x3e77b5bc9db47d00, 0xbe88588212e670c2, 0x3e935f42db1989fa, 0xbe98cd98865c4ff0, 0x3e9a2b8587c48078, 0xbe971aa2de99af9c, 0x3e913a89805c15d9, 0xbe85b53ca1bcf01a ],\n", "[ 0x3fefffffffc0748f, 0x3c66ef7a9caef280, 0x3e31edfa3c5f5ccb, 0x3ac368f60e2e6cfa, 0xbe53c025a6810c37, 0x3e6c42f78a0989ad, 0xbe7d7c6c3583c6e3, 0x3e87dd6ccb5c93b4, 0xbe8f1ec2f699fdcc, 0x3e90bf7a04407a8c, 0xbe8e3aafe6dfd4e0, 0x3e871bc3a55b63f4, 0xbe7df66b11724e7c ],\n", "[ 0x3fefffffffdbff2a, 0x3c749438981099b2, 0x3e24979ac8b28928, 0xbacc2f44bcf3ce52, 0xbe47015eec37753a, 0x3e60b487791590cf, 0xbe71b44b64c3c995, 0x3e7d23ff3ef8dd83, 0xbe8357d673d1ccfc, 0x3e853a563ce0e9e3, 0xbe83921106a960f6, 0x3e7ea527d318f96e, 0xbe746bd6cea7103d ],\n", "[ 0x3fefffffffebc1a9, 0x3c7e0e5facabfab4, 0x3e177756ec9f78fb, 0x3aae20366d0e0306, 0xbe3a9530780ca70c, 0x3e53962ecb10df65, 0xbe651494525dee64, 0x3e71a2961b90efb0, 0xbe77d35cd0b404bf, 0x3e7aa596d9d73afb, 0xbe791493d8d43ba2, 0x3e74184505343c2d, 0xbe6b7d977f1a3402 ],\n", "[ 0x3feffffffff4b453, 0x3c859b25048a61cc, 0x3e0a887bd2b4404f, 0xba82556d8ad4dd44, 0xbe2e78be33fb01da, 0x3e46c6ef0b68629e, 0xbe58e36e9a44c497, 0x3e65286ee37c531e, 0xbe6d146395886537, 0x3e7090902855d5f0, 0xbe6fd0d1e8fcb6df, 0x3e6a10f65c3c5a7b, 0xbe624888c323daf3 ],\n", "[ 0x3feffffffff9bec8, 0xbc76755054654b62, 0x3dfdc479de0ef004, 0xba9c3434581af3b8, 0xbe21535aee3eb1b2, 0x3e3a4547ed264758, 0xbe4d2308d0dead0f, 0x3e5929d46a9a7edc, 0xbe6195dbfd4afd19, 0x3e646630f49ccd2f, 0xbe63fa4637c64ebc, 0x3e60b98a6e0cfc02, 0xbe58093f032972f3 ],\n", "[ 0x3feffffffffc901c, 0x3c69c951c943961c, 0x3df0916f04b6e18d, 0x3a81bdf9650721ea, 0xbe138b90f78fbe14, 0x3e2e0d7765326885, 0xbe40e9760d0ac127, 0x3e4daad91166722d, 0xbe5513c51b9838ed, 0x3e58e27fb85ba534, 0xbe58d6f6bd99eaff, 0x3e553c31e52fff08, 0xbe4f3bfd31796bc0 ],\n", "[ 0x3feffffffffe202d, 0x3c8a54841f566a61, 0x3de24caf2c32af16, 0x3a802e3358112fa1, 0xbe05dfa962d49548, 0x3e210ca1ff2af812, 0xbe3377c7e98dd9b4, 0x3e4156649e0b5dd2, 0xbe49092f4db426c5, 0x3e4e12a29b227972, 0xbe4e94e18d5271a9, 0x3e4aae38927ee69b, 0xbe441121b0293be1 ],\n", "[ 0x3feffffffffefc57, 0xbc68225a9658ef84, 0x3dd40dfd87456f4f, 0xba7a6d5c55f8e63b, 0xbdf848f101ce14c8, 0x3e132fed47f8dd28, 0xbe2638ff4a6975f2, 0x3e3416d25168a6b8, 0xbe3d78fb22f58668, 0x3e42009c6b4e61ea, 0xbe42a459e59c850b, 0x3e4096a3e8dac0ea, 0xbe397fba69de37d8 ],\n", "[ 0x3fefffffffff748e, 0x3c6ae15e36044aac, 0x3dc5ce9ab1670dd6, 0x3a4cc9bbfb723fc4, 0xbdeabf69bd9866f7, 0x3e056ae1e8abbbbf, 0xbe1927ca04d1a7a8, 0x3e2713d3b07d7a36, 0xbe31318f5d7d717b, 0x3e355ab94fdfd1f4, 0xbe368216fb90717a, 0x3e346ad5ce577d65, 0xbe30065a20073e81 ],\n", "[ 0x3fefffffffffb5b0, 0xbc850fb19119064f, 0x3db7872d9fa10ab2, 0xba57760afdf543a4, 0xbddd39eaac4a0b47, 0x3df7b67ab8af33d6, 0xbe0c3ced54e694ea, 0x3e1a4875d8a47f12, 0xbe23e213e6f5c296, 0x3e2919137301f897, 0xbe2aea6bd9b34930, 0x3e28e06e4ab5925f, 0xbe23ed1d979421b2 ],\n", "[ 0x3fefffffffffd8b3, 0xbc65182469c211e0, 0x3da92ff33023d5c3, 0xba42932180032bd1, 0xbdcfae4fe28d12dd, 0x3dea0a80964d6e97, 0xbdff6f47be478e2a, 0x3e0dad968cdacb13, 0xbe16ca68a8bfdb81, 0x3e1d3a79e5305b4a, 0xbe1fe1534ebf69c7, 0x3e1e01ee76d92779, 0xbe1883ed9069f3fd ],\n", "[ 0x3fefffffffffeb60, 0xbc74d3f53e684bf8, 0x3d9ac0f5f322937a, 0xba38e8ab19224e58, 0xbdc108dc99cf03e5, 0x3ddc5db17016a0c6, 0xbdf159f41ea079c3, 0x3e009ced3e9b7204, 0xbe09e4dace066800, 0x3e10dd5e0e9749b6, 0xbe12b3aa6599d0b5, 0x3e11eb5e8e4ffe8f, 0xbe0dd8955967ed31 ],\n", "[ 0x3feffffffffff542, 0x3c6b57ed63ed8110, 0x3d8c324c20e337e5, 0x3a253fd8abf42ed9, 0xbdb22c6b11327305, 0x3dcea5f66f89cbd4, 0xbde2ff1e0a81bedc, 0x3df270ddbd8e501f, 0xbdfd2992b5c25c93, 0x3e03492d76bdf266, 0xbe05bc7361853dde, 0x3e053121ae3f1d2e, 0xbe01fb0f7e3f242b ],\n", "[ 0x3feffffffffffa73, 0xbc76fead614b7934, 0x3d7d7c593130dd16, 0xba08e78574fe0514, 0xbda33c1e2f16e037, 0x3dc06c53fdc74764, 0xbdd4a029a87915ac, 0x3de44bd86238ff0d, 0xbdf0474ac3a80072, 0x3df5db2a89e9bc47, 0xbdf906f4b51a7f75, 0x3df8d189784c1f50, 0xbdf571a4760f483d ],\n", "[ 0x3feffffffffffd27, 0x3c719e1a84064c56, 0x3d6e9810295890f9, 0x3a0f998d55766fdb, 0xbd943262ab4b77b2, 0x3db1756eae580a28, 0xbdc6359d5b0d251e, 0x3dd626391bd58994, 0xbde203efc6c9f556, 0x3de88c0b111be900, 0xbdec8ca211a38811, 0x3decc911f684d612, 0xbde950e3edf09a71 ],\n", "[ 0x3feffffffffffe8d, 0x3c5e766e2c801398, 0x3d5f7f338086a87b, 0xb9ddfa0c27b527e0, 0xbd8509f766d9f287, 0x3da268e278ede221, 0xbdb7b7b43e9a1b0e, 0x3dc7f7aadab6b398, 0xbdd3c3cc6aafba0b, 0x3ddb52c69b4ab6de, 0xbde0222c438d1182, 0x3de0888e14314f83, 0xbddd96aaea63b362 ],\n", "[ 0x3fefffffffffff45, 0xbc85948eec884df5, 0x3d501647ba79874e, 0x3986d5d39dabc300, 0xbd75be1cf20840dc, 0x3d93418096320daf, 0xbda91e9beb94b447, 0x3db9b762261756a7, 0xbdc57f320a630c91, 0x3dce24b78ce82b11, 0xbdd2112fff5c77aa, 0x3dd2cfdd93a41786, 0xbdd11ea1f35b4d2b ],\n", "[ 0x3fefffffffffffa2, 0x3c6d07509a1a9440, 0x3d404e15ecc7f401, 0xb9d0858e34f7a6a6, 0xbd664ac1f9b95f96, 0x3d83fa8302ade993, 0xbd9a62b70897719e, 0x3dab5c619266e9f0, 0xbdb72de32129cbb8, 0x3dc07ae94305c398, 0xbdc40c45a9e95152, 0x3dc533d127efdf16, 0xbdc39dc242ba4cda ],\n", "[ 0x3fefffffffffffd1, 0x3c83b6fc0b729759, 0x3d3065b9616170e1, 0xb9c49459f5147526, 0xbd56acaa58a8be12, 0x3d748fb92d0947e7, 0xbd8b7ce1a1ea8ea5, 0x3d9cddc552bbebeb, 0xbda8c751cc1a5784, 0x3db1dc79b52007b0, 0xbdb60b3d17e7714c, 0x3db7ac1d379afc28, 0xbdb641ca84798564 ],\n", "[ 0x3fefffffffffffe9, 0xbc55fe91226dd510, 0x3d205ca50205d279, 0xb9c7a281f9edb8e6, 0xbd46e18ec0d42451, 0x3d64fdb051100a15, 0xbd7c66b3f3fe565e, 0x3d8e331281475b54, 0xbd9a42e6965b2b9a, 0x3da3301ef4931960, 0xbda804fcc1524d74, 0x3daa2ef0c13a3daa, 0xbda9028a915f98d3 ],\n", "[ 0x3feffffffffffff5, 0xbc8238f8ed17d9b3, 0x3d10330f0fd69931, 0x39ba2c00e0c6dcba, 0xbd36e8334c65749d, 0x3d5541d561058477, 0xbd6d1ac042ada69e, 0x3d7f54864c5a530e, 0xbd8b984c73c1d301, 0x3d946ec7009c291f, 0xbd99efc2df737760, 0x3d9cb12ac38f37ca, 0xbd9bd54fcd67b8d4 ],\n", "[ 0x3feffffffffffffb, 0xbc8efa4d64f59f62, 0x3cffd3de10d6287a, 0xb99e1fdae91c5cfe, 0xbd26c073be0916e6, 0x3d455a8eab9e129a, 0xbd5d94c87c1bc304, 0x3d701db0818bec24, 0xbd7cbfbe4c0ef6ee, 0x3d859179d8c519c4, 0xbd8bc172710440bd, 0x3d8f26a4f726814e, 0xbd8ead889e052555 ],\n", "[ 0x3feffffffffffffd, 0x3c86be96953fe014, 0x3cef05e82aae2be2, 0xb98070a8237b4337, 0xbd166b44c6d7ddb6, 0x3d35474bd9d072f3, 0xbd4dd1e8c33100cc, 0x3d60711486984913, 0xbd6db2522b66a6ce, 0x3d76919a06329739, 0xbd7d6fe8f87926e8, 0x3d80c1488010ff5c, 0xbd80bf9fa407e9ab ],\n", "[ 0x3fefffffffffffff, 0xbc80fecc5ed770de, 0x3cde00e9148a1d52, 0x394f7a503c7a2ad8, 0xbd05eaaa4200e355, 0x3d25088b6566fced, 0xbd3dd0b48e0f634e, 0x3d50a27116d7478e, 0xbd5e6a3e1d5c214f, 0x3d6769249755a4bc, 0xbd6ef16049050b69, 0x3d71dbf2744f66db, 0xbd721c636bd8f5a9 ],\n", "[ 0x3fefffffffffffff, 0x3c8989c6c5d51227, 0x3ccccaaea71ab110, 0x394152f323a1f3b4, 0xbcf541a2f15eb476, 0x3d149fd53e85cdf3, 0xbd2d9144beee6b4a, 0x3d40b09b02f533a1, 0xbd4ee312fcf48076, 0x3d5812ed2f01f60a, 0xbd601e6391f47ad7, 0x3d62dce8f6b8c896, 0xbd6365d5011db0df ],\n" ] } ], "source": [ "import struct\n", "# ERF double C1\n", "data = \"\"\"\n", "{0x1.b0081148a873ap-4, -0x1.f0295f16ba5d8p-61, 0x1.1e565bca400d4p+0, -0x1.62d0ac26c78d3p-54, -0x1.ad8189af6013dp-4, -0x1.7712743c42914p-2, 0x1.aafd4760d7634p-5, 0x1.ba14988b4127ep-4, -0x1.1afcdb244078ap-6, -0x1.9d72ee25cf211p-6, 0x1.19502f7beca8fp-8, 0x1.3b955bfd46624p-8, -0x1.a4e2d4d32228bp-11}, \n", "{0x1.662a0bdf7a89fp-3, -0x1.ef7bc5856c2d4p-59, 0x1.19e5e92b964abp+0, 0x1.cca4dec08a64p-57, -0x1.605f63767bdd6p-3, -0x1.6582e9b69c9a9p-2, 0x1.5aa32b580ec64p-4, 0x1.97594c2593d3ep-4, -0x1.c69c62749fb7fp-6, -0x1.6fa7f611aacdcp-6, 0x1.bf1e628a4606ep-8, 0x1.0e50e4329e8a9p-8, -0x1.68ca9c1954b4cp-10}, \n", "{0x1.f190aa85540e2p-3, -0x1.e522ac9f718e6p-57, 0x1.135e3075d076bp+0, -0x1.e2d8ed30e4a48p-57, -0x1.e1e4d4ce2ccfbp-3, -0x1.4c04e66e0d59bp-2, 0x1.d2855d59988e8p-4, 0x1.659a35f29781ap-4, -0x1.2cf6266a634c8p-5, -0x1.2ef4180b1f3fap-6, 0x1.23199a6da60e3p-7, 0x1.9e80d13a3368cp-9, -0x1.ba4e4eff641ddp-10}, /* i=3 70.889 */\n", "{0x1.3c9aa8b84bedap-2, 0x1.38ec27d3e582p-58, 0x1.0ae54fa490723p+0, -0x1.d016b7bc67433p-54, -0x1.2c41f99922807p-2, -0x1.2b900b640a201p-2, 0x1.1c6c7eef8fa14p-3, 0x1.277ad7822021ep-4, -0x1.66c9b2023b9dfp-5, -0x1.bf7e7b4e8559ep-7, 0x1.53005de4b5751p-7, 0x1.0737c6ba405fp-9, -0x1.06ccc916b15dcp-9}, /* i=4 70.343 */\n", "{0x1.7e15944d9d3e4p-2, -0x1.95f819cf77862p-57, 0x1.00abcf3e187a9p+0, 0x1.5860d868dc542p-55, -0x1.60ec3cf561a89p-2, -0x1.05599bafe4eccp-2, 0x1.451ef6280e70fp-3, 0x1.c06c6e434be6fp-5, -0x1.8e2d73679096fp-5, -0x1.0ea4a60550d9cp-7, 0x1.6c911882cc99cp-7, 0x1.8c65a9990353bp-11, -0x1.1e8a88301a7b5p-9}, /* i=5 69.074 */\n", "{0x1.bccfec24855b8p-2, -0x1.472ab1c2b898cp-56, 0x1.e9d5a8e4c934ep-1, -0x1.9a002a2814a72p-56, -0x1.8dfd9939e37afp-2, -0x1.b588d8dc5bb96p-3, 0x1.62338788aee97p-3, 0x1.26cf85bc6dff9p-5, -0x1.a1bcaa91da902p-5, -0x1.5b4a7d42d0f64p-9, 0x1.6edef7de2b68dp-7, -0x1.037b458e2da8cp-11, -0x1.e8d6001a54334p-10}, /* i=6 70.183 */\n", "{0x1.f86faa9428f9dp-2, 0x1.9996c0c376e32p-56, 0x1.cfc41e36c7df9p-1, -0x1.9be994724ea34p-56, -0x1.b2c7dc535b619p-2, -0x1.5a9de93f9c0d5p-3, 0x1.7317958d24aaep-3, 0x1.133e02ab7d777p-6, -0x1.a155bbde32db8p-5, 0x1.72049c0cc8525p-9, 0x1.5adde5c722d85p-7, -0x1.b0a7ec5dc80fcp-10, -0x1.aa9393b806535p-10}, /* i=7 70.135 */\n", "{0x1.1855a5fd3dd5p-1, 0x1.8f6964e67d61ap-55, 0x1.b3aafcc27502ep-1, -0x1.a9dd26edea8a2p-56, -0x1.cee5ac8e9c531p-2, -0x1.fa02983c853d1p-4, 0x1.77cd75ec731p-3, -0x1.fa6f82f9333b7p-10, -0x1.8e0db5528e559p-5, 0x1.00bf7062212bcp-7, 0x1.3319e670adc9fp-7, -0x1.58833e091aa36p-9, -0x1.8f99b6e81e8f5p-10}, /* i=8 69.816 */\n", "{0x1.32a54cb8db67bp-1, -0x1.96221f7e18978p-57, 0x1.96164fafd8de3p-1, 0x1.0887f82841accp-56, -0x1.e23a7ea0d187ep-2, -0x1.3f5ee1564be49p-4, 0x1.70e469de06907p-3, -0x1.3da6878ae6fd8p-6, -0x1.6a0d076468415p-5, 0x1.8cf081f1fc304p-7, 0x1.f6d62866525e6p-8, -0x1.b93149d5701a4p-9, -0x1.1a6c1a9f7ea73p-10}, /* i=9 70.229 */\n", "{0x1.4b13713ad3513p-1, 0x1.e944ee1b212e4p-57, 0x1.7791b886e7403p-1, -0x1.da43cb53d911cp-57, -0x1.ecef42310f844p-2, -0x1.15c3c5ce705dfp-5, 0x1.5f6890affa468p-3, -0x1.1da642fabd4dap-5, -0x1.385991202c7ebp-5, 0x1.fa4f37fc7c6d4p-7, 0x1.7156b4e430998p-8, -0x1.f546a4377d648p-9, -0x1.32e4e5abb1e1ap-11}, /* i=10 70.743 */\n", "{0x1.61955607dd15dp-1, 0x1.98ff39319ab83p-55, 0x1.58a445da7c74cp-1, 0x1.08ec8e156809bp-55, -0x1.ef6c246a12e7ep-2, 0x1.e83e0da03048p-8, 0x1.44cc65df8bfc7p-3, -0x1.87d3c8dd62c82p-5, -0x1.f9271a8a1d4e2p-6, 0x1.225234c1c0a0ep-6, 0x1.c0b0e055a0c48p-9, -0x1.0585251f84919p-8, -0x1.85bfb02436e0fp-13}, /* i=11 70.022 */\n", "{0x1.762870f720c6fp-1, 0x1.118b1ba6da9a7p-55, 0x1.39ccc1b136d5ap-1, 0x1.faa9371c0dd8p-58, -0x1.ea4feea4e5addp-2, 0x1.715e595343353p-5, 0x1.22cdbdb4cdd0cp-3, -0x1.da50ae547e69ep-5, -0x1.75578f87f217dp-6, 0x1.353319c65f251p-6, 0x1.39db53a2d03d5p-10, -0x1.fc0364ce1787p-9, 0x1.272bc18b0f2cep-12}, /* i=12 70.545 */\n", "{0x1.88d1cd474a2ep-1, 0x1.6f571ada77d52p-55, 0x1.1b7e98fe26217p-1, 0x1.952bd607eb12ep-56, -0x1.de65a22ce0587p-2, 0x1.40686a3f3dc2bp-4, 0x1.f6b0cb6926c42p-4, -0x1.09c7caecd317dp-4, -0x1.da668f759eaeap-7, 0x1.364e72035e80ap-6, -0x1.d421975736447p-11, -0x1.cc98454e96141p-9, 0x1.a8860fdf17259p-11}, /* i=13 71.537 */\n", "{0x1.999d4192a5715p-1, -0x1.c888a5759a92cp-55, 0x1.fc3ee5d1524bp-2, -0x1.27e60faac0278p-58, -0x1.cc990045b293fp-2, 0x1.b37338e6ac814p-4, 0x1.a0d11fe9ba61ap-4, -0x1.19bb2ca3816bap-4, -0x1.a0b7d94791f03p-8, 0x1.274a59774d5e6p-6, -0x1.64adea7b36f57p-9, -0x1.83684bd8ef173p-9, 0x1.38905afd229ffp-10}, /* i=14 70.033 */\n", "{0x1.a89c850b7d54dp-1, -0x1.e2752ebf0cd02p-55, 0x1.c40b0729ed548p-2, -0x1.c4c1c4927306dp-56, -0x1.b5eaaef09de9dp-2, 0x1.0847c7dad86afp-3, 0x1.47de0a4f796cap-4, -0x1.1d9de8b54a3ecp-4, 0x1.33252fb810c7cp-10, 0x1.0ab3e329ded2fp-6, -0x1.12d82076274edp-8, -0x1.287bb4a78d728p-9, 0x1.57d31bd574dap-10}, /* i=15 70.519 */\n", "{0x1.b5e62fce16095p-1, 0x1.bc3cff4400364p-56, 0x1.8eed36b886d93p-2, 0x1.ea7e17b96436dp-56, -0x1.9b64a06e4b1p-2, 0x1.2bb6e2c74d4fep-3, 0x1.dee322c062364p-5, -0x1.169960d5a983dp-4, 0x1.feab4ad0bfc14p-8, 0x1.c76eb94b07a5fp-7, -0x1.584474ae8f994p-8, -0x1.88df75be9251fp-10, 0x1.4edef5031709p-10}, /* i=16 72.437 */\n", "{0x1.c194b1d49a184p-1, -0x1.6770a58b27668p-57, 0x1.5d4fd33729015p-2, -0x1.6db7d76e9e97bp-56, -0x1.7e0f4f0454d97p-2, 0x1.444bc66c35bc4p-3, 0x1.356dbb543255p-5, -0x1.0643de6e8c574p-4, 0x1.b2e1f789415e4p-7, 0x1.6ba6d9f4af32fp-7, -0x1.8138bf4573a6ap-8, -0x1.7e6e52a583322p-11, 0x1.0f87322fa18a3p-10}, /* i=17 70.211 */\n", "{0x1.cbc54b476248dp-1, 0x1.1a5083b01ec0dp-55, 0x1.2f7cc3fe6f423p-2, 0x1.9fbb4b774e85dp-56, -0x1.5ee8429e30a49p-2, 0x1.52a8395f9627p-3, 0x1.313759f199499p-6, -0x1.dcf844d90282cp-5, 0x1.1e45f25ab54a1p-6, 0x1.091cb68a58665p-7, -0x1.8ea40b0ac8b7bp-8, -0x1.6b91b1bf985f2p-17, 0x1.158d9c0e1c327p-10}, /* i=18 73.007 */\n", "{0x1.d4970f9ce00d9p-1, -0x1.56704209fca7p-56, 0x1.059f59af7a906p-2, -0x1.0ce27da57f153p-56, -0x1.3eda354ddd5ffp-2, 0x1.57b85ad436067p-3, 0x1.8e90c2a157e8dp-10, -0x1.a2893b28f4033p-5, 0x1.4d6af4484a1cbp-6, 0x1.4ccee8c8b1f57p-8, -0x1.83304b9e2e312p-8, 0x1.40cb679d0a832p-11, 0x1.d6b5f4bdef24bp-11}, /* i=19 75.628 */\n", "{0x1.dc29fb60715afp-1, 0x1.ab029f047a087p-55, 0x1.bf8e1b1ca2279p-3, 0x1.0426e10a38p-65, -0x1.1eb7095e57e16p-2, 0x1.549ea6f7a013fp-3, -0x1.b10f20d110552p-7, -0x1.61420b5b34a55p-5, 0x1.677b7ea46c6f2p-6, 0x1.24f9940ffd84p-9, -0x1.6304445e5f6cap-8, 0x1.222fabfa75bbp-10, 0x1.fdcf55be3c03ep-12}, /* i=20 70.096 */\n", "{0x1.e29e22a89d766p-1, 0x1.bcc9d569ed217p-55, 0x1.7bd5c7df3fe9cp-3, 0x1.488f3b06e1394p-57, -0x1.fe674493fde22p-3, 0x1.4a9feacf7e222p-3, -0x1.a0082c90a1b0dp-6, -0x1.1cf0e7655f99ap-5, 0x1.6e3396f04262p-6, -0x1.3a2d2cdd5650dp-12, -0x1.334add14b9a31p-8, 0x1.7e12864580191p-10, 0x1.dae75c3e2be46p-12}, /* i=21 74.177 */\n", "{0x1.e812fc64db369p-1, 0x1.3c66a6a23d9a5p-55, 0x1.3fda6bc016994p-3, 0x1.586ddaff31a18p-57, -0x1.c1cb27861fc79p-3, 0x1.3b1051230b982p-3, -0x1.1e645a2a638ffp-5, -0x1.b1f643b14fd89p-6, 0x1.64297d7a66c2p-6, -0x1.3e365adfbccaep-9, -0x1.f2aa2b3ef5ec2p-9, 0x1.b3339ee2c8c49p-10, 0x1.0ef571022311p-13}, /* i=22 71.398 */\n", "{0x1.eca6ccd709544p-1, 0x1.f3de8f195347p-57, 0x1.0b3f52ce8c383p-3, 0x1.d1234b508bcfbp-57, -0x1.8885019f5df29p-3, 0x1.274275fc87eaep-3, -0x1.57f7386bfd263p-5, -0x1.30769f45aaa8bp-6, 0x1.4c8231709cfeep-6, -0x1.0c2c99c75913fp-8, -0x1.7514483efc09p-9, 0x1.c3ebcf121a533p-10, 0x1.de2f1801b848p-17}, /* i=23 73.855 */\n", "{0x1.f0762fde45ee6p-1, 0x1.9c3612a14fb77p-55, 0x1.bb1c972f23e5p-4, 0x1.ba69c564971e1p-58, -0x1.5341e3c0177b6p-3, 0x1.107929f6e7528p-3, -0x1.7e1b362eacfe6p-5, -0x1.73b61e487b8a9p-7, 0x1.2aa763e0343a9p-6, -0x1.59a388fd2272dp-8, -0x1.eea3c7f50e8dep-10, 0x1.b5026fd87d0cap-10, -0x1.0f2c660125dc6p-12}, /* i=24 71.363 */\n", "{0x1.f39bc242e43e6p-1, -0x1.dbae0fd9b967dp-55, 0x1.6c7e64e7281cbp-4, 0x1.aa87392dc4c2p-58, -0x1.2274b86833f6ep-3, 0x1.efb890e5b6633p-4, -0x1.92c7dbb880b5cp-5, -0x1.4547708842f2bp-8, 0x1.02047ab6c08c4p-6, -0x1.888355239e9ecp-8, -0x1.0313bb85e86e1p-10, 0x1.8ced9ddf3d834p-10, -0x1.2d520499bd799p-12}, /* i=25 73.472 */\n", "{0x1.f62fe80272419p-1, -0x1.b7c2d17fc31d3p-55, 0x1.297db960e4f63p-4, -0x1.22bea9385fad9p-58, -0x1.ecb83b087b37bp-4, 0x1.bce18363bbbb9p-4, -0x1.985aaf97891cbp-5, 0x1.cd95f2aa8601ap-12, 0x1.ab9d43270d20fp-7, -0x1.9b93410d46789p-8, -0x1.9b530b472cadfp-13, 0x1.52f54de527458p-10, -0x1.6844d43c7d693p-12}, /* i=26 72.129 */\n", "{0x1.f848acb544e95p-1, -0x1.b27aa2c376c3cp-55, 0x1.e1d4cf1e2450ap-5, -0x1.783e14555c1e9p-59, -0x1.9e12e1fde7354p-4, 0x1.8a27806de834fp-4, -0x1.91674e13a339ap-5, 0x1.3bc75e8f9d448p-8, 0x1.51b4d09ac47b8p-7, -0x1.96dc7b5f9bd66p-8, 0x1.e16520532bde9p-12, 0x1.0e742b323f434p-10, -0x1.ac319bfed91d4p-12}, /* i=27 72.979 */\n", "{0x1.f9f9ba8d3c733p-1, 0x1.cd5790ff03ab3p-55, 0x1.83298d717210ep-5, 0x1.740e2b04276bfp-59, -0x1.58d101f909971p-4, 0x1.58f1456f7db5ep-4, -0x1.808d17b33b814p-5, 0x1.0c1bdce673b1p-7, 0x1.f5ff1c06e9df2p-8, -0x1.7f26b8865f398p-8, 0x1.f87060e6f646p-11, 0x1.8c6056bea9223p-11, -0x1.e3499a90b84f5p-12}, /* i=28 73.403 */\n", "{0x1.fb54641aebbc9p-1, -0x1.79975513f67e7p-55, 0x1.34ac36ad8dafep-5, 0x1.902fb5363d36p-63, -0x1.1c8ec267fe9e2p-4, 0x1.2a52c5d83c05p-4, -0x1.68541b2c0582cp-5, 0x1.5afe422155ad5p-7, 0x1.56303c111cd8ap-8, -0x1.597ead749c06ap-8, 0x1.57b0870a7b4cfp-10, 0x1.ffc0efb0ac024p-12, -0x1.9e3ea349ab39ep-12}, /* i=29 73.624 */\n", "{0x1.fc67bcf2d7b8fp-1, -0x1.0d2748f976e8cp-55, 0x1.e85c449e377f3p-6, -0x1.cb7ccd2616394p-60, -0x1.d177f166cce53p-5, 0x1.fe23b75845cdfp-5, -0x1.4b120f9dde895p-5, 0x1.8d9906d138bd5p-7, 0x1.9201b7e469e83p-9, -0x1.2aceacb2954fp-8, 0x1.8d4e8140dc518p-10, 0x1.00a33f7e93047p-12, -0x1.72b7adfeee575p-12}, /* i=30 74.601 */\n", "{0x1.fd40bd6d7a785p-1, 0x1.60d45e630998fp-55, 0x1.7f5188610ddc8p-6, -0x1.60e8565137ecbp-60, -0x1.7954423f89a51p-5, 0x1.af5baae337ae6p-5, -0x1.2ad77b77d17dcp-5, 0x1.a7b8c4a8d53fep-7, 0x1.4593adc5d737ap-10, -0x1.ef1cf14455c9cp-9, 0x1.a1a04ce289b4bp-10, 0x1.3d14f37840954p-15, -0x1.50b861df174eep-12}, /* i=31 73.251 */\n", "{0x1.fdea6e062d0c9p-1, -0x1.64c70f379f67p-56, 0x1.2a875b5ffab56p-6, 0x1.531231987c3b8p-63, -0x1.2f3178cd7aa03p-5, 0x1.68d1c45b96efep-5, -0x1.09648dd332653p-5, 0x1.ad8b148089c02p-7, -0x1.f00fa01e6ca19p-13, -0x1.8718785b346p-9, 0x1.9a7b0da775387p-10, -0x1.090258ede6532p-13, -0x1.b3980b454d442p-13}, /* i=32 73.521 */\n", "{0x1.fe6e1742f7cf6p-1, -0x1.cebced8a49e04p-55, 0x1.cd5ec93c12432p-7, -0x1.bb85326a5eff3p-61, -0x1.e2ff3aaae31e4p-6, 0x1.2aa4e5824252p-5, -0x1.d049824fc44dbp-6, 0x1.a34eda0fc336ep-7, -0x1.682d8d1801582p-10, -0x1.239bf51e17ea8p-9, 0x1.7e761274bf059p-10, -0x1.01e715d70d49fp-12, -0x1.4d89f3d9c30d5p-13}, /* i=33 76.244 */\n", "{0x1.fed37386190fbp-1, 0x1.72b1549ea44eep-55, 0x1.61beae53b72b7p-7, 0x1.401790f84b248p-64, -0x1.7d6193f2417adp-6, 0x1.e947279e4a43bp-6, -0x1.9060301092cdcp-6, 0x1.8d14d4bdaa7f4p-7, -0x1.1f795ac88038p-9, -0x1.9222edb6bd145p-10, 0x1.53f95c7b01615p-10, -0x1.529b07d094e1dp-12, -0x1.5b533d0382e2p-14}, /* i=34 74.706 */\n", "{0x1.ff20e0a7ba8c2p-1, -0x1.03f86c5a13f78p-57, 0x1.0d1d69569b82dp-7, -0x1.a5e866bd1366ep-62, -0x1.2a8ca0dc14852p-6, 0x1.8cc071b719c43p-6, -0x1.54a148886e917p-6, 0x1.6e91361df3c9ep-7, -0x1.65c02e0d08291p-9, -0x1.e94b0adc3b1cap-11, 0x1.210781b57b089p-10, -0x1.7b88f8c82fbffp-12, -0x1.68df27e9a1688p-15}, /* i=35 74.851 */\n", "{0x1.ff5b8fb26f5f6p-1, -0x1.7e917ec20b615p-55, 0x1.9646f35a76624p-8, -0x1.f771f32fd191bp-62, -0x1.cf68ed932f081p-7, 0x1.3e8735b5b73b1p-6, -0x1.1e1611aabcbeap-6, 0x1.4afd8cd100d7p-7, -0x1.8c72005b1cfcfp-9, -0x1.c6a7216b336aap-12, 0x1.d577412afc2e2p-11, -0x1.836a0c0e10a99p-12, 0x1.a8f39f410252ap-19}, /* i=36 75.151 */\n", "{0x1.ff87b1913e853p-1, -0x1.3ca98afc58454p-56, 0x1.30499b503957fp-8, -0x1.d1eabb1c04f5p-64, -0x1.6496420203331p-7, 0x1.fa73d7eb1b70dp-7, -0x1.daa3005c2d3fep-7, 0x1.250942c31c3adp-7, -0x1.997578dc240a8p-9, -0x1.3904177639e63p-15, 0x1.6a6ed488a1f54p-11, -0x1.71cf0c5789c7dp-12, 0x1.43cb84231ab1cp-15}, /* i=37 75.856 */\n", "{0x1.ffa89fe5b3625p-1, 0x1.934b2bcb7f9a3p-55, 0x1.c4412bf4b8f0bp-9, -0x1.bbcc9dca4ec6p-67, -0x1.100f34713740dp-7, 0x1.8ebda0768e8e6p-7, -0x1.850c68e8e5c3cp-7, 0x1.fdac8346071b3p-8, -0x1.929de70d00321p-9, 0x1.10c7101bc52d8p-12, 0x1.070f7e89ec1e2p-11, -0x1.4e4b3dcf4f08dp-12, 0x1.f0d43b9869b19p-15}, /* i=38 75.476 */\n", "{0x1.ffc10194fcb64p-1, 0x1.ea14750ac9b59p-55, 0x1.4d78bba8ca5fdp-9, 0x1.4d9a93566b5b4p-65, -0x1.9ba107a459ce4p-8, 0x1.36f273fbd909bp-7, -0x1.3b38708f7bef7p-7, 0x1.b3fdff1de2112p-8, -0x1.7d55d55d262d8p-9, 0x1.eae5e05e74fccp-12, 0x1.5ebc1e53214a9p-12, -0x1.1fd7c1cd5d63ep-12, 0x1.49559a04c8568p-14}, /* i=39 76.483 */\n", "{0x1.ffd2eae369a07p-1, -0x1.83b09df7f7db4p-57, 0x1.e7f232d9e263p-10, 0x1.a26ac725599e5p-64, -0x1.34c7442de142bp-8, 0x1.e066bed09942fp-8, -0x1.f914f2c60b9bbp-8, 0x1.6f4662f6be13bp-8, -0x1.5e664591d6604p-9, 0x1.3a1598d880f36p-11, 0x1.965b2e78a4544p-13, -0x1.d8db42b193729p-13, 0x1.449172919598ep-14}, /* i=40 76.603 */\n", "{0x1.ffdff92db56e5p-1, -0x1.8aeef4ee0690ap-56, 0x1.6235fbd7a4345p-10, -0x1.11380fe434056p-65, -0x1.cb5e029ba8f3dp-9, 0x1.6fa4c7ef470e9p-8, -0x1.903a08305eebp-8, 0x1.30f12c83fdb23p-8, -0x1.39d769a774af1p-9, 0x1.5d79439ceaefdp-11, 0x1.5326883e7dfebp-14, -0x1.7199782285958p-13, 0x1.47181c8911603p-14}, /* i=41 77.827 */\n", "{0x1.ffe96a78a04a9p-1, -0x1.2816fe4528f9bp-55, 0x1.fe41cd9bb4eeep-11, 0x1.e3be508cae7ecp-66, -0x1.52d7b2896626ap-9, 0x1.16c192d8803dcp-8, -0x1.39bfce9b4ecc2p-8, 0x1.f376a554e5decp-9, -0x1.12e67cb7aa486p-9, 0x1.66d6e460b1614p-11, -0x1.54f70e4bde32bp-18, -0x1.10e125571fe1ep-13, 0x1.2842d46eb9f29p-14}, /* i=42 78.426 */\n", "{0x1.fff0312b010b5p-1, 0x1.155dec9cdc96bp-55, 0x1.6caa0d3582fe9p-11, -0x1.97d95851163fcp-67, -0x1.efb729f4be121p-10, 0x1.a2da7cec01564p-9, -0x1.e6c27ad2b1cep-9, 0x1.93b1f34b17723p-9, -0x1.d8179cd2ad34fp-10, 0x1.5cf51e0add9bbp-11, -0x1.16d8f4b5119c7p-14, -0x1.768557564f5f5p-14, 0x1.f4fc9dde73f24p-15}, /* i=43 78.437 */\n", "{0x1.fff50456dab8cp-1, -0x1.a197a986f0dep-58, 0x1.0295ef6591848p-11, -0x1.262bd83520706p-66, -0x1.679880e93e5c4p-10, 0x1.37d38e3a705afp-9, -0x1.75b371a264745p-9, 0x1.4231c3bfe3e65p-9, -0x1.8e184d4921105p-10, 0x1.45d5b5a7f77fap-11, -0x1.bf8ece4afedd2p-14, -0x1.ccd677aaa82f7p-15, 0x1.9e5241d5b6b15p-15}, /* i=44 80.203 */\n", "{0x1.fff86cfd3e657p-1, -0x1.2e06adb26f84ep-56, 0x1.6be02102b352p-12, 0x1.448bcfd3cfe0cp-68, -0x1.02b15777eb7c5p-10, 0x1.cc1d886874d5bp-10, -0x1.1bff70664651dp-9, 0x1.fc0f76c943696p-10, -0x1.4a22286622d3ep-10, 0x1.268887688a6e6p-11, -0x1.0fa2692fd7da2p-13, -0x1.cc13d1a82f742p-16, 0x1.4153e6537aae5p-15}, /* i=45 79.393 */\n", "{0x1.fffad0b901755p-1, 0x1.70d5c9a92b65cp-57, 0x1.fc0d55470cf51p-13, -0x1.6f2b03553d4c8p-67, -0x1.7121aff59f6a1p-11, 0x1.506d6992fc8ffp-10, -0x1.ab596015fc183p-10, 0x1.8bdd79a098723p-10, -0x1.0d88da9deb868p-10, 0x1.031cdd07e4507p-11, -0x1.22fc41430a37dp-13, -0x1.b5cc9546afcecp-18, 0x1.d7ea1c7b8fdb6p-16}, /* i=46 79.358 */\n", "{0x1.fffc7a37857d2p-1, -0x1.97b30fd4b6b48p-56, 0x1.5feada379d8b7p-13, -0x1.0546c4da57036p-67, -0x1.05304df546ed8p-11, 0x1.e79c081b79ebcp-11, -0x1.3e5dc1062db15p-10, 0x1.30eb20ccc1f98p-10, -0x1.b1b06c20a060dp-11, 0x1.bd52fbd55e0efp-12, -0x1.214afb8835b23p-13, 0x1.19ae9d16650ap-17, 0x1.42d933ee154fdp-16}, /* i=47 79.5 */\n", "{0x1.fffd9fdeabccep-1, 0x1.0c43c3bc59762p-55, 0x1.e3bcf436a1a95p-14, -0x1.6458a28a3f9b6p-69, -0x1.6e95311166825p-12, 0x1.5e3edf674e2dbp-11, -0x1.d5be6d15abe3ap-11, 0x1.d07da13e640c2p-11, -0x1.58106cc648748p-11, 0x1.76c840985e5ebp-12, -0x1.111de112b1a2ep-13, 0x1.315fc34053fbdp-16, 0x1.939439a75a553p-17}, /* i=48 80.809 */\n", "{0x1.fffe68f4fa777p-1, 0x1.2f21786b7644p-60, 0x1.49e17724f4d41p-14, 0x1.747684f0023e4p-69, -0x1.fe48c44d2ab81p-13, 0x1.f2bd95d72a532p-12, -0x1.57389188a71a9p-11, 0x1.5decc4058f7a1p-11, -0x1.0d559cf0f2957p-11, 0x1.3583904af6f83p-12, -0x1.efd7979333337p-14, 0x1.904cf9fa5c1f6p-16, 0x1.a13a094bd56a2p-18}, /* i=49 81.559 */\n", "{0x1.fffef1960d85dp-1, -0x1.f7cc78053f6adp-55, 0x1.be6abbb10a5aap-15, -0x1.e50b219d40126p-70, -0x1.60403819b22b8p-13, 0x1.5fff1dde5305ep-12, -0x1.f0c93c73e7f42p-12, 0x1.04cbf67af6c26p-11, -0x1.a04893510426cp-12, 0x1.f66b51a7bc4ap-13, -0x1.b410d7f2fd319p-14, 0x1.b99f9eb427956p-16, 0x1.f26fcffb14441p-20}, /* i=50 82.307 */\n", "{0x1.ffff4db27f146p-1, 0x1.ddecdd5e1d408p-55, 0x1.2bb5cc22e5db6p-15, 0x1.c5112eca8acdep-70, -0x1.e258948829ed1p-14, 0x1.ec8a8e59d9d5bp-13, -0x1.6425722b9f3cdp-12, 0x1.80a83a7103b4bp-12, -0x1.3dbb9374004f9p-12, 0x1.913b301d37bdep-13, -0x1.7563b0d94459fp-14, 0x1.bc01eea9a10bep-16, -0x1.3df26463df6a5p-20}, /* i=51 82.355 */\n", "{0x1.ffff8b500e77cp-1, -0x1.1014e1f83ed4cp-56, 0x1.8f4ccca7fc90dp-16, 0x1.a5d4ec8b9de43p-70, -0x1.478cffe1cd2edp-14, 0x1.559f04ad4de62p-13, -0x1.f9e163b15c466p-13, 0x1.18bda8b8c1315p-12, -0x1.df381bd3c058ep-13, 0x1.3b94f531bb6bep-13, -0x1.385f32481ed94p-14, 0x1.a414bd2b7cb3cp-16, -0x1.ac2bbe30f8767p-19}, /* i=52 83.754 */\n", "{0x1.ffffb43555b5fp-1, 0x1.c17f83b8d73a2p-55, 0x1.07ebd2a2d2844p-16, 0x1.d1bbdc704f49bp-70, -0x1.b93e442837f52p-15, 0x1.d5cf1514977f3p-14, -0x1.63f5eb46877fdp-13, 0x1.95a0411e668b1p-13, -0x1.652e5f2a88269p-13, 0x1.e950ddb7f5444p-14, -0x1.ffeb9383bdb3dp-15, 0x1.7c24392346fddp-16, -0x1.1f3b3254d723p-18}, /* i=53 83.181 */\n", "{0x1.ffffcf23ff5fcp-1, -0x1.b18a8b25039c4p-55, 0x1.5a2adfa0b4bc4p-17, 0x1.eb6d61aaaf95cp-71, -0x1.26c8826ed9e85p-15, 0x1.40473571d5383p-14, -0x1.f057dbf365c0ap-14, 0x1.2217929fed933p-13, -0x1.07324014ddb42p-13, 0x1.762758a56d654p-14, -0x1.9ba250c662e9p-15, 0x1.4c25759179e3dp-16, -0x1.3e800358f1a7bp-18}, /* i=54 83.812 */\n", "{0x1.ffffe0bd3e852p-1, -0x1.d7ece4ab5315p-58, 0x1.c282cd3957edap-18, 0x1.eb3cf4fd1428p-73, -0x1.86ad6df7ba401p-16, 0x1.b0f313eeb65a6p-15, -0x1.56e457745d637p-14, 0x1.9ad1f65a78253p-14, -0x1.7f92ad8542929p-14, 0x1.1a5578c0d30b3p-14, -0x1.4548d876bb0a3p-15, 0x1.19e60bf53b25ap-16, -0x1.3f1745170e2d3p-18}, /* i=55 85.046 */\n", "{0x1.ffffec2641a9ep-1, -0x1.e7ba4fdaaa8c8p-55, 0x1.22df298214423p-18, -0x1.a9d49552152a4p-74, -0x1.00c902a4d5e27p-16, 0x1.22234eb745941p-15, -0x1.d57a2be01db67p-15, 0x1.200c2ffad65f1p-14, -0x1.147585d43f49ap-14, 0x1.a4b07aec797e9p-15, -0x1.f9d088bbeff64p-16, 0x1.d2b2be4e42422p-17, -0x1.2bb57c0cf2941p-18}, /* i=56 84.87 */\n", "{0x1.fffff37d63a36p-1, -0x1.753e3241c01bp-57, 0x1.74adc8f4064d3p-19, 0x1.de8a904d5c372p-73, -0x1.4ed4228b3da96p-17, 0x1.81918baca1979p-16, -0x1.3e81c09c29601p-15, 0x1.9004afed1bde9p-15, -0x1.8a40e183ee3fcp-15, 0x1.359242a8b8c58p-15, -0x1.834b953bcb845p-16, 0x1.79e345fb0b20dp-17, -0x1.0bb2d323900cep-18}, /* i=57 85.252 */\n", "{0x1.fffff82cdcf1bp-1, 0x1.046bbe9897fd5p-55, 0x1.d9c73698fb1dcp-20, 0x1.88de36481dfb5p-74, -0x1.b11017e7d5893p-18, 0x1.fc0dfadc2c6d6p-17, -0x1.ac4e1aa499ac6p-16, 0x1.131810ab2e2e3p-15, -0x1.1629d94abc864p-15, 0x1.c22a71036c259p-16, -0x1.244452f74de31p-16, 0x1.2bf17664310c1p-17, -0x1.cd1b31a8349bep-19}, /* i=58 84.869 */\n", "{0x1.fffffb248c39dp-1, 0x1.9b9a41713558cp-55, 0x1.2acee2f5ecdb8p-20, -0x1.2d1692a9a105cp-76, -0x1.15cc5700a2341p-18, 0x1.4be757b934819p-17, -0x1.1d6ab6f8cbf7cp-16, 0x1.76c5a3035bdabp-16, -0x1.847332578dfacp-16, 0x1.437f23f8d25ffp-16, -0x1.b305e625a092dp-17, 0x1.d3886ff986fefp-18, -0x1.81f2189b385a2p-19}, /* i=59 85.208 */\n", "{0x1.fffffd01f36afp-1, -0x1.d41915db812efp-55, 0x1.75fa8dbc84becp-21, 0x1.a5cd79572a1a6p-76, -0x1.6186d9fc357c5p-19, 0x1.ae02322e08822p-18, -0x1.79082befd50cap-17, 0x1.f9c26e211b174p-17, -0x1.0c768235c378bp-16, 0x1.cba7164e1064fp-17, -0x1.3f75c28c31ac8p-17, 0x1.663fcfff77e44p-18, -0x1.3a6da35f36ee6p-19}, /* i=60 85.253 */\n", "{0x1.fffffe2ba0ea5p-1, -0x1.26cd7908cba2bp-55, 0x1.d06ad6ecdf971p-22, -0x1.020b74d9d30fbp-76, -0x1.be46aa879edb2p-20, 0x1.143860c49d129p-18, -0x1.edabcbc3e620dp-18, 0x1.52139c87e9c82p-17, -0x1.6f567cd982028p-17, 0x1.42ebd266abd62p-17, -0x1.cf2f0c6adfb3ep-18, 0x1.0e2c0ed67786cp-18, -0x1.f50cb81b9b19p-20}, /* i=61 85.484 */\n", "{0x1.fffffee3cc32cp-1, 0x1.e429188c949b8p-56, 0x1.1e1e857adc568p-22, 0x1.2439f8a1649bbp-76, -0x1.1769ce59fb2c8p-20, 0x1.5fe5d47560794p-19, -0x1.405da04875e51p-18, 0x1.bfc96a938083dp-18, -0x1.f19ff5e59cbe9p-18, 0x1.c0c4d50d275bfp-18, -0x1.4b9df120462aep-18, 0x1.916640ee35de4p-19, -0x1.874483d99c37ep-20}, /* i=62 85.73 */\n", "{0x1.ffffff54dab72p-1, -0x1.a443df643729ap-55, 0x1.5dcd669f2cd34p-23, -0x1.ceb1ec59e0c28p-78, -0x1.5b11cbd1ee799p-21, 0x1.bc91a6b1c1839p-20, -0x1.9c2c5d12dfa2cp-19, 0x1.25d1e3c70364fp-18, -0x1.4dbe26c88e4f7p-18, 0x1.347bb8350b422p-18, -0x1.d51d3280da8ap-19, 0x1.25ed8e5b466b5p-19, -0x1.2b9c5d3390919p-20}, /* i=63 86.036 */\n", "{0x1.ffffff99b79d2p-1, -0x1.58ff1c425f8dep-56, 0x1.a854ea14102a9p-24, -0x1.21745e4b4fcb3p-78, -0x1.aba593e8384aep-22, 0x1.167c252a45678p-20, -0x1.06d78ca0424a3p-19, 0x1.7e0f59fcfa53dp-19, -0x1.bb4d48383b847p-19, 0x1.a39f3ad9a397fp-19, -0x1.47e836879c374p-19, 0x1.a89244d14b829p-20, -0x1.c33e15a6dbe37p-21}, /* i=64 86.403 */\n", "{0x1.ffffffc355dfdp-1, 0x1.88cb60fd4511cp-57, 0x1.febc107d5efabp-25, -0x1.d9ed10902067cp-81, -0x1.055a3c70279a4p-22, 0x1.59ff37766e9a7p-21, -0x1.4c53adb9dcc4dp-20, 0x1.ec49242997849p-20, -0x1.23927ad6ac54fp-19, 0x1.1a6e0676c7463p-19, -0x1.c5239f6a88a96p-20, 0x1.2e991308bf6fap-20, -0x1.4e276c09fe81bp-21}, /* i=65 86.718 */\n", "{0x1.ffffffdc4ad7ap-1, -0x1.d75de787812d4p-55, 0x1.30f93c3699079p-25, -0x1.8f941ab38e9dap-80, -0x1.3ce2f890bb01dp-23, 0x1.aa5010863c83bp-22, -0x1.a08ef1ca1636p-21, 0x1.3a4a6af3cafacp-20, -0x1.7be1e832218fp-20, 0x1.784775c30c386p-20, -0x1.3593046482ce3p-20, 0x1.a9d448178fbfdp-21, -0x1.e77bb85451c65p-22}, /* i=66 87.121 */\n", "{0x1.ffffffeb24467p-1, 0x1.bff89ef33d6ddp-55, 0x1.6961b8d641d07p-26, -0x1.74a7fc97b1544p-80, -0x1.7d2510f1f969dp-24, 0x1.0476b165ac852p-22, -0x1.02d3a3b9d195ep-21, 0x1.8db3567bef1dfp-21, -0x1.ea3ef4e3a126bp-21, 0x1.f03b0861a59acp-21, -0x1.a250ca467705ap-21, 0x1.27e9995f6dfcdp-21, -0x1.5e77b673c6d74p-22}, /* i=67 87.557 */\n", "{0x1.fffffff3e8892p-1, 0x1.befbf8d294678p-58, 0x1.a8e405e651ab7p-27, 0x1.167a2d8cf6b18p-84, -0x1.c6c40e5083698p-25, 0x1.3ba47a17512fdp-23, -0x1.3ee334beef6ecp-22, 0x1.f2bf9e6c43e99p-22, -0x1.395c08ac8e281p-21, 0x1.43ee4b521ccadp-21, -0x1.178f0deeb9b2p-21, 0x1.964e51b0f0532p-22, -0x1.f0cc4ecca5c2fp-23}, /* i=68 87.991 */\n", "{0x1.fffffff90b2e3p-1, -0x1.d82d94a90f1e4p-56, 0x1.efac5187b2864p-28, 0x1.f1301ae680614p-83, -0x1.0d229044adeeep-25, 0x1.7b5bc9db47dp-24, -0x1.8588212e670c2p-23, 0x1.35f42db1989fap-22, -0x1.8cd98865c4ffp-22, 0x1.a2b8587c48078p-22, -0x1.71aa2de99af9cp-22, 0x1.13a89805c15d9p-22, -0x1.5b53ca1bcf01ap-23}, /* i=69 88.463 */\n", "{0x1.fffffffc0748fp-1, 0x1.6ef7a9caef28p-57, 0x1.1edfa3c5f5ccbp-28, 0x1.368f60e2e6cfap-83, -0x1.3c025a6810c37p-26, 0x1.c42f78a0989adp-25, -0x1.d7c6c3583c6e3p-24, 0x1.7dd6ccb5c93b4p-23, -0x1.f1ec2f699fdccp-23, 0x1.0bf7a04407a8cp-22, -0x1.e3aafe6dfd4ep-23, 0x1.71bc3a55b63f4p-23, -0x1.df66b11724e7cp-24}, /* i=70 88.939 */\n", "{0x1.fffffffdbff2ap-1, 0x1.49438981099b2p-56, 0x1.4979ac8b28928p-29, -0x1.c2f44bcf3ce52p-83, -0x1.7015eec37753ap-27, 0x1.0b487791590cfp-25, -0x1.1b44b64c3c995p-24, 0x1.d23ff3ef8dd83p-24, -0x1.357d673d1ccfcp-23, 0x1.53a563ce0e9e3p-23, -0x1.3921106a960f6p-23, 0x1.ea527d318f96ep-24, -0x1.46bd6cea7103dp-24}, /* i=71 89.458 */\n", "{0x1.fffffffebc1a9p-1, 0x1.e0e5facabfab4p-56, 0x1.77756ec9f78fbp-30, 0x1.e20366d0e0306p-85, -0x1.a9530780ca70cp-28, 0x1.3962ecb10df65p-26, -0x1.51494525dee64p-25, 0x1.1a2961b90efbp-24, -0x1.7d35cd0b404bfp-24, 0x1.aa596d9d73afbp-24, -0x1.91493d8d43ba2p-24, 0x1.4184505343c2dp-24, -0x1.b7d977f1a3402p-25}, /* i=72 89.993 */\n", "{0x1.ffffffff4b453p-1, 0x1.59b25048a61ccp-55, 0x1.a887bd2b4404fp-31, -0x1.2556d8ad4dd44p-87, -0x1.e78be33fb01dap-29, 0x1.6c6ef0b68629ep-27, -0x1.8e36e9a44c497p-26, 0x1.5286ee37c531ep-25, -0x1.d146395886537p-25, 0x1.090902855d5fp-24, -0x1.fd0d1e8fcb6dfp-25, 0x1.a10f65c3c5a7bp-25, -0x1.24888c323daf3p-25}, /* i=73 90.536 */\n", "{0x1.ffffffff9bec8p-1, -0x1.6755054654b62p-56, 0x1.dc479de0ef004p-32, -0x1.c3434581af3b8p-86, -0x1.1535aee3eb1b2p-29, 0x1.a4547ed264758p-28, -0x1.d2308d0dead0fp-27, 0x1.929d46a9a7edcp-26, -0x1.195dbfd4afd19p-25, 0x1.46630f49ccd2fp-25, -0x1.3fa4637c64ebcp-25, 0x1.0b98a6e0cfc02p-25, -0x1.8093f032972f3p-26}, /* i=74 91.092 */\n", "{0x1.ffffffffc901cp-1, 0x1.9c951c943961cp-57, 0x1.0916f04b6e18dp-32, 0x1.1bdf9650721eap-87, -0x1.38b90f78fbe14p-30, 0x1.e0d7765326885p-29, -0x1.0e9760d0ac127p-27, 0x1.daad91166722dp-27, -0x1.513c51b9838edp-26, 0x1.8e27fb85ba534p-26, -0x1.8d6f6bd99eaffp-26, 0x1.53c31e52fff08p-26, -0x1.f3bfd31796bcp-27}, /* i=75 91.685 */\n", "{0x1.ffffffffe202dp-1, 0x1.a54841f566a61p-55, 0x1.24caf2c32af16p-33, 0x1.02e3358112fa1p-87, -0x1.5dfa962d49548p-31, 0x1.10ca1ff2af812p-29, -0x1.377c7e98dd9b4p-28, 0x1.156649e0b5dd2p-27, -0x1.9092f4db426c5p-27, 0x1.e12a29b227972p-27, -0x1.e94e18d5271a9p-27, 0x1.aae38927ee69bp-27, -0x1.41121b0293be1p-27}, /* i=76 92.286 */\n", "{0x1.ffffffffefc57p-1, -0x1.8225a9658ef84p-57, 0x1.40dfd87456f4fp-34, -0x1.a6d5c55f8e63bp-88, -0x1.848f101ce14c8p-32, 0x1.32fed47f8dd28p-30, -0x1.638ff4a6975f2p-29, 0x1.416d25168a6b8p-28, -0x1.d78fb22f58668p-28, 0x1.2009c6b4e61eap-27, -0x1.2a459e59c850bp-27, 0x1.096a3e8dac0eap-27, -0x1.97fba69de37d8p-28}, /* i=77 92.91 */\n", "{0x1.fffffffff748ep-1, 0x1.ae15e36044aacp-57, 0x1.5ce9ab1670dd6p-35, 0x1.cc9bbfb723fc4p-91, -0x1.abf69bd9866f7p-33, 0x1.56ae1e8abbbbfp-31, -0x1.927ca04d1a7a8p-30, 0x1.713d3b07d7a36p-29, -0x1.1318f5d7d717bp-28, 0x1.55ab94fdfd1f4p-28, -0x1.68216fb90717ap-28, 0x1.46ad5ce577d65p-28, -0x1.0065a20073e81p-28}, /* i=78 93.545 */\n", "{0x1.fffffffffb5bp-1, -0x1.50fb19119064fp-55, 0x1.7872d9fa10ab2p-36, -0x1.7760afdf543a4p-90, -0x1.d39eaac4a0b47p-34, 0x1.7b67ab8af33d6p-32, -0x1.c3ced54e694eap-31, 0x1.a4875d8a47f12p-30, -0x1.3e213e6f5c296p-29, 0x1.919137301f897p-29, -0x1.aea6bd9b3493p-29, 0x1.8e06e4ab5925fp-29, -0x1.3ed1d979421b2p-29}, /* i=79 94.198 */\n", "{0x1.fffffffffd8b3p-1, -0x1.5182469c211ep-57, 0x1.92ff33023d5c3p-37, -0x1.2932180032bd1p-91, -0x1.fae4fe28d12ddp-35, 0x1.a0a80964d6e97p-33, -0x1.f6f47be478e2ap-32, 0x1.dad968cdacb13p-31, -0x1.6ca68a8bfdb81p-30, 0x1.d3a79e5305b4ap-30, -0x1.fe1534ebf69c7p-30, 0x1.e01ee76d92779p-30, -0x1.883ed9069f3fdp-30}, /* i=80 94.867 */\n", "{0x1.fffffffffeb6p-1, -0x1.4d3f53e684bf8p-56, 0x1.ac0f5f322937ap-38, -0x1.8e8ab19224e58p-92, -0x1.108dc99cf03e5p-35, 0x1.c5db17016a0c6p-34, -0x1.159f41ea079c3p-32, 0x1.09ced3e9b7204p-31, -0x1.9e4dace0668p-31, 0x1.0dd5e0e9749b6p-30, -0x1.2b3aa6599d0b5p-30, 0x1.1eb5e8e4ffe8fp-30, -0x1.dd8955967ed31p-31}, /* i=81 95.555 */\n", "{0x1.ffffffffff542p-1, 0x1.b57ed63ed811p-57, 0x1.c324c20e337e5p-39, 0x1.53fd8abf42ed9p-93, -0x1.22c6b11327305p-36, 0x1.ea5f66f89cbd4p-35, -0x1.2ff1e0a81bedcp-33, 0x1.270ddbd8e501fp-32, -0x1.d2992b5c25c93p-32, 0x1.3492d76bdf266p-31, -0x1.5bc7361853ddep-31, 0x1.53121ae3f1d2ep-31, -0x1.1fb0f7e3f242bp-31}, /* i=82 96.256 */\n", "{0x1.ffffffffffa73p-1, -0x1.6fead614b7934p-56, 0x1.d7c593130dd16p-40, -0x1.8e78574fe0514p-95, -0x1.33c1e2f16e037p-37, 0x1.06c53fdc74764p-35, -0x1.4a029a87915acp-34, 0x1.44bd86238ff0dp-33, -0x1.0474ac3a80072p-32, 0x1.5db2a89e9bc47p-32, -0x1.906f4b51a7f75p-32, 0x1.8d189784c1f5p-32, -0x1.571a4760f483dp-32}, /* i=83 96.973 */\n", "{0x1.ffffffffffd27p-1, 0x1.19e1a84064c56p-56, 0x1.e9810295890f9p-41, 0x1.f998d55766fdbp-95, -0x1.43262ab4b77b2p-38, 0x1.1756eae580a28p-36, -0x1.6359d5b0d251ep-35, 0x1.626391bd58994p-34, -0x1.203efc6c9f556p-33, 0x1.88c0b111be9p-33, -0x1.c8ca211a38811p-33, 0x1.cc911f684d612p-33, -0x1.950e3edf09a71p-33}, /* i=84 97.706 */\n", "{0x1.ffffffffffe8dp-1, 0x1.e766e2c801398p-58, 0x1.f7f338086a87bp-42, -0x1.dfa0c27b527ep-98, -0x1.509f766d9f287p-39, 0x1.268e278ede221p-37, -0x1.7b7b43e9a1b0ep-36, 0x1.7f7aadab6b398p-35, -0x1.3c3cc6aafba0bp-34, 0x1.b52c69b4ab6dep-34, -0x1.0222c438d1182p-33, 0x1.0888e14314f83p-33, -0x1.d96aaea63b362p-34}, /* i=85 98.453 */\n", "{0x1.fffffffffff45p-1, -0x1.5948eec884df5p-55, 0x1.01647ba79874ep-42, 0x1.6d5d39dabc3p-103, -0x1.5be1cf20840dcp-40, 0x1.3418096320dafp-38, -0x1.91e9beb94b447p-37, 0x1.9b762261756a7p-36, -0x1.57f320a630c91p-35, 0x1.e24b78ce82b11p-35, -0x1.2112fff5c77aap-34, 0x1.2cfdd93a41786p-34, -0x1.11ea1f35b4d2bp-34}, /* i=86 99.218 */\n", "{0x1.fffffffffffa2p-1, 0x1.d07509a1a944p-57, 0x1.04e15ecc7f401p-43, -0x1.0858e34f7a6a6p-98, -0x1.64ac1f9b95f96p-41, 0x1.3fa8302ade993p-39, -0x1.a62b70897719ep-38, 0x1.b5c619266e9fp-37, -0x1.72de32129cbb8p-36, 0x1.07ae94305c398p-35, -0x1.40c45a9e95152p-35, 0x1.533d127efdf16p-35, -0x1.39dc242ba4cdap-35}, /* i=87 99.994 */\n", "{0x1.fffffffffffd1p-1, 0x1.3b6fc0b729759p-55, 0x1.065b9616170e1p-44, -0x1.49459f5147526p-99, -0x1.6acaa58a8be12p-42, 0x1.48fb92d0947e7p-40, -0x1.b7ce1a1ea8ea5p-39, 0x1.cddc552bbebebp-38, -0x1.8c751cc1a5784p-37, 0x1.1dc79b52007bp-36, -0x1.60b3d17e7714cp-36, 0x1.7ac1d379afc28p-36, -0x1.641ca84798564p-36}, /* i=88 100.787 */\n", "{0x1.fffffffffffe9p-1, -0x1.5fe91226dd51p-58, 0x1.05ca50205d279p-45, -0x1.7a281f9edb8e6p-99, -0x1.6e18ec0d42451p-43, 0x1.4fdb051100a15p-41, -0x1.c66b3f3fe565ep-40, 0x1.e331281475b54p-39, -0x1.a42e6965b2b9ap-38, 0x1.3301ef493196p-37, -0x1.804fcc1524d74p-37, 0x1.a2ef0c13a3daap-37, -0x1.9028a915f98d3p-37}, /* i=89 101.591 */\n", "{0x1.ffffffffffff5p-1, -0x1.238f8ed17d9b3p-55, 0x1.0330f0fd69931p-46, 0x1.a2c00e0c6dcbap-100, -0x1.6e8334c65749dp-44, 0x1.541d561058477p-42, -0x1.d1ac042ada69ep-41, 0x1.f54864c5a530ep-40, -0x1.b984c73c1d301p-39, 0x1.46ec7009c291fp-38, -0x1.9efc2df73776p-38, 0x1.cb12ac38f37cap-38, -0x1.bd54fcd67b8d4p-38}, /* i=90 102.407 */\n", "{0x1.ffffffffffffbp-1, -0x1.efa4d64f59f62p-55, 0x1.fd3de10d6287ap-48, -0x1.e1fdae91c5cfep-102, -0x1.6c073be0916e6p-45, 0x1.55a8eab9e129ap-43, -0x1.d94c87c1bc304p-42, 0x1.01db0818bec24p-40, -0x1.cbfbe4c0ef6eep-40, 0x1.59179d8c519c4p-39, -0x1.bc172710440bdp-39, 0x1.f26a4f726814ep-39, -0x1.ead889e052555p-39}, /* i=91 103.247 */\n", "{0x1.ffffffffffffdp-1, 0x1.6be96953fe014p-55, 0x1.f05e82aae2be2p-49, -0x1.070a8237b4337p-103, -0x1.66b44c6d7ddb6p-46, 0x1.5474bd9d072f3p-44, -0x1.dd1e8c33100ccp-43, 0x1.0711486984913p-41, -0x1.db2522b66a6cep-41, 0x1.6919a06329739p-40, -0x1.d6fe8f87926e8p-40, 0x1.0c1488010ff5cp-39, -0x1.0bf9fa407e9abp-39}, /* i=92 104.083 */\n", "{0x1.fffffffffffffp-1, -0x1.0fecc5ed770dep-55, 0x1.e00e9148a1d52p-50, 0x1.f7a503c7a2ad8p-107, -0x1.5eaaa4200e355p-47, 0x1.5088b6566fcedp-45, -0x1.dd0b48e0f634ep-44, 0x1.0a27116d7478ep-42, -0x1.e6a3e1d5c214fp-42, 0x1.769249755a4bcp-41, -0x1.ef16049050b69p-41, 0x1.1dbf2744f66dbp-40, -0x1.21c636bd8f5a9p-40}, /* i=93 104.933 */\n", "{0x1.fffffffffffffp-1, 0x1.989c6c5d51227p-55, 0x1.ccaaea71ab11p-51, 0x1.152f323a1f3b4p-107, -0x1.541a2f15eb476p-48, 0x1.49fd53e85cdf3p-46, -0x1.d9144beee6b4ap-45, 0x1.0b09b02f533a1p-43, -0x1.ee312fcf48076p-43, 0x1.812ed2f01f60ap-42, -0x1.01e6391f47ad7p-41, 0x1.2dce8f6b8c896p-41, -0x1.365d5011db0dfp-41}, /* i=94 105.705 */\n", "\"\"\"\n", "\n", "import re\n", "\n", "def strip_c_comments(code: str) -> str:\n", " return re.sub(r'/\\*.*?\\*/', '', code)\n", "\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in strip_c_comments(data).strip().splitlines():\n", " floats = line.strip(\"{}, \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"[ {', '.join(encoded)} ],\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "075d7743-afd8-4f2a-95a6-51172acf3f6d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0x3fcac45e37fe2526, 0x3c648d48536c61e3, 0x3ff16e2d7093cd8c, 0x3c9979a52f906b4d, 0xbfca254428ddb453, 0x3c69c98838a77aea, 0xbfd59b3da8e1e176, 0xbc41f650c25d97b0, 0x3fb988648fe88219, 0xbc55aecf0c7bb6c1, 0x3fb803427310d199, 0xbc5a14576e703eb2, 0xbfa09e7bce5592c9, 0x3c3eb7c7f3e76998, 0xbf9516b205318414, 0xbc2941aa998b1fa4, 0x3f8038d3f3a16b57, 0x3f6e19d52695ad59, 0xbf59542e7ed01428, 0xbf41f9b6e46418dc, 0x3f30796a08a400f4, 0x3f12610d97c70323, 0xbf025d31d73f96d1, 0xbee05e1fa9e02f11, 0x3ed1e616f979139c, 0x3ea9b3d54f1f222a, 0xbe97ad96beea439a ],\n", "[ 0x3fd5da9f415ff23f, 0xbc4a72e51e191950, 0x3ff05fd3ecbec298, 0xbc9f17d49717adf8, 0xbfd477c8e7ee733d, 0xbc792236432236b7, 0xbfd1917b60acab73, 0x3c7c06e6c21b4b3b, 0x3fc322a728d4ed12, 0x3c3ffa8aef321410, 0x3fb04c50a9cd2c12, 0xbc4edd0562dce396, 0xbfa7ce764eeddd86, 0x3c29afeb391c029c, 0xbf868aac5801171d, 0x3c24f9655411fc03, 0x3f862aa895f51cd3, 0x3f56c003c3cedb10, 0xbf6079502dbbafff, 0xbf1d9c7cbb799b47, 0x3f345a995aede3f4, 0x3eb0c04ea8c98fc9, 0xbf057edfa53128d0, 0x3eba96286bf3ef56, 0x3ed3c8ab12e6d24b, 0xbe97454eba0cb203, 0xbe8f02a6f6847617 ],\n", "[ 0x3fddb081ce6e2a48, 0xbc77ff0a3296d9cb, 0x3fedd167c4cf9d2a, 0x3c844f2832f90a97, 0xbfda173acc35a985, 0xbc3c5432c9a22740, 0xbfc889a80f4ad955, 0xbc6f6123bf467942, 0x3fc6c2eea0d17b39, 0xbc61f4935c3cf5b1, 0x3f9b0645438e5d17, 0x3c37a5f08ebaf9d0, 0xbfaa3fd9fcbb6d6d, 0x3c494a1b58b5916f, 0x3f2060b78c935b8e, 0x3bb9cec375875a1c, 0x3f8678b51a9c4b0a, 0xbf51e03bfc8eebb4, 0xbf5e653535cab33f, 0x3f355f31366d2c5c, 0x3f30dcf1445cbb88, 0xbf1098913ad4dcc7, 0xbeff6e252329eeed, 0x3ee41ad0a5afe51d, 0x3ec8fd4609222f1c, 0xbeb4465926de1a35, 0xbea407a1f42b46d4 ],\n", "[ 0x3fe25b8a88b6dd7f, 0x3c89534a3b5bd215, 0x3fea5074e2157620, 0x3c7fad8c0ef6fae6, 0xbfdd9a837e5824e4, 0xbc71d19ec86adc7c, 0xbfb9c41d1d5fae55, 0x3c374c230d6afba4, 0x3fc75bebc1b18d1c, 0x3c501ece95d4dffc, 0xbf86410ad9332666, 0xbc216523d167a40c, 0xbfa7df8890b11fa7, 0x3c4d6a99d1387564, 0x3f84a54816d3608a, 0xbc2f810ad06699cc, 0x3f818f36eb18f3d7, 0xbf68d661c030e174, 0xbf53628ede23e249, 0x3f4438eb2b3c4d27, 0x3f1fd3c13e725e91, 0xbf1991b866a32c87, 0xbee1237c600dab6f, 0x3eea9c701140d4c0, 0x3e71801e61adfdda, 0xbeb785516863e6ce, 0xbe83e033ef590125 ],\n", "[ 0x3fe569243d2b3a9b, 0x3c78eef7012e8df4, 0x3fe681ff24b4ab04, 0xbc5dba6493354c70, 0xbfdef2bed2786b25, 0xbc7ae3f6b6b2b679, 0xbf8a4254557d722f, 0xbc20ff7bffd10053, 0x3fc532415c267962, 0x3c62eacc4bd2e841, 0xbfa558b4c55a835c, 0x3c3c21c40815d70a, 0xbfa1b7ad5b777f1b, 0xbc42115b2bd8d644, 0x3f91201d3bd0e758, 0xbc0b39b845442560, 0x3f72995e3a88a890, 0xbf70294c3e93cdb0, 0xbf3159644a564f83, 0x3f463daf9b3858ef, 0xbf03beeb4a1255ac, 0xbf180c5178c36c72, 0x3eed4f6f5bab7dfa, 0x3ee521deb6d2f46e, 0xbec4ef3208231a8b, 0xbeae7d2b4e06e4a2, 0x3e921536d5b8bdf9 ],\n", "[ 0x3fe7fb9bfaed8078, 0x3c766cf14bcad032, 0x3fe2a8dcede3673b, 0xbc77378e2c70325e, 0xbfde5267029187c0, 0x3c7add23841b110a, 0x3fafe0796bb9d05a, 0xbc37a992e13ce574, 0x3fc0fa23021ad0ac, 0xbc417f4228359928, 0xbfafa21ebca76761, 0x3c3278ca2820f66c, 0xbf931546d5c4edb4, 0x3c136fcf151892a0, 0x3f937e5469efb7a6, 0xbc39553630321d4f, 0x3f2097966e2e87ea, 0xbf6e82ab020887a7, 0x3f4318270c11ae74, 0x3f412652e433da97, 0xbf24dc9bd6368bb8, 0xbf0c441138d4ff53, 0x3efc91d8dc5b66ec, 0x3ecf3ba57b86d474, 0xbecdd3403d11a818, 0xbe731f497a106a7c, 0x3e9436dbcc93d342 ],\n", "[ 0x3fea1551a16aaeaf, 0x3c6a558a46df5f68, 0x3fddfca26f5bbf88, 0xbc6ddcbaf85587b6, 0xbfdc1cd84866038f, 0xbc7200885b97f453, 0x3fbe4c9975da0987, 0xbc5f162e7576c79c, 0x3fb747e31bf47af3, 0xbc56178f12d62ed9, 0xbfb1d1f00109e42a, 0x3c5002b06e023544, 0xbf647654175ceb42, 0x3bd683389ccacfa8, 0x3f91a817c594b8cb, 0x3c336ac477166efb, 0xbf6cb8acd699cca6, 0xbf657b72bf874db6, 0x3f524493dca8b6fa, 0x3f2f556774c6aaf6, 0xbf2b09ec5c8ba626, 0xbed09bd1a09f38e8, 0x3efd149c3e776976, 0xbec8f7c2a6575e92, 0xbec8391d4afaf16a, 0x3ea5a7552081d1d5, 0x3e932d1bb2d1d0ca ],\n", "[ 0x3febbef0fbde6221, 0xbc8322c1148e0d48, 0x3fd75a91a7f4d2ed, 0x3c56eb826a9df85c, 0xbfd8d03ac274201c, 0x3c57a5c56eb7f6a0, 0x3fc3954778d6a0df, 0xbc5863eca74d1838, 0x3fa88e0f7b183fc6, 0x3c4226527d05ce39, 0xbfb0f7c15f75ee13, 0xbc156f74f3513660, 0x3f85e22cfa1aab51, 0x3c24b49a250c6474, 0x3f89ad28c5557c22, 0x3c299920b730ecd5, 0xbf7704ec5d29fc83, 0xbf523360304f19ba, 0x3f543ca3fcdf079d, 0xbf0dcb97a9e04bd4, 0xbf2735e26c43d267, 0x3f0360c3b06ffbb4, 0x3ef29a6b5798e781, 0xbeddbc35e4cf98f5, 0xbeb2f6e8e81287bb, 0x3eaeeb2fdddad355, 0x3e81ae65e387ac52 ],\n", "[ 0x3fed0580b2cfd249, 0x3c84fca6318dfee9, 0x3fd1a0dc51a9934d, 0xbc6ca89d2d78fba4, 0xbfd4ef05a0f95eeb, 0xbc65f7c55a00231c, 0x3fc5648b5dc47417, 0xbc6fb8fa09976e07, 0x3f840fbaba44504c, 0x3bf435c75f61f1e0, 0xbfac0db89d0a41a4, 0xbc11dd02d9441b98, 0x3f9388c3ec056942, 0x3c38e7498172c914, 0x3f7aecb7463cf446, 0xbbe0d6701a009d70, 0xbf78bca53327e075, 0x3f34add4a8239f4a, 0x3f505ce4abd10484, 0xbf3183f198a0b620, 0xbf19cd1a9b9fc69b, 0x3f0d30363021af83, 0x3ecda66f2161c4c6, 0xbedf41f1f238827d, 0x3ea725a07b1177b7, 0x3ea84c3b2483eb6a, 0x3e6e30e89d6e85cd ],\n", "[ 0x3fedf85ea8db188e, 0xbc8f71e8254d11a9, 0x3fc9cb5bd549b111, 0xbc4973e73caa1edc, 0xbfd0ed7443f85c33, 0xbc574bf040302ad8, 0x3fc5066cda84bba9, 0x3c4beb86d9e281a8, 0xbf9419fa10b6ed7d, 0x3c35157491034c58, 0xbfa3f41761d5a941, 0x3c494a1c1f7af153, 0x3f96d1d724baaae4, 0x3c3c41090a704426, 0x3f4e377f5703f7ff, 0xbbea753be0c53963, 0xbf74cc916ad63c27, 0x3f5553ef0d12719f, 0x3f426240f55987fd, 0xbf36bbf0fffb7138, 0xbee320cf6663c40d, 0x3f0a9d4850aaa197, 0xbee17036c4011c91, 0xbed441ea26a91a02, 0x3ebd81eb8e2ef452, 0x3e917d7b798a4322, 0xbe4b7b0dfb2559d0 ],\n", "[ 0x3feea7730ed0bbb9, 0x3c82c5bd7ce1388b, 0x3fc24a7b84d38971, 0x3c6aa0c5e788ed5e, 0xbfca4b118ef01593, 0xbc3238e3e6a99de0, 0x3fc319c7a75f9187, 0x3c4a8f8fff24b0ac, 0xbfa3db5bed47faf6, 0x3c429cf699c8512c, 0xbf97019bda6c2fdd, 0x3c1dd56b84622d88, 0x3f959d3aa402c32e, 0xbc08de701f1e95e8, 0xbf6b324eab9c87a9, 0xbbec3a4329771a44, 0xbf6b4774d37d0dd6, 0x3f5c01377485a844, 0x3f1a5db5f627539b, 0xbf340d9c429b8932, 0x3f0e720d935ef7db, 0x3effc8295ac052de, 0xbeed1ccde95c6551, 0xbeb251c256ca45cb, 0x3ebe892cc5397b1b, 0xbe88f6831febdf3d, 0xbe9aa5ef30a52421 ],\n", "[ 0x3fef21c9f12f0677, 0xbc57efe429672268, 0x3fb92470a61b6965, 0x3c5c6acd40cee352, 0xbfc3a47801c56a57, 0xbc6033705aa16f01, 0x3fc0453f90d3bd35, 0xbc6686e281ba5405, 0xbfa8a7c6a239217b, 0x3c32a988808a7222, 0xbf8075c088031ee3, 0xbc1665bd0a645f40, 0x3f916f9c9c127b80, 0xbc1e1813af47374c, 0xbf774c2fc9bdfe97, 0x3c15cf2dbe53783b, 0xbf5760c522bd5bec, 0x3f5a3cdb656adb44, 0xbf302c3c1ab0a7ba, 0xbf292892013c7e15, 0x3f16e7b268d42034, 0x3ed970751eb9359f, 0xbeeb00b549bbdf58, 0x3ec033f8545bcc6a, 0x3eb2d8b6f0a2204a, 0xbe9c1c1335b105c5, 0x3e661bbb2d003b8a ],\n", "[ 0x3fef74a6d9a38383, 0x3c8c33a329423946, 0x3fb0bf97e95f2a64, 0xbc5446051f6fef82, 0xbfbc435059d09788, 0xbc4b93aeb5e5cf84, 0x3fba3687c1eaf1ad, 0x3c564513fb767a13, 0xbfa9647a30b16824, 0xbc486357831221be, 0x3f66981061dfbb09, 0xbbfccc83193c8742, 0x3f87e8755da47040, 0xbbec1eaeb3371490, 0xbf79be731fdab95d, 0xbc0ab79fedbfccd2, 0x3f23a95ae0a75542, 0x3f5319f780e962d8, 0xbf3b88dd51a4f261, 0xbf1037f168a8f581, 0x3f153fc5e83e3199, 0xbee9d5bf30917222, 0xbee03045c999d17a, 0x3ecb5d376e96179f, 0x3e8c66d2e5aa2274, 0xbe9aef24a52bcaca, 0x3e7b20b678e8a0c6 ],\n", "[ 0x3fefab0dd89d1309, 0xbc8ae61bd9db1bab, 0x3fa5a08e85af27e0, 0x3c4e4f9cfc8c2382, 0xbfb399812926bc23, 0xbc5b782644df6665, 0x3fb4140efb719cb0, 0x3c308fa5a48311e8, 0xbfa7535a61a4193d, 0x3c359e0501c376b2, 0x3f8374c88c7e6abd, 0x3bfc2578bd7e3f00, 0x3f7a40709e010e77, 0xbbf18c33197d9138, 0xbf76dc078888efa7, 0x3c02b49da4c86c70, 0x3f52ee6d200993b0, 0x3f444f175e22a161, 0xbf3c2fb051c92f92, 0x3f0523035ed3964b, 0x3f0bc7b666856fc1, 0xbef574549f39ee50, 0xbebc57f3c47b39d9, 0x3ec8acc76ac31fcd, 0xbe9f70e8b7deaa9a, 0xbe8e1a28a0c1a6a6, 0x3e6bfa0e5b606c5e ],\n", "[ 0x3fefcdacca0bfb73, 0xbc82c33d88729e43, 0x3f9b1160991ff737, 0xbc2d940a504353bc, 0xbfaa38d59456f77d, 0xbc1d625808eb9778, 0x3fad5bd91b6b0123, 0x3c222b86f5e3e16c, 0xbfa3b35dcbc80146, 0x3c482838d776d958, 0x3f89d76b0a0535c7, 0x3c260fda06bca0a0, 0x3f614c887a83a0e6, 0x3be55ef222558d68, 0xbf7117f42cc6e9f4, 0x3bed4213a7e14a18, 0x3f59b477bdad8e08, 0x3f21d219fb0e1bc8, 0xbf35bb59d3ca4fa9, 0x3f18ca373c577821, 0x3ef4a9b74153a4a3, 0xbef424a8a8831410, 0x3ec6ce0877965abc, 0x3ebc1ed3c11b1dd1, 0xbea86b0a731d831a, 0xbe55cea3996396c5, 0x3e9640950bde5eb3 ],\n", "[ 0x3fefe307f2b503d0, 0xbc68a555000387f8, 0x3f906ae13b0d3255, 0xbc388abd7f4be982, 0xbfa0ee3844e59be7, 0xbc40b0ec94b96d83, 0x3fa48b127f8ed8a5, 0x3c3b6a1f18c2c162, 0xbf9f155b4e7d8c3b, 0x3c3adb2d99b0c1fc, 0x3f8aa2c0753d569a, 0x3c29a37b9864b8e6, 0xbf4bbf7e2795837b, 0xbbe4784a66288abf, 0xbf65478d784d271c, 0x3be27115917a7ec0, 0x3f58eae08cdf9546, 0xbf292946556037e6, 0xbf290f27ae61444c, 0x3f1b076b78538f02, 0xbedb2906f1b92d5d, 0xbeea2f66822d4a01, 0x3ed3031c4f7c4a97, 0x3e941708ced2abd0, 0xbea45ffd6deae2a8, 0x3e7e844ebdc8456a, 0x3e7c0bbf2b711595 ],\n", "[ 0x3fefefcce6813974, 0xbc5b27cf5025d1c8, 0x3f834d7dbc76d7e5, 0x3c23780d6e7eb351, 0xbf951cc18621fc23, 0x3c2969629e4b64a6, 0x3f9b925a99886bb7, 0x3c29c8f65efdd1f4, 0xbf971e7d408c8c6f, 0xbc3c5621deaf4cfc, 0x3f87ea58080a81ef, 0xbc22f25b7f384ff3, 0xbf646eb9d203e071, 0x3beff569e38360a4, 0xbf5403333682fa5e, 0xbbe36256a95953a6, 0x3f53b37d5bd14a40, 0xbf36be130822dbdf, 0xbf103d4bcdafd553, 0x3f155848476c8142, 0xbef5492bf3c6eee6, 0xbed3823d4328e9c5, 0x3ed152fefc353e5a, 0xbea5199dbf7bc4c6, 0xbe94dda2bebe08f2, 0x3e83fb850b47210a, 0x3e6bcd1b284c4798 ],\n", "[ 0x3feff733814af88c, 0x3c70a87238cea4fa, 0x3f75ff2750fe7820, 0xbc15f184847ca667, 0xbf896f0575a63ae5, 0x3c295f4139297a96, 0x3f91c5a643f04363, 0xbc16ea87997fba3c, 0xbf904f5caaf2196f, 0x3c119502347d3b54, 0x3f8382a146afb9d2, 0xbc0f93bde902d2d0, 0xbf695cab93aa68d2, 0x3be0f716a5fc18c4, 0xbf2d2fd90fe62928, 0xbbb4e00d5fcc484a, 0x3f49f50fb94c0b86, 0xbf37d7378074399b, 0x3efcc0c9cb9ede1e, 0x3f092a3a29471895, 0xbef7c127858c909a, 0x3eb5a72fde935a48, 0x3ec57b9d90a92106, 0xbeafdb8443754cf7, 0xbe56c7d633eab55a, 0x3e7ddcfc714a2b67, 0xbe89fedf738e84b4 ],\n", "[ 0x3feffb5bdf67fe6f, 0x3c14e830346f6e80, 0x3f684ba3004a50d0, 0xbbf90b93d4632206, 0xbf7d9c2ea85a927d, 0xbc10bcf1ea93cfdc, 0x3f860898536e104a, 0xbc1ab6aa911c445e, 0xbf85eb1c899f0b70, 0x3c21bc22eed1f1fb, 0x3f7d854f73e74c87, 0x3c07a977a3364c40, 0xbf6897719a9d257e, 0xbbeab523e3f93994, 0x3f388cdc8b807c97, 0x3b94875acc7c06a0, 0x3f3b325a11c1f45a, 0xbf3381548f692740, 0x3f12b1fd05559bfa, 0x3ef1ed31cd6feb26, 0xbef29cf593fdf00a, 0x3ed1cea99b59228c, 0x3eaceff221e3598a, 0xbeab0ad4b899b2d9, 0x3e83761b047e21d1, 0x3e696c31c2256049, 0xbe60a714c57f7adf ],\n", "[ 0x3feffd9f78c7524a, 0x3c804ed6ff98e45d, 0x3f5a024365f771bd, 0x3bf3c8f5202cb405, 0xbf70a9732d5284dd, 0xbc11acbd0899ce7e, 0x3f7a4bf47a43042a, 0x3c0e6cb2580d0920, 0xbf7c23802d8a5bb7, 0xbbd9963700abfc80, 0x3f74f40070668329, 0xbc1e1fe1c0e1182a, 0xbf64c9a2c9dccd04, 0x3c080fb9c9cd78c1, 0x3f44f7a50b5bc019, 0xbbd40906b7a1de3a, 0x3f218b04eb90c737, 0xbf2a4c3880c0ea69, 0x3f14b7b82a86f423, 0xbed0bc762b1c2aaa, 0xbee589d6f8892acf, 0x3ed357ab63f7bdf9, 0xbe96675858bbff5e, 0xbe9ea96dcb12a15c, 0x3e88c572fcf5610e, 0xbe3700c93da86dee, 0x3e57ae9ceb75e26e ],\n", "[ 0x3feffed167b12ac2, 0xbc8ddc0ce3ed8fcb, 0x3f4afc85e0f82e12, 0x3bd438f22895e03e, 0xbf6221a9f326bef4, 0xbbf99642b37af330, 0x3f6e3c9aab90bcf4, 0x3bb7dcdfdccc72a0, 0xbf714b1b98141f21, 0x3c1af6edf50eba66, 0x3f6c1c19b9e63d70, 0x3bd4d1e9411f1d28, 0xbf5feac3dbeb5124, 0x3be2400e6ffbc1c8, 0x3f463e88178b0e49, 0x3be3e4ae97774f91, 0xbf04441c86c93f39, 0xbf1c8ceebc5fc50b, 0x3f1125b77a79aa6c, 0xbeeda7be990bc718, 0xbece019960474aff, 0x3ecd229185ef6279, 0xbeacea9fa10885e7, 0xbe8044fd6a2e447a, 0x3e83695f88fc641d, 0xbe60c0dc0ba0d589, 0xbe89194748828b93 ],\n", "[ 0x3fefff6dee89352e, 0x3c8b96c0ba13851d, 0x3f3b23a5a23e4210, 0x3bc727bce1be0014, 0xbf5315107613c673, 0xbbf823f8673f5b7a, 0x3f60c243329a9ca1, 0xbbf65e361cefe652, 0xbf64630116262084, 0xbc00ea6ee40daf79, 0x3f61e84d1022e8cb, 0xbbd9b77b85eed4f0, 0xbf56b41872716325, 0x3bd3e9e001100f64, 0x3f436edde582b265, 0xbbe1cb479a94e148, 0xbf1f7870ebc38e77, 0xbf051ecfdc37801d, 0x3f0711d817e0d3b6, 0xbef0ae90d500d1d8, 0x3eaa85b1bf54920c, 0x3ebfe73958205038, 0xbead222bfef33aa4, 0x3e7833f8b13b1a4e, 0x3e7233b5a19285db, 0xbe61adcf574b7db6, 0x3e7ab10bedc44532 ],\n", "[ 0x3fefffbb8f1049c6, 0x3c7d2c6266b51f26, 0x3f2a740684026555, 0xbba7e24cc3ac5710, 0xbf436d34c8f1c26a, 0xbbe69d73e7d1c977, 0x3f51eb6e14974a25, 0xbbf99b78600e0664, 0xbf5714eb8cc0947f, 0x3bf3613f37c7410b, 0x3f55bec08c01b1d7, 0xbbf3e3a262f6c68a, 0xbf4e4621d82dad12, 0x3bc302878843e2cc, 0x3f3e1b7b564b0e79, 0x3bcf894fc1f14d54, 0xbf224564b69716aa, 0x3ebbf8e3b47f3ccd, 0x3ef8f55a9be1a264, 0xbeeb3b76e6203281, 0x3ec713c795a07e0c, 0x3ea3bb092cfd93e0, 0xbea473b0a8333dee, 0x3e8645526869c143, 0x3e41a343e004b33d, 0xbe576c7e253faad1, 0x3e7e16080963cffe ],\n", "[ 0x3fefffe0e0140857, 0xbc66aa36f86c14dc, 0x3f18fdc1b2dcf7b9, 0x3b87050f50b8f308, 0xbf3322484cf12daa, 0x3bd4cc0408806d4f, 0x3f427dc1bc6cfef5, 0x3beffbb5229f6bb7, 0xbf49202f465eb421, 0x3ba8f3f063b40660, 0x3f493b4c9746835f, 0xbbe04e2d6df2fce5, 0xbf430e9e6142fe9b, 0xbbd0396045094744, 0x3f3555b9d5fb4825, 0x3bd9a40d2ca5ef0b, 0xbf2055983c4ac7a6, 0x3ef68e6c75a5d068, 0x3ee2d4a50d2757ce, 0xbee1de08b56479aa, 0x3ec9110ccc7fe6fd, 0xbe8bb3184d789af8, 0xbe94629a164e82a0, 0x3e8413b087ee5e4d, 0xbe5648d7786f9fbc, 0xbe4293289f8c327d, 0xbe6c283008e726f7 ],\n", "[ 0x3feffff2436a21dc, 0xbc83607959a29d36, 0x3f06e2367dc27f95, 0x3b6d96e6f0151020, 0xbf223c436c36fdab, 0x3bbf0d77fc600a50, 0x3f326bf00867a835, 0xbbdc92e1aecdc750, 0xbf3a51fb50b15f22, 0x3ba248227c6d2260, 0x3f3c0825378fda08, 0x3bd5a8a09c053451, 0xbf36c3dbfe0cbe4a, 0xbbde65769c33f8a1, 0x3f2c1dd1438378df, 0x3ba91bd161f34158, 0xbf194c36a9d7c0dc, 0x3efbf0aab116ca41, 0x3e86bdbd2f103930, 0xbed2b32e8d43ef25, 0x3ec3a7403459770b, 0xbea17411873320fa, 0xbe735bb2691c9b29, 0x3e798313537ed069, 0xbe5cb4b60e85a341, 0x3e02be214cf4c9eb, 0xbe8350a1a851865a ],\n", "[ 0x3feffffa1de8c582, 0x3c8832540129302a, 0x3ef44f21e49054f2, 0x3b8f338cf4086346, 0xbf10d18811478659, 0x3bb914a7a08b6a2b, 0x3f21b964d438f622, 0x3bca52c94c56aaaf, 0xbf2a8d7851f26bf0, 0x3bcc38dbf3ee1223, 0x3f2ddd6df9b6852d, 0xbbc3b0dd7eac9b91, 0xbf29e52b7aac1644, 0x3bc904036dfb5764, 0x3f2165b2034fcab2, 0x3bc27beac4bf3866, 0xbf11b75c3332673a, 0x3ef91a253c42f4e7, 0xbed020b498095051, 0xbebade63f30809ae, 0x3eb89bb0d75e59b7, 0xbea180c78d3dca28, 0x3e6cabfd39b38553, 0x3e66013ffba86cfd, 0xbe564f2b123e1f0b, 0x3e335bf3e5021105, 0xbe8177828ffd35af ],\n", "[ 0x3feffffd8e1a2f22, 0xbc8c10adf6b19989, 0x3ee1783ceac28910, 0xbb87f19d8ee58337, 0xbefe06a8b37e5b93, 0x3b824e8db1358f2e, 0x3f107978c7b8496b, 0x3bbf163b5580927c, 0xbf19d039884f8be5, 0x3bbfce53cd30b1eb, 0x3f1e8d1145e94a54, 0xbbbd0f6e009a99ee, 0xbf1c1f7251172a87, 0xbb83ce0f013dfe90, 0x3f1458b9e0854d68, 0xbbb897cf3950b1a7, 0xbf06eb0557245429, 0x3ef33045cf65279e, 0xbed42c8adf18ab62, 0x3e491109b80f9918, 0x3ea83a9b44249fbf, 0xbe99bcbaf0a8dfd1, 0x3e7900325b58a857, 0x3e34a3cf9c161684, 0xbe50cbcc4d0a916a, 0x3e34275e1b91f084, 0x3e839180c75350e1 ],\n", "[ 0x3fefffff039f9e8f, 0xbc89d1bcd6174e99, 0x3ecd21397ead99cb, 0xbb46abd9c029c47c, 0xbee9f19734d29cf9, 0x3b820c4383da36c1, 0x3efd982bd41d8954, 0x3b8d9bc9988e9666, 0xbf08320fc4836be5, 0x3b7526638b9926a8, 0x3f0e0a1cb1d071f3, 0x3b9d9f5d232bab90, 0xbf0d384223047b9c, 0xbba30d0b2b8a170d, 0x3f0696daf6422bd4, 0x3baba6ac732f399e, 0xbefbb6e2d311a93f, 0x3eea4fcb0ea87efb, 0xbed1c940c5303daf, 0x3ea7469913f4e9c6, 0x3e8ef4b4f8ab67ae, 0xbe8e189c28e8e041, 0x3e7678b281d5bc55, 0xbe49c3bf4e9f2b5d, 0xbe374c9ba997ffed, 0x3e2b4b843f8c7068, 0x3e6c901764507862 ],\n", "[ 0x3fefffff9d446ccc, 0xbc6bb06bab98bc80, 0x3eb789fb715aae95, 0xbaf226d93bf89b40, 0xbed5b333cc7f98f1, 0xbb76bd1091d25440, 0x3ee9b12fdbf90f62, 0x3b8d4b6b0ee9cf46, 0xbef5e06923144d70, 0x3b4c593194857860, 0x3efc6a071925631d, 0xbb8835ef595952e4, 0xbefd178cb0388a82, 0xbb9039272760f01c, 0x3ef7e29d33ac92b6, 0x3b921ff8b0e9d5eb, 0xbeef9203429baad6, 0x3ee094dadeee395c, 0xbeca771cf3500d9f, 0x3eab8fd1c29c21ea, 0xbe5cc8573d7de110, 0xbe7b0362da1722cb, 0x3e6e5eae518f94e9, 0xbe507963addd99a6, 0xbe23f496093d0bef, 0x3e199078a326092d, 0x3e842681ecfe4da1 ],\n", "[ 0x3fefffffda86faa9, 0xbc7d230252d68f26, 0x3ea26f9df8519bd7, 0xbb4e339871c015b7, 0xbec1926290adc888, 0xbb6e36d23dbb2644, 0x3ed5900c02d97304, 0x3b7fa7d21e3ed616, 0xbee3166de6a8c640, 0x3b8b014157867958, 0x3ee9dfcc328729e0, 0x3b820e9fee0b7665, 0xbeebcab1ed5ec38d, 0x3b6d9003794f0fe0, 0x3ee81cd74a57ce17, 0xbb8809fde9c0f6f5, 0xbee106e95b6bf556, 0x3ed379625a71385f, 0xbec1970a5b5bd443, 0x3ea74761c8333ff2, 0xbe80864e125c9951, 0xbe5b83bf9019aa3b, 0x3e60397611c35b28, 0xbe4a25392adb29ac, 0xbe17b832af40d9d4, 0x3df62a02eb79577b, 0x3e8a6da58ffe94f4 ],\n", "[ 0x3feffffff233ee1d, 0x3c8db123ed17221d, 0x3e8bfd7555a3bd68, 0x3b20151cf177b53a, 0xbeab8d7f804d2e73, 0x3b482b366f0bc2dc, 0x3ec17f93e5149289, 0x3b391997bfd26568, 0xbed013b0457d08fa, 0xbb60d6d5a7f06298, 0x3ed6b245d7e1d829, 0xbb79985e02c8ce3b, 0xbed98077548c6951, 0x3b701cd3f1d12c93, 0x3ed7492048ab3ceb, 0xbb70368a0dc0750e, 0xbed17506c7b39cb0, 0x3ec57e94a4c5f5a6, 0xbeb570971200d7db, 0x3ea0a0f956947b21, 0xbe81a9b7bd5bba32, 0x3e451bfc00de3146, 0x3e495b6967f79cbe, 0xbe3fe3c43cb3cf84, 0x3e32f364a7a2dc5f, 0xbdf007442a10cc14, 0xbe7ef5ab6fc5e849 ],\n", "[ 0x3feffffffb127525, 0x3c8504f382db4102, 0x3e74980cb3c80949, 0x3b17fbdd923f8057, 0xbe94ea6ce697296f, 0x3b3ea42f9c9de533, 0x3eab771d9b6f07b8, 0xbb1e9c1ca9662fe8, 0xbeba26c653fad5b8, 0xbb5146c4cee0e898, 0x3ec3302bb89379de, 0x3b64c55b83ef7a68, 0xbec67f42e5264334, 0xbb66779da26b4197, 0x3ec58b4adafb958e, 0x3b68351251b45e84, 0xbec10f576796285a, 0x3eb66ca44250dd07, 0xbea84ee0ada37543, 0x3e953b6065291e6b, 0xbe7c09ebfd0c581c, 0x3e563062625d59c0, 0x3e1e259c60eb7b83, 0xbe2e43802ad25514, 0x3e351bcdabe8cda5, 0xbdf930fc3df6e909, 0xbe881cdd770e1c81 ],\n", "[ 0x3feffffffe4aed5e, 0x3c4389c0f32ad0f0, 0x3e5d5f3a8dea7357, 0x3affa07c18622dd2, 0xbe7ebfb14c9170c0, 0x3b19e40632b4145d, 0x3e94d9228525f449, 0x3b2d35bd7f959136, 0xbea48b536addac5f, 0xbb461ace22b32569, 0x3eaf48ccf23a68e2, 0xbb4ee1d13c79c281, 0xbeb3183b6134cf03, 0x3b4e1f4d5fe2a06c, 0x3eb31efde2215f01, 0xbb564a7021e23fba, 0xbeafd9eeb0f18fdb, 0x3ea63414459ae298, 0xbe99dda81be20b5a, 0x3e88da7d306423c5, 0xbe7303da86a4fc28, 0x3e54f5e1327706b9, 0xbe23efb5eefcbe53, 0xbe131bc5ce1ce65d, 0xbe13eafe1b05c93f, 0xbdf47fc2d9cc851e, 0x3e7d27265006a9df ],\n", "[ 0x3fefffffff6d1e56, 0xbc864d969b4be4c4, 0x3e444d26de513197, 0x3ae76fc20fc4b365, 0xbe65e32de7af8977, 0xbaf888fd6ae18a1c, 0x3e7e9e05b3c8f38a, 0x3b17532141b12aa7, 0xbe8f2f6fa7db5b1d, 0x3b2b3bf498e3462c, 0x3e9899dcace485eb, 0x3b11885a0ae9e878, 0xbe9f34b7eef3c9b2, 0x3b3294a3b618b470, 0x3ea04be030272d14, 0xbb4df83095e40f79, 0xbe9c73bd22571559, 0x3e94edda838439f5, 0xbe89fc860b504677, 0x3e7b0d686a260420, 0xbe672370c2fdbe10, 0x3e4ee29f0d197d25, 0xbe2b4d88d500c5be, 0x3dc96014c45b0178, 0x3e0238f19dc8fd82, 0xbde8d34d46ae6567, 0xbe454105fe4a9cd8 ],\n", "[ 0x3fefffffffd01f89, 0xbc735e8e39884f62, 0x3e2b334fac4b9f99, 0x3ac32178ed1a4971, 0xbe4e2cec6323e50e, 0xbac0e5693f9d4908, 0x3e65c027d5bba36a, 0xbaefc46fb3cc7ae0, 0xbe76df4d024fffbe, 0xbb090fd7226ec57a, 0x3e82aaf7c205b9ea, 0x3b2dbec2005b45a8, 0xbe88902edfbfefdd, 0xbb2c353aca58d08a, 0x3e8ab2ab1b338249, 0x3b2b498186c39105, 0xbe885abe0ff198d3, 0x3e82d32f7c3621eb, 0xbe78c141c71dbc95, 0x3e6b9fa6fbb9b198, 0xbe59db5fe2c2f5b9, 0x3e43b8e07840483e, 0xbe26d95e5070d91d, 0x3dfd7616168b0e49, 0x3e1f2be0744b3a5f, 0xbdd737a375809985, 0xbe7936d4936fb865 ],\n", "[ 0x3feffffffff0dd2b, 0x3c80df73e7d2fc98, 0x3e11a94ff571654f, 0x3abfbf537b47967d, 0xbe34251f33f5578f, 0x3ad4c9cece8f41b2, 0x3e4de6bc1f75bb9b, 0x3a894afb459a3000, 0xbe6036b5fd1c4158, 0xbb0d582afa097896, 0x3e6b58f1385def96, 0xbaf8778854601996, 0xbe72a2347efb2133, 0xbb026f9e1ef0f378, 0x3e7508db866ffe00, 0x3b164de561a68a21, 0xbe73ffea934685b9, 0x3e702ff87b2e2576, 0xbe666e54eae5fa4b, 0x3e5a9ea2195c567d, 0xbe4ae3b91fecafa1, 0x3e36bb883d2e5ed1, 0xbe1ee10e97715c11, 0x3dfe2873d2b77f1f, 0xbdeaf385ae29d57b, 0xbdbd793eecfc2513, 0x3e420d80dcfa68d1 ],\n", "[ 0x3feffffffffb5be5, 0xbc7729d6819c7f34, 0x3df63ac6b4edc88e, 0xba7c45991835da24, 0xbe1a0ce0dc06a706, 0xbab1b72d11da9dab, 0x3e33e380dd7593a5, 0xbad8ad868a7b5674, 0xbe4638bc4fb02cba, 0x3a87a84506fcda40, 0x3e535753ad4c5875, 0x3aead190ab170366, 0xbe5b41f33cafccba, 0x3af0e3539bf61116, 0x3e5fe694e371a659, 0xbad3a84e01866ea8, 0xbe5f8af0121aa0ab, 0x3e5aa77274dab3d8, 0xbe53616fe8f6a259, 0x3e484fddf4c681a1, 0xbe3a3de05d1b8a31, 0x3e2822529aca9f83, 0xbe126c3dfba84378, 0x3df64c287a84aa09, 0xbe0107d2dac5d83b, 0xbd4e251d1ab1d873, 0x3e58f37005f17b42 ],\n", "[ 0x3feffffffffe9eb0, 0xbc5ea527e0bef1e8, 0x3ddb1e5acf351d87, 0x3a5dc96583ba19f0, 0xbe005042a0a5f3c3, 0xbaa2023f0f13867c, 0x3e199ac8fd63c66c, 0xbaabf57c5fd0501a, 0xbe2d72344378e114, 0x3acc77758959af41, 0x3e3a6be9a123435b, 0x3acdab4af8807c36, 0xbe433aacb4bf6dea, 0x3aebd241ea49ac35, 0x3e474b732e7ceaa7, 0x3adc7c89730b0264, 0xbe47e7eab6531ccb, 0x3e450959f2daae39, 0xbe3ffed4cef94261, 0x3e351c7f99f908a2, 0xbe282b5fd5fbedfc, 0x3e17e1c8e715c978, 0xbe051536822c861b, 0x3debe7e4c220ca82, 0x3e2f5bb67c461296, 0x3da1d7cf04529bf0, 0xbe8acc021ab828c4 ],\n", "[ 0x3fefffffffff9a1b, 0xbc66a87270d2450c, 0x3dc0084ff125639d, 0xba58ad61debedc86, 0xbde3ca42adaa26f6, 0x3a8c20c6583dccdd, 0x3dffe73513c67bf8, 0x3a920d28c0c7e686, 0xbe12dd9aa5a2bee3, 0x3aad76d7235461be, 0x3e216ef6b93944a8, 0xbacf07bd785566de, 0xbe2a2d58e9b22b26, 0xbab19e6ea91dd55e, 0x3e306389b9748f25, 0x3adfbcc52565c0be, 0xbe316cdd9eb58ba2, 0x3e2fdd861b55c500, 0xbe29457846c943d2, 0x3e2178f3905f435c, 0xbe1518cf20c53de2, 0x3e06329939a34b66, 0xbdf5ef3ad85e5d3b, 0x3ddf2b41494e49e9, 0x3e2bad43bc0b622d, 0x3da21a45fa9dcebf, 0xbe8790b3d88f69fe ],\n", "[ 0x3fefffffffffe380, 0x3c87ce07114e4fe0, 0x3da25f9ee0b923dc, 0xba4174c43a73a4d1, 0xbdc74105146a5162, 0xba47d0740e56625c, 0x3de33cde4f35d941, 0xba72a344950797c6, 0xbdf760fe7b666392, 0x3a9a8b77c82ed644, 0x3e063a70fd66d485, 0x3aa6b87715649d6d, 0xbe11324f6fb6dfa1, 0x3ab3fc045e39915f, 0x3e163a31a36b815c, 0xba502dec9bc1a700, 0xbe18724ca8970b91, 0x3e172e290891e5de, 0xbe131fc03858aab1, 0x3e0b9e8b0e7fa253, 0xbe01821a002637bd, 0x3df37ba5f3fba5eb, 0xbde3578bf23dc654, 0x3dcfdaf2015d7b54, 0x3df7f6a435069067, 0x3d99d14ee557ec62, 0xbe555f4c743ee571 ],\n", "[ 0x3feffffffffff845, 0x3c7b0edc5a89ab8e, 0x3d846897d4b69fc6, 0x3a2a74852415bb49, 0xbdaa77a4e7dcd735, 0xba434edb43ab7de6, 0x3dc67543695dcc12, 0xba329ae577004af8, 0xbddc05c1e2fc710e, 0x3a5dbbf42d2537a8, 0x3deb639419fedf8e, 0xba8ed72eb9e7a59e, 0xbdf5cfd7eb9bfe87, 0xba7e97db27125fc0, 0x3dfd11578959ba45, 0xba8c0635ac2b5768, 0xbe0082f9e9f7eb37, 0x3e00354ceadad8b3, 0xbdfbc2dee0154fc6, 0x3df4e11efdc66eae, 0xbdebb357c0253f64, 0x3de035f9889bc29c, 0xbdc8e7bdb10b7441, 0x3dbe364571102661, 0xbe212cffcf49a2e8, 0x3d8ee9362bcfec26, 0x3e7cc5b58dd85301 ],\n", "[ 0x3feffffffffffdf8, 0xbc8dcf8b10ff973b, 0x3d65f8b87a31bd85, 0x39d65b265455b658, 0xbd8d2e55024a0fb5, 0x3a2444e1d84cea02, 0x3da9612cc225df4b, 0xba4c784edb664ce7, 0xbdc03ee5f38b9b4d, 0xba691ca8efa41a30, 0x3dd04f2f71e2e96b, 0xba633f36a4e51350, 0xbddab7099f99ced9, 0xba54af7a67f2110c, 0x3de2554b8f609fd1, 0xba729e641eb44218, 0xbde57c87529ca968, 0x3de5cd182c967671, 0xbde3580a2517d57a, 0x3dde3be72b1be982, 0xbdd4e9908689ad08, 0x3dc9a61979d3395b, 0xbdb7b826aadd1c89, 0x3daad3a9fc4a0d1e, 0xbe00e9325ed20970, 0x3d80722198ff452c, 0x3e5c2ef85611aa11 ],\n", "[ 0x3fefffffffffff7b, 0x3c800fa07f7fb612, 0x3d46ed2f2515e933, 0x39d2bc1802a42b92, 0xbd6f2a6c1669c901, 0xba07b3e174cc1840, 0x3d8bc42ba38a13f8, 0x3a2460463d59d3df, 0xbda2391e135afae4, 0xba3bd08c8c5f7b18, 0x3db2c6c24550f64f, 0xba3fdc861a487110, 0xbdbf9a3c1b0d63ec, 0xba5843dc8d9ad3d5, 0x3dc6502546ab341a, 0x3a645f812e48eb98, 0xbdcaf223186006d1, 0x3dcc388dd1764f41, 0xbdc9e65a242b52aa, 0x3dc4fcd2787781eb, 0xbdbe3cbdb20a48d6, 0x3db35639e9fcd410, 0xbd55b8e97774b2c9, 0x3d966ffe6a100bc9, 0xbe15706c390c113e, 0x3d6ff0d11cf61949, 0x3e72054de347e3f8 ],\n", "[ 0x3fefffffffffffdf, 0x3c75669e670f914c, 0x3d272fd93e036cdc, 0x39b1c553d12fbbd0, 0xbd501f450d1e61b2, 0x39cbed807e60c078, 0x3d6d68fb81b2ed89, 0x39dc7ea3c4444cc0, 0xbd83c706aa4d2328, 0x3a2d6d2d51dd414d, 0x3d94e6479565838e, 0x3a350580f36c14c1, 0xbda20e9eb83b3dd9, 0xba104b6334a32fd0, 0x3daa35b9d2fcac80, 0x3a1c07c6978bf2f0, 0xbdb04a134f6e3dcb, 0x3db196579f27ddbe, 0xbdb0ab97aa74c700, 0x3dabf68355f542b1, 0xbda49da25a547134, 0x3d9bd64993a3958e, 0xbdc1193990186399, 0x3d81c0e98335ae18, 0x3e2e08edb685494a, 0x3d5cb9fcc058465b, 0xbe894cacccfb8964 ],\n", "[ 0x3feffffffffffff8, 0x3c70160ef15c497e, 0x3d06ba91ac734786, 0xb9af81d6fa69b5b2, 0xbd3028a39099f4db, 0xb9c83ed68de15404, 0x3d4e292863e1795e, 0xb9db292e812abb68, 0xbd64c4e690fbdd14, 0xba080991e1d4ef25, 0x3d767e6e5ac60fd1, 0x3a01d2ca68dcf0e8, 0xbd83f00d80afa00c, 0xba23e174dc7225ac, 0x3d8db88ee63eb28a, 0x3a28abd97527892f, 0xbd92fe58a1f19368, 0x3d951dbeae22a5c8, 0xbd94a4d54823e0fc, 0x3d91e432d674cfba, 0xbd8b001e26c6e764, 0x3d8328ce695259fe, 0xbdb4e492cf7d4f4c, 0x3d6aaa77d339dc00, 0x3e2366538db382e5, 0x3d4826ad7d581503, 0xbe8056e0810b14da ],\n", "[ 0x3feffffffffffffe, 0x3c759ab24e589a30, 0x3ce5982008db1304, 0xb981cf9bda64b38a, 0xbd0f610e8cde57ac, 0xb99884dcd86f98c8, 0x3d2df2dac2f2d47f, 0xb997f27bf279d988, 0xbd451b17f95fc0b4, 0xb9e063e04485c3e7, 0x3d576996ddc975d7, 0xb9e21489d6648428, 0xbd6546155a972b18, 0xb9b9d3fb518aa7c0, 0x3d70456ed89c4f24, 0x3a1eee772fc32c5e, 0xbd755d6295aa388a, 0x3d786ead99977388, 0xbd789b3d387efa6e, 0x3d76011e175e64f8, 0xbd70cd70515af47b, 0x3d69402199dfdde7, 0xbda806743bc32b08, 0x3d530e561550364a, 0x3e170093985e2c1b, 0x3d331999a27ace63, 0xbe735f54db0f4dbc ],\n", "[ 0x3ff0000000000000, 0xbc8a6d7d18831888, 0x3cc3e296303b2297, 0x39668cf648cfed1c, 0xbced8456ef97c744, 0x398fcded17005500, 0x3d0ccb92e6c24c8d, 0xb9aa704dc202cff2, 0xbd24c1aa8cf1229b, 0x39c652efa61e4ec2, 0x3d37918b6b83c0fb, 0x39b2fb01fb8836dc, 0xbd45f073659de44d, 0xb9e9ceb48a2d1931, 0x3d5134d070b5921e, 0x39d9af3038fcc184, 0xbd5730a2938c09dd, 0x3d5b4091041f5905, 0xbd5c3c44ab8c8421, 0x3d5a06b4f4c3044d, 0xbd5704f511555fe7, 0x3d4fe51fcfc1acba, 0x3d95e7229a07e7cd, 0x3d39f8121f6c3146, 0xbe0692b2f9b3f445, 0x3d1c8c34f73d3823, 0x3e6301e540260d52 ],\n" ] } ], "source": [ "import struct\n", "# ERF double C2\n", "\n", "data = \"\"\"\n", " {0x1.ac45e37fe2526p-3, 0x1.48d48536c61e3p-57, 0x1.16e2d7093cd8cp+0, 0x1.979a52f906b4dp-54, -0x1.a254428ddb453p-3, 0x1.9c98838a77aeap-57, -0x1.59b3da8e1e176p-2, -0x1.1f650c25d97bp-59, 0x1.988648fe88219p-4, -0x1.5aecf0c7bb6c1p-58, 0x1.803427310d199p-4, -0x1.a14576e703eb2p-58, -0x1.09e7bce5592c9p-5, 0x1.eb7c7f3e76998p-60, -0x1.516b205318414p-6, -0x1.941aa998b1fa4p-61, 0x1.038d3f3a16b57p-7, 0x1.e19d52695ad59p-9, -0x1.9542e7ed01428p-10, -0x1.1f9b6e46418dcp-11, 0x1.0796a08a400f4p-12, 0x1.2610d97c70323p-14, -0x1.25d31d73f96d1p-15, -0x1.05e1fa9e02f11p-17, 0x1.1e616f979139cp-18, 0x1.9b3d54f1f222ap-21, -0x1.7ad96beea439ap-22}, /* i=1 108.83 */\n", " {0x1.5da9f415ff23fp-2, -0x1.a72e51e19195p-59, 0x1.05fd3ecbec298p+0, -0x1.f17d49717adf8p-54, -0x1.477c8e7ee733dp-2, -0x1.92236432236b7p-56, -0x1.1917b60acab73p-2, 0x1.c06e6c21b4b3bp-56, 0x1.322a728d4ed12p-3, 0x1.ffa8aef32141p-60, 0x1.04c50a9cd2c12p-4, -0x1.edd0562dce396p-59, -0x1.7ce764eeddd86p-5, 0x1.9afeb391c029cp-61, -0x1.68aac5801171dp-7, 0x1.4f9655411fc03p-61, 0x1.62aa895f51cd3p-7, 0x1.6c003c3cedb1p-10, -0x1.079502dbbafffp-9, -0x1.d9c7cbb799b47p-14, 0x1.45a995aede3f4p-12, 0x1.0c04ea8c98fc9p-20, -0x1.57edfa53128dp-15, 0x1.a96286bf3ef56p-20, 0x1.3c8ab12e6d24bp-18, -0x1.7454eba0cb203p-22, -0x1.f02a6f6847617p-23}, /* i=2 107.115 */\n", " {0x1.db081ce6e2a48p-2, -0x1.7ff0a3296d9cbp-56, 0x1.dd167c4cf9d2ap-1, 0x1.44f2832f90a97p-55, -0x1.a173acc35a985p-2, -0x1.c5432c9a2274p-60, -0x1.889a80f4ad955p-3, -0x1.f6123bf467942p-57, 0x1.6c2eea0d17b39p-3, -0x1.1f4935c3cf5b1p-57, 0x1.b0645438e5d17p-6, 0x1.7a5f08ebaf9dp-60, -0x1.a3fd9fcbb6d6dp-5, 0x1.94a1b58b5916fp-59, 0x1.060b78c935b8ep-13, 0x1.9cec375875a1cp-68, 0x1.678b51a9c4b0ap-7, -0x1.1e03bfc8eebb4p-10, -0x1.e653535cab33fp-10, 0x1.55f31366d2c5cp-12, 0x1.0dcf1445cbb88p-12, -0x1.098913ad4dcc7p-14, -0x1.f6e252329eeedp-16, 0x1.41ad0a5afe51dp-17, 0x1.8fd4609222f1cp-19, -0x1.4465926de1a35p-20, -0x1.407a1f42b46d4p-21}, /* i=3 107.489 */\n", " {0x1.25b8a88b6dd7fp-1, 0x1.9534a3b5bd215p-55, 0x1.a5074e215762p-1, 0x1.fad8c0ef6fae6p-56, -0x1.d9a837e5824e4p-2, -0x1.1d19ec86adc7cp-56, -0x1.9c41d1d5fae55p-4, 0x1.74c230d6afba4p-60, 0x1.75bebc1b18d1cp-3, 0x1.01ece95d4dffcp-58, -0x1.6410ad9332666p-7, -0x1.16523d167a40cp-61, -0x1.7df8890b11fa7p-5, 0x1.d6a99d1387564p-59, 0x1.4a54816d3608ap-7, -0x1.f810ad06699ccp-61, 0x1.18f36eb18f3d7p-7, -0x1.8d661c030e174p-9, -0x1.3628ede23e249p-10, 0x1.438eb2b3c4d27p-11, 0x1.fd3c13e725e91p-14, -0x1.991b866a32c87p-14, -0x1.1237c600dab6fp-17, 0x1.a9c701140d4cp-17, 0x1.1801e61adfddap-24, -0x1.785516863e6cep-20, -0x1.3e033ef590125p-23}, /* i=4 107.484 */\n", " {0x1.569243d2b3a9bp-1, 0x1.8eef7012e8df4p-56, 0x1.681ff24b4ab04p-1, -0x1.dba6493354c7p-58, -0x1.ef2bed2786b25p-2, -0x1.ae3f6b6b2b679p-56, -0x1.a4254557d722fp-7, -0x1.0ff7bffd10053p-61, 0x1.532415c267962p-3, 0x1.2eacc4bd2e841p-57, -0x1.558b4c55a835cp-5, 0x1.c21c40815d70ap-60, -0x1.1b7ad5b777f1bp-5, -0x1.2115b2bd8d644p-59, 0x1.1201d3bd0e758p-6, -0x1.b39b84544256p-63, 0x1.2995e3a88a89p-8, -0x1.0294c3e93cdbp-8, -0x1.159644a564f83p-12, 0x1.63daf9b3858efp-11, -0x1.3beeb4a1255acp-15, -0x1.80c5178c36c72p-14, 0x1.d4f6f5bab7dfap-17, 0x1.521deb6d2f46ep-17, -0x1.4ef3208231a8bp-19, -0x1.e7d2b4e06e4a2p-21, 0x1.21536d5b8bdf9p-22}, /* i=5 107.637 */\n", " {0x1.7fb9bfaed8078p-1, 0x1.66cf14bcad032p-56, 0x1.2a8dcede3673bp-1, -0x1.7378e2c70325ep-56, -0x1.e5267029187cp-2, 0x1.add23841b110ap-56, 0x1.fe0796bb9d05ap-5, -0x1.7a992e13ce574p-60, 0x1.0fa23021ad0acp-3, -0x1.17f4228359928p-59, -0x1.fa21ebca76761p-5, 0x1.278ca2820f66cp-60, -0x1.31546d5c4edb4p-6, 0x1.36fcf151892ap-62, 0x1.37e5469efb7a6p-6, -0x1.9553630321d4fp-60, 0x1.097966e2e87eap-13, -0x1.e82ab020887a7p-9, 0x1.318270c11ae74p-11, 0x1.12652e433da97p-11, -0x1.4dc9bd6368bb8p-13, -0x1.c441138d4ff53p-15, 0x1.c91d8dc5b66ecp-16, 0x1.f3ba57b86d474p-19, -0x1.dd3403d11a818p-19, -0x1.31f497a106a7cp-24, 0x1.436dbcc93d342p-22}, /* i=6 108.888 */\n", " {0x1.a1551a16aaeafp-1, 0x1.a558a46df5f68p-57, 0x1.dfca26f5bbf88p-2, -0x1.ddcbaf85587b6p-57, -0x1.c1cd84866038fp-2, -0x1.200885b97f453p-56, 0x1.e4c9975da0987p-4, -0x1.f162e7576c79cp-58, 0x1.747e31bf47af3p-4, -0x1.6178f12d62ed9p-58, -0x1.1d1f00109e42ap-4, 0x1.002b06e023544p-58, -0x1.47654175ceb42p-9, 0x1.683389ccacfa8p-66, 0x1.1a817c594b8cbp-6, 0x1.36ac477166efbp-60, -0x1.cb8acd699cca6p-9, -0x1.57b72bf874db6p-9, 0x1.24493dca8b6fap-10, 0x1.f556774c6aaf6p-13, -0x1.b09ec5c8ba626p-13, -0x1.09bd1a09f38e8p-18, 0x1.d149c3e776976p-16, -0x1.8f7c2a6575e92p-19, -0x1.8391d4afaf16ap-19, 0x1.5a7552081d1d5p-21, 0x1.32d1bb2d1d0cap-22}, /* i=7 109.125 */\n", " {0x1.bbef0fbde6221p-1, -0x1.322c1148e0d48p-55, 0x1.75a91a7f4d2edp-2, 0x1.6eb826a9df85cp-58, -0x1.8d03ac274201cp-2, 0x1.7a5c56eb7f6ap-58, 0x1.3954778d6a0dfp-3, -0x1.863eca74d1838p-58, 0x1.88e0f7b183fc6p-5, 0x1.226527d05ce39p-59, -0x1.0f7c15f75ee13p-4, -0x1.56f74f351366p-62, 0x1.5e22cfa1aab51p-7, 0x1.4b49a250c6474p-61, 0x1.9ad28c5557c22p-7, 0x1.99920b730ecd5p-61, -0x1.704ec5d29fc83p-8, -0x1.23360304f19bap-10, 0x1.43ca3fcdf079dp-10, -0x1.dcb97a9e04bd4p-15, -0x1.735e26c43d267p-13, 0x1.360c3b06ffbb4p-15, 0x1.29a6b5798e781p-16, -0x1.dbc35e4cf98f5p-18, -0x1.2f6e8e81287bbp-20, 0x1.eeb2fdddad355p-21, 0x1.1ae65e387ac52p-23}, /* i=8 108.742 */\n", " {0x1.d0580b2cfd249p-1, 0x1.4fca6318dfee9p-55, 0x1.1a0dc51a9934dp-2, -0x1.ca89d2d78fba4p-57, -0x1.4ef05a0f95eebp-2, -0x1.5f7c55a00231cp-57, 0x1.5648b5dc47417p-3, -0x1.fb8fa09976e07p-57, 0x1.40fbaba44504cp-7, 0x1.435c75f61f1ep-64, -0x1.c0db89d0a41a4p-5, -0x1.1dd02d9441b98p-62, 0x1.388c3ec056942p-6, 0x1.8e7498172c914p-60, 0x1.aecb7463cf446p-8, -0x1.0d6701a009d7p-65, -0x1.8bca53327e075p-8, 0x1.4add4a8239f4ap-12, 0x1.05ce4abd10484p-10, -0x1.183f198a0b62p-12, -0x1.9cd1a9b9fc69bp-14, 0x1.d30363021af83p-15, 0x1.da66f2161c4c6p-19, -0x1.f41f1f238827dp-18, 0x1.725a07b1177b7p-21, 0x1.84c3b2483eb6ap-21, 0x1.e30e89d6e85cdp-25}, /* i=9 110.374 */\n", " {0x1.df85ea8db188ep-1, -0x1.f71e8254d11a9p-55, 0x1.9cb5bd549b111p-3, -0x1.973e73caa1edcp-59, -0x1.0ed7443f85c33p-2, -0x1.74bf040302ad8p-58, 0x1.5066cda84bba9p-3, 0x1.beb86d9e281a8p-59, -0x1.419fa10b6ed7dp-6, 0x1.5157491034c58p-60, -0x1.3f41761d5a941p-5, 0x1.94a1c1f7af153p-59, 0x1.6d1d724baaae4p-6, 0x1.c41090a704426p-60, 0x1.e377f5703f7ffp-11, -0x1.a753be0c53963p-65, -0x1.4cc916ad63c27p-8, 0x1.553ef0d12719fp-10, 0x1.26240f55987fdp-11, -0x1.6bbf0fffb7138p-12, -0x1.320cf6663c40dp-17, 0x1.a9d4850aaa197p-15, -0x1.17036c4011c91p-17, -0x1.441ea26a91a02p-18, 0x1.d81eb8e2ef452p-20, 0x1.17d7b798a4322p-22, -0x1.b7b0dfb2559dp-27}, /* i=10 110.102 */\n", " {0x1.ea7730ed0bbb9p-1, 0x1.2c5bd7ce1388bp-55, 0x1.24a7b84d38971p-3, 0x1.aa0c5e788ed5ep-57, -0x1.a4b118ef01593p-3, -0x1.238e3e6a99dep-60, 0x1.319c7a75f9187p-3, 0x1.a8f8fff24b0acp-59, -0x1.3db5bed47faf6p-5, 0x1.29cf699c8512cp-59, -0x1.7019bda6c2fddp-6, 0x1.dd56b84622d88p-62, 0x1.59d3aa402c32ep-6, -0x1.8de701f1e95e8p-63, -0x1.b324eab9c87a9p-9, -0x1.c3a4329771a44p-65, -0x1.b4774d37d0dd6p-9, 0x1.c01377485a844p-10, 0x1.a5db5f627539bp-14, -0x1.40d9c429b8932p-12, 0x1.e720d935ef7dbp-15, 0x1.fc8295ac052dep-16, -0x1.d1ccde95c6551p-17, -0x1.251c256ca45cbp-20, 0x1.e892cc5397b1bp-20, -0x1.8f6831febdf3dp-23, -0x1.aa5ef30a52421p-22}, /* i=11 108.586 */\n", " {0x1.f21c9f12f0677p-1, -0x1.7efe429672268p-58, 0x1.92470a61b6965p-4, 0x1.c6acd40cee352p-58, -0x1.3a47801c56a57p-3, -0x1.033705aa16f01p-57, 0x1.0453f90d3bd35p-3, -0x1.686e281ba5405p-57, -0x1.8a7c6a239217bp-5, 0x1.2a988808a7222p-60, -0x1.075c088031ee3p-7, -0x1.665bd0a645f4p-62, 0x1.16f9c9c127b8p-6, -0x1.e1813af47374cp-62, -0x1.74c2fc9bdfe97p-8, 0x1.5cf2dbe53783bp-62, -0x1.760c522bd5becp-10, 0x1.a3cdb656adb44p-10, -0x1.02c3c1ab0a7bap-12, -0x1.92892013c7e15p-13, 0x1.6e7b268d42034p-14, 0x1.970751eb9359fp-18, -0x1.b00b549bbdf58p-17, 0x1.033f8545bcc6ap-19, 0x1.2d8b6f0a2204ap-20, -0x1.c1c1335b105c5p-22, 0x1.61bbb2d003b8ap-25}, /* i=12 109.215 */\n", " {0x1.f74a6d9a38383p-1, 0x1.c33a329423946p-55, 0x1.0bf97e95f2a64p-4, -0x1.446051f6fef82p-58, -0x1.c435059d09788p-4, -0x1.b93aeb5e5cf84p-59, 0x1.a3687c1eaf1adp-4, 0x1.64513fb767a13p-58, -0x1.9647a30b16824p-5, -0x1.86357831221bep-59, 0x1.6981061dfbb09p-9, -0x1.ccc83193c8742p-64, 0x1.7e8755da4704p-7, -0x1.c1eaeb337149p-65, -0x1.9be731fdab95dp-8, -0x1.ab79fedbfccd2p-63, 0x1.3a95ae0a75542p-13, 0x1.319f780e962d8p-10, -0x1.b88dd51a4f261p-12, -0x1.037f168a8f581p-14, 0x1.53fc5e83e3199p-14, -0x1.9d5bf30917222p-17, -0x1.03045c999d17ap-17, 0x1.b5d376e96179fp-19, 0x1.c66d2e5aa2274p-23, -0x1.aef24a52bcacap-22, 0x1.b20b678e8a0c6p-24}, /* i=13 110.24 */\n", " {0x1.fab0dd89d1309p-1, -0x1.ae61bd9db1babp-55, 0x1.5a08e85af27ep-5, 0x1.e4f9cfc8c2382p-59, -0x1.399812926bc23p-4, -0x1.b782644df6665p-58, 0x1.4140efb719cbp-4, 0x1.08fa5a48311e8p-60, -0x1.7535a61a4193dp-5, 0x1.59e0501c376b2p-60, 0x1.374c88c7e6abdp-7, 0x1.c2578bd7e3fp-64, 0x1.a40709e010e77p-8, -0x1.18c33197d9138p-64, -0x1.6dc078888efa7p-8, 0x1.2b49da4c86c7p-63, 0x1.2ee6d200993bp-10, 0x1.44f175e22a161p-11, -0x1.c2fb051c92f92p-12, 0x1.523035ed3964bp-15, 0x1.bc7b666856fc1p-15, -0x1.574549f39ee5p-16, -0x1.c57f3c47b39d9p-20, 0x1.8acc76ac31fcdp-19, -0x1.f70e8b7deaa9ap-22, -0x1.e1a28a0c1a6a6p-23, 0x1.bfa0e5b606c5ep-25}, /* i=14 108.959 */\n", " {0x1.fcdacca0bfb73p-1, -0x1.2c33d88729e43p-55, 0x1.b1160991ff737p-6, -0x1.d940a504353bcp-61, -0x1.a38d59456f77dp-5, -0x1.d625808eb9778p-62, 0x1.d5bd91b6b0123p-5, 0x1.22b86f5e3e16cp-61, -0x1.3b35dcbc80146p-5, 0x1.82838d776d958p-59, 0x1.9d76b0a0535c7p-7, 0x1.60fda06bca0ap-61, 0x1.14c887a83a0e6p-9, 0x1.55ef222558d68p-65, -0x1.117f42cc6e9f4p-8, 0x1.d4213a7e14a18p-65, 0x1.9b477bdad8e08p-10, 0x1.1d219fb0e1bc8p-13, -0x1.5bb59d3ca4fa9p-12, 0x1.8ca373c577821p-14, 0x1.4a9b74153a4a3p-16, -0x1.424a8a883141p-16, 0x1.6ce0877965abcp-19, 0x1.c1ed3c11b1dd1p-20, -0x1.86b0a731d831ap-21, -0x1.5cea3996396c5p-26, 0x1.640950bde5eb3p-22}, /* i=15 108.063 */\n", " {0x1.fe307f2b503dp-1, -0x1.8a555000387f8p-57, 0x1.06ae13b0d3255p-6, -0x1.88abd7f4be982p-60, -0x1.0ee3844e59be7p-5, -0x1.0b0ec94b96d83p-59, 0x1.48b127f8ed8a5p-5, 0x1.b6a1f18c2c162p-60, -0x1.f155b4e7d8c3bp-6, 0x1.adb2d99b0c1fcp-60, 0x1.aa2c0753d569ap-7, 0x1.9a37b9864b8e6p-61, -0x1.bbf7e2795837bp-11, -0x1.4784a66288abfp-65, -0x1.5478d784d271cp-9, 0x1.27115917a7ecp-65, 0x1.8eae08cdf9546p-10, -0x1.92946556037e6p-13, -0x1.90f27ae61444cp-13, 0x1.b076b78538f02p-14, -0x1.b2906f1b92d5dp-18, -0x1.a2f66822d4a01p-17, 0x1.3031c4f7c4a97p-18, 0x1.41708ced2abdp-22, -0x1.45ffd6deae2a8p-21, 0x1.e844ebdc8456ap-24, 0x1.c0bbf2b711595p-24}, /* i=16 111.558 */\n", " {0x1.fefcce6813974p-1, -0x1.b27cf5025d1c8p-58, 0x1.34d7dbc76d7e5p-7, 0x1.3780d6e7eb351p-61, -0x1.51cc18621fc23p-6, 0x1.969629e4b64a6p-61, 0x1.b925a99886bb7p-6, 0x1.9c8f65efdd1f4p-61, -0x1.71e7d408c8c6fp-6, -0x1.c5621deaf4cfcp-60, 0x1.7ea58080a81efp-7, -0x1.2f25b7f384ff3p-61, -0x1.46eb9d203e071p-9, 0x1.ff569e38360a4p-65, -0x1.403333682fa5ep-10, -0x1.36256a95953a6p-65, 0x1.3b37d5bd14a4p-10, -0x1.6be130822dbdfp-12, -0x1.03d4bcdafd553p-14, 0x1.55848476c8142p-14, -0x1.5492bf3c6eee6p-16, -0x1.3823d4328e9c5p-18, 0x1.152fefc353e5ap-18, -0x1.5199dbf7bc4c6p-21, -0x1.4dda2bebe08f2p-22, 0x1.3fb850b47210ap-23, 0x1.bcd1b284c4798p-25}, /* i=17 112.32 */\n", " {0x1.ff733814af88cp-1, 0x1.0a87238cea4fap-56, 0x1.5ff2750fe782p-8, -0x1.5f184847ca667p-62, -0x1.96f0575a63ae5p-7, 0x1.95f4139297a96p-61, 0x1.1c5a643f04363p-6, -0x1.6ea87997fba3cp-62, -0x1.04f5caaf2196fp-6, 0x1.19502347d3b54p-62, 0x1.382a146afb9d2p-7, -0x1.f93bde902d2dp-63, -0x1.95cab93aa68d2p-9, 0x1.0f716a5fc18c4p-65, -0x1.d2fd90fe62928p-13, -0x1.4e00d5fcc484ap-68, 0x1.9f50fb94c0b86p-11, -0x1.7d7378074399bp-12, 0x1.cc0c9cb9ede1ep-16, 0x1.92a3a29471895p-15, -0x1.7c127858c909ap-16, 0x1.5a72fde935a48p-20, 0x1.57b9d90a92106p-19, -0x1.fdb8443754cf7p-21, -0x1.6c7d633eab55ap-26, 0x1.ddcfc714a2b67p-24, -0x1.9fedf738e84b4p-23}, /* i=18 108.141 */\n", " {0x1.ffb5bdf67fe6fp-1, 0x1.4e830346f6e8p-62, 0x1.84ba3004a50dp-9, -0x1.90b93d4632206p-64, -0x1.d9c2ea85a927dp-8, -0x1.0bcf1ea93cfdcp-62, 0x1.60898536e104ap-7, -0x1.ab6aa911c445ep-62, -0x1.5eb1c899f0b7p-7, 0x1.1bc22eed1f1fbp-61, 0x1.d854f73e74c87p-8, 0x1.7a977a3364c4p-63, -0x1.897719a9d257ep-9, -0x1.ab523e3f93994p-65, 0x1.88cdc8b807c97p-12, 0x1.4875acc7c06ap-70, 0x1.b325a11c1f45ap-12, -0x1.381548f69274p-12, 0x1.2b1fd05559bfap-14, 0x1.1ed31cd6feb26p-16, -0x1.29cf593fdf00ap-16, 0x1.1cea99b59228cp-18, 0x1.ceff221e3598ap-21, -0x1.b0ad4b899b2d9p-21, 0x1.3761b047e21d1p-23, 0x1.96c31c2256049p-25, -0x1.0a714c57f7adfp-25}, /* i=19 114.101 */\n", " {0x1.ffd9f78c7524ap-1, 0x1.04ed6ff98e45dp-55, 0x1.a024365f771bdp-10, 0x1.3c8f5202cb405p-64, -0x1.0a9732d5284ddp-8, -0x1.1acbd0899ce7ep-62, 0x1.a4bf47a43042ap-8, 0x1.e6cb2580d092p-63, -0x1.c23802d8a5bb7p-8, -0x1.9963700abfc8p-66, 0x1.4f40070668329p-8, -0x1.e1fe1c0e1182ap-62, -0x1.4c9a2c9dccd04p-9, 0x1.80fb9c9cd78c1p-63, 0x1.4f7a50b5bc019p-11, -0x1.40906b7a1de3ap-66, 0x1.18b04eb90c737p-13, -0x1.a4c3880c0ea69p-13, 0x1.4b7b82a86f423p-14, -0x1.0bc762b1c2aaap-18, -0x1.589d6f8892acfp-17, 0x1.357ab63f7bdf9p-18, -0x1.6675858bbff5ep-22, -0x1.ea96dcb12a15cp-22, 0x1.8c572fcf5610ep-23, -0x1.700c93da86deep-28, 0x1.7ae9ceb75e26ep-26}, /* i=20 110.433 */\n", " {0x1.ffed167b12ac2p-1, -0x1.ddc0ce3ed8fcbp-55, 0x1.afc85e0f82e12p-11, 0x1.438f22895e03ep-66, -0x1.221a9f326bef4p-9, -0x1.99642b37af33p-64, 0x1.e3c9aab90bcf4p-9, 0x1.7dcdfdccc72ap-68, -0x1.14b1b98141f21p-8, 0x1.af6edf50eba66p-62, 0x1.c1c19b9e63d7p-9, 0x1.4d1e9411f1d28p-66, -0x1.feac3dbeb5124p-10, 0x1.2400e6ffbc1c8p-65, 0x1.63e88178b0e49p-11, 0x1.3e4ae97774f91p-65, -0x1.4441c86c93f39p-15, -0x1.c8ceebc5fc50bp-14, 0x1.125b77a79aa6cp-14, -0x1.da7be990bc718p-17, -0x1.e019960474affp-19, 0x1.d229185ef6279p-19, -0x1.cea9fa10885e7p-21, -0x1.044fd6a2e447ap-23, 0x1.3695f88fc641dp-23, -0x1.0c0dc0ba0d589p-25, -0x1.9194748828b93p-23}, /* i=21 108.145 */\n", " {0x1.fff6dee89352ep-1, 0x1.b96c0ba13851dp-55, 0x1.b23a5a23e421p-12, 0x1.727bce1be0014p-67, -0x1.315107613c673p-10, -0x1.823f8673f5b7ap-64, 0x1.0c243329a9ca1p-9, -0x1.65e361cefe652p-64, -0x1.4630116262084p-9, -0x1.0ea6ee40daf79p-63, 0x1.1e84d1022e8cbp-9, -0x1.9b77b85eed4fp-66, -0x1.6b41872716325p-10, 0x1.3e9e001100f64p-66, 0x1.36edde582b265p-11, -0x1.1cb479a94e148p-65, -0x1.f7870ebc38e77p-14, -0x1.51ecfdc37801dp-15, 0x1.711d817e0d3b6p-15, -0x1.0ae90d500d1d8p-16, 0x1.a85b1bf54920cp-21, 0x1.fe73958205038p-20, -0x1.d222bfef33aa4p-21, 0x1.833f8b13b1a4ep-24, 0x1.233b5a19285dbp-24, -0x1.1adcf574b7db6p-25, 0x1.ab10bedc44532p-24}, /* i=22 109.015 */\n", " {0x1.fffbb8f1049c6p-1, 0x1.d2c6266b51f26p-56, 0x1.a740684026555p-13, -0x1.7e24cc3ac571p-69, -0x1.36d34c8f1c26ap-11, -0x1.69d73e7d1c977p-65, 0x1.1eb6e14974a25p-10, -0x1.99b78600e0664p-64, -0x1.714eb8cc0947fp-10, 0x1.3613f37c7410bp-64, 0x1.5bec08c01b1d7p-10, -0x1.3e3a262f6c68ap-64, -0x1.e4621d82dad12p-11, 0x1.302878843e2ccp-67, 0x1.e1b7b564b0e79p-12, 0x1.f894fc1f14d54p-67, -0x1.24564b69716aap-13, 0x1.bf8e3b47f3ccdp-20, 0x1.8f55a9be1a264p-16, -0x1.b3b76e6203281p-17, 0x1.713c795a07e0cp-19, 0x1.3bb092cfd93ep-21, -0x1.473b0a8333deep-21, 0x1.645526869c143p-23, 0x1.1a343e004b33dp-27, -0x1.76c7e253faad1p-26, 0x1.e16080963cffep-24}, /* i=23 108.853 */\n", " {0x1.fffe0e0140857p-1, -0x1.6aa36f86c14dcp-57, 0x1.8fdc1b2dcf7b9p-14, 0x1.7050f50b8f308p-71, -0x1.322484cf12daap-12, 0x1.4cc0408806d4fp-66, 0x1.27dc1bc6cfef5p-11, 0x1.ffbb5229f6bb7p-65, -0x1.9202f465eb421p-11, 0x1.8f3f063b4066p-69, 0x1.93b4c9746835fp-11, -0x1.04e2d6df2fce5p-65, -0x1.30e9e6142fe9bp-11, -0x1.0396045094744p-66, 0x1.555b9d5fb4825p-12, 0x1.9a40d2ca5ef0bp-66, -0x1.055983c4ac7a6p-13, 0x1.68e6c75a5d068p-16, 0x1.2d4a50d2757cep-17, -0x1.1de08b56479aap-17, 0x1.9110ccc7fe6fdp-19, -0x1.bb3184d789af8p-23, -0x1.4629a164e82ap-22, 0x1.413b087ee5e4dp-23, -0x1.648d7786f9fbcp-26, -0x1.293289f8c327dp-27, -0x1.c283008e726f7p-25}, /* i=24 109.772 */\n", " {0x1.ffff2436a21dcp-1, -0x1.3607959a29d36p-55, 0x1.6e2367dc27f95p-15, 0x1.d96e6f015102p-73, -0x1.23c436c36fdabp-13, 0x1.f0d77fc600a5p-68, 0x1.26bf00867a835p-12, -0x1.c92e1aecdc75p-66, -0x1.a51fb50b15f22p-12, 0x1.248227c6d226p-69, 0x1.c0825378fda08p-12, 0x1.5a8a09c053451p-66, -0x1.6c3dbfe0cbe4ap-12, -0x1.e65769c33f8a1p-66, 0x1.c1dd1438378dfp-13, 0x1.91bd161f34158p-69, -0x1.94c36a9d7c0dcp-14, 0x1.bf0aab116ca41p-16, 0x1.6bdbd2f10393p-23, -0x1.2b32e8d43ef25p-18, 0x1.3a7403459770bp-19, -0x1.17411873320fap-21, -0x1.35bb2691c9b29p-24, 0x1.98313537ed069p-24, -0x1.cb4b60e85a341p-26, 0x1.2be214cf4c9ebp-31, -0x1.350a1a851865ap-23}, /* i=25 108.474 */\n", " {0x1.ffffa1de8c582p-1, 0x1.832540129302ap-55, 0x1.44f21e49054f2p-16, 0x1.f338cf4086346p-71, -0x1.0d18811478659p-14, 0x1.914a7a08b6a2bp-68, 0x1.1b964d438f622p-13, 0x1.a52c94c56aaafp-67, -0x1.a8d7851f26bfp-13, 0x1.c38dbf3ee1223p-67, 0x1.ddd6df9b6852dp-13, -0x1.3b0dd7eac9b91p-67, -0x1.9e52b7aac1644p-13, 0x1.904036dfb5764p-67, 0x1.165b2034fcab2p-13, 0x1.27beac4bf3866p-67, -0x1.1b75c3332673ap-14, 0x1.91a253c42f4e7p-16, -0x1.020b498095051p-18, -0x1.ade63f30809aep-20, 0x1.89bb0d75e59b7p-20, -0x1.180c78d3dca28p-21, 0x1.cabfd39b38553p-25, 0x1.6013ffba86cfdp-25, -0x1.64f2b123e1f0bp-26, 0x1.35bf3e5021105p-28, -0x1.177828ffd35afp-23}, /* i=26 108.645 */\n", " {0x1.ffffd8e1a2f22p-1, -0x1.c10adf6b19989p-55, 0x1.1783ceac2891p-17, -0x1.7f19d8ee58337p-71, -0x1.e06a8b37e5b93p-16, 0x1.24e8db1358f2ep-71, 0x1.07978c7b8496bp-14, 0x1.f163b5580927cp-68, -0x1.9d039884f8be5p-14, 0x1.fce53cd30b1ebp-68, 0x1.e8d1145e94a54p-14, -0x1.d0f6e009a99eep-68, -0x1.c1f7251172a87p-14, -0x1.3ce0f013dfe9p-71, 0x1.458b9e0854d68p-14, -0x1.897cf3950b1a7p-68, -0x1.6eb0557245429p-15, 0x1.33045cf65279ep-16, -0x1.42c8adf18ab62p-18, 0x1.91109b80f9918p-27, 0x1.83a9b44249fbfp-21, -0x1.9bcbaf0a8dfd1p-22, 0x1.900325b58a857p-24, 0x1.4a3cf9c161684p-28, -0x1.0cbcc4d0a916ap-26, 0x1.4275e1b91f084p-28, 0x1.39180c75350e1p-23}, /* i=27 108.443 */\n", " {0x1.fffff039f9e8fp-1, -0x1.9d1bcd6174e99p-55, 0x1.d21397ead99cbp-19, -0x1.6abd9c029c47cp-75, -0x1.9f19734d29cf9p-17, 0x1.20c4383da36c1p-71, 0x1.d982bd41d8954p-16, 0x1.d9bc9988e9666p-71, -0x1.8320fc4836be5p-15, 0x1.526638b9926a8p-72, 0x1.e0a1cb1d071f3p-15, 0x1.d9f5d232bab9p-70, -0x1.d384223047b9cp-15, -0x1.30d0b2b8a170dp-69, 0x1.696daf6422bd4p-15, 0x1.ba6ac732f399ep-69, -0x1.bb6e2d311a93fp-16, 0x1.a4fcb0ea87efbp-17, -0x1.1c940c5303dafp-18, 0x1.7469913f4e9c6p-21, 0x1.ef4b4f8ab67aep-23, -0x1.e189c28e8e041p-23, 0x1.678b281d5bc55p-24, -0x1.9c3bf4e9f2b5dp-27, -0x1.74c9ba997ffedp-28, 0x1.b4b843f8c7068p-29, 0x1.c901764507862p-25}, /* i=28 109.895 */\n", " {0x1.fffff9d446cccp-1, -0x1.bb06bab98bc8p-57, 0x1.789fb715aae95p-20, -0x1.226d93bf89b4p-80, -0x1.5b333cc7f98f1p-18, -0x1.6bd1091d2544p-72, 0x1.9b12fdbf90f62p-17, 0x1.d4b6b0ee9cf46p-71, -0x1.5e06923144d7p-16, 0x1.c59319485786p-75, 0x1.c6a071925631dp-16, -0x1.835ef595952e4p-71, -0x1.d178cb0388a82p-16, -0x1.039272760f01cp-70, 0x1.7e29d33ac92b6p-16, 0x1.21ff8b0e9d5ebp-70, -0x1.f9203429baad6p-17, 0x1.094dadeee395cp-17, -0x1.a771cf3500d9fp-19, 0x1.b8fd1c29c21eap-21, -0x1.cc8573d7de11p-26, -0x1.b0362da1722cbp-24, 0x1.e5eae518f94e9p-25, -0x1.07963addd99a6p-26, -0x1.3f496093d0befp-29, 0x1.99078a326092dp-30, 0x1.42681ecfe4da1p-23}, /* i=29 108.41 */\n", " {0x1.fffffda86faa9p-1, -0x1.d230252d68f26p-56, 0x1.26f9df8519bd7p-21, -0x1.e339871c015b7p-75, -0x1.1926290adc888p-19, -0x1.e36d23dbb2644p-73, 0x1.5900c02d97304p-18, 0x1.fa7d21e3ed616p-72, -0x1.3166de6a8c64p-17, 0x1.b014157867958p-71, 0x1.9dfcc328729ep-17, 0x1.20e9fee0b7665p-71, -0x1.bcab1ed5ec38dp-17, 0x1.d9003794f0fep-73, 0x1.81cd74a57ce17p-17, -0x1.809fde9c0f6f5p-71, -0x1.106e95b6bf556p-17, 0x1.379625a71385fp-18, -0x1.1970a5b5bd443p-19, 0x1.74761c8333ff2p-21, -0x1.0864e125c9951p-23, -0x1.b83bf9019aa3bp-26, 0x1.0397611c35b28p-25, -0x1.a25392adb29acp-27, -0x1.7b832af40d9d4p-30, 0x1.62a02eb79577bp-32, 0x1.a6da58ffe94f4p-23}, /* i=30 108.026 */\n", " {0x1.ffffff233ee1dp-1, 0x1.db123ed17221dp-55, 0x1.bfd7555a3bd68p-23, 0x1.0151cf177b53ap-77, -0x1.b8d7f804d2e73p-21, 0x1.82b366f0bc2dcp-75, 0x1.17f93e5149289p-19, 0x1.91997bfd26568p-76, -0x1.013b0457d08fap-18, -0x1.0d6d5a7f06298p-73, 0x1.6b245d7e1d829p-18, -0x1.9985e02c8ce3bp-72, -0x1.98077548c6951p-18, 0x1.01cd3f1d12c93p-72, 0x1.7492048ab3cebp-18, -0x1.0368a0dc0750ep-72, -0x1.17506c7b39cbp-18, 0x1.57e94a4c5f5a6p-19, -0x1.570971200d7dbp-20, 0x1.0a0f956947b21p-21, -0x1.1a9b7bd5bba32p-23, 0x1.51bfc00de3146p-27, 0x1.95b6967f79cbep-27, -0x1.fe3c43cb3cf84p-28, 0x1.2f364a7a2dc5fp-28, -0x1.007442a10cc14p-32, -0x1.ef5ab6fc5e849p-24}, /* i=31 108.802 */\n", " {0x1.ffffffb127525p-1, 0x1.504f382db4102p-55, 0x1.4980cb3c80949p-24, 0x1.7fbdd923f8057p-78, -0x1.4ea6ce697296fp-22, 0x1.ea42f9c9de533p-76, 0x1.b771d9b6f07b8p-21, -0x1.e9c1ca9662fe8p-78, -0x1.a26c653fad5b8p-20, -0x1.146c4cee0e898p-74, 0x1.3302bb89379dep-19, 0x1.4c55b83ef7a68p-73, -0x1.67f42e5264334p-19, -0x1.6779da26b4197p-73, 0x1.58b4adafb958ep-19, 0x1.8351251b45e84p-73, -0x1.10f576796285ap-19, 0x1.66ca44250dd07p-20, -0x1.84ee0ada37543p-21, 0x1.53b6065291e6bp-22, -0x1.c09ebfd0c581cp-24, 0x1.63062625d59cp-26, 0x1.e259c60eb7b83p-30, -0x1.e43802ad25514p-29, 0x1.51bcdabe8cda5p-28, -0x1.930fc3df6e909p-32, -0x1.81cdd770e1c81p-23}, /* i=32 108.16 */\n", " {0x1.ffffffe4aed5ep-1, 0x1.389c0f32ad0fp-59, 0x1.d5f3a8dea7357p-26, 0x1.fa07c18622dd2p-80, -0x1.ebfb14c9170cp-24, 0x1.9e40632b4145dp-78, 0x1.4d9228525f449p-22, 0x1.d35bd7f959136p-77, -0x1.48b536addac5fp-21, -0x1.61ace22b32569p-75, 0x1.f48ccf23a68e2p-21, -0x1.ee1d13c79c281p-75, -0x1.3183b6134cf03p-20, 0x1.e1f4d5fe2a06cp-75, 0x1.31efde2215f01p-20, -0x1.64a7021e23fbap-74, -0x1.fd9eeb0f18fdbp-21, 0x1.63414459ae298p-21, -0x1.9dda81be20b5ap-22, 0x1.8da7d306423c5p-23, -0x1.303da86a4fc28p-24, 0x1.4f5e1327706b9p-26, -0x1.3efb5eefcbe53p-29, -0x1.31bc5ce1ce65dp-30, -0x1.3eafe1b05c93fp-30, -0x1.47fc2d9cc851ep-32, 0x1.d27265006a9dfp-24}, /* i=33 108.887 */\n", " {0x1.fffffff6d1e56p-1, -0x1.64d969b4be4c4p-55, 0x1.44d26de513197p-27, 0x1.76fc20fc4b365p-81, -0x1.5e32de7af8977p-25, -0x1.888fd6ae18a1cp-80, 0x1.e9e05b3c8f38ap-24, 0x1.7532141b12aa7p-78, -0x1.f2f6fa7db5b1dp-23, 0x1.b3bf498e3462cp-77, 0x1.899dcace485ebp-22, 0x1.1885a0ae9e878p-78, -0x1.f34b7eef3c9b2p-22, 0x1.294a3b618b47p-76, 0x1.04be030272d14p-21, -0x1.df83095e40f79p-75, -0x1.c73bd22571559p-22, 0x1.4edda838439f5p-22, -0x1.9fc860b504677p-23, 0x1.b0d686a26042p-24, -0x1.72370c2fdbe1p-25, 0x1.ee29f0d197d25p-27, -0x1.b4d88d500c5bep-29, 0x1.96014c45b0178p-35, 0x1.238f19dc8fd82p-31, -0x1.8d34d46ae6567p-33, -0x1.54105fe4a9cd8p-27}, /* i=34 112.335 */\n", " {0x1.fffffffd01f89p-1, -0x1.35e8e39884f62p-56, 0x1.b334fac4b9f99p-29, 0x1.32178ed1a4971p-83, -0x1.e2cec6323e50ep-27, -0x1.0e5693f9d4908p-83, 0x1.5c027d5bba36ap-25, -0x1.fc46fb3cc7aep-81, -0x1.6df4d024fffbep-24, -0x1.90fd7226ec57ap-79, 0x1.2aaf7c205b9eap-23, 0x1.dbec2005b45a8p-77, -0x1.8902edfbfefddp-23, -0x1.c353aca58d08ap-77, 0x1.ab2ab1b338249p-23, 0x1.b498186c39105p-77, -0x1.85abe0ff198d3p-23, 0x1.2d32f7c3621ebp-23, -0x1.8c141c71dbc95p-24, 0x1.b9fa6fbb9b198p-25, -0x1.9db5fe2c2f5b9p-26, 0x1.3b8e07840483ep-27, -0x1.6d95e5070d91dp-29, 0x1.d7616168b0e49p-32, 0x1.f2be0744b3a5fp-30, -0x1.737a375809985p-34, -0x1.936d4936fb865p-24}, /* i=35 109.095 */\n", " {0x1.ffffffff0dd2bp-1, 0x1.0df73e7d2fc98p-55, 0x1.1a94ff571654fp-30, 0x1.fbf537b47967dp-84, -0x1.4251f33f5578fp-28, 0x1.4c9cece8f41b2p-82, 0x1.de6bc1f75bb9bp-27, 0x1.94afb459a3p-87, -0x1.036b5fd1c4158p-25, -0x1.d582afa097896p-79, 0x1.b58f1385def96p-25, -0x1.8778854601996p-80, -0x1.2a2347efb2133p-24, -0x1.26f9e1ef0f378p-79, 0x1.508db866ffep-24, 0x1.64de561a68a21p-78, -0x1.3ffea934685b9p-24, 0x1.02ff87b2e2576p-24, -0x1.66e54eae5fa4bp-25, 0x1.a9ea2195c567dp-26, -0x1.ae3b91fecafa1p-27, 0x1.6bb883d2e5ed1p-28, -0x1.ee10e97715c11p-30, 0x1.e2873d2b77f1fp-32, -0x1.af385ae29d57bp-33, -0x1.d793eecfc2513p-36, 0x1.20d80dcfa68d1p-27}, /* i=36 112.58 */\n", " {0x1.ffffffffb5be5p-1, -0x1.729d6819c7f34p-56, 0x1.63ac6b4edc88ep-32, -0x1.c45991835da24p-88, -0x1.a0ce0dc06a706p-30, -0x1.1b72d11da9dabp-84, 0x1.3e380dd7593a5p-28, -0x1.8ad868a7b5674p-82, -0x1.638bc4fb02cbap-27, 0x1.7a84506fcda4p-87, 0x1.35753ad4c5875p-26, 0x1.ad190ab170366p-81, -0x1.b41f33cafccbap-26, 0x1.0e3539bf61116p-80, 0x1.fe694e371a659p-26, -0x1.3a84e01866ea8p-82, -0x1.f8af0121aa0abp-26, 0x1.aa77274dab3d8p-26, -0x1.3616fe8f6a259p-26, 0x1.84fddf4c681a1p-27, -0x1.a3de05d1b8a31p-28, 0x1.822529aca9f83p-29, -0x1.26c3dfba84378p-30, 0x1.64c287a84aa09p-32, -0x1.107d2dac5d83bp-31, -0x1.e251d1ab1d873p-43, 0x1.8f37005f17b42p-26}, /* i=37 111.111 */\n", " {0x1.ffffffffe9ebp-1, -0x1.ea527e0bef1e8p-58, 0x1.b1e5acf351d87p-34, 0x1.dc96583ba19fp-90, -0x1.05042a0a5f3c3p-31, -0x1.2023f0f13867cp-85, 0x1.99ac8fd63c66cp-30, -0x1.bf57c5fd0501ap-85, -0x1.d72344378e114p-29, 0x1.c77758959af41p-83, 0x1.a6be9a123435bp-28, 0x1.dab4af8807c36p-83, -0x1.33aacb4bf6deap-27, 0x1.bd241ea49ac35p-81, 0x1.74b732e7ceaa7p-27, 0x1.c7c89730b0264p-82, -0x1.7e7eab6531ccbp-27, 0x1.50959f2daae39p-27, -0x1.ffed4cef94261p-28, 0x1.51c7f99f908a2p-28, -0x1.82b5fd5fbedfcp-29, 0x1.7e1c8e715c978p-30, -0x1.51536822c861bp-31, 0x1.be7e4c220ca82p-33, 0x1.f5bb67c461296p-29, 0x1.1d7cf04529bfp-37, -0x1.acc021ab828c4p-23}, /* i=38 108.008 */\n", " {0x1.fffffffff9a1bp-1, -0x1.6a87270d2450cp-57, 0x1.0084ff125639dp-35, -0x1.8ad61debedc86p-90, -0x1.3ca42adaa26f6p-33, 0x1.c20c6583dccddp-87, 0x1.fe73513c67bf8p-32, 0x1.20d28c0c7e686p-86, -0x1.2dd9aa5a2bee3p-30, 0x1.d76d7235461bep-85, 0x1.16ef6b93944a8p-29, -0x1.f07bd785566dep-83, -0x1.a2d58e9b22b26p-29, -0x1.19e6ea91dd55ep-84, 0x1.06389b9748f25p-28, 0x1.fbcc52565c0bep-82, -0x1.16cdd9eb58ba2p-28, 0x1.fdd861b55c5p-29, -0x1.9457846c943d2p-29, 0x1.178f3905f435cp-29, -0x1.518cf20c53de2p-30, 0x1.6329939a34b66p-31, -0x1.5ef3ad85e5d3bp-32, 0x1.f2b41494e49e9p-34, 0x1.bad43bc0b622dp-29, 0x1.21a45fa9dcebfp-37, -0x1.790b3d88f69fep-23}, /* i=39 108.193 */\n", " {0x1.fffffffffe38p-1, 0x1.7ce07114e4fep-55, 0x1.25f9ee0b923dcp-37, -0x1.174c43a73a4d1p-91, -0x1.74105146a5162p-35, -0x1.7d0740e56625cp-91, 0x1.33cde4f35d941p-33, -0x1.2a344950797c6p-88, -0x1.760fe7b666392p-32, 0x1.a8b77c82ed644p-86, 0x1.63a70fd66d485p-31, 0x1.6b87715649d6dp-85, -0x1.1324f6fb6dfa1p-30, 0x1.3fc045e39915fp-84, 0x1.63a31a36b815cp-30, -0x1.02dec9bc1a7p-90, -0x1.8724ca8970b91p-30, 0x1.72e290891e5dep-30, -0x1.31fc03858aab1p-30, 0x1.b9e8b0e7fa253p-31, -0x1.1821a002637bdp-31, 0x1.37ba5f3fba5ebp-32, -0x1.3578bf23dc654p-33, 0x1.fdaf2015d7b54p-35, 0x1.7f6a435069067p-32, 0x1.9d14ee557ec62p-38, -0x1.55f4c743ee571p-26}, /* i=40 111.334 */\n", " {0x1.ffffffffff845p-1, 0x1.b0edc5a89ab8ep-56, 0x1.46897d4b69fc6p-39, 0x1.a74852415bb49p-93, -0x1.a77a4e7dcd735p-37, -0x1.34edb43ab7de6p-91, 0x1.67543695dcc12p-35, -0x1.29ae577004af8p-92, -0x1.c05c1e2fc710ep-34, 0x1.dbbf42d2537a8p-90, 0x1.b639419fedf8ep-33, -0x1.ed72eb9e7a59ep-87, -0x1.5cfd7eb9bfe87p-32, -0x1.e97db27125fcp-88, 0x1.d11578959ba45p-32, -0x1.c0635ac2b5768p-87, -0x1.082f9e9f7eb37p-31, 0x1.0354ceadad8b3p-31, -0x1.bc2dee0154fc6p-32, 0x1.4e11efdc66eaep-32, -0x1.bb357c0253f64p-33, 0x1.035f9889bc29cp-33, -0x1.8e7bdb10b7441p-35, 0x1.e364571102661p-36, -0x1.12cffcf49a2e8p-29, 0x1.ee9362bcfec26p-39, 0x1.cc5b58dd85301p-24}, /* i=41 108.905 */\n", " {0x1.ffffffffffdf8p-1, -0x1.dcf8b10ff973bp-55, 0x1.5f8b87a31bd85p-41, 0x1.65b265455b658p-98, -0x1.d2e55024a0fb5p-39, 0x1.444e1d84cea02p-93, 0x1.9612cc225df4bp-37, -0x1.c784edb664ce7p-91, -0x1.03ee5f38b9b4dp-35, -0x1.91ca8efa41a3p-89, 0x1.04f2f71e2e96bp-34, -0x1.33f36a4e5135p-89, -0x1.ab7099f99ced9p-34, -0x1.4af7a67f2110cp-90, 0x1.2554b8f609fd1p-33, -0x1.29e641eb44218p-88, -0x1.57c87529ca968p-33, 0x1.5cd182c967671p-33, -0x1.3580a2517d57ap-33, 0x1.e3be72b1be982p-34, -0x1.4e9908689ad08p-34, 0x1.9a61979d3395bp-35, -0x1.7b826aadd1c89p-36, 0x1.ad3a9fc4a0d1ep-37, -0x1.0e9325ed2097p-31, 0x1.0722198ff452cp-39, 0x1.c2ef85611aa11p-26}, /* i=42 110.935 */\n", " {0x1.fffffffffff7bp-1, 0x1.00fa07f7fb612p-55, 0x1.6ed2f2515e933p-43, 0x1.2bc1802a42b92p-98, -0x1.f2a6c1669c901p-41, -0x1.7b3e174cc184p-95, 0x1.bc42ba38a13f8p-39, 0x1.460463d59d3dfp-93, -0x1.2391e135afae4p-37, -0x1.bd08c8c5f7b18p-92, 0x1.2c6c24550f64fp-36, -0x1.fdc861a48711p-92, -0x1.f9a3c1b0d63ecp-36, -0x1.843dc8d9ad3d5p-90, 0x1.6502546ab341ap-35, 0x1.45f812e48eb98p-89, -0x1.af223186006d1p-35, 0x1.c388dd1764f41p-35, -0x1.9e65a242b52aap-35, 0x1.4fcd2787781ebp-35, -0x1.e3cbdb20a48d6p-36, 0x1.35639e9fcd41p-36, -0x1.5b8e97774b2c9p-42, 0x1.66ffe6a100bc9p-38, -0x1.5706c390c113ep-30, 0x1.ff0d11cf61949p-41, 0x1.2054de347e3f8p-24}, /* i=43 109.58 */\n", " {0x1.fffffffffffdfp-1, 0x1.5669e670f914cp-56, 0x1.72fd93e036cdcp-45, 0x1.1c553d12fbbdp-100, -0x1.01f450d1e61b2p-42, 0x1.bed807e60c078p-99, 0x1.d68fb81b2ed89p-41, 0x1.c7ea3c4444ccp-98, -0x1.3c706aa4d2328p-39, 0x1.d6d2d51dd414dp-93, 0x1.4e6479565838ep-38, 0x1.50580f36c14c1p-92, -0x1.20e9eb83b3dd9p-37, -0x1.04b6334a32fdp-94, 0x1.a35b9d2fcac8p-37, 0x1.c07c6978bf2fp-94, -0x1.04a134f6e3dcbp-36, 0x1.196579f27ddbep-36, -0x1.0ab97aa74c7p-36, 0x1.bf68355f542b1p-37, -0x1.49da25a547134p-37, 0x1.bd64993a3958ep-38, -0x1.1193990186399p-35, 0x1.1c0e98335ae18p-39, 0x1.e08edb685494ap-29, 0x1.cb9fcc058465bp-42, -0x1.94cacccfb8964p-23}, /* i=44 108.091 */\n", " {0x1.ffffffffffff8p-1, 0x1.0160ef15c497ep-56, 0x1.6ba91ac734786p-47, -0x1.f81d6fa69b5b2p-101, -0x1.028a39099f4dbp-44, -0x1.83ed68de15404p-99, 0x1.e292863e1795ep-43, -0x1.b292e812abb68p-98, -0x1.4c4e690fbdd14p-41, -0x1.80991e1d4ef25p-95, 0x1.67e6e5ac60fd1p-40, 0x1.1d2ca68dcf0e8p-95, -0x1.3f00d80afa00cp-39, -0x1.3e174dc7225acp-93, 0x1.db88ee63eb28ap-39, 0x1.8abd97527892fp-93, -0x1.2fe58a1f19368p-38, 0x1.51dbeae22a5c8p-38, -0x1.4a4d54823e0fcp-38, 0x1.1e432d674cfbap-38, -0x1.b001e26c6e764p-39, 0x1.328ce695259fep-39, -0x1.4e492cf7d4f4cp-36, 0x1.aaa77d339dcp-41, 0x1.366538db382e5p-29, 0x1.826ad7d581503p-43, -0x1.056e0810b14dap-23}, /* i=45 108.721 */\n", " {0x1.ffffffffffffep-1, 0x1.59ab24e589a3p-56, 0x1.5982008db1304p-49, -0x1.1cf9bda64b38ap-103, -0x1.f610e8cde57acp-47, -0x1.884dcd86f98c8p-102, 0x1.df2dac2f2d47fp-45, -0x1.7f27bf279d988p-102, -0x1.51b17f95fc0b4p-43, -0x1.063e04485c3e7p-97, 0x1.76996ddc975d7p-42, -0x1.21489d6648428p-97, -0x1.546155a972b18p-41, -0x1.9d3fb518aa7cp-100, 0x1.0456ed89c4f24p-40, 0x1.eee772fc32c5ep-94, -0x1.55d6295aa388ap-40, 0x1.86ead99977388p-40, -0x1.89b3d387efa6ep-40, 0x1.6011e175e64f8p-40, -0x1.0cd70515af47bp-40, 0x1.9402199dfdde7p-41, -0x1.806743bc32b08p-37, 0x1.30e561550364ap-42, 0x1.70093985e2c1bp-30, 0x1.31999a27ace63p-44, -0x1.35f54db0f4dbcp-24}, /* i=46 109.476 */\n", " {0x1p+0, -0x1.a6d7d18831888p-55, 0x1.3e296303b2297p-51, 0x1.68cf648cfed1cp-105, -0x1.d8456ef97c744p-49, 0x1.fcded170055p-103, 0x1.ccb92e6c24c8dp-47, -0x1.a704dc202cff2p-101, -0x1.4c1aa8cf1229bp-45, 0x1.652efa61e4ec2p-99, 0x1.7918b6b83c0fbp-44, 0x1.2fb01fb8836dcp-100, -0x1.5f073659de44dp-43, -0x1.9ceb48a2d1931p-97, 0x1.134d070b5921ep-42, 0x1.9af3038fcc184p-98, -0x1.730a2938c09ddp-42, 0x1.b4091041f5905p-42, -0x1.c3c44ab8c8421p-42, 0x1.a06b4f4c3044dp-42, -0x1.704f511555fe7p-42, 0x1.fe51fcfc1acbap-43, 0x1.5e7229a07e7cdp-38, 0x1.9f8121f6c3146p-44, -0x1.692b2f9b3f445p-31, 0x1.c8c34f73d3823p-46, 0x1.301e540260d52p-25}, /* i=47 110.503 */\n", "\"\"\"\n", "\n", "import re\n", "\n", "def strip_c_comments(code: str) -> str:\n", " return re.sub(r'/\\*.*?\\*/', '', code)\n", "\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in strip_c_comments(data).strip().splitlines():\n", " floats = line.strip(\"{}, \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"[ {', '.join(encoded)} ],\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "ec279b25-a6b0-42ad-ac6e-215ae7bd4174", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0x3fcac45e37fe2526, 0x3c648d48536c61e3, 0x3ff16e2d7093cd8c, 0x3c9979a52f906b4d, 0xbfca254428ddb453, 0x3c69c98838a77aea, 0xbfd59b3da8e1e176, 0xbc41f650c25d97b0, 0x3fb988648fe88219, 0xbc55aecf0c7bb6c1, 0x3fb803427310d199, 0xbc5a14576e703eb2, 0xbfa09e7bce5592c9, 0x3c3eb7c7f3e76998, 0xbf9516b205318414, 0xbc2941aa998b1fa4, 0x3f8038d3f3a16b57, 0x3f6e19d52695ad59, 0xbf59542e7ed01428, 0xbf41f9b6e46418dc, 0x3f30796a08a400f4, 0x3f12610d97c70323, 0xbf025d31d73f96d1, 0xbee05e1fa9e02f11, 0x3ed1e616f979139c, 0x3ea9b3d54f1f222a, 0xbe97ad96beea439a ],\n", "[ 0x3fd5da9f415ff23f, 0xbc4a72e51e191950, 0x3ff05fd3ecbec298, 0xbc9f17d49717adf8, 0xbfd477c8e7ee733d, 0xbc792236432236b7, 0xbfd1917b60acab73, 0x3c7c06e6c21b4b3b, 0x3fc322a728d4ed12, 0x3c3ffa8aef321410, 0x3fb04c50a9cd2c12, 0xbc4edd0562dce396, 0xbfa7ce764eeddd86, 0x3c29afeb391c029c, 0xbf868aac5801171d, 0x3c24f9655411fc03, 0x3f862aa895f51cd3, 0x3f56c003c3cedb10, 0xbf6079502dbbafff, 0xbf1d9c7cbb799b47, 0x3f345a995aede3f4, 0x3eb0c04ea8c98fc9, 0xbf057edfa53128d0, 0x3eba96286bf3ef56, 0x3ed3c8ab12e6d24b, 0xbe97454eba0cb203, 0xbe8f02a6f6847617 ],\n", "[ 0x3fddb081ce6e2a48, 0xbc77ff0a3296d9cb, 0x3fedd167c4cf9d2a, 0x3c844f2832f90a97, 0xbfda173acc35a985, 0xbc3c5432c9a22740, 0xbfc889a80f4ad955, 0xbc6f6123bf467942, 0x3fc6c2eea0d17b39, 0xbc61f4935c3cf5b1, 0x3f9b0645438e5d17, 0x3c37a5f08ebaf9d0, 0xbfaa3fd9fcbb6d6d, 0x3c494a1b58b5916f, 0x3f2060b78c935b8e, 0x3bb9cec375875a1c, 0x3f8678b51a9c4b0a, 0xbf51e03bfc8eebb4, 0xbf5e653535cab33f, 0x3f355f31366d2c5c, 0x3f30dcf1445cbb88, 0xbf1098913ad4dcc7, 0xbeff6e252329eeed, 0x3ee41ad0a5afe51d, 0x3ec8fd4609222f1c, 0xbeb4465926de1a35, 0xbea407a1f42b46d4 ],\n", "[ 0x3fe25b8a88b6dd7f, 0x3c89534a3b5bd215, 0x3fea5074e2157620, 0x3c7fad8c0ef6fae6, 0xbfdd9a837e5824e4, 0xbc71d19ec86adc7c, 0xbfb9c41d1d5fae55, 0x3c374c230d6afba4, 0x3fc75bebc1b18d1c, 0x3c501ece95d4dffc, 0xbf86410ad9332666, 0xbc216523d167a40c, 0xbfa7df8890b11fa7, 0x3c4d6a99d1387564, 0x3f84a54816d3608a, 0xbc2f810ad06699cc, 0x3f818f36eb18f3d7, 0xbf68d661c030e174, 0xbf53628ede23e249, 0x3f4438eb2b3c4d27, 0x3f1fd3c13e725e91, 0xbf1991b866a32c87, 0xbee1237c600dab6f, 0x3eea9c701140d4c0, 0x3e71801e61adfdda, 0xbeb785516863e6ce, 0xbe83e033ef590125 ],\n", "[ 0x3fe569243d2b3a9b, 0x3c78eef7012e8df4, 0x3fe681ff24b4ab04, 0xbc5dba6493354c70, 0xbfdef2bed2786b25, 0xbc7ae3f6b6b2b679, 0xbf8a4254557d722f, 0xbc20ff7bffd10053, 0x3fc532415c267962, 0x3c62eacc4bd2e841, 0xbfa558b4c55a835c, 0x3c3c21c40815d70a, 0xbfa1b7ad5b777f1b, 0xbc42115b2bd8d644, 0x3f91201d3bd0e758, 0xbc0b39b845442560, 0x3f72995e3a88a890, 0xbf70294c3e93cdb0, 0xbf3159644a564f83, 0x3f463daf9b3858ef, 0xbf03beeb4a1255ac, 0xbf180c5178c36c72, 0x3eed4f6f5bab7dfa, 0x3ee521deb6d2f46e, 0xbec4ef3208231a8b, 0xbeae7d2b4e06e4a2, 0x3e921536d5b8bdf9 ],\n", "[ 0x3fe7fb9bfaed8078, 0x3c766cf14bcad032, 0x3fe2a8dcede3673b, 0xbc77378e2c70325e, 0xbfde5267029187c0, 0x3c7add23841b110a, 0x3fafe0796bb9d05a, 0xbc37a992e13ce574, 0x3fc0fa23021ad0ac, 0xbc417f4228359928, 0xbfafa21ebca76761, 0x3c3278ca2820f66c, 0xbf931546d5c4edb4, 0x3c136fcf151892a0, 0x3f937e5469efb7a6, 0xbc39553630321d4f, 0x3f2097966e2e87ea, 0xbf6e82ab020887a7, 0x3f4318270c11ae74, 0x3f412652e433da97, 0xbf24dc9bd6368bb8, 0xbf0c441138d4ff53, 0x3efc91d8dc5b66ec, 0x3ecf3ba57b86d474, 0xbecdd3403d11a818, 0xbe731f497a106a7c, 0x3e9436dbcc93d342 ],\n", "[ 0x3fea1551a16aaeaf, 0x3c6a558a46df5f68, 0x3fddfca26f5bbf88, 0xbc6ddcbaf85587b6, 0xbfdc1cd84866038f, 0xbc7200885b97f453, 0x3fbe4c9975da0987, 0xbc5f162e7576c79c, 0x3fb747e31bf47af3, 0xbc56178f12d62ed9, 0xbfb1d1f00109e42a, 0x3c5002b06e023544, 0xbf647654175ceb42, 0x3bd683389ccacfa8, 0x3f91a817c594b8cb, 0x3c336ac477166efb, 0xbf6cb8acd699cca6, 0xbf657b72bf874db6, 0x3f524493dca8b6fa, 0x3f2f556774c6aaf6, 0xbf2b09ec5c8ba626, 0xbed09bd1a09f38e8, 0x3efd149c3e776976, 0xbec8f7c2a6575e92, 0xbec8391d4afaf16a, 0x3ea5a7552081d1d5, 0x3e932d1bb2d1d0ca ],\n", "[ 0x3febbef0fbde6221, 0xbc8322c1148e0d48, 0x3fd75a91a7f4d2ed, 0x3c56eb826a9df85c, 0xbfd8d03ac274201c, 0x3c57a5c56eb7f6a0, 0x3fc3954778d6a0df, 0xbc5863eca74d1838, 0x3fa88e0f7b183fc6, 0x3c4226527d05ce39, 0xbfb0f7c15f75ee13, 0xbc156f74f3513660, 0x3f85e22cfa1aab51, 0x3c24b49a250c6474, 0x3f89ad28c5557c22, 0x3c299920b730ecd5, 0xbf7704ec5d29fc83, 0xbf523360304f19ba, 0x3f543ca3fcdf079d, 0xbf0dcb97a9e04bd4, 0xbf2735e26c43d267, 0x3f0360c3b06ffbb4, 0x3ef29a6b5798e781, 0xbeddbc35e4cf98f5, 0xbeb2f6e8e81287bb, 0x3eaeeb2fdddad355, 0x3e81ae65e387ac52 ],\n", "[ 0x3fed0580b2cfd249, 0x3c84fca6318dfee9, 0x3fd1a0dc51a9934d, 0xbc6ca89d2d78fba4, 0xbfd4ef05a0f95eeb, 0xbc65f7c55a00231c, 0x3fc5648b5dc47417, 0xbc6fb8fa09976e07, 0x3f840fbaba44504c, 0x3bf435c75f61f1e0, 0xbfac0db89d0a41a4, 0xbc11dd02d9441b98, 0x3f9388c3ec056942, 0x3c38e7498172c914, 0x3f7aecb7463cf446, 0xbbe0d6701a009d70, 0xbf78bca53327e075, 0x3f34add4a8239f4a, 0x3f505ce4abd10484, 0xbf3183f198a0b620, 0xbf19cd1a9b9fc69b, 0x3f0d30363021af83, 0x3ecda66f2161c4c6, 0xbedf41f1f238827d, 0x3ea725a07b1177b7, 0x3ea84c3b2483eb6a, 0x3e6e30e89d6e85cd ],\n", "[ 0x3fedf85ea8db188e, 0xbc8f71e8254d11a9, 0x3fc9cb5bd549b111, 0xbc4973e73caa1edc, 0xbfd0ed7443f85c33, 0xbc574bf040302ad8, 0x3fc5066cda84bba9, 0x3c4beb86d9e281a8, 0xbf9419fa10b6ed7d, 0x3c35157491034c58, 0xbfa3f41761d5a941, 0x3c494a1c1f7af153, 0x3f96d1d724baaae4, 0x3c3c41090a704426, 0x3f4e377f5703f7ff, 0xbbea753be0c53963, 0xbf74cc916ad63c27, 0x3f5553ef0d12719f, 0x3f426240f55987fd, 0xbf36bbf0fffb7138, 0xbee320cf6663c40d, 0x3f0a9d4850aaa197, 0xbee17036c4011c91, 0xbed441ea26a91a02, 0x3ebd81eb8e2ef452, 0x3e917d7b798a4322, 0xbe4b7b0dfb2559d0 ],\n", "[ 0x3feea7730ed0bbb9, 0x3c82c5bd7ce1388b, 0x3fc24a7b84d38971, 0x3c6aa0c5e788ed5e, 0xbfca4b118ef01593, 0xbc3238e3e6a99de0, 0x3fc319c7a75f9187, 0x3c4a8f8fff24b0ac, 0xbfa3db5bed47faf6, 0x3c429cf699c8512c, 0xbf97019bda6c2fdd, 0x3c1dd56b84622d88, 0x3f959d3aa402c32e, 0xbc08de701f1e95e8, 0xbf6b324eab9c87a9, 0xbbec3a4329771a44, 0xbf6b4774d37d0dd6, 0x3f5c01377485a844, 0x3f1a5db5f627539b, 0xbf340d9c429b8932, 0x3f0e720d935ef7db, 0x3effc8295ac052de, 0xbeed1ccde95c6551, 0xbeb251c256ca45cb, 0x3ebe892cc5397b1b, 0xbe88f6831febdf3d, 0xbe9aa5ef30a52421 ],\n", "[ 0x3fef21c9f12f0677, 0xbc57efe429672268, 0x3fb92470a61b6965, 0x3c5c6acd40cee352, 0xbfc3a47801c56a57, 0xbc6033705aa16f01, 0x3fc0453f90d3bd35, 0xbc6686e281ba5405, 0xbfa8a7c6a239217b, 0x3c32a988808a7222, 0xbf8075c088031ee3, 0xbc1665bd0a645f40, 0x3f916f9c9c127b80, 0xbc1e1813af47374c, 0xbf774c2fc9bdfe97, 0x3c15cf2dbe53783b, 0xbf5760c522bd5bec, 0x3f5a3cdb656adb44, 0xbf302c3c1ab0a7ba, 0xbf292892013c7e15, 0x3f16e7b268d42034, 0x3ed970751eb9359f, 0xbeeb00b549bbdf58, 0x3ec033f8545bcc6a, 0x3eb2d8b6f0a2204a, 0xbe9c1c1335b105c5, 0x3e661bbb2d003b8a ],\n", "[ 0x3fef74a6d9a38383, 0x3c8c33a329423946, 0x3fb0bf97e95f2a64, 0xbc5446051f6fef82, 0xbfbc435059d09788, 0xbc4b93aeb5e5cf84, 0x3fba3687c1eaf1ad, 0x3c564513fb767a13, 0xbfa9647a30b16824, 0xbc486357831221be, 0x3f66981061dfbb09, 0xbbfccc83193c8742, 0x3f87e8755da47040, 0xbbec1eaeb3371490, 0xbf79be731fdab95d, 0xbc0ab79fedbfccd2, 0x3f23a95ae0a75542, 0x3f5319f780e962d8, 0xbf3b88dd51a4f261, 0xbf1037f168a8f581, 0x3f153fc5e83e3199, 0xbee9d5bf30917222, 0xbee03045c999d17a, 0x3ecb5d376e96179f, 0x3e8c66d2e5aa2274, 0xbe9aef24a52bcaca, 0x3e7b20b678e8a0c6 ],\n", "[ 0x3fefab0dd89d1309, 0xbc8ae61bd9db1bab, 0x3fa5a08e85af27e0, 0x3c4e4f9cfc8c2382, 0xbfb399812926bc23, 0xbc5b782644df6665, 0x3fb4140efb719cb0, 0x3c308fa5a48311e8, 0xbfa7535a61a4193d, 0x3c359e0501c376b2, 0x3f8374c88c7e6abd, 0x3bfc2578bd7e3f00, 0x3f7a40709e010e77, 0xbbf18c33197d9138, 0xbf76dc078888efa7, 0x3c02b49da4c86c70, 0x3f52ee6d200993b0, 0x3f444f175e22a161, 0xbf3c2fb051c92f92, 0x3f0523035ed3964b, 0x3f0bc7b666856fc1, 0xbef574549f39ee50, 0xbebc57f3c47b39d9, 0x3ec8acc76ac31fcd, 0xbe9f70e8b7deaa9a, 0xbe8e1a28a0c1a6a6, 0x3e6bfa0e5b606c5e ],\n", "[ 0x3fefcdacca0bfb73, 0xbc82c33d88729e43, 0x3f9b1160991ff737, 0xbc2d940a504353bc, 0xbfaa38d59456f77d, 0xbc1d625808eb9778, 0x3fad5bd91b6b0123, 0x3c222b86f5e3e16c, 0xbfa3b35dcbc80146, 0x3c482838d776d958, 0x3f89d76b0a0535c7, 0x3c260fda06bca0a0, 0x3f614c887a83a0e6, 0x3be55ef222558d68, 0xbf7117f42cc6e9f4, 0x3bed4213a7e14a18, 0x3f59b477bdad8e08, 0x3f21d219fb0e1bc8, 0xbf35bb59d3ca4fa9, 0x3f18ca373c577821, 0x3ef4a9b74153a4a3, 0xbef424a8a8831410, 0x3ec6ce0877965abc, 0x3ebc1ed3c11b1dd1, 0xbea86b0a731d831a, 0xbe55cea3996396c5, 0x3e9640950bde5eb3 ],\n", "[ 0x3fefe307f2b503d0, 0xbc68a555000387f8, 0x3f906ae13b0d3255, 0xbc388abd7f4be982, 0xbfa0ee3844e59be7, 0xbc40b0ec94b96d83, 0x3fa48b127f8ed8a5, 0x3c3b6a1f18c2c162, 0xbf9f155b4e7d8c3b, 0x3c3adb2d99b0c1fc, 0x3f8aa2c0753d569a, 0x3c29a37b9864b8e6, 0xbf4bbf7e2795837b, 0xbbe4784a66288abf, 0xbf65478d784d271c, 0x3be27115917a7ec0, 0x3f58eae08cdf9546, 0xbf292946556037e6, 0xbf290f27ae61444c, 0x3f1b076b78538f02, 0xbedb2906f1b92d5d, 0xbeea2f66822d4a01, 0x3ed3031c4f7c4a97, 0x3e941708ced2abd0, 0xbea45ffd6deae2a8, 0x3e7e844ebdc8456a, 0x3e7c0bbf2b711595 ],\n", "[ 0x3fefefcce6813974, 0xbc5b27cf5025d1c8, 0x3f834d7dbc76d7e5, 0x3c23780d6e7eb351, 0xbf951cc18621fc23, 0x3c2969629e4b64a6, 0x3f9b925a99886bb7, 0x3c29c8f65efdd1f4, 0xbf971e7d408c8c6f, 0xbc3c5621deaf4cfc, 0x3f87ea58080a81ef, 0xbc22f25b7f384ff3, 0xbf646eb9d203e071, 0x3beff569e38360a4, 0xbf5403333682fa5e, 0xbbe36256a95953a6, 0x3f53b37d5bd14a40, 0xbf36be130822dbdf, 0xbf103d4bcdafd553, 0x3f155848476c8142, 0xbef5492bf3c6eee6, 0xbed3823d4328e9c5, 0x3ed152fefc353e5a, 0xbea5199dbf7bc4c6, 0xbe94dda2bebe08f2, 0x3e83fb850b47210a, 0x3e6bcd1b284c4798 ],\n", "[ 0x3feff733814af88c, 0x3c70a87238cea4fa, 0x3f75ff2750fe7820, 0xbc15f184847ca667, 0xbf896f0575a63ae5, 0x3c295f4139297a96, 0x3f91c5a643f04363, 0xbc16ea87997fba3c, 0xbf904f5caaf2196f, 0x3c119502347d3b54, 0x3f8382a146afb9d2, 0xbc0f93bde902d2d0, 0xbf695cab93aa68d2, 0x3be0f716a5fc18c4, 0xbf2d2fd90fe62928, 0xbbb4e00d5fcc484a, 0x3f49f50fb94c0b86, 0xbf37d7378074399b, 0x3efcc0c9cb9ede1e, 0x3f092a3a29471895, 0xbef7c127858c909a, 0x3eb5a72fde935a48, 0x3ec57b9d90a92106, 0xbeafdb8443754cf7, 0xbe56c7d633eab55a, 0x3e7ddcfc714a2b67, 0xbe89fedf738e84b4 ],\n", "[ 0x3feffb5bdf67fe6f, 0x3c14e830346f6e80, 0x3f684ba3004a50d0, 0xbbf90b93d4632206, 0xbf7d9c2ea85a927d, 0xbc10bcf1ea93cfdc, 0x3f860898536e104a, 0xbc1ab6aa911c445e, 0xbf85eb1c899f0b70, 0x3c21bc22eed1f1fb, 0x3f7d854f73e74c87, 0x3c07a977a3364c40, 0xbf6897719a9d257e, 0xbbeab523e3f93994, 0x3f388cdc8b807c97, 0x3b94875acc7c06a0, 0x3f3b325a11c1f45a, 0xbf3381548f692740, 0x3f12b1fd05559bfa, 0x3ef1ed31cd6feb26, 0xbef29cf593fdf00a, 0x3ed1cea99b59228c, 0x3eaceff221e3598a, 0xbeab0ad4b899b2d9, 0x3e83761b047e21d1, 0x3e696c31c2256049, 0xbe60a714c57f7adf ],\n", "[ 0x3feffd9f78c7524a, 0x3c804ed6ff98e45d, 0x3f5a024365f771bd, 0x3bf3c8f5202cb405, 0xbf70a9732d5284dd, 0xbc11acbd0899ce7e, 0x3f7a4bf47a43042a, 0x3c0e6cb2580d0920, 0xbf7c23802d8a5bb7, 0xbbd9963700abfc80, 0x3f74f40070668329, 0xbc1e1fe1c0e1182a, 0xbf64c9a2c9dccd04, 0x3c080fb9c9cd78c1, 0x3f44f7a50b5bc019, 0xbbd40906b7a1de3a, 0x3f218b04eb90c737, 0xbf2a4c3880c0ea69, 0x3f14b7b82a86f423, 0xbed0bc762b1c2aaa, 0xbee589d6f8892acf, 0x3ed357ab63f7bdf9, 0xbe96675858bbff5e, 0xbe9ea96dcb12a15c, 0x3e88c572fcf5610e, 0xbe3700c93da86dee, 0x3e57ae9ceb75e26e ],\n", "[ 0x3feffed167b12ac2, 0xbc8ddc0ce3ed8fcb, 0x3f4afc85e0f82e12, 0x3bd438f22895e03e, 0xbf6221a9f326bef4, 0xbbf99642b37af330, 0x3f6e3c9aab90bcf4, 0x3bb7dcdfdccc72a0, 0xbf714b1b98141f21, 0x3c1af6edf50eba66, 0x3f6c1c19b9e63d70, 0x3bd4d1e9411f1d28, 0xbf5feac3dbeb5124, 0x3be2400e6ffbc1c8, 0x3f463e88178b0e49, 0x3be3e4ae97774f91, 0xbf04441c86c93f39, 0xbf1c8ceebc5fc50b, 0x3f1125b77a79aa6c, 0xbeeda7be990bc718, 0xbece019960474aff, 0x3ecd229185ef6279, 0xbeacea9fa10885e7, 0xbe8044fd6a2e447a, 0x3e83695f88fc641d, 0xbe60c0dc0ba0d589, 0xbe89194748828b93 ],\n", "[ 0x3fefff6dee89352e, 0x3c8b96c0ba13851d, 0x3f3b23a5a23e4210, 0x3bc727bce1be0014, 0xbf5315107613c673, 0xbbf823f8673f5b7a, 0x3f60c243329a9ca1, 0xbbf65e361cefe652, 0xbf64630116262084, 0xbc00ea6ee40daf79, 0x3f61e84d1022e8cb, 0xbbd9b77b85eed4f0, 0xbf56b41872716325, 0x3bd3e9e001100f64, 0x3f436edde582b265, 0xbbe1cb479a94e148, 0xbf1f7870ebc38e77, 0xbf051ecfdc37801d, 0x3f0711d817e0d3b6, 0xbef0ae90d500d1d8, 0x3eaa85b1bf54920c, 0x3ebfe73958205038, 0xbead222bfef33aa4, 0x3e7833f8b13b1a4e, 0x3e7233b5a19285db, 0xbe61adcf574b7db6, 0x3e7ab10bedc44532 ],\n", "[ 0x3fefffbb8f1049c6, 0x3c7d2c6266b51f26, 0x3f2a740684026555, 0xbba7e24cc3ac5710, 0xbf436d34c8f1c26a, 0xbbe69d73e7d1c977, 0x3f51eb6e14974a25, 0xbbf99b78600e0664, 0xbf5714eb8cc0947f, 0x3bf3613f37c7410b, 0x3f55bec08c01b1d7, 0xbbf3e3a262f6c68a, 0xbf4e4621d82dad12, 0x3bc302878843e2cc, 0x3f3e1b7b564b0e79, 0x3bcf894fc1f14d54, 0xbf224564b69716aa, 0x3ebbf8e3b47f3ccd, 0x3ef8f55a9be1a264, 0xbeeb3b76e6203281, 0x3ec713c795a07e0c, 0x3ea3bb092cfd93e0, 0xbea473b0a8333dee, 0x3e8645526869c143, 0x3e41a343e004b33d, 0xbe576c7e253faad1, 0x3e7e16080963cffe ],\n", "[ 0x3fefffe0e0140857, 0xbc66aa36f86c14dc, 0x3f18fdc1b2dcf7b9, 0x3b87050f50b8f308, 0xbf3322484cf12daa, 0x3bd4cc0408806d4f, 0x3f427dc1bc6cfef5, 0x3beffbb5229f6bb7, 0xbf49202f465eb421, 0x3ba8f3f063b40660, 0x3f493b4c9746835f, 0xbbe04e2d6df2fce5, 0xbf430e9e6142fe9b, 0xbbd0396045094744, 0x3f3555b9d5fb4825, 0x3bd9a40d2ca5ef0b, 0xbf2055983c4ac7a6, 0x3ef68e6c75a5d068, 0x3ee2d4a50d2757ce, 0xbee1de08b56479aa, 0x3ec9110ccc7fe6fd, 0xbe8bb3184d789af8, 0xbe94629a164e82a0, 0x3e8413b087ee5e4d, 0xbe5648d7786f9fbc, 0xbe4293289f8c327d, 0xbe6c283008e726f7 ],\n", "[ 0x3feffff2436a21dc, 0xbc83607959a29d36, 0x3f06e2367dc27f95, 0x3b6d96e6f0151020, 0xbf223c436c36fdab, 0x3bbf0d77fc600a50, 0x3f326bf00867a835, 0xbbdc92e1aecdc750, 0xbf3a51fb50b15f22, 0x3ba248227c6d2260, 0x3f3c0825378fda08, 0x3bd5a8a09c053451, 0xbf36c3dbfe0cbe4a, 0xbbde65769c33f8a1, 0x3f2c1dd1438378df, 0x3ba91bd161f34158, 0xbf194c36a9d7c0dc, 0x3efbf0aab116ca41, 0x3e86bdbd2f103930, 0xbed2b32e8d43ef25, 0x3ec3a7403459770b, 0xbea17411873320fa, 0xbe735bb2691c9b29, 0x3e798313537ed069, 0xbe5cb4b60e85a341, 0x3e02be214cf4c9eb, 0xbe8350a1a851865a ],\n", "[ 0x3feffffa1de8c582, 0x3c8832540129302a, 0x3ef44f21e49054f2, 0x3b8f338cf4086346, 0xbf10d18811478659, 0x3bb914a7a08b6a2b, 0x3f21b964d438f622, 0x3bca52c94c56aaaf, 0xbf2a8d7851f26bf0, 0x3bcc38dbf3ee1223, 0x3f2ddd6df9b6852d, 0xbbc3b0dd7eac9b91, 0xbf29e52b7aac1644, 0x3bc904036dfb5764, 0x3f2165b2034fcab2, 0x3bc27beac4bf3866, 0xbf11b75c3332673a, 0x3ef91a253c42f4e7, 0xbed020b498095051, 0xbebade63f30809ae, 0x3eb89bb0d75e59b7, 0xbea180c78d3dca28, 0x3e6cabfd39b38553, 0x3e66013ffba86cfd, 0xbe564f2b123e1f0b, 0x3e335bf3e5021105, 0xbe8177828ffd35af ],\n", "[ 0x3feffffd8e1a2f22, 0xbc8c10adf6b19989, 0x3ee1783ceac28910, 0xbb87f19d8ee58337, 0xbefe06a8b37e5b93, 0x3b824e8db1358f2e, 0x3f107978c7b8496b, 0x3bbf163b5580927c, 0xbf19d039884f8be5, 0x3bbfce53cd30b1eb, 0x3f1e8d1145e94a54, 0xbbbd0f6e009a99ee, 0xbf1c1f7251172a87, 0xbb83ce0f013dfe90, 0x3f1458b9e0854d68, 0xbbb897cf3950b1a7, 0xbf06eb0557245429, 0x3ef33045cf65279e, 0xbed42c8adf18ab62, 0x3e491109b80f9918, 0x3ea83a9b44249fbf, 0xbe99bcbaf0a8dfd1, 0x3e7900325b58a857, 0x3e34a3cf9c161684, 0xbe50cbcc4d0a916a, 0x3e34275e1b91f084, 0x3e839180c75350e1 ],\n", "[ 0x3fefffff039f9e8f, 0xbc89d1bcd6174e99, 0x3ecd21397ead99cb, 0xbb46abd9c029c47c, 0xbee9f19734d29cf9, 0x3b820c4383da36c1, 0x3efd982bd41d8954, 0x3b8d9bc9988e9666, 0xbf08320fc4836be5, 0x3b7526638b9926a8, 0x3f0e0a1cb1d071f3, 0x3b9d9f5d232bab90, 0xbf0d384223047b9c, 0xbba30d0b2b8a170d, 0x3f0696daf6422bd4, 0x3baba6ac732f399e, 0xbefbb6e2d311a93f, 0x3eea4fcb0ea87efb, 0xbed1c940c5303daf, 0x3ea7469913f4e9c6, 0x3e8ef4b4f8ab67ae, 0xbe8e189c28e8e041, 0x3e7678b281d5bc55, 0xbe49c3bf4e9f2b5d, 0xbe374c9ba997ffed, 0x3e2b4b843f8c7068, 0x3e6c901764507862 ],\n", "[ 0x3fefffff9d446ccc, 0xbc6bb06bab98bc80, 0x3eb789fb715aae95, 0xbaf226d93bf89b40, 0xbed5b333cc7f98f1, 0xbb76bd1091d25440, 0x3ee9b12fdbf90f62, 0x3b8d4b6b0ee9cf46, 0xbef5e06923144d70, 0x3b4c593194857860, 0x3efc6a071925631d, 0xbb8835ef595952e4, 0xbefd178cb0388a82, 0xbb9039272760f01c, 0x3ef7e29d33ac92b6, 0x3b921ff8b0e9d5eb, 0xbeef9203429baad6, 0x3ee094dadeee395c, 0xbeca771cf3500d9f, 0x3eab8fd1c29c21ea, 0xbe5cc8573d7de110, 0xbe7b0362da1722cb, 0x3e6e5eae518f94e9, 0xbe507963addd99a6, 0xbe23f496093d0bef, 0x3e199078a326092d, 0x3e842681ecfe4da1 ],\n", "[ 0x3fefffffda86faa9, 0xbc7d230252d68f26, 0x3ea26f9df8519bd7, 0xbb4e339871c015b7, 0xbec1926290adc888, 0xbb6e36d23dbb2644, 0x3ed5900c02d97304, 0x3b7fa7d21e3ed616, 0xbee3166de6a8c640, 0x3b8b014157867958, 0x3ee9dfcc328729e0, 0x3b820e9fee0b7665, 0xbeebcab1ed5ec38d, 0x3b6d9003794f0fe0, 0x3ee81cd74a57ce17, 0xbb8809fde9c0f6f5, 0xbee106e95b6bf556, 0x3ed379625a71385f, 0xbec1970a5b5bd443, 0x3ea74761c8333ff2, 0xbe80864e125c9951, 0xbe5b83bf9019aa3b, 0x3e60397611c35b28, 0xbe4a25392adb29ac, 0xbe17b832af40d9d4, 0x3df62a02eb79577b, 0x3e8a6da58ffe94f4 ],\n", "[ 0x3feffffff233ee1d, 0x3c8db123ed17221d, 0x3e8bfd7555a3bd68, 0x3b20151cf177b53a, 0xbeab8d7f804d2e73, 0x3b482b366f0bc2dc, 0x3ec17f93e5149289, 0x3b391997bfd26568, 0xbed013b0457d08fa, 0xbb60d6d5a7f06298, 0x3ed6b245d7e1d829, 0xbb79985e02c8ce3b, 0xbed98077548c6951, 0x3b701cd3f1d12c93, 0x3ed7492048ab3ceb, 0xbb70368a0dc0750e, 0xbed17506c7b39cb0, 0x3ec57e94a4c5f5a6, 0xbeb570971200d7db, 0x3ea0a0f956947b21, 0xbe81a9b7bd5bba32, 0x3e451bfc00de3146, 0x3e495b6967f79cbe, 0xbe3fe3c43cb3cf84, 0x3e32f364a7a2dc5f, 0xbdf007442a10cc14, 0xbe7ef5ab6fc5e849 ],\n", "[ 0x3feffffffb127525, 0x3c8504f382db4102, 0x3e74980cb3c80949, 0x3b17fbdd923f8057, 0xbe94ea6ce697296f, 0x3b3ea42f9c9de533, 0x3eab771d9b6f07b8, 0xbb1e9c1ca9662fe8, 0xbeba26c653fad5b8, 0xbb5146c4cee0e898, 0x3ec3302bb89379de, 0x3b64c55b83ef7a68, 0xbec67f42e5264334, 0xbb66779da26b4197, 0x3ec58b4adafb958e, 0x3b68351251b45e84, 0xbec10f576796285a, 0x3eb66ca44250dd07, 0xbea84ee0ada37543, 0x3e953b6065291e6b, 0xbe7c09ebfd0c581c, 0x3e563062625d59c0, 0x3e1e259c60eb7b83, 0xbe2e43802ad25514, 0x3e351bcdabe8cda5, 0xbdf930fc3df6e909, 0xbe881cdd770e1c81 ],\n", "[ 0x3feffffffe4aed5e, 0x3c4389c0f32ad0f0, 0x3e5d5f3a8dea7357, 0x3affa07c18622dd2, 0xbe7ebfb14c9170c0, 0x3b19e40632b4145d, 0x3e94d9228525f449, 0x3b2d35bd7f959136, 0xbea48b536addac5f, 0xbb461ace22b32569, 0x3eaf48ccf23a68e2, 0xbb4ee1d13c79c281, 0xbeb3183b6134cf03, 0x3b4e1f4d5fe2a06c, 0x3eb31efde2215f01, 0xbb564a7021e23fba, 0xbeafd9eeb0f18fdb, 0x3ea63414459ae298, 0xbe99dda81be20b5a, 0x3e88da7d306423c5, 0xbe7303da86a4fc28, 0x3e54f5e1327706b9, 0xbe23efb5eefcbe53, 0xbe131bc5ce1ce65d, 0xbe13eafe1b05c93f, 0xbdf47fc2d9cc851e, 0x3e7d27265006a9df ],\n", "[ 0x3fefffffff6d1e56, 0xbc864d969b4be4c4, 0x3e444d26de513197, 0x3ae76fc20fc4b365, 0xbe65e32de7af8977, 0xbaf888fd6ae18a1c, 0x3e7e9e05b3c8f38a, 0x3b17532141b12aa7, 0xbe8f2f6fa7db5b1d, 0x3b2b3bf498e3462c, 0x3e9899dcace485eb, 0x3b11885a0ae9e878, 0xbe9f34b7eef3c9b2, 0x3b3294a3b618b470, 0x3ea04be030272d14, 0xbb4df83095e40f79, 0xbe9c73bd22571559, 0x3e94edda838439f5, 0xbe89fc860b504677, 0x3e7b0d686a260420, 0xbe672370c2fdbe10, 0x3e4ee29f0d197d25, 0xbe2b4d88d500c5be, 0x3dc96014c45b0178, 0x3e0238f19dc8fd82, 0xbde8d34d46ae6567, 0xbe454105fe4a9cd8 ],\n", "[ 0x3fefffffffd01f89, 0xbc735e8e39884f62, 0x3e2b334fac4b9f99, 0x3ac32178ed1a4971, 0xbe4e2cec6323e50e, 0xbac0e5693f9d4908, 0x3e65c027d5bba36a, 0xbaefc46fb3cc7ae0, 0xbe76df4d024fffbe, 0xbb090fd7226ec57a, 0x3e82aaf7c205b9ea, 0x3b2dbec2005b45a8, 0xbe88902edfbfefdd, 0xbb2c353aca58d08a, 0x3e8ab2ab1b338249, 0x3b2b498186c39105, 0xbe885abe0ff198d3, 0x3e82d32f7c3621eb, 0xbe78c141c71dbc95, 0x3e6b9fa6fbb9b198, 0xbe59db5fe2c2f5b9, 0x3e43b8e07840483e, 0xbe26d95e5070d91d, 0x3dfd7616168b0e49, 0x3e1f2be0744b3a5f, 0xbdd737a375809985, 0xbe7936d4936fb865 ],\n", "[ 0x3feffffffff0dd2b, 0x3c80df73e7d2fc98, 0x3e11a94ff571654f, 0x3abfbf537b47967d, 0xbe34251f33f5578f, 0x3ad4c9cece8f41b2, 0x3e4de6bc1f75bb9b, 0x3a894afb459a3000, 0xbe6036b5fd1c4158, 0xbb0d582afa097896, 0x3e6b58f1385def96, 0xbaf8778854601996, 0xbe72a2347efb2133, 0xbb026f9e1ef0f378, 0x3e7508db866ffe00, 0x3b164de561a68a21, 0xbe73ffea934685b9, 0x3e702ff87b2e2576, 0xbe666e54eae5fa4b, 0x3e5a9ea2195c567d, 0xbe4ae3b91fecafa1, 0x3e36bb883d2e5ed1, 0xbe1ee10e97715c11, 0x3dfe2873d2b77f1f, 0xbdeaf385ae29d57b, 0xbdbd793eecfc2513, 0x3e420d80dcfa68d1 ],\n", "[ 0x3feffffffffb5be5, 0xbc7729d6819c7f34, 0x3df63ac6b4edc88e, 0xba7c45991835da24, 0xbe1a0ce0dc06a706, 0xbab1b72d11da9dab, 0x3e33e380dd7593a5, 0xbad8ad868a7b5674, 0xbe4638bc4fb02cba, 0x3a87a84506fcda40, 0x3e535753ad4c5875, 0x3aead190ab170366, 0xbe5b41f33cafccba, 0x3af0e3539bf61116, 0x3e5fe694e371a659, 0xbad3a84e01866ea8, 0xbe5f8af0121aa0ab, 0x3e5aa77274dab3d8, 0xbe53616fe8f6a259, 0x3e484fddf4c681a1, 0xbe3a3de05d1b8a31, 0x3e2822529aca9f83, 0xbe126c3dfba84378, 0x3df64c287a84aa09, 0xbe0107d2dac5d83b, 0xbd4e251d1ab1d873, 0x3e58f37005f17b42 ],\n", "[ 0x3feffffffffe9eb0, 0xbc5ea527e0bef1e8, 0x3ddb1e5acf351d87, 0x3a5dc96583ba19f0, 0xbe005042a0a5f3c3, 0xbaa2023f0f13867c, 0x3e199ac8fd63c66c, 0xbaabf57c5fd0501a, 0xbe2d72344378e114, 0x3acc77758959af41, 0x3e3a6be9a123435b, 0x3acdab4af8807c36, 0xbe433aacb4bf6dea, 0x3aebd241ea49ac35, 0x3e474b732e7ceaa7, 0x3adc7c89730b0264, 0xbe47e7eab6531ccb, 0x3e450959f2daae39, 0xbe3ffed4cef94261, 0x3e351c7f99f908a2, 0xbe282b5fd5fbedfc, 0x3e17e1c8e715c978, 0xbe051536822c861b, 0x3debe7e4c220ca82, 0x3e2f5bb67c461296, 0x3da1d7cf04529bf0, 0xbe8acc021ab828c4 ],\n", "[ 0x3fefffffffff9a1b, 0xbc66a87270d2450c, 0x3dc0084ff125639d, 0xba58ad61debedc86, 0xbde3ca42adaa26f6, 0x3a8c20c6583dccdd, 0x3dffe73513c67bf8, 0x3a920d28c0c7e686, 0xbe12dd9aa5a2bee3, 0x3aad76d7235461be, 0x3e216ef6b93944a8, 0xbacf07bd785566de, 0xbe2a2d58e9b22b26, 0xbab19e6ea91dd55e, 0x3e306389b9748f25, 0x3adfbcc52565c0be, 0xbe316cdd9eb58ba2, 0x3e2fdd861b55c500, 0xbe29457846c943d2, 0x3e2178f3905f435c, 0xbe1518cf20c53de2, 0x3e06329939a34b66, 0xbdf5ef3ad85e5d3b, 0x3ddf2b41494e49e9, 0x3e2bad43bc0b622d, 0x3da21a45fa9dcebf, 0xbe8790b3d88f69fe ],\n", "[ 0x3fefffffffffe380, 0x3c87ce07114e4fe0, 0x3da25f9ee0b923dc, 0xba4174c43a73a4d1, 0xbdc74105146a5162, 0xba47d0740e56625c, 0x3de33cde4f35d941, 0xba72a344950797c6, 0xbdf760fe7b666392, 0x3a9a8b77c82ed644, 0x3e063a70fd66d485, 0x3aa6b87715649d6d, 0xbe11324f6fb6dfa1, 0x3ab3fc045e39915f, 0x3e163a31a36b815c, 0xba502dec9bc1a700, 0xbe18724ca8970b91, 0x3e172e290891e5de, 0xbe131fc03858aab1, 0x3e0b9e8b0e7fa253, 0xbe01821a002637bd, 0x3df37ba5f3fba5eb, 0xbde3578bf23dc654, 0x3dcfdaf2015d7b54, 0x3df7f6a435069067, 0x3d99d14ee557ec62, 0xbe555f4c743ee571 ],\n", "[ 0x3feffffffffff845, 0x3c7b0edc5a89ab8e, 0x3d846897d4b69fc6, 0x3a2a74852415bb49, 0xbdaa77a4e7dcd735, 0xba434edb43ab7de6, 0x3dc67543695dcc12, 0xba329ae577004af8, 0xbddc05c1e2fc710e, 0x3a5dbbf42d2537a8, 0x3deb639419fedf8e, 0xba8ed72eb9e7a59e, 0xbdf5cfd7eb9bfe87, 0xba7e97db27125fc0, 0x3dfd11578959ba45, 0xba8c0635ac2b5768, 0xbe0082f9e9f7eb37, 0x3e00354ceadad8b3, 0xbdfbc2dee0154fc6, 0x3df4e11efdc66eae, 0xbdebb357c0253f64, 0x3de035f9889bc29c, 0xbdc8e7bdb10b7441, 0x3dbe364571102661, 0xbe212cffcf49a2e8, 0x3d8ee9362bcfec26, 0x3e7cc5b58dd85301 ],\n", "[ 0x3feffffffffffdf8, 0xbc8dcf8b10ff973b, 0x3d65f8b87a31bd85, 0x39d65b265455b658, 0xbd8d2e55024a0fb5, 0x3a2444e1d84cea02, 0x3da9612cc225df4b, 0xba4c784edb664ce7, 0xbdc03ee5f38b9b4d, 0xba691ca8efa41a30, 0x3dd04f2f71e2e96b, 0xba633f36a4e51350, 0xbddab7099f99ced9, 0xba54af7a67f2110c, 0x3de2554b8f609fd1, 0xba729e641eb44218, 0xbde57c87529ca968, 0x3de5cd182c967671, 0xbde3580a2517d57a, 0x3dde3be72b1be982, 0xbdd4e9908689ad08, 0x3dc9a61979d3395b, 0xbdb7b826aadd1c89, 0x3daad3a9fc4a0d1e, 0xbe00e9325ed20970, 0x3d80722198ff452c, 0x3e5c2ef85611aa11 ],\n", "[ 0x3fefffffffffff7b, 0x3c800fa07f7fb612, 0x3d46ed2f2515e933, 0x39d2bc1802a42b92, 0xbd6f2a6c1669c901, 0xba07b3e174cc1840, 0x3d8bc42ba38a13f8, 0x3a2460463d59d3df, 0xbda2391e135afae4, 0xba3bd08c8c5f7b18, 0x3db2c6c24550f64f, 0xba3fdc861a487110, 0xbdbf9a3c1b0d63ec, 0xba5843dc8d9ad3d5, 0x3dc6502546ab341a, 0x3a645f812e48eb98, 0xbdcaf223186006d1, 0x3dcc388dd1764f41, 0xbdc9e65a242b52aa, 0x3dc4fcd2787781eb, 0xbdbe3cbdb20a48d6, 0x3db35639e9fcd410, 0xbd55b8e97774b2c9, 0x3d966ffe6a100bc9, 0xbe15706c390c113e, 0x3d6ff0d11cf61949, 0x3e72054de347e3f8 ],\n", "[ 0x3fefffffffffffdf, 0x3c75669e670f914c, 0x3d272fd93e036cdc, 0x39b1c553d12fbbd0, 0xbd501f450d1e61b2, 0x39cbed807e60c078, 0x3d6d68fb81b2ed89, 0x39dc7ea3c4444cc0, 0xbd83c706aa4d2328, 0x3a2d6d2d51dd414d, 0x3d94e6479565838e, 0x3a350580f36c14c1, 0xbda20e9eb83b3dd9, 0xba104b6334a32fd0, 0x3daa35b9d2fcac80, 0x3a1c07c6978bf2f0, 0xbdb04a134f6e3dcb, 0x3db196579f27ddbe, 0xbdb0ab97aa74c700, 0x3dabf68355f542b1, 0xbda49da25a547134, 0x3d9bd64993a3958e, 0xbdc1193990186399, 0x3d81c0e98335ae18, 0x3e2e08edb685494a, 0x3d5cb9fcc058465b, 0xbe894cacccfb8964 ],\n", "[ 0x3feffffffffffff8, 0x3c70160ef15c497e, 0x3d06ba91ac734786, 0xb9af81d6fa69b5b2, 0xbd3028a39099f4db, 0xb9c83ed68de15404, 0x3d4e292863e1795e, 0xb9db292e812abb68, 0xbd64c4e690fbdd14, 0xba080991e1d4ef25, 0x3d767e6e5ac60fd1, 0x3a01d2ca68dcf0e8, 0xbd83f00d80afa00c, 0xba23e174dc7225ac, 0x3d8db88ee63eb28a, 0x3a28abd97527892f, 0xbd92fe58a1f19368, 0x3d951dbeae22a5c8, 0xbd94a4d54823e0fc, 0x3d91e432d674cfba, 0xbd8b001e26c6e764, 0x3d8328ce695259fe, 0xbdb4e492cf7d4f4c, 0x3d6aaa77d339dc00, 0x3e2366538db382e5, 0x3d4826ad7d581503, 0xbe8056e0810b14da ],\n", "[ 0x3feffffffffffffe, 0x3c759ab24e589a30, 0x3ce5982008db1304, 0xb981cf9bda64b38a, 0xbd0f610e8cde57ac, 0xb99884dcd86f98c8, 0x3d2df2dac2f2d47f, 0xb997f27bf279d988, 0xbd451b17f95fc0b4, 0xb9e063e04485c3e7, 0x3d576996ddc975d7, 0xb9e21489d6648428, 0xbd6546155a972b18, 0xb9b9d3fb518aa7c0, 0x3d70456ed89c4f24, 0x3a1eee772fc32c5e, 0xbd755d6295aa388a, 0x3d786ead99977388, 0xbd789b3d387efa6e, 0x3d76011e175e64f8, 0xbd70cd70515af47b, 0x3d69402199dfdde7, 0xbda806743bc32b08, 0x3d530e561550364a, 0x3e170093985e2c1b, 0x3d331999a27ace63, 0xbe735f54db0f4dbc ],\n", "[ 0x3ff0000000000000, 0xbc8a6d7d18831888, 0x3cc3e296303b2297, 0x39668cf648cfed1c, 0xbced8456ef97c744, 0x398fcded17005500, 0x3d0ccb92e6c24c8d, 0xb9aa704dc202cff2, 0xbd24c1aa8cf1229b, 0x39c652efa61e4ec2, 0x3d37918b6b83c0fb, 0x39b2fb01fb8836dc, 0xbd45f073659de44d, 0xb9e9ceb48a2d1931, 0x3d5134d070b5921e, 0x39d9af3038fcc184, 0xbd5730a2938c09dd, 0x3d5b4091041f5905, 0xbd5c3c44ab8c8421, 0x3d5a06b4f4c3044d, 0xbd5704f511555fe7, 0x3d4fe51fcfc1acba, 0x3d95e7229a07e7cd, 0x3d39f8121f6c3146, 0xbe0692b2f9b3f445, 0x3d1c8c34f73d3823, 0x3e6301e540260d52 ],\n" ] } ], "source": [ "import struct\n", "# ERF double C2\n", "\n", "data = \"\"\"\n", " {0x1.ac45e37fe2526p-3, 0x1.48d48536c61e3p-57, 0x1.16e2d7093cd8cp+0, 0x1.979a52f906b4dp-54, -0x1.a254428ddb453p-3, 0x1.9c98838a77aeap-57, -0x1.59b3da8e1e176p-2, -0x1.1f650c25d97bp-59, 0x1.988648fe88219p-4, -0x1.5aecf0c7bb6c1p-58, 0x1.803427310d199p-4, -0x1.a14576e703eb2p-58, -0x1.09e7bce5592c9p-5, 0x1.eb7c7f3e76998p-60, -0x1.516b205318414p-6, -0x1.941aa998b1fa4p-61, 0x1.038d3f3a16b57p-7, 0x1.e19d52695ad59p-9, -0x1.9542e7ed01428p-10, -0x1.1f9b6e46418dcp-11, 0x1.0796a08a400f4p-12, 0x1.2610d97c70323p-14, -0x1.25d31d73f96d1p-15, -0x1.05e1fa9e02f11p-17, 0x1.1e616f979139cp-18, 0x1.9b3d54f1f222ap-21, -0x1.7ad96beea439ap-22}, /* i=1 108.83 */\n", " {0x1.5da9f415ff23fp-2, -0x1.a72e51e19195p-59, 0x1.05fd3ecbec298p+0, -0x1.f17d49717adf8p-54, -0x1.477c8e7ee733dp-2, -0x1.92236432236b7p-56, -0x1.1917b60acab73p-2, 0x1.c06e6c21b4b3bp-56, 0x1.322a728d4ed12p-3, 0x1.ffa8aef32141p-60, 0x1.04c50a9cd2c12p-4, -0x1.edd0562dce396p-59, -0x1.7ce764eeddd86p-5, 0x1.9afeb391c029cp-61, -0x1.68aac5801171dp-7, 0x1.4f9655411fc03p-61, 0x1.62aa895f51cd3p-7, 0x1.6c003c3cedb1p-10, -0x1.079502dbbafffp-9, -0x1.d9c7cbb799b47p-14, 0x1.45a995aede3f4p-12, 0x1.0c04ea8c98fc9p-20, -0x1.57edfa53128dp-15, 0x1.a96286bf3ef56p-20, 0x1.3c8ab12e6d24bp-18, -0x1.7454eba0cb203p-22, -0x1.f02a6f6847617p-23}, /* i=2 107.115 */\n", " {0x1.db081ce6e2a48p-2, -0x1.7ff0a3296d9cbp-56, 0x1.dd167c4cf9d2ap-1, 0x1.44f2832f90a97p-55, -0x1.a173acc35a985p-2, -0x1.c5432c9a2274p-60, -0x1.889a80f4ad955p-3, -0x1.f6123bf467942p-57, 0x1.6c2eea0d17b39p-3, -0x1.1f4935c3cf5b1p-57, 0x1.b0645438e5d17p-6, 0x1.7a5f08ebaf9dp-60, -0x1.a3fd9fcbb6d6dp-5, 0x1.94a1b58b5916fp-59, 0x1.060b78c935b8ep-13, 0x1.9cec375875a1cp-68, 0x1.678b51a9c4b0ap-7, -0x1.1e03bfc8eebb4p-10, -0x1.e653535cab33fp-10, 0x1.55f31366d2c5cp-12, 0x1.0dcf1445cbb88p-12, -0x1.098913ad4dcc7p-14, -0x1.f6e252329eeedp-16, 0x1.41ad0a5afe51dp-17, 0x1.8fd4609222f1cp-19, -0x1.4465926de1a35p-20, -0x1.407a1f42b46d4p-21}, /* i=3 107.489 */\n", " {0x1.25b8a88b6dd7fp-1, 0x1.9534a3b5bd215p-55, 0x1.a5074e215762p-1, 0x1.fad8c0ef6fae6p-56, -0x1.d9a837e5824e4p-2, -0x1.1d19ec86adc7cp-56, -0x1.9c41d1d5fae55p-4, 0x1.74c230d6afba4p-60, 0x1.75bebc1b18d1cp-3, 0x1.01ece95d4dffcp-58, -0x1.6410ad9332666p-7, -0x1.16523d167a40cp-61, -0x1.7df8890b11fa7p-5, 0x1.d6a99d1387564p-59, 0x1.4a54816d3608ap-7, -0x1.f810ad06699ccp-61, 0x1.18f36eb18f3d7p-7, -0x1.8d661c030e174p-9, -0x1.3628ede23e249p-10, 0x1.438eb2b3c4d27p-11, 0x1.fd3c13e725e91p-14, -0x1.991b866a32c87p-14, -0x1.1237c600dab6fp-17, 0x1.a9c701140d4cp-17, 0x1.1801e61adfddap-24, -0x1.785516863e6cep-20, -0x1.3e033ef590125p-23}, /* i=4 107.484 */\n", " {0x1.569243d2b3a9bp-1, 0x1.8eef7012e8df4p-56, 0x1.681ff24b4ab04p-1, -0x1.dba6493354c7p-58, -0x1.ef2bed2786b25p-2, -0x1.ae3f6b6b2b679p-56, -0x1.a4254557d722fp-7, -0x1.0ff7bffd10053p-61, 0x1.532415c267962p-3, 0x1.2eacc4bd2e841p-57, -0x1.558b4c55a835cp-5, 0x1.c21c40815d70ap-60, -0x1.1b7ad5b777f1bp-5, -0x1.2115b2bd8d644p-59, 0x1.1201d3bd0e758p-6, -0x1.b39b84544256p-63, 0x1.2995e3a88a89p-8, -0x1.0294c3e93cdbp-8, -0x1.159644a564f83p-12, 0x1.63daf9b3858efp-11, -0x1.3beeb4a1255acp-15, -0x1.80c5178c36c72p-14, 0x1.d4f6f5bab7dfap-17, 0x1.521deb6d2f46ep-17, -0x1.4ef3208231a8bp-19, -0x1.e7d2b4e06e4a2p-21, 0x1.21536d5b8bdf9p-22}, /* i=5 107.637 */\n", " {0x1.7fb9bfaed8078p-1, 0x1.66cf14bcad032p-56, 0x1.2a8dcede3673bp-1, -0x1.7378e2c70325ep-56, -0x1.e5267029187cp-2, 0x1.add23841b110ap-56, 0x1.fe0796bb9d05ap-5, -0x1.7a992e13ce574p-60, 0x1.0fa23021ad0acp-3, -0x1.17f4228359928p-59, -0x1.fa21ebca76761p-5, 0x1.278ca2820f66cp-60, -0x1.31546d5c4edb4p-6, 0x1.36fcf151892ap-62, 0x1.37e5469efb7a6p-6, -0x1.9553630321d4fp-60, 0x1.097966e2e87eap-13, -0x1.e82ab020887a7p-9, 0x1.318270c11ae74p-11, 0x1.12652e433da97p-11, -0x1.4dc9bd6368bb8p-13, -0x1.c441138d4ff53p-15, 0x1.c91d8dc5b66ecp-16, 0x1.f3ba57b86d474p-19, -0x1.dd3403d11a818p-19, -0x1.31f497a106a7cp-24, 0x1.436dbcc93d342p-22}, /* i=6 108.888 */\n", " {0x1.a1551a16aaeafp-1, 0x1.a558a46df5f68p-57, 0x1.dfca26f5bbf88p-2, -0x1.ddcbaf85587b6p-57, -0x1.c1cd84866038fp-2, -0x1.200885b97f453p-56, 0x1.e4c9975da0987p-4, -0x1.f162e7576c79cp-58, 0x1.747e31bf47af3p-4, -0x1.6178f12d62ed9p-58, -0x1.1d1f00109e42ap-4, 0x1.002b06e023544p-58, -0x1.47654175ceb42p-9, 0x1.683389ccacfa8p-66, 0x1.1a817c594b8cbp-6, 0x1.36ac477166efbp-60, -0x1.cb8acd699cca6p-9, -0x1.57b72bf874db6p-9, 0x1.24493dca8b6fap-10, 0x1.f556774c6aaf6p-13, -0x1.b09ec5c8ba626p-13, -0x1.09bd1a09f38e8p-18, 0x1.d149c3e776976p-16, -0x1.8f7c2a6575e92p-19, -0x1.8391d4afaf16ap-19, 0x1.5a7552081d1d5p-21, 0x1.32d1bb2d1d0cap-22}, /* i=7 109.125 */\n", " {0x1.bbef0fbde6221p-1, -0x1.322c1148e0d48p-55, 0x1.75a91a7f4d2edp-2, 0x1.6eb826a9df85cp-58, -0x1.8d03ac274201cp-2, 0x1.7a5c56eb7f6ap-58, 0x1.3954778d6a0dfp-3, -0x1.863eca74d1838p-58, 0x1.88e0f7b183fc6p-5, 0x1.226527d05ce39p-59, -0x1.0f7c15f75ee13p-4, -0x1.56f74f351366p-62, 0x1.5e22cfa1aab51p-7, 0x1.4b49a250c6474p-61, 0x1.9ad28c5557c22p-7, 0x1.99920b730ecd5p-61, -0x1.704ec5d29fc83p-8, -0x1.23360304f19bap-10, 0x1.43ca3fcdf079dp-10, -0x1.dcb97a9e04bd4p-15, -0x1.735e26c43d267p-13, 0x1.360c3b06ffbb4p-15, 0x1.29a6b5798e781p-16, -0x1.dbc35e4cf98f5p-18, -0x1.2f6e8e81287bbp-20, 0x1.eeb2fdddad355p-21, 0x1.1ae65e387ac52p-23}, /* i=8 108.742 */\n", " {0x1.d0580b2cfd249p-1, 0x1.4fca6318dfee9p-55, 0x1.1a0dc51a9934dp-2, -0x1.ca89d2d78fba4p-57, -0x1.4ef05a0f95eebp-2, -0x1.5f7c55a00231cp-57, 0x1.5648b5dc47417p-3, -0x1.fb8fa09976e07p-57, 0x1.40fbaba44504cp-7, 0x1.435c75f61f1ep-64, -0x1.c0db89d0a41a4p-5, -0x1.1dd02d9441b98p-62, 0x1.388c3ec056942p-6, 0x1.8e7498172c914p-60, 0x1.aecb7463cf446p-8, -0x1.0d6701a009d7p-65, -0x1.8bca53327e075p-8, 0x1.4add4a8239f4ap-12, 0x1.05ce4abd10484p-10, -0x1.183f198a0b62p-12, -0x1.9cd1a9b9fc69bp-14, 0x1.d30363021af83p-15, 0x1.da66f2161c4c6p-19, -0x1.f41f1f238827dp-18, 0x1.725a07b1177b7p-21, 0x1.84c3b2483eb6ap-21, 0x1.e30e89d6e85cdp-25}, /* i=9 110.374 */\n", " {0x1.df85ea8db188ep-1, -0x1.f71e8254d11a9p-55, 0x1.9cb5bd549b111p-3, -0x1.973e73caa1edcp-59, -0x1.0ed7443f85c33p-2, -0x1.74bf040302ad8p-58, 0x1.5066cda84bba9p-3, 0x1.beb86d9e281a8p-59, -0x1.419fa10b6ed7dp-6, 0x1.5157491034c58p-60, -0x1.3f41761d5a941p-5, 0x1.94a1c1f7af153p-59, 0x1.6d1d724baaae4p-6, 0x1.c41090a704426p-60, 0x1.e377f5703f7ffp-11, -0x1.a753be0c53963p-65, -0x1.4cc916ad63c27p-8, 0x1.553ef0d12719fp-10, 0x1.26240f55987fdp-11, -0x1.6bbf0fffb7138p-12, -0x1.320cf6663c40dp-17, 0x1.a9d4850aaa197p-15, -0x1.17036c4011c91p-17, -0x1.441ea26a91a02p-18, 0x1.d81eb8e2ef452p-20, 0x1.17d7b798a4322p-22, -0x1.b7b0dfb2559dp-27}, /* i=10 110.102 */\n", " {0x1.ea7730ed0bbb9p-1, 0x1.2c5bd7ce1388bp-55, 0x1.24a7b84d38971p-3, 0x1.aa0c5e788ed5ep-57, -0x1.a4b118ef01593p-3, -0x1.238e3e6a99dep-60, 0x1.319c7a75f9187p-3, 0x1.a8f8fff24b0acp-59, -0x1.3db5bed47faf6p-5, 0x1.29cf699c8512cp-59, -0x1.7019bda6c2fddp-6, 0x1.dd56b84622d88p-62, 0x1.59d3aa402c32ep-6, -0x1.8de701f1e95e8p-63, -0x1.b324eab9c87a9p-9, -0x1.c3a4329771a44p-65, -0x1.b4774d37d0dd6p-9, 0x1.c01377485a844p-10, 0x1.a5db5f627539bp-14, -0x1.40d9c429b8932p-12, 0x1.e720d935ef7dbp-15, 0x1.fc8295ac052dep-16, -0x1.d1ccde95c6551p-17, -0x1.251c256ca45cbp-20, 0x1.e892cc5397b1bp-20, -0x1.8f6831febdf3dp-23, -0x1.aa5ef30a52421p-22}, /* i=11 108.586 */\n", " {0x1.f21c9f12f0677p-1, -0x1.7efe429672268p-58, 0x1.92470a61b6965p-4, 0x1.c6acd40cee352p-58, -0x1.3a47801c56a57p-3, -0x1.033705aa16f01p-57, 0x1.0453f90d3bd35p-3, -0x1.686e281ba5405p-57, -0x1.8a7c6a239217bp-5, 0x1.2a988808a7222p-60, -0x1.075c088031ee3p-7, -0x1.665bd0a645f4p-62, 0x1.16f9c9c127b8p-6, -0x1.e1813af47374cp-62, -0x1.74c2fc9bdfe97p-8, 0x1.5cf2dbe53783bp-62, -0x1.760c522bd5becp-10, 0x1.a3cdb656adb44p-10, -0x1.02c3c1ab0a7bap-12, -0x1.92892013c7e15p-13, 0x1.6e7b268d42034p-14, 0x1.970751eb9359fp-18, -0x1.b00b549bbdf58p-17, 0x1.033f8545bcc6ap-19, 0x1.2d8b6f0a2204ap-20, -0x1.c1c1335b105c5p-22, 0x1.61bbb2d003b8ap-25}, /* i=12 109.215 */\n", " {0x1.f74a6d9a38383p-1, 0x1.c33a329423946p-55, 0x1.0bf97e95f2a64p-4, -0x1.446051f6fef82p-58, -0x1.c435059d09788p-4, -0x1.b93aeb5e5cf84p-59, 0x1.a3687c1eaf1adp-4, 0x1.64513fb767a13p-58, -0x1.9647a30b16824p-5, -0x1.86357831221bep-59, 0x1.6981061dfbb09p-9, -0x1.ccc83193c8742p-64, 0x1.7e8755da4704p-7, -0x1.c1eaeb337149p-65, -0x1.9be731fdab95dp-8, -0x1.ab79fedbfccd2p-63, 0x1.3a95ae0a75542p-13, 0x1.319f780e962d8p-10, -0x1.b88dd51a4f261p-12, -0x1.037f168a8f581p-14, 0x1.53fc5e83e3199p-14, -0x1.9d5bf30917222p-17, -0x1.03045c999d17ap-17, 0x1.b5d376e96179fp-19, 0x1.c66d2e5aa2274p-23, -0x1.aef24a52bcacap-22, 0x1.b20b678e8a0c6p-24}, /* i=13 110.24 */\n", " {0x1.fab0dd89d1309p-1, -0x1.ae61bd9db1babp-55, 0x1.5a08e85af27ep-5, 0x1.e4f9cfc8c2382p-59, -0x1.399812926bc23p-4, -0x1.b782644df6665p-58, 0x1.4140efb719cbp-4, 0x1.08fa5a48311e8p-60, -0x1.7535a61a4193dp-5, 0x1.59e0501c376b2p-60, 0x1.374c88c7e6abdp-7, 0x1.c2578bd7e3fp-64, 0x1.a40709e010e77p-8, -0x1.18c33197d9138p-64, -0x1.6dc078888efa7p-8, 0x1.2b49da4c86c7p-63, 0x1.2ee6d200993bp-10, 0x1.44f175e22a161p-11, -0x1.c2fb051c92f92p-12, 0x1.523035ed3964bp-15, 0x1.bc7b666856fc1p-15, -0x1.574549f39ee5p-16, -0x1.c57f3c47b39d9p-20, 0x1.8acc76ac31fcdp-19, -0x1.f70e8b7deaa9ap-22, -0x1.e1a28a0c1a6a6p-23, 0x1.bfa0e5b606c5ep-25}, /* i=14 108.959 */\n", " {0x1.fcdacca0bfb73p-1, -0x1.2c33d88729e43p-55, 0x1.b1160991ff737p-6, -0x1.d940a504353bcp-61, -0x1.a38d59456f77dp-5, -0x1.d625808eb9778p-62, 0x1.d5bd91b6b0123p-5, 0x1.22b86f5e3e16cp-61, -0x1.3b35dcbc80146p-5, 0x1.82838d776d958p-59, 0x1.9d76b0a0535c7p-7, 0x1.60fda06bca0ap-61, 0x1.14c887a83a0e6p-9, 0x1.55ef222558d68p-65, -0x1.117f42cc6e9f4p-8, 0x1.d4213a7e14a18p-65, 0x1.9b477bdad8e08p-10, 0x1.1d219fb0e1bc8p-13, -0x1.5bb59d3ca4fa9p-12, 0x1.8ca373c577821p-14, 0x1.4a9b74153a4a3p-16, -0x1.424a8a883141p-16, 0x1.6ce0877965abcp-19, 0x1.c1ed3c11b1dd1p-20, -0x1.86b0a731d831ap-21, -0x1.5cea3996396c5p-26, 0x1.640950bde5eb3p-22}, /* i=15 108.063 */\n", " {0x1.fe307f2b503dp-1, -0x1.8a555000387f8p-57, 0x1.06ae13b0d3255p-6, -0x1.88abd7f4be982p-60, -0x1.0ee3844e59be7p-5, -0x1.0b0ec94b96d83p-59, 0x1.48b127f8ed8a5p-5, 0x1.b6a1f18c2c162p-60, -0x1.f155b4e7d8c3bp-6, 0x1.adb2d99b0c1fcp-60, 0x1.aa2c0753d569ap-7, 0x1.9a37b9864b8e6p-61, -0x1.bbf7e2795837bp-11, -0x1.4784a66288abfp-65, -0x1.5478d784d271cp-9, 0x1.27115917a7ecp-65, 0x1.8eae08cdf9546p-10, -0x1.92946556037e6p-13, -0x1.90f27ae61444cp-13, 0x1.b076b78538f02p-14, -0x1.b2906f1b92d5dp-18, -0x1.a2f66822d4a01p-17, 0x1.3031c4f7c4a97p-18, 0x1.41708ced2abdp-22, -0x1.45ffd6deae2a8p-21, 0x1.e844ebdc8456ap-24, 0x1.c0bbf2b711595p-24}, /* i=16 111.558 */\n", " {0x1.fefcce6813974p-1, -0x1.b27cf5025d1c8p-58, 0x1.34d7dbc76d7e5p-7, 0x1.3780d6e7eb351p-61, -0x1.51cc18621fc23p-6, 0x1.969629e4b64a6p-61, 0x1.b925a99886bb7p-6, 0x1.9c8f65efdd1f4p-61, -0x1.71e7d408c8c6fp-6, -0x1.c5621deaf4cfcp-60, 0x1.7ea58080a81efp-7, -0x1.2f25b7f384ff3p-61, -0x1.46eb9d203e071p-9, 0x1.ff569e38360a4p-65, -0x1.403333682fa5ep-10, -0x1.36256a95953a6p-65, 0x1.3b37d5bd14a4p-10, -0x1.6be130822dbdfp-12, -0x1.03d4bcdafd553p-14, 0x1.55848476c8142p-14, -0x1.5492bf3c6eee6p-16, -0x1.3823d4328e9c5p-18, 0x1.152fefc353e5ap-18, -0x1.5199dbf7bc4c6p-21, -0x1.4dda2bebe08f2p-22, 0x1.3fb850b47210ap-23, 0x1.bcd1b284c4798p-25}, /* i=17 112.32 */\n", " {0x1.ff733814af88cp-1, 0x1.0a87238cea4fap-56, 0x1.5ff2750fe782p-8, -0x1.5f184847ca667p-62, -0x1.96f0575a63ae5p-7, 0x1.95f4139297a96p-61, 0x1.1c5a643f04363p-6, -0x1.6ea87997fba3cp-62, -0x1.04f5caaf2196fp-6, 0x1.19502347d3b54p-62, 0x1.382a146afb9d2p-7, -0x1.f93bde902d2dp-63, -0x1.95cab93aa68d2p-9, 0x1.0f716a5fc18c4p-65, -0x1.d2fd90fe62928p-13, -0x1.4e00d5fcc484ap-68, 0x1.9f50fb94c0b86p-11, -0x1.7d7378074399bp-12, 0x1.cc0c9cb9ede1ep-16, 0x1.92a3a29471895p-15, -0x1.7c127858c909ap-16, 0x1.5a72fde935a48p-20, 0x1.57b9d90a92106p-19, -0x1.fdb8443754cf7p-21, -0x1.6c7d633eab55ap-26, 0x1.ddcfc714a2b67p-24, -0x1.9fedf738e84b4p-23}, /* i=18 108.141 */\n", " {0x1.ffb5bdf67fe6fp-1, 0x1.4e830346f6e8p-62, 0x1.84ba3004a50dp-9, -0x1.90b93d4632206p-64, -0x1.d9c2ea85a927dp-8, -0x1.0bcf1ea93cfdcp-62, 0x1.60898536e104ap-7, -0x1.ab6aa911c445ep-62, -0x1.5eb1c899f0b7p-7, 0x1.1bc22eed1f1fbp-61, 0x1.d854f73e74c87p-8, 0x1.7a977a3364c4p-63, -0x1.897719a9d257ep-9, -0x1.ab523e3f93994p-65, 0x1.88cdc8b807c97p-12, 0x1.4875acc7c06ap-70, 0x1.b325a11c1f45ap-12, -0x1.381548f69274p-12, 0x1.2b1fd05559bfap-14, 0x1.1ed31cd6feb26p-16, -0x1.29cf593fdf00ap-16, 0x1.1cea99b59228cp-18, 0x1.ceff221e3598ap-21, -0x1.b0ad4b899b2d9p-21, 0x1.3761b047e21d1p-23, 0x1.96c31c2256049p-25, -0x1.0a714c57f7adfp-25}, /* i=19 114.101 */\n", " {0x1.ffd9f78c7524ap-1, 0x1.04ed6ff98e45dp-55, 0x1.a024365f771bdp-10, 0x1.3c8f5202cb405p-64, -0x1.0a9732d5284ddp-8, -0x1.1acbd0899ce7ep-62, 0x1.a4bf47a43042ap-8, 0x1.e6cb2580d092p-63, -0x1.c23802d8a5bb7p-8, -0x1.9963700abfc8p-66, 0x1.4f40070668329p-8, -0x1.e1fe1c0e1182ap-62, -0x1.4c9a2c9dccd04p-9, 0x1.80fb9c9cd78c1p-63, 0x1.4f7a50b5bc019p-11, -0x1.40906b7a1de3ap-66, 0x1.18b04eb90c737p-13, -0x1.a4c3880c0ea69p-13, 0x1.4b7b82a86f423p-14, -0x1.0bc762b1c2aaap-18, -0x1.589d6f8892acfp-17, 0x1.357ab63f7bdf9p-18, -0x1.6675858bbff5ep-22, -0x1.ea96dcb12a15cp-22, 0x1.8c572fcf5610ep-23, -0x1.700c93da86deep-28, 0x1.7ae9ceb75e26ep-26}, /* i=20 110.433 */\n", " {0x1.ffed167b12ac2p-1, -0x1.ddc0ce3ed8fcbp-55, 0x1.afc85e0f82e12p-11, 0x1.438f22895e03ep-66, -0x1.221a9f326bef4p-9, -0x1.99642b37af33p-64, 0x1.e3c9aab90bcf4p-9, 0x1.7dcdfdccc72ap-68, -0x1.14b1b98141f21p-8, 0x1.af6edf50eba66p-62, 0x1.c1c19b9e63d7p-9, 0x1.4d1e9411f1d28p-66, -0x1.feac3dbeb5124p-10, 0x1.2400e6ffbc1c8p-65, 0x1.63e88178b0e49p-11, 0x1.3e4ae97774f91p-65, -0x1.4441c86c93f39p-15, -0x1.c8ceebc5fc50bp-14, 0x1.125b77a79aa6cp-14, -0x1.da7be990bc718p-17, -0x1.e019960474affp-19, 0x1.d229185ef6279p-19, -0x1.cea9fa10885e7p-21, -0x1.044fd6a2e447ap-23, 0x1.3695f88fc641dp-23, -0x1.0c0dc0ba0d589p-25, -0x1.9194748828b93p-23}, /* i=21 108.145 */\n", " {0x1.fff6dee89352ep-1, 0x1.b96c0ba13851dp-55, 0x1.b23a5a23e421p-12, 0x1.727bce1be0014p-67, -0x1.315107613c673p-10, -0x1.823f8673f5b7ap-64, 0x1.0c243329a9ca1p-9, -0x1.65e361cefe652p-64, -0x1.4630116262084p-9, -0x1.0ea6ee40daf79p-63, 0x1.1e84d1022e8cbp-9, -0x1.9b77b85eed4fp-66, -0x1.6b41872716325p-10, 0x1.3e9e001100f64p-66, 0x1.36edde582b265p-11, -0x1.1cb479a94e148p-65, -0x1.f7870ebc38e77p-14, -0x1.51ecfdc37801dp-15, 0x1.711d817e0d3b6p-15, -0x1.0ae90d500d1d8p-16, 0x1.a85b1bf54920cp-21, 0x1.fe73958205038p-20, -0x1.d222bfef33aa4p-21, 0x1.833f8b13b1a4ep-24, 0x1.233b5a19285dbp-24, -0x1.1adcf574b7db6p-25, 0x1.ab10bedc44532p-24}, /* i=22 109.015 */\n", " {0x1.fffbb8f1049c6p-1, 0x1.d2c6266b51f26p-56, 0x1.a740684026555p-13, -0x1.7e24cc3ac571p-69, -0x1.36d34c8f1c26ap-11, -0x1.69d73e7d1c977p-65, 0x1.1eb6e14974a25p-10, -0x1.99b78600e0664p-64, -0x1.714eb8cc0947fp-10, 0x1.3613f37c7410bp-64, 0x1.5bec08c01b1d7p-10, -0x1.3e3a262f6c68ap-64, -0x1.e4621d82dad12p-11, 0x1.302878843e2ccp-67, 0x1.e1b7b564b0e79p-12, 0x1.f894fc1f14d54p-67, -0x1.24564b69716aap-13, 0x1.bf8e3b47f3ccdp-20, 0x1.8f55a9be1a264p-16, -0x1.b3b76e6203281p-17, 0x1.713c795a07e0cp-19, 0x1.3bb092cfd93ep-21, -0x1.473b0a8333deep-21, 0x1.645526869c143p-23, 0x1.1a343e004b33dp-27, -0x1.76c7e253faad1p-26, 0x1.e16080963cffep-24}, /* i=23 108.853 */\n", " {0x1.fffe0e0140857p-1, -0x1.6aa36f86c14dcp-57, 0x1.8fdc1b2dcf7b9p-14, 0x1.7050f50b8f308p-71, -0x1.322484cf12daap-12, 0x1.4cc0408806d4fp-66, 0x1.27dc1bc6cfef5p-11, 0x1.ffbb5229f6bb7p-65, -0x1.9202f465eb421p-11, 0x1.8f3f063b4066p-69, 0x1.93b4c9746835fp-11, -0x1.04e2d6df2fce5p-65, -0x1.30e9e6142fe9bp-11, -0x1.0396045094744p-66, 0x1.555b9d5fb4825p-12, 0x1.9a40d2ca5ef0bp-66, -0x1.055983c4ac7a6p-13, 0x1.68e6c75a5d068p-16, 0x1.2d4a50d2757cep-17, -0x1.1de08b56479aap-17, 0x1.9110ccc7fe6fdp-19, -0x1.bb3184d789af8p-23, -0x1.4629a164e82ap-22, 0x1.413b087ee5e4dp-23, -0x1.648d7786f9fbcp-26, -0x1.293289f8c327dp-27, -0x1.c283008e726f7p-25}, /* i=24 109.772 */\n", " {0x1.ffff2436a21dcp-1, -0x1.3607959a29d36p-55, 0x1.6e2367dc27f95p-15, 0x1.d96e6f015102p-73, -0x1.23c436c36fdabp-13, 0x1.f0d77fc600a5p-68, 0x1.26bf00867a835p-12, -0x1.c92e1aecdc75p-66, -0x1.a51fb50b15f22p-12, 0x1.248227c6d226p-69, 0x1.c0825378fda08p-12, 0x1.5a8a09c053451p-66, -0x1.6c3dbfe0cbe4ap-12, -0x1.e65769c33f8a1p-66, 0x1.c1dd1438378dfp-13, 0x1.91bd161f34158p-69, -0x1.94c36a9d7c0dcp-14, 0x1.bf0aab116ca41p-16, 0x1.6bdbd2f10393p-23, -0x1.2b32e8d43ef25p-18, 0x1.3a7403459770bp-19, -0x1.17411873320fap-21, -0x1.35bb2691c9b29p-24, 0x1.98313537ed069p-24, -0x1.cb4b60e85a341p-26, 0x1.2be214cf4c9ebp-31, -0x1.350a1a851865ap-23}, /* i=25 108.474 */\n", " {0x1.ffffa1de8c582p-1, 0x1.832540129302ap-55, 0x1.44f21e49054f2p-16, 0x1.f338cf4086346p-71, -0x1.0d18811478659p-14, 0x1.914a7a08b6a2bp-68, 0x1.1b964d438f622p-13, 0x1.a52c94c56aaafp-67, -0x1.a8d7851f26bfp-13, 0x1.c38dbf3ee1223p-67, 0x1.ddd6df9b6852dp-13, -0x1.3b0dd7eac9b91p-67, -0x1.9e52b7aac1644p-13, 0x1.904036dfb5764p-67, 0x1.165b2034fcab2p-13, 0x1.27beac4bf3866p-67, -0x1.1b75c3332673ap-14, 0x1.91a253c42f4e7p-16, -0x1.020b498095051p-18, -0x1.ade63f30809aep-20, 0x1.89bb0d75e59b7p-20, -0x1.180c78d3dca28p-21, 0x1.cabfd39b38553p-25, 0x1.6013ffba86cfdp-25, -0x1.64f2b123e1f0bp-26, 0x1.35bf3e5021105p-28, -0x1.177828ffd35afp-23}, /* i=26 108.645 */\n", " {0x1.ffffd8e1a2f22p-1, -0x1.c10adf6b19989p-55, 0x1.1783ceac2891p-17, -0x1.7f19d8ee58337p-71, -0x1.e06a8b37e5b93p-16, 0x1.24e8db1358f2ep-71, 0x1.07978c7b8496bp-14, 0x1.f163b5580927cp-68, -0x1.9d039884f8be5p-14, 0x1.fce53cd30b1ebp-68, 0x1.e8d1145e94a54p-14, -0x1.d0f6e009a99eep-68, -0x1.c1f7251172a87p-14, -0x1.3ce0f013dfe9p-71, 0x1.458b9e0854d68p-14, -0x1.897cf3950b1a7p-68, -0x1.6eb0557245429p-15, 0x1.33045cf65279ep-16, -0x1.42c8adf18ab62p-18, 0x1.91109b80f9918p-27, 0x1.83a9b44249fbfp-21, -0x1.9bcbaf0a8dfd1p-22, 0x1.900325b58a857p-24, 0x1.4a3cf9c161684p-28, -0x1.0cbcc4d0a916ap-26, 0x1.4275e1b91f084p-28, 0x1.39180c75350e1p-23}, /* i=27 108.443 */\n", " {0x1.fffff039f9e8fp-1, -0x1.9d1bcd6174e99p-55, 0x1.d21397ead99cbp-19, -0x1.6abd9c029c47cp-75, -0x1.9f19734d29cf9p-17, 0x1.20c4383da36c1p-71, 0x1.d982bd41d8954p-16, 0x1.d9bc9988e9666p-71, -0x1.8320fc4836be5p-15, 0x1.526638b9926a8p-72, 0x1.e0a1cb1d071f3p-15, 0x1.d9f5d232bab9p-70, -0x1.d384223047b9cp-15, -0x1.30d0b2b8a170dp-69, 0x1.696daf6422bd4p-15, 0x1.ba6ac732f399ep-69, -0x1.bb6e2d311a93fp-16, 0x1.a4fcb0ea87efbp-17, -0x1.1c940c5303dafp-18, 0x1.7469913f4e9c6p-21, 0x1.ef4b4f8ab67aep-23, -0x1.e189c28e8e041p-23, 0x1.678b281d5bc55p-24, -0x1.9c3bf4e9f2b5dp-27, -0x1.74c9ba997ffedp-28, 0x1.b4b843f8c7068p-29, 0x1.c901764507862p-25}, /* i=28 109.895 */\n", " {0x1.fffff9d446cccp-1, -0x1.bb06bab98bc8p-57, 0x1.789fb715aae95p-20, -0x1.226d93bf89b4p-80, -0x1.5b333cc7f98f1p-18, -0x1.6bd1091d2544p-72, 0x1.9b12fdbf90f62p-17, 0x1.d4b6b0ee9cf46p-71, -0x1.5e06923144d7p-16, 0x1.c59319485786p-75, 0x1.c6a071925631dp-16, -0x1.835ef595952e4p-71, -0x1.d178cb0388a82p-16, -0x1.039272760f01cp-70, 0x1.7e29d33ac92b6p-16, 0x1.21ff8b0e9d5ebp-70, -0x1.f9203429baad6p-17, 0x1.094dadeee395cp-17, -0x1.a771cf3500d9fp-19, 0x1.b8fd1c29c21eap-21, -0x1.cc8573d7de11p-26, -0x1.b0362da1722cbp-24, 0x1.e5eae518f94e9p-25, -0x1.07963addd99a6p-26, -0x1.3f496093d0befp-29, 0x1.99078a326092dp-30, 0x1.42681ecfe4da1p-23}, /* i=29 108.41 */\n", " {0x1.fffffda86faa9p-1, -0x1.d230252d68f26p-56, 0x1.26f9df8519bd7p-21, -0x1.e339871c015b7p-75, -0x1.1926290adc888p-19, -0x1.e36d23dbb2644p-73, 0x1.5900c02d97304p-18, 0x1.fa7d21e3ed616p-72, -0x1.3166de6a8c64p-17, 0x1.b014157867958p-71, 0x1.9dfcc328729ep-17, 0x1.20e9fee0b7665p-71, -0x1.bcab1ed5ec38dp-17, 0x1.d9003794f0fep-73, 0x1.81cd74a57ce17p-17, -0x1.809fde9c0f6f5p-71, -0x1.106e95b6bf556p-17, 0x1.379625a71385fp-18, -0x1.1970a5b5bd443p-19, 0x1.74761c8333ff2p-21, -0x1.0864e125c9951p-23, -0x1.b83bf9019aa3bp-26, 0x1.0397611c35b28p-25, -0x1.a25392adb29acp-27, -0x1.7b832af40d9d4p-30, 0x1.62a02eb79577bp-32, 0x1.a6da58ffe94f4p-23}, /* i=30 108.026 */\n", " {0x1.ffffff233ee1dp-1, 0x1.db123ed17221dp-55, 0x1.bfd7555a3bd68p-23, 0x1.0151cf177b53ap-77, -0x1.b8d7f804d2e73p-21, 0x1.82b366f0bc2dcp-75, 0x1.17f93e5149289p-19, 0x1.91997bfd26568p-76, -0x1.013b0457d08fap-18, -0x1.0d6d5a7f06298p-73, 0x1.6b245d7e1d829p-18, -0x1.9985e02c8ce3bp-72, -0x1.98077548c6951p-18, 0x1.01cd3f1d12c93p-72, 0x1.7492048ab3cebp-18, -0x1.0368a0dc0750ep-72, -0x1.17506c7b39cbp-18, 0x1.57e94a4c5f5a6p-19, -0x1.570971200d7dbp-20, 0x1.0a0f956947b21p-21, -0x1.1a9b7bd5bba32p-23, 0x1.51bfc00de3146p-27, 0x1.95b6967f79cbep-27, -0x1.fe3c43cb3cf84p-28, 0x1.2f364a7a2dc5fp-28, -0x1.007442a10cc14p-32, -0x1.ef5ab6fc5e849p-24}, /* i=31 108.802 */\n", " {0x1.ffffffb127525p-1, 0x1.504f382db4102p-55, 0x1.4980cb3c80949p-24, 0x1.7fbdd923f8057p-78, -0x1.4ea6ce697296fp-22, 0x1.ea42f9c9de533p-76, 0x1.b771d9b6f07b8p-21, -0x1.e9c1ca9662fe8p-78, -0x1.a26c653fad5b8p-20, -0x1.146c4cee0e898p-74, 0x1.3302bb89379dep-19, 0x1.4c55b83ef7a68p-73, -0x1.67f42e5264334p-19, -0x1.6779da26b4197p-73, 0x1.58b4adafb958ep-19, 0x1.8351251b45e84p-73, -0x1.10f576796285ap-19, 0x1.66ca44250dd07p-20, -0x1.84ee0ada37543p-21, 0x1.53b6065291e6bp-22, -0x1.c09ebfd0c581cp-24, 0x1.63062625d59cp-26, 0x1.e259c60eb7b83p-30, -0x1.e43802ad25514p-29, 0x1.51bcdabe8cda5p-28, -0x1.930fc3df6e909p-32, -0x1.81cdd770e1c81p-23}, /* i=32 108.16 */\n", " {0x1.ffffffe4aed5ep-1, 0x1.389c0f32ad0fp-59, 0x1.d5f3a8dea7357p-26, 0x1.fa07c18622dd2p-80, -0x1.ebfb14c9170cp-24, 0x1.9e40632b4145dp-78, 0x1.4d9228525f449p-22, 0x1.d35bd7f959136p-77, -0x1.48b536addac5fp-21, -0x1.61ace22b32569p-75, 0x1.f48ccf23a68e2p-21, -0x1.ee1d13c79c281p-75, -0x1.3183b6134cf03p-20, 0x1.e1f4d5fe2a06cp-75, 0x1.31efde2215f01p-20, -0x1.64a7021e23fbap-74, -0x1.fd9eeb0f18fdbp-21, 0x1.63414459ae298p-21, -0x1.9dda81be20b5ap-22, 0x1.8da7d306423c5p-23, -0x1.303da86a4fc28p-24, 0x1.4f5e1327706b9p-26, -0x1.3efb5eefcbe53p-29, -0x1.31bc5ce1ce65dp-30, -0x1.3eafe1b05c93fp-30, -0x1.47fc2d9cc851ep-32, 0x1.d27265006a9dfp-24}, /* i=33 108.887 */\n", " {0x1.fffffff6d1e56p-1, -0x1.64d969b4be4c4p-55, 0x1.44d26de513197p-27, 0x1.76fc20fc4b365p-81, -0x1.5e32de7af8977p-25, -0x1.888fd6ae18a1cp-80, 0x1.e9e05b3c8f38ap-24, 0x1.7532141b12aa7p-78, -0x1.f2f6fa7db5b1dp-23, 0x1.b3bf498e3462cp-77, 0x1.899dcace485ebp-22, 0x1.1885a0ae9e878p-78, -0x1.f34b7eef3c9b2p-22, 0x1.294a3b618b47p-76, 0x1.04be030272d14p-21, -0x1.df83095e40f79p-75, -0x1.c73bd22571559p-22, 0x1.4edda838439f5p-22, -0x1.9fc860b504677p-23, 0x1.b0d686a26042p-24, -0x1.72370c2fdbe1p-25, 0x1.ee29f0d197d25p-27, -0x1.b4d88d500c5bep-29, 0x1.96014c45b0178p-35, 0x1.238f19dc8fd82p-31, -0x1.8d34d46ae6567p-33, -0x1.54105fe4a9cd8p-27}, /* i=34 112.335 */\n", " {0x1.fffffffd01f89p-1, -0x1.35e8e39884f62p-56, 0x1.b334fac4b9f99p-29, 0x1.32178ed1a4971p-83, -0x1.e2cec6323e50ep-27, -0x1.0e5693f9d4908p-83, 0x1.5c027d5bba36ap-25, -0x1.fc46fb3cc7aep-81, -0x1.6df4d024fffbep-24, -0x1.90fd7226ec57ap-79, 0x1.2aaf7c205b9eap-23, 0x1.dbec2005b45a8p-77, -0x1.8902edfbfefddp-23, -0x1.c353aca58d08ap-77, 0x1.ab2ab1b338249p-23, 0x1.b498186c39105p-77, -0x1.85abe0ff198d3p-23, 0x1.2d32f7c3621ebp-23, -0x1.8c141c71dbc95p-24, 0x1.b9fa6fbb9b198p-25, -0x1.9db5fe2c2f5b9p-26, 0x1.3b8e07840483ep-27, -0x1.6d95e5070d91dp-29, 0x1.d7616168b0e49p-32, 0x1.f2be0744b3a5fp-30, -0x1.737a375809985p-34, -0x1.936d4936fb865p-24}, /* i=35 109.095 */\n", " {0x1.ffffffff0dd2bp-1, 0x1.0df73e7d2fc98p-55, 0x1.1a94ff571654fp-30, 0x1.fbf537b47967dp-84, -0x1.4251f33f5578fp-28, 0x1.4c9cece8f41b2p-82, 0x1.de6bc1f75bb9bp-27, 0x1.94afb459a3p-87, -0x1.036b5fd1c4158p-25, -0x1.d582afa097896p-79, 0x1.b58f1385def96p-25, -0x1.8778854601996p-80, -0x1.2a2347efb2133p-24, -0x1.26f9e1ef0f378p-79, 0x1.508db866ffep-24, 0x1.64de561a68a21p-78, -0x1.3ffea934685b9p-24, 0x1.02ff87b2e2576p-24, -0x1.66e54eae5fa4bp-25, 0x1.a9ea2195c567dp-26, -0x1.ae3b91fecafa1p-27, 0x1.6bb883d2e5ed1p-28, -0x1.ee10e97715c11p-30, 0x1.e2873d2b77f1fp-32, -0x1.af385ae29d57bp-33, -0x1.d793eecfc2513p-36, 0x1.20d80dcfa68d1p-27}, /* i=36 112.58 */\n", " {0x1.ffffffffb5be5p-1, -0x1.729d6819c7f34p-56, 0x1.63ac6b4edc88ep-32, -0x1.c45991835da24p-88, -0x1.a0ce0dc06a706p-30, -0x1.1b72d11da9dabp-84, 0x1.3e380dd7593a5p-28, -0x1.8ad868a7b5674p-82, -0x1.638bc4fb02cbap-27, 0x1.7a84506fcda4p-87, 0x1.35753ad4c5875p-26, 0x1.ad190ab170366p-81, -0x1.b41f33cafccbap-26, 0x1.0e3539bf61116p-80, 0x1.fe694e371a659p-26, -0x1.3a84e01866ea8p-82, -0x1.f8af0121aa0abp-26, 0x1.aa77274dab3d8p-26, -0x1.3616fe8f6a259p-26, 0x1.84fddf4c681a1p-27, -0x1.a3de05d1b8a31p-28, 0x1.822529aca9f83p-29, -0x1.26c3dfba84378p-30, 0x1.64c287a84aa09p-32, -0x1.107d2dac5d83bp-31, -0x1.e251d1ab1d873p-43, 0x1.8f37005f17b42p-26}, /* i=37 111.111 */\n", " {0x1.ffffffffe9ebp-1, -0x1.ea527e0bef1e8p-58, 0x1.b1e5acf351d87p-34, 0x1.dc96583ba19fp-90, -0x1.05042a0a5f3c3p-31, -0x1.2023f0f13867cp-85, 0x1.99ac8fd63c66cp-30, -0x1.bf57c5fd0501ap-85, -0x1.d72344378e114p-29, 0x1.c77758959af41p-83, 0x1.a6be9a123435bp-28, 0x1.dab4af8807c36p-83, -0x1.33aacb4bf6deap-27, 0x1.bd241ea49ac35p-81, 0x1.74b732e7ceaa7p-27, 0x1.c7c89730b0264p-82, -0x1.7e7eab6531ccbp-27, 0x1.50959f2daae39p-27, -0x1.ffed4cef94261p-28, 0x1.51c7f99f908a2p-28, -0x1.82b5fd5fbedfcp-29, 0x1.7e1c8e715c978p-30, -0x1.51536822c861bp-31, 0x1.be7e4c220ca82p-33, 0x1.f5bb67c461296p-29, 0x1.1d7cf04529bfp-37, -0x1.acc021ab828c4p-23}, /* i=38 108.008 */\n", " {0x1.fffffffff9a1bp-1, -0x1.6a87270d2450cp-57, 0x1.0084ff125639dp-35, -0x1.8ad61debedc86p-90, -0x1.3ca42adaa26f6p-33, 0x1.c20c6583dccddp-87, 0x1.fe73513c67bf8p-32, 0x1.20d28c0c7e686p-86, -0x1.2dd9aa5a2bee3p-30, 0x1.d76d7235461bep-85, 0x1.16ef6b93944a8p-29, -0x1.f07bd785566dep-83, -0x1.a2d58e9b22b26p-29, -0x1.19e6ea91dd55ep-84, 0x1.06389b9748f25p-28, 0x1.fbcc52565c0bep-82, -0x1.16cdd9eb58ba2p-28, 0x1.fdd861b55c5p-29, -0x1.9457846c943d2p-29, 0x1.178f3905f435cp-29, -0x1.518cf20c53de2p-30, 0x1.6329939a34b66p-31, -0x1.5ef3ad85e5d3bp-32, 0x1.f2b41494e49e9p-34, 0x1.bad43bc0b622dp-29, 0x1.21a45fa9dcebfp-37, -0x1.790b3d88f69fep-23}, /* i=39 108.193 */\n", " {0x1.fffffffffe38p-1, 0x1.7ce07114e4fep-55, 0x1.25f9ee0b923dcp-37, -0x1.174c43a73a4d1p-91, -0x1.74105146a5162p-35, -0x1.7d0740e56625cp-91, 0x1.33cde4f35d941p-33, -0x1.2a344950797c6p-88, -0x1.760fe7b666392p-32, 0x1.a8b77c82ed644p-86, 0x1.63a70fd66d485p-31, 0x1.6b87715649d6dp-85, -0x1.1324f6fb6dfa1p-30, 0x1.3fc045e39915fp-84, 0x1.63a31a36b815cp-30, -0x1.02dec9bc1a7p-90, -0x1.8724ca8970b91p-30, 0x1.72e290891e5dep-30, -0x1.31fc03858aab1p-30, 0x1.b9e8b0e7fa253p-31, -0x1.1821a002637bdp-31, 0x1.37ba5f3fba5ebp-32, -0x1.3578bf23dc654p-33, 0x1.fdaf2015d7b54p-35, 0x1.7f6a435069067p-32, 0x1.9d14ee557ec62p-38, -0x1.55f4c743ee571p-26}, /* i=40 111.334 */\n", " {0x1.ffffffffff845p-1, 0x1.b0edc5a89ab8ep-56, 0x1.46897d4b69fc6p-39, 0x1.a74852415bb49p-93, -0x1.a77a4e7dcd735p-37, -0x1.34edb43ab7de6p-91, 0x1.67543695dcc12p-35, -0x1.29ae577004af8p-92, -0x1.c05c1e2fc710ep-34, 0x1.dbbf42d2537a8p-90, 0x1.b639419fedf8ep-33, -0x1.ed72eb9e7a59ep-87, -0x1.5cfd7eb9bfe87p-32, -0x1.e97db27125fcp-88, 0x1.d11578959ba45p-32, -0x1.c0635ac2b5768p-87, -0x1.082f9e9f7eb37p-31, 0x1.0354ceadad8b3p-31, -0x1.bc2dee0154fc6p-32, 0x1.4e11efdc66eaep-32, -0x1.bb357c0253f64p-33, 0x1.035f9889bc29cp-33, -0x1.8e7bdb10b7441p-35, 0x1.e364571102661p-36, -0x1.12cffcf49a2e8p-29, 0x1.ee9362bcfec26p-39, 0x1.cc5b58dd85301p-24}, /* i=41 108.905 */\n", " {0x1.ffffffffffdf8p-1, -0x1.dcf8b10ff973bp-55, 0x1.5f8b87a31bd85p-41, 0x1.65b265455b658p-98, -0x1.d2e55024a0fb5p-39, 0x1.444e1d84cea02p-93, 0x1.9612cc225df4bp-37, -0x1.c784edb664ce7p-91, -0x1.03ee5f38b9b4dp-35, -0x1.91ca8efa41a3p-89, 0x1.04f2f71e2e96bp-34, -0x1.33f36a4e5135p-89, -0x1.ab7099f99ced9p-34, -0x1.4af7a67f2110cp-90, 0x1.2554b8f609fd1p-33, -0x1.29e641eb44218p-88, -0x1.57c87529ca968p-33, 0x1.5cd182c967671p-33, -0x1.3580a2517d57ap-33, 0x1.e3be72b1be982p-34, -0x1.4e9908689ad08p-34, 0x1.9a61979d3395bp-35, -0x1.7b826aadd1c89p-36, 0x1.ad3a9fc4a0d1ep-37, -0x1.0e9325ed2097p-31, 0x1.0722198ff452cp-39, 0x1.c2ef85611aa11p-26}, /* i=42 110.935 */\n", " {0x1.fffffffffff7bp-1, 0x1.00fa07f7fb612p-55, 0x1.6ed2f2515e933p-43, 0x1.2bc1802a42b92p-98, -0x1.f2a6c1669c901p-41, -0x1.7b3e174cc184p-95, 0x1.bc42ba38a13f8p-39, 0x1.460463d59d3dfp-93, -0x1.2391e135afae4p-37, -0x1.bd08c8c5f7b18p-92, 0x1.2c6c24550f64fp-36, -0x1.fdc861a48711p-92, -0x1.f9a3c1b0d63ecp-36, -0x1.843dc8d9ad3d5p-90, 0x1.6502546ab341ap-35, 0x1.45f812e48eb98p-89, -0x1.af223186006d1p-35, 0x1.c388dd1764f41p-35, -0x1.9e65a242b52aap-35, 0x1.4fcd2787781ebp-35, -0x1.e3cbdb20a48d6p-36, 0x1.35639e9fcd41p-36, -0x1.5b8e97774b2c9p-42, 0x1.66ffe6a100bc9p-38, -0x1.5706c390c113ep-30, 0x1.ff0d11cf61949p-41, 0x1.2054de347e3f8p-24}, /* i=43 109.58 */\n", " {0x1.fffffffffffdfp-1, 0x1.5669e670f914cp-56, 0x1.72fd93e036cdcp-45, 0x1.1c553d12fbbdp-100, -0x1.01f450d1e61b2p-42, 0x1.bed807e60c078p-99, 0x1.d68fb81b2ed89p-41, 0x1.c7ea3c4444ccp-98, -0x1.3c706aa4d2328p-39, 0x1.d6d2d51dd414dp-93, 0x1.4e6479565838ep-38, 0x1.50580f36c14c1p-92, -0x1.20e9eb83b3dd9p-37, -0x1.04b6334a32fdp-94, 0x1.a35b9d2fcac8p-37, 0x1.c07c6978bf2fp-94, -0x1.04a134f6e3dcbp-36, 0x1.196579f27ddbep-36, -0x1.0ab97aa74c7p-36, 0x1.bf68355f542b1p-37, -0x1.49da25a547134p-37, 0x1.bd64993a3958ep-38, -0x1.1193990186399p-35, 0x1.1c0e98335ae18p-39, 0x1.e08edb685494ap-29, 0x1.cb9fcc058465bp-42, -0x1.94cacccfb8964p-23}, /* i=44 108.091 */\n", " {0x1.ffffffffffff8p-1, 0x1.0160ef15c497ep-56, 0x1.6ba91ac734786p-47, -0x1.f81d6fa69b5b2p-101, -0x1.028a39099f4dbp-44, -0x1.83ed68de15404p-99, 0x1.e292863e1795ep-43, -0x1.b292e812abb68p-98, -0x1.4c4e690fbdd14p-41, -0x1.80991e1d4ef25p-95, 0x1.67e6e5ac60fd1p-40, 0x1.1d2ca68dcf0e8p-95, -0x1.3f00d80afa00cp-39, -0x1.3e174dc7225acp-93, 0x1.db88ee63eb28ap-39, 0x1.8abd97527892fp-93, -0x1.2fe58a1f19368p-38, 0x1.51dbeae22a5c8p-38, -0x1.4a4d54823e0fcp-38, 0x1.1e432d674cfbap-38, -0x1.b001e26c6e764p-39, 0x1.328ce695259fep-39, -0x1.4e492cf7d4f4cp-36, 0x1.aaa77d339dcp-41, 0x1.366538db382e5p-29, 0x1.826ad7d581503p-43, -0x1.056e0810b14dap-23}, /* i=45 108.721 */\n", " {0x1.ffffffffffffep-1, 0x1.59ab24e589a3p-56, 0x1.5982008db1304p-49, -0x1.1cf9bda64b38ap-103, -0x1.f610e8cde57acp-47, -0x1.884dcd86f98c8p-102, 0x1.df2dac2f2d47fp-45, -0x1.7f27bf279d988p-102, -0x1.51b17f95fc0b4p-43, -0x1.063e04485c3e7p-97, 0x1.76996ddc975d7p-42, -0x1.21489d6648428p-97, -0x1.546155a972b18p-41, -0x1.9d3fb518aa7cp-100, 0x1.0456ed89c4f24p-40, 0x1.eee772fc32c5ep-94, -0x1.55d6295aa388ap-40, 0x1.86ead99977388p-40, -0x1.89b3d387efa6ep-40, 0x1.6011e175e64f8p-40, -0x1.0cd70515af47bp-40, 0x1.9402199dfdde7p-41, -0x1.806743bc32b08p-37, 0x1.30e561550364ap-42, 0x1.70093985e2c1bp-30, 0x1.31999a27ace63p-44, -0x1.35f54db0f4dbcp-24}, /* i=46 109.476 */\n", " {0x1p+0, -0x1.a6d7d18831888p-55, 0x1.3e296303b2297p-51, 0x1.68cf648cfed1cp-105, -0x1.d8456ef97c744p-49, 0x1.fcded170055p-103, 0x1.ccb92e6c24c8dp-47, -0x1.a704dc202cff2p-101, -0x1.4c1aa8cf1229bp-45, 0x1.652efa61e4ec2p-99, 0x1.7918b6b83c0fbp-44, 0x1.2fb01fb8836dcp-100, -0x1.5f073659de44dp-43, -0x1.9ceb48a2d1931p-97, 0x1.134d070b5921ep-42, 0x1.9af3038fcc184p-98, -0x1.730a2938c09ddp-42, 0x1.b4091041f5905p-42, -0x1.c3c44ab8c8421p-42, 0x1.a06b4f4c3044dp-42, -0x1.704f511555fe7p-42, 0x1.fe51fcfc1acbap-43, 0x1.5e7229a07e7cdp-38, 0x1.9f8121f6c3146p-44, -0x1.692b2f9b3f445p-31, 0x1.c8c34f73d3823p-46, 0x1.301e540260d52p-25}, /* i=47 110.503 */\n", "\"\"\"\n", "\n", "import re\n", "\n", "def strip_c_comments(code: str) -> str:\n", " return re.sub(r'/\\*.*?\\*/', '', code)\n", "\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in strip_c_comments(data).strip().splitlines():\n", " floats = line.strip(\"{}, \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"[ {', '.join(encoded)} ],\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "414aee2d-1bd3-4ff1-bce5-2452bb2a2676", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0x3fec162355429b28, 0x400d99999999999a, 0x3fdda951cece2b85, 0xbff70ef6cff4bcc4, 0x4003d7f7b3d617de, 0xc009d0aa47537c51, 0x4009754ea9a3fcb1, 0xc0027a5453fcc015, 0x3ff1ef2e0531aeba, 0xbfceca090f5a1c06, 0xbfb7a3cd173a063c, 0x3fb30fa68a68fddd, 0x3f555ad9a326993a, 0xbf907e7b0bb39fbf, 0x3f52328706c0e950, 0x3f6d6aa0b7b19cfe ],\n", "[ 0x401137c8983f8516, 0x400799999999999a, 0x3fc05b53aa241333, 0xbfca3f53872bf870, 0x3fbde4c30742c9d5, 0xbfacb24bfa591986, 0x3f9666aec059ca5f, 0xbf7a61250eb26b0b, 0x3f52b28b7924b34d, 0x3f041b13a9d45013, 0xbf16dd5e8a273613, 0x3ef09ce8ea5e8da5, 0x3ed33923b4102981, 0xbec1dfd161e3f984, 0xbe8c87618fcae3b3, 0x3e8e8a6ffa0ba2c7 ],\n" ] } ], "source": [ "import struct\n", "# ERFC f32\n", "\n", "data = \"\"\"\n", "{0x1.c162355429b28p-1, 0x1.d99999999999ap+1, 0x1.da951cece2b85p-2, -0x1.70ef6cff4bcc4p+0, 0x1.3d7f7b3d617dep+1, -0x1.9d0aa47537c51p+1, 0x1.9754ea9a3fcb1p+1, -0x1.27a5453fcc015p+1,0x1.1ef2e0531aebap+0, -0x1.eca090f5a1c06p-3, -0x1.7a3cd173a063cp-4, 0x1.30fa68a68fdddp-4,0x1.55ad9a326993ap-10, -0x1.07e7b0bb39fbfp-6, 0x1.2328706c0e95p-10, 0x1.d6aa0b7b19cfep-9},\n", "{0x1.137c8983f8516p+2, 0x1.799999999999ap+1, 0x1.05b53aa241333p-3, -0x1.a3f53872bf87p-3, 0x1.de4c30742c9d5p-4, -0x1.cb24bfa591986p-5, 0x1.666aec059ca5fp-6, -0x1.a61250eb26b0bp-8,0x1.2b28b7924b34dp-10, 0x1.41b13a9d45013p-15, -0x1.6dd5e8a273613p-14, 0x1.09ce8ea5e8da5p-16, 0x1.33923b4102981p-18, -0x1.1dfd161e3f984p-19, -0x1.c87618fcae3b3p-23, 0x1.e8a6ffa0ba2c7p-23}\n", "\"\"\"\n", "\n", "import re\n", "\n", "def strip_c_comments(code: str) -> str:\n", " return re.sub(r'/\\*.*?\\*/', '', code)\n", "\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in strip_c_comments(data).strip().splitlines():\n", " floats = line.strip(\"{}, \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"[ {', '.join(encoded)} ],\")" ] }, { "cell_type": "code", "execution_count": 7, "id": "e9a21e20-2940-4917-ab6c-070134cdc644", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0x3fe20dd750429b6d, 0x3c61ae3a912b08f0, 0xbfd20dd750429b6d, 0xbc51ae34c0606d68, 0x3fdb14c2f863e924, 0xbc796c0f4c848fc8, 0xbff0ecf9db3e71b6, 0x3c645d756bd288b0, 0x400d9eb53fad4672, 0xbcac61629de9adf2, 0xc030a945f3d147ea, 0x3cb8fec5ad7ece20, 0x4056e8c02f27ca6d, 0xc0829d1c21c363e0, 0x40b17349b70be627, 0xc0e28a6bb4686182, 0x411602d1662523ca, 0xc14ccae7625c4111, 0x4184237d064f6e0d, 0xc1bb1e5466ca3a2f, 0x41e90ae06a0f6cc1 ],\n", "[ 0x3fe20dd750429b6d, 0x3c61adaa62435c10, 0xbfd20dd750429b6d, 0xbc441516126827c8, 0x3fdb14c2f863e90b, 0x3c7a535780ba5ed4, 0xbff0ecf9db3e65d6, 0xbc9089edde27ad07, 0x400d9eb53fa52f20, 0xbcabc9737e9464ac, 0xc030a945f2cd7621, 0xbcc589f28b700332, 0x4056e8bffd7e194e, 0xc0829d18716876e2, 0x40b17312abe18250, 0xc0e287e73592805c, 0x4115ebf7394a39c1, 0xc14c2f14d46d0cf9, 0x4182af3d256f955e, 0xc1b7041659ebd7aa, 0x41e6039c232e2f71, 0xc2070ca15c5a07cb ],\n", "[ 0x3fe20dd750429b6d, 0x3c5d3c35b5d37410, 0xbfd20dd750429b56, 0xbc7c028415f6f81b, 0x3fdb14c2f863c1cf, 0x3c51bb0de6470dbc, 0xbff0ecf9db33c363, 0x3c80f8068459eb16, 0x400d9eb53b9ce57b, 0x3ca20cce33e7d84a, 0xc030a945aa2ec4fa, 0xbcdf6e0fcd7c6030, 0x4056e8b824d2bfaa, 0xc0829cc372a6d0b0, 0x40b1703a99ddd429, 0xc0e2749f9a267cc6, 0x4115856a17271849, 0xc14a8bcb4ba9753f, 0x418035dcce882940, 0xc1b1e5d8c5e6e043, 0x41dfe3b4f365386e, 0xc20398fdef2b98fe, 0x42184234d4f4ea12 ],\n", "[ 0x3fe20dd750429b6a, 0x3c8ae622b765e9fd, 0xbfd20dd750428f0e, 0x3c703c6c67d69513, 0x3fdb14c2f8563e8e, 0x3c6766a6bd7aa89c, 0xbff0ecf9d8dedd48, 0x3c90af52e90336e3, 0x400d9eb4aad086fe, 0x3ca640d371d54a19, 0xc030a93f1d01cfe0, 0xbcc68dbd8d9c522c, 0x4056e842e9fd5898, 0xc08299886ef1fb80, 0x40b15e0f0162c9a0, 0xc0e222dbc6b04cd8, 0x411460268db1ebdf, 0xc1474f53ce065fb3, 0x417961ca8553f870, 0xc1a8788395d13798, 0x41d35e37b25d0e81, 0xc1f707b7457c8f5e, 0x4211ff852df1c023, 0xc21b75d0ec56e2cd ],\n", "[ 0x3fe20dd750429a8f, 0xbc766d8dda59bcea, 0xbfd20dd7503fdbab, 0x3c6707bdffc2b3fe, 0x3fdb14c2f6526025, 0xbc27fa4bb9541140, 0xbff0ecf99c417d45, 0xbc9748645ef7af94, 0x400d9eaa9c712a7d, 0x3ca79e478994ebb4, 0xc030a8ef11fbf141, 0x3cbb5c72d69f8954, 0x4056e4653e0455b1, 0xc08286909448e6cf, 0x40b113424ce76821, 0xc0e1346d859e76de, 0x4111f9f6cf2293bf, 0xc14258e6e3b337db, 0x41714029ecd465fb, 0xc19c530df5337a6f, 0x41c34bc4bbccd336, 0xc1e4a37c52641688, 0x420019707cec2974, 0xc21031fe736ea169, 0x420f6b3003de3ddf ],\n", "[ 0x3fe20dd75042756b, 0x3c84ad9178b56910, 0xbfd20dd74feda9e8, 0xbc78141c70bbc8d6, 0x3fdb14c2cb128467, 0xbc709aebaa106821, 0xbff0ecf603921a0b, 0x3c97d3cb5bceaf0b, 0x400d9e3e1751ca59, 0x3c76622ae5642670, 0xc030a686af57f547, 0x3cc083b320aff6b6, 0x4056cf0b6c027326, 0xc0823afcb69443d3, 0x40b03ab450d9f1b9, 0xc0de74cdb76bcab4, 0x410c671b60e607f1, 0xc138f1376d324ce4, 0x4163b64276234676, 0xc18aff0ce13c5a8e, 0x41aef20247251e87, 0xc1cc9f5662f721f6, 0x41e4687858e185e1, 0xc1f4fa507be073c2, 0x41fb99ac35ee4acc, 0xc1f16cb585ee3fa9 ],\n", "[ 0x3fe20dd7503e730d, 0x3c84e524a098a467, 0xbfd20dd7498fa6b2, 0x3c260a4e27751c80, 0x3fdb14c061bd2a0c, 0x3c695a8f847d2fc2, 0xbff0ecd0f11b8c7d, 0xbc94126deea76061, 0x400d9b1344463548, 0x3cafe09a4eca9b0e, 0xc030996ea52a87ed, 0xbca924f920db26c0, 0x40567a2264b556b0, 0xc0815dfc2c86b6b5, 0x40accc291b62efe4, 0xc0d81375a78e746a, 0x41033a6f15546329, 0xc12c1e9dc1216010, 0x4152397ea3d43fda, 0xc174661e5b2ea512, 0x4193412367ca5d45, 0xc1ade56b9d7f37c4, 0x41c2851d9722146d, 0xc1d19027baf0c3fe, 0x41d7e7b8b6ab58ac, 0xc1d4c446d56aaf22, 0x41c1492190400505 ],\n", "[ 0x3fe20dd74ff10852, 0x3c8a32f26deff875, 0xbfd20dd6f06c491c, 0x3c770c16e1793358, 0x3fdb14a7d5e7fd4a, 0x3c7479998b54db5b, 0xbff0ebbdb3889c5f, 0xbc759b853e11369c, 0x400d89dd249d7ef8, 0xbc84b5edf0c8c314, 0xc0306526fb386114, 0xbc840d04eed7c7e0, 0x40557ff657e429ce, 0xc07ef63e90d38630, 0x40a6d4f34c4ea3da, 0xc0d04542b9e36a54, 0x40f577bf19097738, 0xc119702fe47c736d, 0x413a7ae12b54fdc6, 0xc157ca3f0f7c4fa9, 0x417225d983963cbf, 0xc1871a6eac612f9e, 0x4198086324225e1e, 0xc1a3de68670a7716, 0x41a91674de4dcbe9, 0xc1a6b44cc15b76c2, 0x419a36dae0f30d80, 0xc17cffc1747ea3dc ],\n", "[ 0x3fe20dd74ba8f300, 0xbc59dd256871d210, 0xbfd20dd3593675bc, 0x3c7ec0e7ffa91ad9, 0x3fdb13eef86a077a, 0xbc74fb5d78d411b8, 0xbff0e5cf52a11f3a, 0xbc851f36c779dc8c, 0x400d4417a08b39d5, 0x3c91be9fb5956638, 0xc02f91b9f6ce80c3, 0xbccc9c99dd42829c, 0x405356439f45bb43, 0xc078c0ca12819b48, 0x409efcad2ecd6671, 0xc0c21b0af6fc1039, 0x40e327d215ee30c9, 0xc101fabda96167b0, 0x411d82e4373b315d, 0xc134ed9e2ff591e9, 0x41495c85dcd8eab5, 0xc159f016f0a3d62a, 0x41660e89d918b96f, 0xc16e97be202cba64, 0x4170d8a081619793, 0xc16c5422b4fcfc65, 0x4161131a9dc6aed1, 0xc14a457d9dced257, 0x4123605e980e8b86 ],\n", "[ 0x3fe20dd7319d4d25, 0x3c82b02992c3b7ab, 0xbfd20dc29c13ab1b, 0xbc7d78d79b4ad767, 0x3fdb115a57b5ab13, 0xbc6aa8c45be0aa2e, 0xbff0d58ec437efd7, 0xbc5994f00a15e850, 0x400cb1742e229f23, 0xbca8000471d54399, 0xc02d99a5edf7b946, 0xbcbaf76ed7e35cde, 0x4050a8b71058eb28, 0xc072d88289da5bfc, 0x40943ddf24168edb, 0xc0b3e9dfc38b6d1a, 0x40d18d4df97ab3df, 0xc0eb550fc62dcab5, 0x41029cb71f116ed1, 0xc115fc9cc4e854e3, 0x41265915fd0567b1, 0xc1335eb5fca0e46d, 0x413c5261ecc0d789, 0xc14138932dc4eafc, 0x414117d4eb18facd, 0xc13af96163e35eca, 0x4130454a3a63c766, 0xc11c2ebc1d39b44a, 0x40ff3327698e0e6b, 0xc0d094febc3dff35 ],\n" ] } ], "source": [ "import struct\n", "# ERFC f32\n", "\n", "data = \"\"\"\n", " {0x1.20dd750429b6dp-1, 0x1.1ae3a912b08fp-57, -0x1.20dd750429b6dp-2, -0x1.1ae34c0606d68p-58, 0x1.b14c2f863e924p-2, -0x1.96c0f4c848fc8p-56, -0x1.0ecf9db3e71b6p+0, 0x1.45d756bd288bp-57, 0x1.d9eb53fad4672p+1, -0x1.c61629de9adf2p-53, -0x1.0a945f3d147eap+4, 0x1.8fec5ad7ece2p-52, 0x1.6e8c02f27ca6dp+6, -0x1.29d1c21c363ep+9, 0x1.17349b70be627p+12, -0x1.28a6bb4686182p+15, 0x1.602d1662523cap+18, -0x1.ccae7625c4111p+21, 0x1.4237d064f6e0dp+25, -0x1.b1e5466ca3a2fp+28, 0x1.90ae06a0f6cc1p+31}, /* asympt_acc0.sollya: [0x1.2ce37fb080c7dp-5,0x1.45p-4], degree 29, relerr <= 2^-107.71 */\n", " {0x1.20dd750429b6dp-1, 0x1.1adaa62435c1p-57, -0x1.20dd750429b6dp-2, -0x1.41516126827c8p-59, 0x1.b14c2f863e90bp-2, 0x1.a535780ba5ed4p-56, -0x1.0ecf9db3e65d6p+0, -0x1.089edde27ad07p-54, 0x1.d9eb53fa52f2p+1, -0x1.bc9737e9464acp-53, -0x1.0a945f2cd7621p+4, -0x1.589f28b700332p-51, 0x1.6e8bffd7e194ep+6, -0x1.29d18716876e2p+9, 0x1.17312abe1825p+12, -0x1.287e73592805cp+15, 0x1.5ebf7394a39c1p+18, -0x1.c2f14d46d0cf9p+21, 0x1.2af3d256f955ep+25, -0x1.7041659ebd7aap+28, 0x1.6039c232e2f71p+31, -0x1.70ca15c5a07cbp+33}, /* asympt_acc1.sollya: [0x1.45p-4,0x1.e0p-4], degree 31, relerr <= 2^-106.203 */\n", " {0x1.20dd750429b6dp-1, 0x1.d3c35b5d3741p-58, -0x1.20dd750429b56p-2, -0x1.c028415f6f81bp-56, 0x1.b14c2f863c1cfp-2, 0x1.1bb0de6470dbcp-58, -0x1.0ecf9db33c363p+0, 0x1.0f8068459eb16p-55, 0x1.d9eb53b9ce57bp+1, 0x1.20cce33e7d84ap-53, -0x1.0a945aa2ec4fap+4, -0x1.f6e0fcd7c603p-50, 0x1.6e8b824d2bfaap+6, -0x1.29cc372a6d0bp+9, 0x1.1703a99ddd429p+12, -0x1.2749f9a267cc6p+15, 0x1.5856a17271849p+18, -0x1.a8bcb4ba9753fp+21, 0x1.035dcce88294p+25, -0x1.1e5d8c5e6e043p+28, 0x1.fe3b4f365386ep+30, -0x1.398fdef2b98fep+33, 0x1.84234d4f4ea12p+34}, /* asympt_acc2.sollya: [0x1.e0p-4,0x1.3fp-3], degree 33, relerr <= 2^-105.859 */\n", " {0x1.20dd750429b6ap-1, 0x1.ae622b765e9fdp-55, -0x1.20dd750428f0ep-2, 0x1.03c6c67d69513p-56, 0x1.b14c2f8563e8ep-2, 0x1.766a6bd7aa89cp-57, -0x1.0ecf9d8dedd48p+0, 0x1.0af52e90336e3p-54, 0x1.d9eb4aad086fep+1, 0x1.640d371d54a19p-53, -0x1.0a93f1d01cfep+4, -0x1.68dbd8d9c522cp-51, 0x1.6e842e9fd5898p+6, -0x1.299886ef1fb8p+9, 0x1.15e0f0162c9ap+12, -0x1.222dbc6b04cd8p+15, 0x1.460268db1ebdfp+18, -0x1.74f53ce065fb3p+21, 0x1.961ca8553f87p+24, -0x1.8788395d13798p+27, 0x1.35e37b25d0e81p+30, -0x1.707b7457c8f5ep+32, 0x1.1ff852df1c023p+34, -0x1.b75d0ec56e2cdp+34}, /* asympt_acc3.sollya: [0x1.3fp-3,0x1.95p-3], degree 35, relerr <= 2^-105.557 */\n", " {0x1.20dd750429a8fp-1, -0x1.66d8dda59bceap-56, -0x1.20dd7503fdbabp-2, 0x1.707bdffc2b3fep-57, 0x1.b14c2f6526025p-2, -0x1.7fa4bb954114p-61, -0x1.0ecf99c417d45p+0, -0x1.748645ef7af94p-54, 0x1.d9eaa9c712a7dp+1, 0x1.79e478994ebb4p-53, -0x1.0a8ef11fbf141p+4, 0x1.b5c72d69f8954p-52, 0x1.6e4653e0455b1p+6, -0x1.286909448e6cfp+9, 0x1.113424ce76821p+12, -0x1.1346d859e76dep+15, 0x1.1f9f6cf2293bfp+18, -0x1.258e6e3b337dbp+21, 0x1.14029ecd465fbp+24, -0x1.c530df5337a6fp+26, 0x1.34bc4bbccd336p+29, -0x1.4a37c52641688p+31, 0x1.019707cec2974p+33, -0x1.031fe736ea169p+34, 0x1.f6b3003de3ddfp+33}, /* asympt_acc4.sollya: [0x1.95p-3,0x1.f5p-3], degree 37, relerr <= 2^-105.539 */\n", " {0x1.20dd75042756bp-1, 0x1.4ad9178b5691p-55, -0x1.20dd74feda9e8p-2, -0x1.8141c70bbc8d6p-56, 0x1.b14c2cb128467p-2, -0x1.09aebaa106821p-56, -0x1.0ecf603921a0bp+0, 0x1.7d3cb5bceaf0bp-54, 0x1.d9e3e1751ca59p+1, 0x1.6622ae564267p-56, -0x1.0a686af57f547p+4, 0x1.083b320aff6b6p-51, 0x1.6cf0b6c027326p+6, -0x1.23afcb69443d3p+9, 0x1.03ab450d9f1b9p+12, -0x1.e74cdb76bcab4p+14, 0x1.c671b60e607f1p+17, -0x1.8f1376d324ce4p+20, 0x1.3b64276234676p+23, -0x1.aff0ce13c5a8ep+25, 0x1.ef20247251e87p+27, -0x1.c9f5662f721f6p+29, 0x1.4687858e185e1p+31, -0x1.4fa507be073c2p+32, 0x1.b99ac35ee4accp+32, -0x1.16cb585ee3fa9p+32}, /* asympt_acc5.sollya: [0x1.f5p-3,0x1.31p-2], degree 39, relerr <= 2^-105.722 */\n", " {0x1.20dd7503e730dp-1, 0x1.4e524a098a467p-55, -0x1.20dd7498fa6b2p-2, 0x1.60a4e27751c8p-61, 0x1.b14c061bd2a0cp-2, 0x1.95a8f847d2fc2p-57, -0x1.0ecd0f11b8c7dp+0, -0x1.4126deea76061p-54, 0x1.d9b1344463548p+1, 0x1.fe09a4eca9b0ep-53, -0x1.0996ea52a87edp+4, -0x1.924f920db26cp-53, 0x1.67a2264b556bp+6, -0x1.15dfc2c86b6b5p+9, 0x1.ccc291b62efe4p+11, -0x1.81375a78e746ap+14, 0x1.33a6f15546329p+17, -0x1.c1e9dc121601p+19, 0x1.2397ea3d43fdap+22, -0x1.4661e5b2ea512p+24, 0x1.3412367ca5d45p+26, -0x1.de56b9d7f37c4p+27, 0x1.2851d9722146dp+29, -0x1.19027baf0c3fep+30, 0x1.7e7b8b6ab58acp+30, -0x1.4c446d56aaf22p+30, 0x1.1492190400505p+29}, /* asympt_acc6.sollya: [0x1.31p-2,0x1.71p-2], degree 41, relerr <= 2^-105.433 */\n", " {0x1.20dd74ff10852p-1, 0x1.a32f26deff875p-55, -0x1.20dd6f06c491cp-2, 0x1.70c16e1793358p-56, 0x1.b14a7d5e7fd4ap-2, 0x1.479998b54db5bp-56, -0x1.0ebbdb3889c5fp+0, -0x1.59b853e11369cp-56, 0x1.d89dd249d7ef8p+1, -0x1.4b5edf0c8c314p-55, -0x1.06526fb386114p+4, -0x1.40d04eed7c7ep-55, 0x1.57ff657e429cep+6, -0x1.ef63e90d3863p+8, 0x1.6d4f34c4ea3dap+11, -0x1.04542b9e36a54p+14, 0x1.577bf19097738p+16, -0x1.9702fe47c736dp+18, 0x1.a7ae12b54fdc6p+20, -0x1.7ca3f0f7c4fa9p+22, 0x1.225d983963cbfp+24, -0x1.71a6eac612f9ep+25, 0x1.8086324225e1ep+26, -0x1.3de68670a7716p+27, 0x1.91674de4dcbe9p+27, -0x1.6b44cc15b76c2p+27, 0x1.a36dae0f30d8p+26, -0x1.cffc1747ea3dcp+24}, /* asympt_acc7.sollya: [0x1.71p-2,0x1.bcp-2], degree 43, relerr <= 2^-105.629 */\n", " {0x1.20dd74ba8f3p-1, -0x1.9dd256871d21p-58, -0x1.20dd3593675bcp-2, 0x1.ec0e7ffa91ad9p-56, 0x1.b13eef86a077ap-2, -0x1.4fb5d78d411b8p-56, -0x1.0e5cf52a11f3ap+0, -0x1.51f36c779dc8cp-55, 0x1.d4417a08b39d5p+1, 0x1.1be9fb5956638p-54, -0x1.f91b9f6ce80c3p+3, -0x1.c9c99dd42829cp-51, 0x1.356439f45bb43p+6, -0x1.8c0ca12819b48p+8, 0x1.efcad2ecd6671p+10, -0x1.21b0af6fc1039p+13, 0x1.327d215ee30c9p+15, -0x1.1fabda96167bp+17, 0x1.d82e4373b315dp+18, -0x1.4ed9e2ff591e9p+20, 0x1.95c85dcd8eab5p+21, -0x1.9f016f0a3d62ap+22, 0x1.60e89d918b96fp+23, -0x1.e97be202cba64p+23, 0x1.0d8a081619793p+24, -0x1.c5422b4fcfc65p+23, 0x1.1131a9dc6aed1p+23, -0x1.a457d9dced257p+21, 0x1.3605e980e8b86p+19}, /* asympt_acc8.sollya: [0x1.bcp-2,0x1.0bp-1], degree 45, relerr <= 2^-105.064 */\n", " {0x1.20dd7319d4d25p-1, 0x1.2b02992c3b7abp-55, -0x1.20dc29c13ab1bp-2, -0x1.d78d79b4ad767p-56, 0x1.b115a57b5ab13p-2, -0x1.aa8c45be0aa2ep-57, -0x1.0d58ec437efd7p+0, -0x1.994f00a15e85p-58, 0x1.cb1742e229f23p+1, -0x1.8000471d54399p-53, -0x1.d99a5edf7b946p+3, -0x1.af76ed7e35cdep-52, 0x1.0a8b71058eb28p+6, -0x1.2d88289da5bfcp+8, 0x1.43ddf24168edbp+10, -0x1.3e9dfc38b6d1ap+12, 0x1.18d4df97ab3dfp+14, -0x1.b550fc62dcab5p+15, 0x1.29cb71f116ed1p+17, -0x1.5fc9cc4e854e3p+18, 0x1.65915fd0567b1p+19, -0x1.35eb5fca0e46dp+20, 0x1.c5261ecc0d789p+20, -0x1.138932dc4eafcp+21, 0x1.117d4eb18facdp+21, -0x1.af96163e35ecap+20, 0x1.0454a3a63c766p+20, -0x1.c2ebc1d39b44ap+18, 0x1.f3327698e0e6bp+16, -0x1.094febc3dff35p+14}, /* asympt_acc9.sollya: [0x1.0bp-1,0x1.2b81f34bfce36p-1], degree 47, relerr <= 2^-117.075 */\n", "\n", "\"\"\"\n", "\n", "import re\n", "\n", "def strip_c_comments(code: str) -> str:\n", " return re.sub(r'/\\*.*?\\*/', '', code)\n", "\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in strip_c_comments(data).strip().splitlines():\n", " floats = line.strip(\"{}, \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"[ {', '.join(encoded)} ],\")" ] }, { "cell_type": "code", "execution_count": 15, "id": "635f2c62-243a-4ad0-a731-aa6b345983c3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0xb172_17f7_d1cf_79ab_c9e3_b398_03f2_f6af_u128\n" ] } ], "source": [ "from sage.all import *\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 4\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "(s, m, e) = RealField(128)(2).log().sign_mantissa_exponent();\n", "print(format_hex(m));" ] }, { "cell_type": "code", "execution_count": null, "id": "6c990adc-d571-40e8-9807-cc21c66b0542", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "0f1ba3a4-d823-4ae4-83a4-16080fdb9ba2", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Log2p1.ipynb000064400000000000000000000117341046102023000141260ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 5, "id": "44dbc3b2-a221-4d14-be37-efce71cd1484", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -128,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -129,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xcccccccc_cccccccc_cccccccc_cccccccd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -130,\n", " mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0x92492492_49249249_24924924_92492492_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -130,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -131,\n", " mantissa: 0xcccccccc_cccccccc_cccccccc_cccccccd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xba2e8ba2_e8ba2e8b_a2e8ba2e_8ba2e8ba_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -131,\n", " mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0x9d89d89d_89d89d89_d89d89d8_9d89d89e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -131,\n", " mantissa: 0x92492492_49249249_24924924_92492492_u128,\n", "},\n" ] } ], "source": [ "from sage.all import *\n", "# Sin coeffs\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"},\")\n", "\n", "R = RealField(256)\n", " \n", "arr = [R(1),\n", "R(-0.5),\n", "R(1)/R(3),\n", "R(-1)/R(4),\n", "R(1)/R(5),\n", "R(-1)/R(6),\n", "R(1)/R(7),\n", "R(-1)/R(8),\n", "R(1)/R(9),\n", "R(-1)/R(10),\n", "R(1)/R(11),\n", "R(-1)/R(12),\n", "R(1)/R(13),\n", "R(-1)/R(14)]\n", "\n", "for num in arr:\n", " print_dyadic(num)" ] }, { "cell_type": "code", "execution_count": 32, "id": "c19ff295-9672-4689-aa66-d09a1ad41298", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x935d_8ddd_aaa8_ac16_ea56_d62b_82d3_0a29_u128\n" ] } ], "source": [ "from sage.all import *\n", "\n", "def format_hex2(value):\n", " l = hex(value)[2:]\n", " n = 4\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "(s, m, e) = (RealField(128)(1)/RealField(128)(10)).log().sign_mantissa_exponent();\n", "print(format_hex2(m));" ] }, { "cell_type": "code", "execution_count": null, "id": "4326ffa3-bdea-4f4f-b9a3-7ff5ddaef1be", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Sinc.ipynb000064400000000000000000000041161046102023000137520ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "02a18733-d191-4b33-a1a5-c7a7bd7a44f0", "metadata": {}, "outputs": [ { "ename": "SyntaxError", "evalue": "cannot assign to function call here. Maybe you meant '==' instead of '='? (3970416357.py, line 2)", "output_type": "error", "traceback": [ " \u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[31m \u001b[39m\u001b[31mf(x) = sin(x)/x\u001b[39m\n ^\n\u001b[31mSyntaxError\u001b[39m\u001b[31m:\u001b[39m cannot assign to function call here. Maybe you meant '==' instead of '='?\n" ] } ], "source": [ "# Define sinc\n", "f(x) = sin(x)/x\n", "\n", "# Define polynomial approximation\n", "# e.g. Taylor series to degree 6\n", "P(x) = 1 + x^2 * (-0.16666666654031270233815575920743867754936218261719 + x^2 * (8.333321217660135879490290733428992098197340965271e-3 + x^2 * (-1.98080586529091463680873896890943797188811004161835e-4)))\n", "\n", "# Define error\n", "err(x) = abs(f(x) - P(x))\n", "\n", "# Interval to check\n", "a, b = 0.0, 0.25 # example interval\n", "\n", "# Find maximum error\n", "max_error = find_local_maximum(err, a, b)\n", "\n", "# Convert to ULPs (near x=0, sinc ≈ 1)\n", "ulp64 = 2.0^-53\n", "ulp_error = max_error / ulp64\n", "\n", "print(\"Maximum error:\", max_error)\n", "print(\"ULP error:\", ulp_error)" ] }, { "cell_type": "code", "execution_count": null, "id": "64bbc549-cf46-462b-9951-176038a1bba0", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Sinc_0_25.ipynb000064400000000000000000000253221046102023000145010ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "b0d80cbb-d24c-457e-9b13-29bee52ad44e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.999999999999394\n", "Maximum error: (3.9834802123550617e-13, 0.0843520076712255)\n", "ULP error: 3.34158539772034e-6\n" ] } ], "source": [ "# Define sinc\n", "import struct\n", "\n", "f(x) = sin(x)/x\n", "\n", "c1 = struct.unpack('!d', 0x3ff0000000000000.to_bytes(8, 'big'))[0]\n", "c2 = struct.unpack('!d', 0xbfc55555550fde98.to_bytes(8, 'big'))[0]\n", "c3 = struct.unpack('!d', 0x3f81110f70c67a6b.to_bytes(8, 'big'))[0]\n", "c4 = struct.unpack('!d', 0xbf29f67b484037dc.to_bytes(8, 'big'))[0]\n", "\n", "P(x) = c1 + x^2 * (c2 + x^2 * (c3 + x^2 * (c4)))\n", "\n", "print(P(-0.000001907348));\n", "\n", "# Define error\n", "err(x) = abs(f(x) - P(x))\n", "\n", "# Interval to check\n", "a, b = 0.0, 0.25 # example interval\n", "\n", "# Find maximum error\n", "max_error = find_local_maximum(err, a, b)\n", "\n", "# Convert to ULPs (near x=0, sinc ≈ 1)\n", "ulp64 = 2.0^-23\n", "ulp_error = max_error[0] / ulp64\n", "\n", "print(\"Maximum error:\", max_error)\n", "print(\"ULP error:\", ulp_error)" ] }, { "cell_type": "code", "execution_count": 24, "id": "45f022f6-f1a5-40f1-8fd9-a8d31b114284", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.958797543531305\n", "Maximum error: (3.0182523147459506e-12, 0.4349118306282373)\n", "ULP error: 0.0000253189355134964\n" ] } ], "source": [ "# Sinc approximation 0.25 - 0.75\n", "import struct\n", "\n", "f(x) = sin(x)/x\n", "\n", "c1 = struct.unpack('!d', 0x3ff0000000000000.to_bytes(8, 'big'))[0]\n", "c2 = struct.unpack('!d', 0xbfc5555554eec3c3.to_bytes(8, 'big'))[0]\n", "c3 = struct.unpack('!d', 0x3f811110a5e9f7da.to_bytes(8, 'big'))[0]\n", "c4 = struct.unpack('!d', 0xbf2a0112d52eb13f.to_bytes(8, 'big'))[0]\n", "c5 = struct.unpack('!d', 0x3ec6d3ed4b8fccdb.to_bytes(8, 'big'))[0]\n", "\n", "P(x) = c1 + x^2 * (c2 + x^2 * (c3 + x^2 * (c4 + x^2 * c5)))\n", "\n", "# Define error\n", "err(x) = abs(f(x) - P(x))\n", "\n", "print(P(0.50032926));\n", "\n", "# Interval to check\n", "a, b = 0.25, 0.75 # example interval\n", "\n", "# Find maximum error\n", "max_error = find_local_maximum(err, a, b)\n", "\n", "# Convert to ULPs (near x=0, sinc ≈ 1)\n", "ulp64 = 2.0^-23\n", "ulp_error = max_error[0] / ulp64\n", "\n", "print(\"Maximum error:\", max_error)\n", "print(\"ULP error:\", ulp_error)" ] }, { "cell_type": "code", "execution_count": 21, "id": "e2a79007-2429-42b2-bab4-79d2a34c65be", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum error: (9.444889315091132e-12, 1.3860856166545408)\n", "ULP error: 0.0000792294740676880\n" ] } ], "source": [ "# Sinc approximation 0.75 - 1.57\n", "import struct\n", "\n", "f(x) = sin(x)/x\n", "\n", "c1 = struct.unpack('!d', 0x3ff0000000000000.to_bytes(8, 'big'))[0]\n", "c2 = struct.unpack('!d', 0xbfc555555352131a.to_bytes(8, 'big'))[0]\n", "c3 = struct.unpack('!d', 0x3f811110917c2d6c.to_bytes(8, 'big'))[0]\n", "c4 = struct.unpack('!d', 0xbf2a017122346053.to_bytes(8, 'big'))[0]\n", "c5 = struct.unpack('!d', 0x3ec715c10948b2bb.to_bytes(8, 'big'))[0]\n", "c6 = struct.unpack('!d', 0xbe598e80b2f564d1.to_bytes(8, 'big'))[0]\n", "\n", "P(x) = c1 + x^2 * (c2 + x^2 * (c3 + x^2 * (c4 + x^2 * (c5 + x^2 * c6))))\n", "\n", "# Define error\n", "err(x) = abs(f(x) - P(x))\n", "\n", "# Interval to check\n", "a, b = 0.75, 1.57 # example interval\n", "\n", "# Find maximum error\n", "max_error = find_local_maximum(err, a, b)\n", "\n", "# Convert to ULPs (near x=0, sinc ≈ 1)\n", "ulp64 = 2.0^-23\n", "ulp_error = max_error[0] / ulp64\n", "\n", "print(\"Maximum error:\", max_error)\n", "print(\"ULP error:\", ulp_error)" ] }, { "cell_type": "code", "execution_count": 26, "id": "70cf54d3-a49d-4549-948a-0a0ff9dd9a71", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum error: (3.063105324940807e-12, 1.8795955862040234)\n", "ULP error: 0.0000256951898336411\n" ] } ], "source": [ "# Sinc approximation 1.57 - 2.45\n", "import struct\n", "\n", "f(x) = sin(x)/x\n", "\n", "c1 = struct.unpack('!d', 0x3ff0000000000000.to_bytes(8, 'big'))[0]\n", "c2 = struct.unpack('!d', 0xbfc555554d9b6e68.to_bytes(8, 'big'))[0]\n", "c3 = struct.unpack('!d', 0x3f81111055765b6d.to_bytes(8, 'big'))[0]\n", "c4 = struct.unpack('!d', 0xbf2a0183046fdadc.to_bytes(8, 'big'))[0]\n", "c5 = struct.unpack('!d', 0x3ec71b86e78faed3.to_bytes(8, 'big'))[0]\n", "c6 = struct.unpack('!d', 0xbe5aafd4090b9833.to_bytes(8, 'big'))[0]\n", "c7 = struct.unpack('!d', 0x3de37a6a05e64649.to_bytes(8, 'big'))[0]\n", "\n", "P(x) = c1 + x^2 * (c2 + x^2 * (c3 + x^2 * (c4 + x^2 * (c5 + x^2 * (c6 + x^2 * c7)))))\n", "\n", "# Define error\n", "err(x) = abs(f(x) - P(x))\n", "\n", "# Interval to check\n", "a, b = 1.57, 2.45 # example interval\n", "\n", "# Find maximum error\n", "max_error = find_local_maximum(err, a, b)\n", "\n", "# Convert to ULPs (near x=0, sinc ≈ 1)\n", "ulp64 = 2.0^-23\n", "ulp_error = max_error[0] / ulp64\n", "\n", "print(\"Maximum error:\", max_error)\n", "print(\"ULP error:\", ulp_error)" ] }, { "cell_type": "code", "execution_count": 37, "id": "c92a71d0-5dba-4b9d-9c40-16ae8fc0815b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum error: (1.1107781361374691e-12, 2.6054360298302033)\n", "ULP error: 9.31788235902786e-6\n" ] } ], "source": [ "# Sinc approximation 2.45 - 2.95\n", "import struct\n", "\n", "f(x) = sin(x)/x\n", "\n", "D = RealField(53)\n", "\n", "c1 = D(struct.unpack('!d', 0x3ff0000000000000.to_bytes(8, 'big'))[0])\n", "c2 = D(struct.unpack('!d', 0xbfc55554760558e3.to_bytes(8, 'big'))[0])\n", "c3 = D(struct.unpack('!d', 0x3f8111058de4ff03.to_bytes(8, 'big'))[0])\n", "c4 = D(struct.unpack('!d', 0xbf2a00a34844c1ca.to_bytes(8, 'big'))[0])\n", "c5 = D(struct.unpack('!d', 0x3ec71252fcdf8a53.to_bytes(8, 'big'))[0])\n", "c6 = D(struct.unpack('!d', 0xbe5a4d6c697efba0.to_bytes(8, 'big'))[0])\n", "c7 = D(struct.unpack('!d', 0x3de1cee3a67bcfb4.to_bytes(8, 'big'))[0])\n", "\n", "P(x) = c1 + x^2 * (c2 + x^2 * (c3 + x^2 * (c4 + x^2 * (c5 + x^2 * (c6 + x^2 * c7)))))\n", "\n", "# Define error\n", "err(x) = abs(f(x) - P(x))\n", "\n", "# Interval to check\n", "a, b = 2.45, 2.95 # example interval\n", "\n", "# Find maximum error\n", "max_error = find_local_maximum(err, a, b)\n", "\n", "# Convert to ULPs (near x=0, sinc ≈ 1)\n", "ulp64 = 2.0^-23\n", "ulp_error = max_error[0] / ulp64\n", "\n", "print(\"Maximum error:\", max_error)\n", "print(\"ULP error:\", ulp_error)" ] }, { "cell_type": "code", "execution_count": 38, "id": "876d1329-a7d4-4bec-b507-2cbe718830ed", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-0.0685314999709694\n" ] } ], "source": [ "P(x) = 1 + x^2 * (-0.16666666503769192453354719418712193146347999572754 + x^2 * (8.333332162275294482944865137596934800967574119568e-3 + x^2 * (-1.9841232994419444020731124744827411632286384701729e-4 + x^2 * (2.75566561227184667065429404808618585320800775662065e-6 + x^2 * (-2.5044636620069638584987922161513573815483368889545e-8 + x^2 * (1.6004967791546758341739649455592962162819858917828e-10 + x^2 * (-7.4006627638321043722392127908527396375985146770304e-13 + x^2 * 2.1564878250304773053066570100773910625219177607942e-15)))))))\n", "print(P(-3.375));" ] }, { "cell_type": "code", "execution_count": 1, "id": "a696c72d-6c2b-4c18-b9de-ad6a902e2710", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'minimax' is not defined", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 9\u001b[39m degree = Integer(\u001b[32m10\u001b[39m)\n\u001b[32m 11\u001b[39m \u001b[38;5;66;03m# Compute minimax polynomial approximation\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m p = \u001b[43mminimax\u001b[49m(f, x, degree, a, b)\n\u001b[32m 14\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mMinimax polynomial of degree\u001b[39m\u001b[33m\"\u001b[39m, degree, \u001b[33m\"\u001b[39m\u001b[33mon [0.25, 0.9]:\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 15\u001b[39m \u001b[38;5;28mprint\u001b[39m(p)\n", "\u001b[31mNameError\u001b[39m: name 'minimax' is not defined" ] } ], "source": [ "from sage.all import *\n", "\n", "# Define the variable and function\n", "x = var('x')\n", "f = sin(x)/x\n", "\n", "# Define the interval and degree\n", "a, b = 0.25, 0.9\n", "degree = 10\n", "\n", "# Compute minimax polynomial approximation\n", "p = minimax(f, x, degree, a, b)\n", "\n", "print(\"Minimax polynomial of degree\", degree, \"on [0.25, 0.9]:\")\n", "print(p)\n", "\n", "# Compute the max error (sup norm) on the interval\n", "err = max([abs(f(x_val) - p(x_val)) for x_val in srange(a, b, 0.001)])\n", "print(\"Max absolute error on interval:\", err)" ] }, { "cell_type": "code", "execution_count": null, "id": "03bcbcf2-d56a-442c-ae87-96f6e7b0c282", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 10.6", "language": "sage", "name": "sagemath-10.6" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Sinc_f64.ipynb000064400000000000000000000336731046102023000144430ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 5, "id": "7bc086d1-23e7-4e24-8a45-708d2084afca", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "P(-0.000001907348) = 0.999999999999394\n", "Maximum error: 1.1102230246251565e-16 at x = 0.22478179847681032\n", "ULP error: 1.0\n", "Def error 1.11022302462516e-16, ziv's 2.46519032881566e-32\n" ] } ], "source": [ "import struct\n", "import math\n", "from sage.numerical.optimize import find_local_maximum\n", "from sage.all import *\n", "\n", "# Define sinc function safely at x=0\n", "def sinc(x):\n", " return math.sin(x)/x if x != 0 else 1.0\n", "\n", "# Helper to unpack hex to double float\n", "def hex_to_double(h):\n", " # h is int representing 64-bit hex\n", " b = h.to_bytes(8, 'big')\n", " return struct.unpack('!d', b)[0]\n", "\n", "def ulp(x):\n", " import struct\n", " if x == 0.0:\n", " # Smallest positive subnormal double\n", " return 2**-1074\n", " packed = struct.pack('>d', x)\n", " intval = struct.unpack('>Q', packed)[0]\n", " next_intval = intval + 1\n", " packed_next = struct.pack('>Q', next_intval)\n", " next_float = struct.unpack('>d', packed_next)[0]\n", " return abs(next_float - x)\n", "\n", "D = RealField(53)\n", "\n", "# Coefficients from hex\n", "c1 = D(hex_to_double(0x3ff0000000000000))\n", "c2 = D(hex_to_double(0xbfc5555555555555))\n", "c3 = D(hex_to_double(0x3f81111111110d43))\n", "c4 = D(hex_to_double(0xbf2a01a019c4ccb1))\n", "c5 = D(hex_to_double(0x3ec71de1eb4146e4))\n", "c6 = D(hex_to_double(0xbe5ada962298aa99))\n", "c7 = D(hex_to_double(0xbdcf5c28d2544fdf))\n", "\n", "# Define polynomial approximation P(x)\n", "def P(x):\n", " return c1 + x**2 * (c2 + x**2 * (c3 + x**2 * (c4 + x**2*(c5 + x**2*(c6 + x**2*c7)))))\n", "\n", "# Test value\n", "print(\"P(-0.000001907348) =\", P(-0.000001907348))\n", "\n", "# Define error function\n", "def err(x):\n", " return abs(sinc(x) - P(x))\n", "\n", "# Interval to check max error\n", "a, b = 0.0, 0.25\n", "\n", "# Find local maximum error on [a, b]\n", "max_error = find_local_maximum(err, a, b)\n", "max_err_val, max_err_point = max_error[0], max_error[1]\n", "\n", "# Compute error in ULPs (for double precision near 1)\n", "ulp64 = 2.0**-53\n", "ulp_error = max_err_val / ulp64\n", "\n", "print(f\"Maximum error: {max_err_val} at x = {max_err_point}\")\n", "print(f\"ULP error: {ulp_error}\")\n", "\n", "def_error = abs(sinc(0.22478179847681032) - P(0.22478179847681032))\n", "zivs_error = ulp(def_error)\n", "print(f\"Def error {def_error}, ziv's {zivs_error}\")\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "f90b16da-a176-4331-acd6-c3d69b865581", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ULP: 1.925929944387236e-34\n", "P(0.5000000018241053) = 0.958851076911921\n", "Maximum error: 1.1102230246251565e-16 at x = 0.6584344092462794\n", "ULP error: 1.0\n", "Def error 1.11022302462516e-16, ziv's 2.46519032881566e-32, eps 1.3684555315672045e-48\n", "ULP error 1.2924697071141057e-26\n" ] } ], "source": [ "import struct\n", "import math\n", "from sage.numerical.optimize import find_local_maximum\n", "from sage.all import *\n", "\n", "DD = RealField(108)\n", "D = RealField(53)\n", "\n", "# Define sinc function safely at x=0\n", "def sinc(x):\n", " return DD(math.sin(x))/DD(x) if x != 0 else 1.0\n", "\n", "# Helper to unpack hex to double float\n", "def hex_to_double(h):\n", " # h is int representing 64-bit hex\n", " b = h.to_bytes(8, 'big')\n", " return struct.unpack('!d', b)[0]\n", "\n", "def ulp(x):\n", " import struct\n", " if x == 0.0:\n", " # Smallest positive subnormal double\n", " return 2**-1074\n", " packed = struct.pack('>d', x)\n", " intval = struct.unpack('>Q', packed)[0]\n", " next_intval = intval + 1\n", " packed_next = struct.pack('>Q', next_intval)\n", " next_float = struct.unpack('>d', packed_next)[0]\n", " return abs(next_float - x)\n", "\n", "print(f\"ULP: {ulp(1.513428473345662200493584297609841363626e-18)}\")\n", "\n", "# Coefficients from hex\n", "c1 = D(hex_to_double(0x3ff0000000000000))\n", "c2 = D(hex_to_double(0xbfc5555555555555))\n", "c3 = D(hex_to_double(0x3f8111111111101a))\n", "c4 = D(hex_to_double(0xbf2a01a019fd0691))\n", "c5 = D(hex_to_double(0x3ec71de39965a2e5))\n", "c6 = D(hex_to_double(0xbe5ae61fdf272202))\n", "c7 = D(hex_to_double(0x3de5c7a9848cf1c0))\n", "c8 = D(hex_to_double(0x3d943d57baadd54c))\n", "c9 = D(hex_to_double(0xbda26dc0e6dc959b))\n", "c10 = D(hex_to_double(0x3da0348571538ead))\n", "c11 = D(hex_to_double(0xbd888756fa3d379a))\n", "\n", "# Define polynomial approximation P(x)\n", "def P(x):\n", " return c1 + x**2 * (c2 + x**2 * (c3 + x**2 * (c4 + x**2*(c5 + x**2*(c6 + x**2*(c7 + x**2*(c8 + x**2*(c9 + x**2*(c10 + x**2*c11)))))))))\n", "\n", "# Test value\n", "print(\"P(0.5000000018241053) =\", P(0.5000000018241053))\n", "\n", "# Define error function\n", "def err(x):\n", " return abs(sinc(x) - P(x))\n", "\n", "# Interval to check max error\n", "a, b = 0.25, 0.7\n", "\n", "# Find local maximum error on [a, b]\n", "max_error = find_local_maximum(err, a, b)\n", "max_err_val, max_err_point = max_error[0], max_error[1]\n", "\n", "# Compute error in ULPs (for double precision near 1)\n", "ulp64 = 2.0**-53\n", "ulp_error = max_err_val / ulp64\n", "\n", "print(f\"Maximum error: {max_err_val} at x = {max_err_point}\")\n", "print(f\"ULP error: {ulp_error}\")\n", "\n", "def_error = abs(sinc(0.6584344092462794) - P(0.6584344092462794))\n", "e = 1.1102230246251565e-16*2**(-53) / (1 - 1.1102230246251565e-16)*2**(-53)\n", "zivs_error = ulp(def_error)\n", "print(f\"Def error {def_error}, ziv's {zivs_error}, eps {e}\")\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "9772da71-a95c-4c0b-afec-15e17a185c72", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0x0000000000000000, 0x3ff0000000000000),\n", "(0x3e15555558000000, 0xbfc5555558000000),\n", "(0x3dc1111110000000, 0x3f81111110000000),\n", "(0xbd700d00d0000000, 0xbf2a01a018000000),\n", "(0xbd1549c668000000, 0x3ec71de3a8000000),\n", "(0x3c45765600000000, 0xbe5ae64568000000),\n", "(0x3c3d432008000000, 0x3de6124610000000),\n", "(0x3b9a8a2a40000000, 0xbd6ae7f3e8000000),\n", "(0x3b38ad4b60000000, 0x3ce952c768000000),\n", "(0xbaa7b0c0a0000000, 0xbc62f49900000000),\n", "(0x3a29ea8e58000000, 0x3bd71a3690000000),\n", "(0x39994f6020000000, 0xbb46e71b58000000),\n" ] } ], "source": [ "import struct\n", "from sage.all import *\n", "\n", "def veltkamp_split(x):\n", " s = 2**27 + 1 # splitting constant for double precision\n", " c = s * x\n", " hi = c - (c - x)\n", " lo = x - hi\n", " return hi, lo\n", "\n", "def double_to_hex(f):\n", " # Pack double into 8 bytes and unpack as 64-bit unsigned int, then convert to hex\n", " return format(struct.unpack('= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"},\")\n", " \n", "arr = [1,\n", "-0.166666666666666666666666655046098333674241424421013,\n", "8.3333333333333333333331831421004348543883293530357e-3,\n", "-1.9841269841269841269753150083731137729917315898448e-4,\n", "2.7557319223985890621576620783905775088236557741698e-6,\n", "-2.5052108385441711522991020660308014545508855347942e-8,\n", "1.60590438368204277871370189786500351551966543276647e-10,\n", "-7.6471637316812555218399795763893819204414937261132e-13,\n", "2.8114572428040154437944346095476833593632491361069e-15,\n", "-8.2206285242834984003520751985570987913105938287195e-18,\n", "1.9570332899853812841548996540992839174401821857085e-20,\n", "-3.807458690891922170447691589270102843057880400501e-23]\n", "\n", "for num in arr:\n", " print_dyadic(num)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "a286d7a5-666d-4ae7-8849-05d1a27bfdef", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/Sincos.ipynb000064400000000000000000001707741046102023000143320ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 2, "id": "2e431ed8-532c-46c2-bcdd-514781027725", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -130,\n", " mantissa: 0xaaaaaaaa_aaaaa800_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -134,\n", " mantissa: 0x88888888_88888800_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -140,\n", " mantissa: 0xd00d00d0_0d00d000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -146,\n", " mantissa: 0xb8ef1d2a_b639a000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -153,\n", " mantissa: 0xd7322b3f_a7275800_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -160,\n", " mantissa: 0xb09213e3_e0c59800_00000000_00000000_u128,\n", "},\n" ] } ], "source": [ "from sage.all import *\n", "# Sin coeffs\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"},\")\n", " \n", "arr = [1,\n", "-0.16666666666666666666666666666666666659050442851964,\n", "8.333333333333333333333333333323619772116535689486e-3,\n", "-1.98412698412698412698412283687705166077213672213636e-4,\n", "2.7557319223985890570951361102810288106745618520922e-6,\n", "-2.5052108385360429827820998158828910822819488754076e-8,\n", "1.60590039740400542784979957085919344398220983549105e-10]\n", "\n", "for num in arr:\n", " print_dyadic(num)" ] }, { "cell_type": "code", "execution_count": 3, "id": "488a9e26-ba71-4e5d-a338-892861ac3303", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -128,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -132,\n", " mantissa: 0xaaaaaaaa_aaaaa800_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -137,\n", " mantissa: 0xb60b60b6_0b60b800_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -143,\n", " mantissa: 0xd00d00d0_0d00d000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -149,\n", " mantissa: 0x93f27dbb_c22b1000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -156,\n", " mantissa: 0x8f76ac91_ba722800_00000000_00000000_u128,\n", "},\n" ] } ], "source": [ "from sage.all import *\n", "# Sin coeffs\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"},\")\n", " \n", "arr = [1,\n", "-0.49999999999999999999999999999999999885683174382533,\n", "4.166666666666666666666666666652090722211927807889e-2,\n", "-1.38888888888888888888888266652018773311359833045342e-3,\n", "2.48015873015873014648745658022100343308694733543046e-5,\n", "-2.7557319223863947053476600591061602210108484050071e-7,\n", "2.0876697191532375136133666649782231753319669015627e-9]\n", "\n", "for num in arr:\n", " print_dyadic(num)" ] }, { "cell_type": "code", "execution_count": 8, "id": "83dd609f-c906-4056-8fa0-9af9bb494d79", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static SIN_K_PI_OVER_128_F128: [DyadicFloat128; 65] = [\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: 0,\n", " mantissa: 0x0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -133,\n", " mantissa: 0xc90a_afbd_1b33_efc9_c539_edcb_fda0_cf2c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -132,\n", " mantissa: 0xc8fb_2f88_6ec0_9f37_6a17_954b_2b7c_5171_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0x96a9_0496_70cf_ae65_f775_7409_4d3c_35c4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xc8bd_35e1_4da1_5f0e_c739_6c89_4bbf_7389_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xfab2_72b5_4b98_71a2_7047_29ae_56d7_8a37_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0x9640_8374_7309_d113_000a_89a1_1e07_c1ff_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xaf10_a224_59fe_32a6_3fee_f3bb_58b1_f10d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xc7c5_c1e3_4d30_55b2_5cc8_c00e_4fcc_d850_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xe05c_1353_f27b_17e5_0ebc_61ad_e6ca_83cc_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xf8cf_cbd9_0af8_d57a_4221_dc4b_a772_598d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x888e_9315_8fb3_bb04_9841_56f5_5334_4306_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x94a0_3176_acf8_2d45_ae4b_a773_da6b_f754_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xa09a_e4a0_bb30_0a19_2f89_5f44_a303_cc0b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xac7c_d3ad_58fe_e7f0_811f_9539_84ef_f83e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xb844_2987_d22c_f576_9cc3_ef36_746d_e3b8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xc3ef_1535_754b_168d_3122_c2a5_9efd_dc37_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xcf7b_ca1d_476c_516d_a812_90bd_baad_62e4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xdae8_804f_0ae6_015b_362c_b974_182e_3030_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xe633_74c9_8e22_f0b4_2872_ce1b_fc7a_d1cc_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xf15a_e9c0_37b1_d8f0_6c48_e9e3_420b_0f1d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0xfc5d_26df_c4d5_cfda_27c0_7c91_1290_b8d1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x839c_3cc9_17ff_6cb4_bfd7_9717_f288_0abf_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x88f5_9aa0_da59_1421_b892_ca83_61d8_c84c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x8e39_d9cd_7346_4364_bba4_cfec_bff5_4868_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x9368_2a66_e896_f544_b178_2191_1e71_c16e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x987f_bfe7_0b81_a708_19ce_c845_ac87_a5c6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x9d7f_d149_0285_c9e3_e25e_3954_9638_ae67_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xa267_9928_48ee_b0c0_3b51_67ee_359a_234e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xa736_55df_1f2f_489e_149f_6e75_9934_68a2_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xabeb_49a4_6764_fd15_1bec_da80_89c1_a94c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb085_baa8_e966_f6da_e4ca_d00d_5c94_bcd1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb504_f333_f9de_6484_597d_89b3_754a_be9f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xb968_41bf_7ffc_b21a_9de1_e3b2_2b8b_f4db_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xbdae_f913_557d_76f0_ac85_320f_528d_6d5c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc1d8_705f_fcbb_6e90_bdf0_715c_b8b2_0bd7_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc5e4_0358_a8ba_05a7_43da_25d9_9267_326b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xc9d1_124c_931f_da7a_8335_241b_e169_3225_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xcd9f_023f_9c3a_059e_23af_31db_7179_a4a9_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xd14d_3d02_313c_0eed_744f_ea20_e8ab_ef92_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xd4db_3148_750d_1819_f630_e8b6_dac8_3e68_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xd848_52c0_a80f_fcdb_24b9_fe00_6635_74a4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xdb94_1a28_cb71_ec87_2c19_b632_53da_43fb_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xdebe_0563_7ca9_4cfb_4b19_aa71_fec3_ae6c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xe1c5_978c_05ed_8691_f4e8_a837_2f8c_5810_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xe4aa_5909_a08f_a7b4_1227_85ae_67f5_515c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xe76b_d7a1_e63b_9786_1251_2952_9d48_a92f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xea09_a68a_6e49_cd62_15ad_45b4_a1b5_e823_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xec83_5e79_946a_3145_7e61_0231_ac1d_6181_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xeed8_9db6_6611_e307_86f8_c20f_b664_b01b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xf109_0827_b437_25fd_6712_7db3_5b28_7315_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xf314_4762_4708_8f74_a548_6bdc_455d_56a3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xf4fa_0ab6_316e_d2ec_163c_5c7f_03b7_18c5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xf6ba_073b_424b_19e8_2c79_1f59_cc1f_fc23_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xf853_f7dc_9186_b952_c7ad_c6b4_9888_91ba_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xf9c7_9d63_272c_4628_4504_ae08_d19b_2981_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xfb14_be7f_bae5_8156_2172_a361_fd2a_722f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xfc3b_27d3_8a5d_49ab_2567_78ff_cb5c_1769_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xfd3a_abf8_4528_b50b_eae6_bd95_1c1d_abbd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xfe13_2387_0cfe_9a3d_90cd_1d95_9db6_74ef_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xfec4_6d1e_8929_2cf0_4139_0efd_c726_e9ef_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xff4e_6d68_0c41_d0a9_0f66_8633_f1ab_858a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xffb1_0f1b_cb6b_ef1d_421e_8eda_af59_453e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xffec_4304_2668_65d9_5657_5523_6696_1732_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128,\n", "},\n", "];\n" ] } ], "source": [ "# Sin K PI over 128\n", "R = RealField(128)\n", "π = R.pi()\n", "\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 4\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"},\")\n", "\n", "# Generate array entries\n", "print(\"pub(crate) static SIN_K_PI_OVER_128_F128: [DyadicFloat128; 65] = [\")\n", "for k in range(65):\n", " value = R(k) * π / 128\n", " print_dyadic(value.sin())\n", "\n", "print(\"];\")\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "c93f3cf6-50da-43a9-98bf-7733e576be30", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -133,\n", " mantissa: 0xc90f_daa2_2168_c234_c4c6_628b_80dc_1cd1_u128,\n", "};\n" ] } ], "source": [ "R = RealField(128)\n", "π = R.pi()\n", "\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 4\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"};\")\n", "\n", "print_dyadic(π/128)" ] }, { "cell_type": "code", "execution_count": 47, "id": "79a63428-431f-45ae-83e4-af4b7101a727", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "( 0x4040000000000014, 0x3ce7cc1b727220a8, 0x39a4fe13abe8fa9c, 0xb66911f924eb5336 ),\n", "( 0x4040000000145f30, 0x3ceb727220a94fe0, 0x39a3abe8fa9a6ee0, 0x364b6c52b3278872 ),\n", "( 0x404000145f306dc8, 0x3d0c882a53f84eb0, 0xb9a70565911f9250, 0x3664acc9e21c8210 ),\n", "( 0x40445f306dc9c884, 0xbd05ac07b1505c14, 0xb9c96447e493ad4c, 0xb67b0ef1bef806ba ),\n", "( 0xc03f246c6efab580, 0xbceec54170565910, 0xb9af924eb53361e0, 0x366c820ff28b1d5f ),\n", "( 0x403391054a7f09d4, 0x3cff47d4d377036c, 0x39b8a5664f10e410, 0x365fe5163abdebbc ),\n", "( 0x401529fc2757d1f4, 0x3cd34ddc0db62958, 0x39993c439041fe50, 0x36563abdebbc561b ),\n", "( 0xbfeec54170565910, 0xbcaf924eb53361e0, 0x396c820ff28b1d60, 0xb620a21d4f246dc9 ),\n", "( 0xc04505c1596447e4, 0xbcf275a99b0ef1c0, 0x39b07f9458eaf7b0, 0xb670ea79236e4717 ),\n", "( 0xc00596447e493ad4, 0xbcb9b0ef1bef806c, 0x39563abdebbc561c, 0xb601b7238b7b645a ),\n", "( 0x404bb81b6c52b328, 0xbcede37df00d74e4, 0x39a5ef5de2b0db94, 0xb66c8e2ded916900 ),\n", "( 0x404b6c52b3278874, 0xbd0f7c035d38a844, 0x39c778ac36e48dc8, 0xb676f6c8b47fe6db ),\n", "( 0x4042b32788720840, 0xbcdae9c5421443a8, 0xb99e48db91c5bdb4, 0x365d2e006492eea1 ),\n", "( 0xc048778df7c035d4, 0x3ced5ef5de2b0db8, 0x39a2371d2126e970, 0x35f924bba8274648 ),\n", "( 0xc03bef806ba71508, 0xbcd443a9e48db91c, 0xb976f6c8b47fe6dc, 0x36277504e8c90e7f ),\n", "( 0xbfdae9c5421443a8, 0xbc9e48db91c5bdb4, 0x395d2e006492eea0, 0x3603a32439fc3bd6 ),\n", "( 0xc0438a84288753c8, 0xbd01b7238b7b645c, 0x39cc00c925dd413c, 0xb68cdbc603c429c7 ),\n", "( 0xc020a21d4f246dc8, 0xbcdc5bdb22d1ff9c, 0x39825dd413a32438, 0x364fc3bd63962535 ),\n", "( 0xc02d4f246dc8e2e0, 0x3ce26e9700324978, 0xb995f62e6de301e4, 0x365eb1cb129a73ef ),\n", "( 0xc03236e4716f6c8c, 0x3ce7003249775050, 0xb9a736f180f10a70, 0xb66a76b2c608bbee ),\n", "( 0x403b8e909374b800, 0x3cf924bba8274648, 0x399cfe1deb1cb128, 0x365a73ee88235f53 ),\n", "( 0x40309374b801924c, 0xbcd15f62e6de3020, 0x399deb1cb129a740, 0xb65177dca0ad144c ),\n", "( 0xc0268ffcdb688afc, 0x3cdd1921cfe1deb0, 0x399cb129a73ee884, 0xb65ca0ad144bb7b1 ),\n", "( 0x3ff924bba8274648, 0x3c9cfe1deb1cb128, 0x395a73ee88235f54, 0xb61144bb7b166390 ),\n", "( 0xc04a22bec5cdbc60, 0xbcde214e34ed658c, 0xb95177dca0ad144c, 0x35f213a671c09ad1 ),\n", "( 0x4003a32439fc3bd8, 0xbccc69dacb1822f0, 0x3961afa975da2428, 0xb616638fd94ba082 ),\n", "( 0xc03b78c0788538d4, 0x3cd29a73ee882360, 0xb985a28976f62cc8, 0x363c09ad17df904e ),\n", "( 0x404fc3bd63962534, 0x3cfcfba208d7d4bc, 0xb9b12edec598e3f8, 0x367ad17df904e647 ),\n", "( 0xc014e34ed658c118, 0x3cc046bea5d76890, 0x3973a671c09ad17c, 0x363f904e64758e61 ),\n", "( 0x40462534e7dd1048, 0xbd0415a28976f62c, 0xb9b8e3f652e82070, 0x3653991d63983534 ),\n", "( 0xc0363045df7282b4, 0xbcd44bb7b16638fc, 0xb9994ba081bec670, 0x365d639835339f4a ),\n", "( 0x404d1046bea5d768, 0x3cf213a671c09ad0, 0x39b7df904e647590, 0xb679f2b3182d8def ),\n", "( 0x402afa975da24274, 0x3cd9c7026b45f7e4, 0x3953991d63983534, 0xb5f82d8dee81d108 ),\n", "( 0xc04a28976f62cc70, 0xbd0fb29741037d8c, 0xb9bb8a719f2b3184, 0x367272117e2ef7e5 ),\n", "( 0xc0476f62cc71fb28, 0xbd0741037d8cdc54, 0x39acc1a99cfa4e44, 0xb66d03a21036be27 ),\n", "( 0x404d338e04d68bf0, 0xbcdbec66e29c67cc, 0x399339f49c845f8c, 0xb63081b5f13801da ),\n", "( 0x403c09ad17df9050, 0xbcf9b8a719f2b318, 0xb986c6f740e8840c, 0xb64af89c00ed0004 ),\n", "( 0x40468befc827323c, 0xbd038cf9598c16c8, 0x39c08bf177bf2508, 0xb673801da00087ea ),\n", "( 0xc04037d8cdc538d0, 0x3cea99cfa4e422fc, 0x39877bf250763ff0, 0x3642fffbc0b301fe ),\n", "( 0xc048cdc538cf9598, 0xbcf82d8dee81d108, 0xb97b5f13801da000, 0xb620fd33f8086877 ),\n", "( 0xc024e33e566305b0, 0xbcebdd03a21036c0, 0x39ad8ffc4bffef04, 0xb6633f80868773a5 ),\n", "( 0xc03f2b3182d8dee8, 0xbcbd1081b5f13800, 0xb97da00087e99fc0, 0xb610d0ee74a5f593 ),\n", "( 0xc048c16c6f740e88, 0xbce036be27003b40, 0xb920fd33f8086878, 0x35d8b5a0a6d1f6d3 ),\n", "( 0x4043908bf177bf24, 0x3d00763ff12fffbc, 0x3976603fbcbc462c, 0x3636829b47db4da0 ),\n", "( 0x4037e2ef7e4a0ec8, 0xbc7da00087e99fc0, 0xb910d0ee74a5f594, 0x35d1f6d367ecf27d ),\n", "( 0xc03081b5f13801dc, 0x3cffff7816603fbc, 0x39a788c5ad053690, 0xb6425930261b069f ),\n", "( 0xc04af89c00ed0004, 0xbcdfa67f010d0ee8, 0x3986b414da3eda6c, 0x363fb3c9f2c26dd4 ),\n", "( 0xc04c00ed00043f4c, 0xbcffc04343b9d298, 0x3984da3eda6cfda0, 0xb64b069ec9161738 ),\n", "( 0x4042fffbc0b301fc, 0x3d0e5e2316b414dc, 0xb9cc125930261b08, 0x3686136e9e8c7ecd ),\n", "( 0xc020fd33f8086878, 0x3cd8b5a0a6d1f6d4, 0xb9830261b069ec90, 0xb6461738132c3403 ),\n", "( 0xc039fc04343b9d28, 0xbcf7d64b824b2604, 0xb9a86c1a7b24585c, 0xb65c09961a015d29 ),\n", "( 0xc010d0ee74a5f594, 0x3cd1f6d367ecf27c, 0x3986136e9e8c7ecc, 0x3643cbfd45aea4f7 ),\n", "( 0xc04dce94beb25c14, 0x3d0a6cfd9e4f9614, 0xb9b22c2e70265868, 0xb615d28ad8453814 ),\n", "( 0xc044beb25c125930, 0xbcd30d834f648b0c, 0x3978fd9a797fa8b4, 0x363d49eeb1faf97c ),\n", "( 0x403b47db4d9fb3c8, 0x3cff2c26dd3d18fc, 0x39b9a797fa8b5d48, 0x367eeb1faf97c5ed ),\n", "( 0xc0425930261b06a0, 0x3d036e9e8c7ecd3c, 0x39b7fa8b5d49eeb0, 0x367faf97c5ecf41d ),\n", "( 0x403fb3c9f2c26dd4, 0xbcc738132c3402bc, 0x398aea4f758fd7cc, 0xb60d0985f18c10eb ),\n", "( 0xc04b069ec9161738, 0xbcc32c3402ba515c, 0x397eeb1faf97c5ec, 0x362e839cfbc52949 ),\n", "( 0xc04ec9161738132c, 0xbcda015d28ad8454, 0x397faf97c5ecf41c, 0x362cfbc529497536 ),\n", "( 0xc0461738132c3404, 0x3d045aea4f758fd8, 0xb99a0e84c2f8c608, 0xb63d6b5b45650128 ),\n", "( 0x402fb34f2ff516bc, 0xbce6c229c0a0d074, 0xb9730be31821d6b4, 0xb63b4565012813b8 ),\n", "( 0x4043cbfd45aea4f8, 0xbcf4e050683a130c, 0x397ce7de294a4ba8, 0x363afed7ec47e357 ),\n", "( 0xc015d28ad8453814, 0xbc9a0e84c2f8c608, 0xb93d6b5b45650128, 0xb5b3b81ca8bdea7f ),\n", "( 0xc0415b08a7028340, 0xbd0d0985f18c10ec, 0x39b4a4ba9afed7ec, 0x3651f8d5d0856033 ),\n", "( 0xc0314e050683a130, 0xbce7c63043ad6b68, 0xb9959404a04ee074, 0x3655d08560330470 ),\n", "( 0xc0141a0e84c2f8c8, 0x3cdf78a5292ea6c0, 0xb972813b81ca8be0, 0x363580cc11bf1edb ),\n", "( 0xc00d0985f18c10ec, 0x3cb4a4ba9afed7ec, 0x3951f8d5d0856034, 0xb60f72070928a81e ),\n", "( 0xc0485f18c10eb5ac, 0xbd0a2b2809409dc0, 0xb9bca8bdea7f33f0, 0x367bf1edaeafc33f ),\n", "( 0xc048c10eb5ada2b4, 0x3d07f6bf623f1abc, 0xb9cef53f99f72070, 0xb67251503cc10f7e ),\n", "( 0xc03d6b5b45650128, 0xbcb3b81ca8bdea80, 0x39698237e3db5d60, 0xb60e6087beca1794 ),\n", "( 0x40425d4d7f6bf624, 0xbcbca8bdea7f33f0, 0x397bf1edaeafc340, 0xb630f7d942f27896 ),\n", "( 0x403afed7ec47e358, 0xbce7bd4fe67dc81c, 0xb97251503cc10f7c, 0xb63942f27895871c ),\n", "( 0xc04409dc0e545ef4, 0xbd03f99f72070928, 0xb9b503cc10f7d944, 0x3670d876a78e4585 ),\n", "( 0xc04c0e545ef53f98, 0xbd0f72070928a820, 0x39c9f784135e86c4, 0xb662b0e374f508cf ),\n", "( 0xc0445ef53f99f720, 0xbcec24a2a0798220, 0x39a04d7a1b0ed4f0, 0x366c8b0af730d843 ),\n", "( 0x403580cc11bf1edc, 0xbcf1503cc10f7d94, 0xb98793c4ac38dd3c, 0xb644233c9ef34ccf ),\n", "( 0xc049f72070928a80, 0xbd0e6087beca1794, 0x399da9e391615ee8, 0xb65e4f79a667aa0f ),\n", "( 0x404f8f6d757e19f8, 0xbceefb285e4f12b0, 0xb99c6e9ea119e4f8, 0x3639666157c5281a ),\n", "( 0xc0428a81e6087bec, 0xbcf42f27895871bc, 0x39b857b986c21968, 0xb679ea83ad7e5efe ),\n", "( 0xc00e6087beca1794, 0x3c9da9e391615ee8, 0xb95e4f79a667aa10, 0x3614a068408dffd9 ),\n", "( 0xc030f7d942f27894, 0xbcf871ba7a846794, 0x3980cb330abe2940, 0x363a10237ff62013 ),\n", "( 0x40435e86c3b53c74, 0xbd0d3d4233c9ef34, 0xb9b99ea83ad7e5f0, 0x3641bffb1009ae65 ),\n", "( 0x402b0ed4f1c8b0b0, 0xbcd19e4f79a667ac, 0x399f14a068408e00, 0xb623bfd9466c677d ),\n", "( 0xc035871ba7a84678, 0xbcf3de6999ea83ac, 0xb9b7e5efdc8009e0, 0x36335cc9cc418185 ),\n", "( 0xc03ba7a846793de8, 0x3cf666157c5281a0, 0x39b0237ff620135c, 0x366939883030aab6 ),\n", "( 0xc044233c9ef34cd0, 0x3cf57c5281a10238, 0xb923bfd9466c677c, 0xb5df9eaa9358c573 ),\n", "( 0x401b086599855f14, 0x3cc40d0811bffb10, 0x39335cc9cc418184, 0x35f55b29cea32584 ),\n", "( 0x4039666157c5281c, 0xbcfefdc8009dfecc, 0x39bcc9cc41818554, 0x367b29cea325838a ),\n", "( 0xc03ea83ad7e5efdc, 0xbce0013bfd9466c8, 0x39a883030aab6538, 0x366d464b0713de04 ),\n", "( 0xc04d6bf2f7ee4004, 0xbcfdfeca33633be8, 0x3978555b29cea324, 0x3638389ef0231ad2 ),\n", "( 0x403a10237ff62014, 0xbce466c677cfcf54, 0xb9a49ac62b9b4f90, 0x3663de04635a3e21 ),\n", "( 0x4041bffb1009ae64, 0x3cfcc41818555b28, 0x39bcea3258389ef0, 0x36418d68f883386d ),\n", "( 0xc023bfd9466c677c, 0xbcdf9eaa9358c574, 0x3982c1c4f78118d8, 0xb647077cc7930644 ),\n", "( 0x40335cc9cc418184, 0x3cf55b29cea32584, 0xb99d843f7394b83c, 0x3619c367cddce809 ),\n", "( 0xc04b19df3f3d5528, 0x3d04e75192c1c4f8, 0xb9afb9ca5c1df320, 0x366b3e6ee7404954 ),\n", "( 0xc04f3f3d5526b18c, 0x3d0192c1c4f78118, 0x39bad1f10670d9f4, 0xb66118bfb6abe532 ),\n", "( 0x401556ca73a8c960, 0x3ccc4f78118d68f8, 0x3970670d9f3773a0, 0x36025506b388ed17 ),\n", "( 0x40494e75192c1c50, 0xbcf0fdce52e0ef98, 0xb9ae4c19118bfb6c, 0x36641ace23b45cb1 ),\n", "( 0xc035cda7c7610fdc, 0xbceca5c1df31e4c0, 0xb9a9118bfb6abe54, 0x365c4768b961ca6e ),\n", "( 0xc043e3b087ee7298, 0x3cff10670d9f3774, 0xb997f6d57ca63b88, 0xb657469e3592250c ),\n", "( 0x403ef0231ad1f108, 0xbcf8f260c88c5fdc, 0x39a541ace23b45cc, 0xb65e3592250bb2eb ),\n", "( 0x40418d68f883386c, 0x3cff3773a024aa0c, 0x39b6711da2e58728, 0x367b76bd13455c64 ),\n", "( 0xc047077cc7930644, 0xbce8bfb6abe531dc, 0xb982e8d3c6b244a0, 0xb64765d51cdf582b ),\n", "( 0x4019c367cddce808, 0x3cd2a8359c4768b8, 0x39961ca6ddaf44d0, 0x3655719053ea5ff0 ),\n", "( 0xc043064462fedab0, 0x3ceace23b45cb0e4, 0x39a36ed7a268ab8c, 0x365053ea5ff07054 ),\n", "( 0xc0218bfb6abe531c, 0xbcec4ba34f1ac914, 0x39a7a268ab8c82a0, 0xb655a00f8fac081d ),\n", "( 0x40025506b388ed18, 0xbcba78d648942ecc, 0x3955719053ea5ff0, 0x35fc14fdf8cfa0cb ),\n", "( 0x40406b388ed172c4, 0xbceac91285d97548, 0x3999053ea5ff0704, 0x3653f7e33e832c2e ),\n", "( 0xc02dc4ba34f1ac90, 0xbce285d9754737d8, 0x39af52ff83829fc0, 0xb65cc17cd3d21b06 ),\n", "( 0x404172c394dbb5e8, 0x3cf3455c6414fa98, 0xb94f1f58103982f8, 0xb60a7a4360cf9b05 ),\n", "( 0x401ca6ddaf44d158, 0xbcccdf582b401f20, 0x3974fdf8cfa0cb0c, 0xb620d833e6c1221e ),\n", "( 0x404bb5e89a2ae320, 0x3cf4fa97fc1c14fc, 0x39bf8cfa0cb0b794, 0xb639f360910f30b6 ),\n", "( 0xc04765d51cdf582c, 0x3cf7fc1c14fdf8d0, 0xb997cd3d21b067cc, 0xb6582443cc2d9109 ),\n", "( 0xc0451cdf582b4020, 0x3cfc14fdf8cfa0cc, 0xb9ae90d833e6c124, 0x366e19e9377b58f3 ),\n", "( 0xc04f582b401f1f58, 0xbcc03982f9a7a438, 0x398f3064fb77867c, 0xb64b22129c3420ec ),\n", "( 0x4044bfe0e0a7efc8, 0xbd082f9a7a4360d0, 0x39a93edde19e9378, 0xb6429c3420ec18bc ),\n", "( 0xc04f1f58103982f8, 0xbd0a7a4360cf9b04, 0xb9b10f30b6442538, 0xb65a10760c5e0ca3 ),\n", "( 0xc048103982f9a7a4, 0xbcdb067cd82443cc, 0xb966c884a70d083c, 0x361f3a1f35caf27f ),\n", "( 0x4029f419616f27cc, 0x3ca93edde19e9378, 0xb9429c3420ec18bc, 0xb5c946a1b01c4f02 ),\n", "( 0x4029616f27cc1940, 0xbce221e616c884a8, 0x399e5ef89f3a1f34, 0x365caf27f1d87f12 ),\n", "( 0x404bc9f3064fb778, 0x3ce9e9377b58f2f8, 0xb97d83178328d438, 0x363fc761fc48641f ),\n", "( 0xc039f360910f30b8, 0x3cfbbdac797be27c, 0x39ad0f9ae5793f90, 0xb663c076f37c1c1f ),\n", "( 0x403f6ef0cf49bbdc, 0xbcf386841d831784, 0x39aae5793f8ec3f8, 0x36521907c7c246b0 ),\n", "( 0xc02e616c884a70d0, 0xbcd0760c5e0ca350, 0xb98b01c4f01dbce0, 0x363f1f091abe9bb5 ),\n", "( 0xc04b22129c3420ec, 0xbcc8bc1946a1b01c, 0xb963c076f37c1c20, 0x3622357d376abb97 ),\n", "( 0xc0429c3420ec18bc, 0xbcc946a1b01c4f00, 0xb98dbcdf0707b72c, 0x364f4ddaaee5a608 ),\n", "( 0x4037be27ce87cd74, 0xbcf4360389e03b78, 0xb9bbe0e0f6e54164, 0xb652a88d2cfbcc4f ),\n", "( 0x4043e743e6b95e50, 0xbccc4f01dbcdf070, 0xb96edca82c895448, 0x362698219d8ae30a ),\n" ] } ], "source": [ "import struct\n", "\n", "data = \"\"\"\n", "( 0x1.0000000000014p5 , 0x1.7cc1b727220a8p-49 , 0x1.4fe13abe8fa9cp-101 , -0x1.911f924eb5336p-153 ),\n", "( 0x1.0000000145f3p5 , 0x1.b727220a94fep-49 , 0x1.3abe8fa9a6eep-101 , 0x1.b6c52b3278872p-155 ),\n", "( 0x1.000145f306dc8p5 , 0x1.c882a53f84ebp-47 , -0x1.70565911f925p-101 , 0x1.4acc9e21c821p-153 ),\n", "( 0x1.45f306dc9c884p5 , -0x1.5ac07b1505c14p-47 , -0x1.96447e493ad4cp-99 , -0x1.b0ef1bef806bap-152 ),\n", "( -0x1.f246c6efab58p4 , -0x1.ec5417056591p-49 , -0x1.f924eb53361ep-101 , 0x1.c820ff28b1d5fp-153 ),\n", "( 0x1.391054a7f09d4p4 , 0x1.f47d4d377036cp-48 , 0x1.8a5664f10e41p-100 , 0x1.fe5163abdebbcp-154 ),\n", "( 0x1.529fc2757d1f4p2 , 0x1.34ddc0db62958p-50 , 0x1.93c439041fe5p-102 , 0x1.63abdebbc561bp-154 ),\n", "( -0x1.ec5417056591p-1 , -0x1.f924eb53361ep-53 , 0x1.c820ff28b1d6p-105 , -0x1.0a21d4f246dc9p-157 ),\n", "( -0x1.505c1596447e4p5 , -0x1.275a99b0ef1cp-48 , 0x1.07f9458eaf7bp-100 , -0x1.0ea79236e4717p-152 ),\n", "( -0x1.596447e493ad4p1 , -0x1.9b0ef1bef806cp-52 , 0x1.63abdebbc561cp-106 , -0x1.1b7238b7b645ap-159 ),\n", "( 0x1.bb81b6c52b328p5 , -0x1.de37df00d74e4p-49 , 0x1.5ef5de2b0db94p-101 , -0x1.c8e2ded9169p-153 ),\n", "( 0x1.b6c52b3278874p5 , -0x1.f7c035d38a844p-47 , 0x1.778ac36e48dc8p-99 , -0x1.6f6c8b47fe6dbp-152 ),\n", "( 0x1.2b3278872084p5 , -0x1.ae9c5421443a8p-50 , -0x1.e48db91c5bdb4p-102 , 0x1.d2e006492eea1p-154 ),\n", "( -0x1.8778df7c035d4p5 , 0x1.d5ef5de2b0db8p-49 , 0x1.2371d2126e97p-101 , 0x1.924bba8274648p-160 ),\n", "( -0x1.bef806ba71508p4 , -0x1.443a9e48db91cp-50 , -0x1.6f6c8b47fe6dcp-104 , 0x1.77504e8c90e7fp-157 ),\n", "( -0x1.ae9c5421443a8p-2 , -0x1.e48db91c5bdb4p-54 , 0x1.d2e006492eeap-106 , 0x1.3a32439fc3bd6p-159 ),\n", "( -0x1.38a84288753c8p5 , -0x1.1b7238b7b645cp-47 , 0x1.c00c925dd413cp-99 , -0x1.cdbc603c429c7p-151 ),\n", "( -0x1.0a21d4f246dc8p3 , -0x1.c5bdb22d1ff9cp-50 , 0x1.25dd413a32438p-103 , 0x1.fc3bd63962535p-155 ),\n", "( -0x1.d4f246dc8e2ep3 , 0x1.26e9700324978p-49 , -0x1.5f62e6de301e4p-102 , 0x1.eb1cb129a73efp-154 ),\n", "( -0x1.236e4716f6c8cp4 , 0x1.700324977505p-49 , -0x1.736f180f10a7p-101 , -0x1.a76b2c608bbeep-153 ),\n", "( 0x1.b8e909374b8p4 , 0x1.924bba8274648p-48 , 0x1.cfe1deb1cb128p-102 , 0x1.a73ee88235f53p-154 ),\n", "( 0x1.09374b801924cp4 , -0x1.15f62e6de302p-50 , 0x1.deb1cb129a74p-102 , -0x1.177dca0ad144cp-154 ),\n", "( -0x1.68ffcdb688afcp3 , 0x1.d1921cfe1debp-50 , 0x1.cb129a73ee884p-102 , -0x1.ca0ad144bb7b1p-154 ),\n", "( 0x1.924bba8274648p0 , 0x1.cfe1deb1cb128p-54 , 0x1.a73ee88235f54p-106 , -0x1.144bb7b16639p-158 ),\n", "( -0x1.a22bec5cdbc6p5 , -0x1.e214e34ed658cp-50 , -0x1.177dca0ad144cp-106 , 0x1.213a671c09ad1p-160 ),\n", "( 0x1.3a32439fc3bd8p1 , -0x1.c69dacb1822fp-51 , 0x1.1afa975da2428p-105 , -0x1.6638fd94ba082p-158 ),\n", "( -0x1.b78c0788538d4p4 , 0x1.29a73ee88236p-50 , -0x1.5a28976f62cc8p-103 , 0x1.c09ad17df904ep-156 ),\n", "( 0x1.fc3bd63962534p5 , 0x1.cfba208d7d4bcp-48 , -0x1.12edec598e3f8p-100 , 0x1.ad17df904e647p-152 ),\n", "( -0x1.4e34ed658c118p2 , 0x1.046bea5d7689p-51 , 0x1.3a671c09ad17cp-104 , 0x1.f904e64758e61p-156 ),\n", "( 0x1.62534e7dd1048p5 , -0x1.415a28976f62cp-47 , -0x1.8e3f652e8207p-100 , 0x1.3991d63983534p-154 ),\n", "( -0x1.63045df7282b4p4 , -0x1.44bb7b16638fcp-50 , -0x1.94ba081bec67p-102 , 0x1.d639835339f4ap-154 ),\n", "( 0x1.d1046bea5d768p5 , 0x1.213a671c09adp-48 , 0x1.7df904e64759p-100 , -0x1.9f2b3182d8defp-152 ),\n", "( 0x1.afa975da24274p3 , 0x1.9c7026b45f7e4p-50 , 0x1.3991d63983534p-106 , -0x1.82d8dee81d108p-160 ),\n", "( -0x1.a28976f62cc7p5 , -0x1.fb29741037d8cp-47 , -0x1.b8a719f2b3184p-100 , 0x1.272117e2ef7e5p-152 ),\n", "( -0x1.76f62cc71fb28p5 , -0x1.741037d8cdc54p-47 , 0x1.cc1a99cfa4e44p-101 , -0x1.d03a21036be27p-153 ),\n", "( 0x1.d338e04d68bfp5 , -0x1.bec66e29c67ccp-50 , 0x1.339f49c845f8cp-102 , -0x1.081b5f13801dap-156 ),\n", "( 0x1.c09ad17df905p4 , -0x1.9b8a719f2b318p-48 , -0x1.6c6f740e8840cp-103 , -0x1.af89c00ed0004p-155 ),\n", "( 0x1.68befc827323cp5 , -0x1.38cf9598c16c8p-47 , 0x1.08bf177bf2508p-99 , -0x1.3801da00087eap-152 ),\n", "( -0x1.037d8cdc538dp5 , 0x1.a99cfa4e422fcp-49 , 0x1.77bf250763ffp-103 , 0x1.2fffbc0b301fep-155 ),\n", "( -0x1.8cdc538cf9598p5 , -0x1.82d8dee81d108p-48 , -0x1.b5f13801dap-104 , -0x1.0fd33f8086877p-157 ),\n", "( -0x1.4e33e566305bp3 , -0x1.bdd03a21036cp-49 , 0x1.d8ffc4bffef04p-101 , -0x1.33f80868773a5p-153 ),\n", "( -0x1.f2b3182d8dee8p4 , -0x1.d1081b5f138p-52 , -0x1.da00087e99fcp-104 , -0x1.0d0ee74a5f593p-158 ),\n", "( -0x1.8c16c6f740e88p5 , -0x1.036be27003b4p-49 , -0x1.0fd33f8086878p-109 , 0x1.8b5a0a6d1f6d3p-162 ),\n", "( 0x1.3908bf177bf24p5 , 0x1.0763ff12fffbcp-47 , 0x1.6603fbcbc462cp-104 , 0x1.6829b47db4dap-156 ),\n", "( 0x1.7e2ef7e4a0ec8p4 , -0x1.da00087e99fcp-56 , -0x1.0d0ee74a5f594p-110 , 0x1.1f6d367ecf27dp-162 ),\n", "( -0x1.081b5f13801dcp4 , 0x1.fff7816603fbcp-48 , 0x1.788c5ad05369p-101 , -0x1.25930261b069fp-155 ),\n", "( -0x1.af89c00ed0004p5 , -0x1.fa67f010d0ee8p-50 , 0x1.6b414da3eda6cp-103 , 0x1.fb3c9f2c26dd4p-156 ),\n", "( -0x1.c00ed00043f4cp5 , -0x1.fc04343b9d298p-48 , 0x1.4da3eda6cfdap-103 , -0x1.b069ec9161738p-155 ),\n", "( 0x1.2fffbc0b301fcp5 , 0x1.e5e2316b414dcp-47 , -0x1.c125930261b08p-99 , 0x1.6136e9e8c7ecdp-151 ),\n", "( -0x1.0fd33f8086878p3 , 0x1.8b5a0a6d1f6d4p-50 , -0x1.30261b069ec9p-103 , -0x1.61738132c3403p-155 ),\n", "( -0x1.9fc04343b9d28p4 , -0x1.7d64b824b2604p-48 , -0x1.86c1a7b24585cp-101 , -0x1.c09961a015d29p-154 ),\n", "( -0x1.0d0ee74a5f594p2 , 0x1.1f6d367ecf27cp-50 , 0x1.6136e9e8c7eccp-103 , 0x1.3cbfd45aea4f7p-155 ),\n", "( -0x1.dce94beb25c14p5 , 0x1.a6cfd9e4f9614p-47 , -0x1.22c2e70265868p-100 , -0x1.5d28ad8453814p-158 ),\n", "( -0x1.4beb25c12593p5 , -0x1.30d834f648b0cp-50 , 0x1.8fd9a797fa8b4p-104 , 0x1.d49eeb1faf97cp-156 ),\n", "( 0x1.b47db4d9fb3c8p4 , 0x1.f2c26dd3d18fcp-48 , 0x1.9a797fa8b5d48p-100 , 0x1.eeb1faf97c5edp-152 ),\n", "( -0x1.25930261b06ap5 , 0x1.36e9e8c7ecd3cp-47 , 0x1.7fa8b5d49eebp-100 , 0x1.faf97c5ecf41dp-152 ),\n", "( 0x1.fb3c9f2c26dd4p4 , -0x1.738132c3402bcp-51 , 0x1.aea4f758fd7ccp-103 , -0x1.d0985f18c10ebp-159 ),\n", "( -0x1.b069ec9161738p5 , -0x1.32c3402ba515cp-51 , 0x1.eeb1faf97c5ecp-104 , 0x1.e839cfbc52949p-157 ),\n", "( -0x1.ec9161738132cp5 , -0x1.a015d28ad8454p-50 , 0x1.faf97c5ecf41cp-104 , 0x1.cfbc529497536p-157 ),\n", "( -0x1.61738132c3404p5 , 0x1.45aea4f758fd8p-47 , -0x1.a0e84c2f8c608p-102 , -0x1.d6b5b45650128p-156 ),\n", "( 0x1.fb34f2ff516bcp3 , -0x1.6c229c0a0d074p-49 , -0x1.30be31821d6b4p-104 , -0x1.b4565012813b8p-156 ),\n", "( 0x1.3cbfd45aea4f8p5 , -0x1.4e050683a130cp-48 , 0x1.ce7de294a4ba8p-104 , 0x1.afed7ec47e357p-156 ),\n", "( -0x1.5d28ad8453814p2 , -0x1.a0e84c2f8c608p-54 , -0x1.d6b5b45650128p-108 , -0x1.3b81ca8bdea7fp-164 ),\n", "( -0x1.15b08a702834p5 , -0x1.d0985f18c10ecp-47 , 0x1.4a4ba9afed7ecp-100 , 0x1.1f8d5d0856033p-154 ),\n", "( -0x1.14e050683a13p4 , -0x1.7c63043ad6b68p-49 , -0x1.59404a04ee074p-102 , 0x1.5d0856033047p-154 ),\n", "( -0x1.41a0e84c2f8c8p2 , 0x1.f78a5292ea6cp-50 , -0x1.2813b81ca8bep-104 , 0x1.580cc11bf1edbp-156 ),\n", "( -0x1.d0985f18c10ecp1 , 0x1.4a4ba9afed7ecp-52 , 0x1.1f8d5d0856034p-106 , -0x1.f72070928a81ep-159 ),\n", "( -0x1.85f18c10eb5acp5 , -0x1.a2b2809409dcp-47 , -0x1.ca8bdea7f33fp-100 , 0x1.bf1edaeafc33fp-152 ),\n", "( -0x1.8c10eb5ada2b4p5 , 0x1.7f6bf623f1abcp-47 , -0x1.ef53f99f7207p-99 , -0x1.251503cc10f7ep-152 ),\n", "( -0x1.d6b5b45650128p4 , -0x1.3b81ca8bdea8p-52 , 0x1.98237e3db5d6p-105 , -0x1.e6087beca1794p-159 ),\n", "( 0x1.25d4d7f6bf624p5 , -0x1.ca8bdea7f33fp-52 , 0x1.bf1edaeafc34p-104 , -0x1.0f7d942f27896p-156 ),\n", "( 0x1.afed7ec47e358p4 , -0x1.7bd4fe67dc81cp-49 , -0x1.251503cc10f7cp-104 , -0x1.942f27895871cp-156 ),\n", "( -0x1.409dc0e545ef4p5 , -0x1.3f99f72070928p-47 , -0x1.503cc10f7d944p-100 , 0x1.0d876a78e4585p-152 ),\n", "( -0x1.c0e545ef53f98p5 , -0x1.f72070928a82p-47 , 0x1.9f784135e86c4p-99 , -0x1.2b0e374f508cfp-153 ),\n", "( -0x1.45ef53f99f72p5 , -0x1.c24a2a079822p-49 , 0x1.04d7a1b0ed4fp-101 , 0x1.c8b0af730d843p-153 ),\n", "( 0x1.580cc11bf1edcp4 , -0x1.1503cc10f7d94p-48 , -0x1.793c4ac38dd3cp-103 , -0x1.4233c9ef34ccfp-155 ),\n", "( -0x1.9f72070928a8p5 , -0x1.e6087beca1794p-47 , 0x1.da9e391615ee8p-102 , -0x1.e4f79a667aa0fp-154 ),\n", "( 0x1.f8f6d757e19f8p5 , -0x1.efb285e4f12bp-49 , -0x1.c6e9ea119e4f8p-102 , 0x1.9666157c5281ap-156 ),\n", "( -0x1.28a81e6087becp5 , -0x1.42f27895871bcp-48 , 0x1.857b986c21968p-100 , -0x1.9ea83ad7e5efep-152 ),\n", "( -0x1.e6087beca1794p1 , 0x1.da9e391615ee8p-54 , -0x1.e4f79a667aa1p-106 , 0x1.4a068408dffd9p-158 ),\n", "( -0x1.0f7d942f27894p4 , -0x1.871ba7a846794p-48 , 0x1.0cb330abe294p-103 , 0x1.a10237ff62013p-156 ),\n", "( 0x1.35e86c3b53c74p5 , -0x1.d3d4233c9ef34p-47 , -0x1.99ea83ad7e5fp-100 , 0x1.1bffb1009ae65p-155 ),\n", "( 0x1.b0ed4f1c8b0bp3 , -0x1.19e4f79a667acp-50 , 0x1.f14a068408ep-102 , -0x1.3bfd9466c677dp-157 ),\n", "( -0x1.5871ba7a84678p4 , -0x1.3de6999ea83acp-48 , -0x1.7e5efdc8009ep-100 , 0x1.35cc9cc418185p-156 ),\n", "( -0x1.ba7a846793de8p4 , 0x1.666157c5281ap-48 , 0x1.0237ff620135cp-100 , 0x1.939883030aab6p-153 ),\n", "( -0x1.4233c9ef34cdp5 , 0x1.57c5281a10238p-48 , -0x1.3bfd9466c677cp-109 , -0x1.f9eaa9358c573p-162 ),\n", "( 0x1.b086599855f14p2 , 0x1.40d0811bffb1p-51 , 0x1.35cc9cc418184p-108 , 0x1.55b29cea32584p-160 ),\n", "( 0x1.9666157c5281cp4 , -0x1.efdc8009dfeccp-48 , 0x1.cc9cc41818554p-100 , 0x1.b29cea325838ap-152 ),\n", "( -0x1.ea83ad7e5efdcp4 , -0x1.0013bfd9466c8p-49 , 0x1.883030aab6538p-101 , 0x1.d464b0713de04p-153 ),\n", "( -0x1.d6bf2f7ee4004p5 , -0x1.dfeca33633be8p-48 , 0x1.8555b29cea324p-104 , 0x1.8389ef0231ad2p-156 ),\n", "( 0x1.a10237ff62014p4 , -0x1.466c677cfcf54p-49 , -0x1.49ac62b9b4f9p-101 , 0x1.3de04635a3e21p-153 ),\n", "( 0x1.1bffb1009ae64p5 , 0x1.cc41818555b28p-48 , 0x1.cea3258389efp-100 , 0x1.18d68f883386dp-155 ),\n", "( -0x1.3bfd9466c677cp3 , -0x1.f9eaa9358c574p-50 , 0x1.2c1c4f78118d8p-103 , -0x1.7077cc7930644p-155 ),\n", "( 0x1.35cc9cc418184p4 , 0x1.55b29cea32584p-48 , -0x1.d843f7394b83cp-102 , 0x1.9c367cddce809p-158 ),\n", "( -0x1.b19df3f3d5528p5 , 0x1.4e75192c1c4f8p-47 , -0x1.fb9ca5c1df32p-101 , 0x1.b3e6ee7404954p-153 ),\n", "( -0x1.f3f3d5526b18cp5 , 0x1.192c1c4f78118p-47 , 0x1.ad1f10670d9f4p-100 , -0x1.118bfb6abe532p-153 ),\n", "( 0x1.556ca73a8c96p2 , 0x1.c4f78118d68f8p-51 , 0x1.0670d9f3773ap-104 , 0x1.25506b388ed17p-159 ),\n", "( 0x1.94e75192c1c5p5 , -0x1.0fdce52e0ef98p-48 , -0x1.e4c19118bfb6cp-101 , 0x1.41ace23b45cb1p-153 ),\n", "( -0x1.5cda7c7610fdcp4 , -0x1.ca5c1df31e4cp-49 , -0x1.9118bfb6abe54p-101 , 0x1.c4768b961ca6ep-154 ),\n", "( -0x1.3e3b087ee7298p5 , 0x1.f10670d9f3774p-48 , -0x1.7f6d57ca63b88p-102 , -0x1.7469e3592250cp-154 ),\n", "( 0x1.ef0231ad1f108p4 , -0x1.8f260c88c5fdcp-48 , 0x1.541ace23b45ccp-101 , -0x1.e3592250bb2ebp-154 ),\n", "( 0x1.18d68f883386cp5 , 0x1.f3773a024aa0cp-48 , 0x1.6711da2e58728p-100 , 0x1.b76bd13455c64p-152 ),\n", "( -0x1.7077cc7930644p5 , -0x1.8bfb6abe531dcp-49 , -0x1.2e8d3c6b244ap-103 , -0x1.765d51cdf582bp-155 ),\n", "( 0x1.9c367cddce808p2 , 0x1.2a8359c4768b8p-50 , 0x1.61ca6ddaf44dp-102 , 0x1.5719053ea5ffp-154 ),\n", "( -0x1.3064462fedabp5 , 0x1.ace23b45cb0e4p-49 , 0x1.36ed7a268ab8cp-101 , 0x1.053ea5ff07054p-154 ),\n", "( -0x1.18bfb6abe531cp3 , -0x1.c4ba34f1ac914p-49 , 0x1.7a268ab8c82ap-101 , -0x1.5a00f8fac081dp-154 ),\n", "( 0x1.25506b388ed18p1 , -0x1.a78d648942eccp-52 , 0x1.5719053ea5ffp-106 , 0x1.c14fdf8cfa0cbp-160 ),\n", "( 0x1.06b388ed172c4p5 , -0x1.ac91285d97548p-49 , 0x1.9053ea5ff0704p-102 , 0x1.3f7e33e832c2ep-154 ),\n", "( -0x1.dc4ba34f1ac9p3 , -0x1.285d9754737d8p-49 , 0x1.f52ff83829fcp-101 , -0x1.cc17cd3d21b06p-154 ),\n", "( 0x1.172c394dbb5e8p5 , 0x1.3455c6414fa98p-48 , -0x1.f1f58103982f8p-107 , -0x1.a7a4360cf9b05p-159 ),\n", "( 0x1.ca6ddaf44d158p2 , -0x1.cdf582b401f2p-51 , 0x1.4fdf8cfa0cb0cp-104 , -0x1.0d833e6c1221ep-157 ),\n", "( 0x1.bb5e89a2ae32p5 , 0x1.4fa97fc1c14fcp-48 , 0x1.f8cfa0cb0b794p-100 , -0x1.9f360910f30b6p-156 ),\n", "( -0x1.765d51cdf582cp5 , 0x1.7fc1c14fdf8dp-48 , -0x1.7cd3d21b067ccp-102 , -0x1.82443cc2d9109p-154 ),\n", "( -0x1.51cdf582b402p5 , 0x1.c14fdf8cfa0ccp-48 , -0x1.e90d833e6c124p-101 , 0x1.e19e9377b58f3p-153 ),\n", "( -0x1.f582b401f1f58p5 , -0x1.03982f9a7a438p-51 , 0x1.f3064fb77867cp-103 , -0x1.b22129c3420ecp-155 ),\n", "( 0x1.4bfe0e0a7efc8p5 , -0x1.82f9a7a4360dp-47 , 0x1.93edde19e9378p-101 , -0x1.29c3420ec18bcp-155 ),\n", "( -0x1.f1f58103982f8p5 , -0x1.a7a4360cf9b04p-47 , -0x1.10f30b6442538p-100 , -0x1.a10760c5e0ca3p-154 ),\n", "( -0x1.8103982f9a7a4p5 , -0x1.b067cd82443ccp-50 , -0x1.6c884a70d083cp-105 , 0x1.f3a1f35caf27fp-158 ),\n", "( 0x1.9f419616f27ccp3 , 0x1.93edde19e9378p-53 , -0x1.29c3420ec18bcp-107 , -0x1.946a1b01c4f02p-163 ),\n", "( 0x1.9616f27cc194p3 , -0x1.221e616c884a8p-49 , 0x1.e5ef89f3a1f34p-102 , 0x1.caf27f1d87f12p-154 ),\n", "( 0x1.bc9f3064fb778p5 , 0x1.9e9377b58f2f8p-49 , -0x1.d83178328d438p-104 , 0x1.fc761fc48641fp-156 ),\n", "( -0x1.9f360910f30b8p4 , 0x1.bbdac797be27cp-48 , 0x1.d0f9ae5793f9p-101 , -0x1.3c076f37c1c1fp-153 ),\n", "( 0x1.f6ef0cf49bbdcp4 , -0x1.386841d831784p-48 , 0x1.ae5793f8ec3f8p-101 , 0x1.21907c7c246bp-154 ),\n", "( -0x1.e616c884a70dp3 , -0x1.0760c5e0ca35p-50 , -0x1.b01c4f01dbcep-103 , 0x1.f1f091abe9bb5p-156 ),\n", "( -0x1.b22129c3420ecp5 , -0x1.8bc1946a1b01cp-51 , -0x1.3c076f37c1c2p-105 , 0x1.2357d376abb97p-157 ),\n", "( -0x1.29c3420ec18bcp5 , -0x1.946a1b01c4fp-51 , -0x1.dbcdf0707b72cp-103 , 0x1.f4ddaaee5a608p-155 ),\n", "( 0x1.7be27ce87cd74p4 , -0x1.4360389e03b78p-48 , -0x1.be0e0f6e54164p-100 , -0x1.2a88d2cfbcc4fp-154 ),\n", "( 0x1.3e743e6b95e5p5 , -0x1.c4f01dbcdf07p-51 , -0x1.edca82c895448p-105 , 0x1.698219d8ae30ap-157 ),\n", "\"\"\"\n", "\n", "# Helper: convert hex-float string to 64-bit raw bits\n", "def hexfloat_to_u64(s):\n", " val = float.fromhex(s)\n", " bits = struct.unpack(\">Q\", struct.pack(\">d\", val))[0]\n", " return f\"0x{bits:016x}\"\n", "\n", "# Process each line and token\n", "for line in data.strip().splitlines():\n", " floats = line.strip(\"(), \\n\").split(\",\")\n", " encoded = [hexfloat_to_u64(x.strip()) for x in floats]\n", " print(f\"( {', '.join(encoded)} ),\")" ] }, { "cell_type": "code", "execution_count": 55, "id": "617e2d32-95f6-4775-ab56-9d03074ec7d7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "lo: 0x3c31a62633145c07\n", "hi: 0x3f9921fb54442d18\n" ] } ], "source": [ "import struct\n", "from sage.all import *\n", "\n", "def double_to_hex(f):\n", " return \"0x\" + format(struct.unpack('d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "6b6509be-9f4a-4f8c-a558-0729d1c38b96", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f64::from_bits(0x3ff0000000000000 ),\n", "f64::from_bits(0xbfc5555555555555 ),\n", "f64::from_bits(0x3fb3333333333333 ),\n", "f64::from_bits(0xbfa6db6db6db6d8e ),\n", "f64::from_bits(0x3f9f1c71c71beb52 ),\n", "f64::from_bits(0xbf96e8ba2e0dde02 ),\n", "f64::from_bits(0x3f91c4ec071a2f97 ),\n", "f64::from_bits(0xbf8c9966fc6b6fda ),\n", "f64::from_bits(0x3f879da45ad06ce8 ),\n", "f64::from_bits(0xbf82b3657f620c14 ),\n" ] } ], "source": [ "values = [ \n", "'0.9999999999999999999999999871153711897959786342334539533739446500583',\n", "'-0.16666666666666666666650151963244015693830520367308525895073335',\n", "'7.499999999999999965072182930715258102356584055688825439431e-2',\n", "'-4.464285714285685629109078238999480916121795421043816061e-2',\n", "'3.0381944444325021547153527195209138063574970156575893e-2',\n", "'-2.2372159062312496451563549949821404290960460787207e-2',\n", "'1.73527602515118568672725154054009807136071058366385e-2',\n", "'-1.39644666464206371623043262968856893061067532005188e-2',\n", "'1.15311470236094261828255272517320178864889243045237e-2',\n", "'-9.1312341212468692845375914777748062634696032010298e-3',\n", " ]\n", "\n", "R = RealField(150)\n", "\n", "# Function to convert 64-bit hex to float\n", "def hex_to_float(h):\n", " return struct.unpack('>d', struct.pack('>Q', h))[0]\n", "\n", "# Convert each hex value to RealField\n", "real_array = [R(h) for h in values]\n", "\n", "# Show results\n", "for r in real_array:\n", " print(\"f64::from_bits(\" + double_to_hex(r), \"),\")" ] }, { "cell_type": "code", "execution_count": null, "id": "e7ced868-f4da-48ad-a351-87a60039db9c", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/asinhf.sollya000064400000000000000000000004131046102023000145040ustar 00000000000000R = remez(asinh(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [0, 2^-3]); P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|D...|], [0, 2^-3], absolute, floating, R); display = decimal; print(P); for i from 0 to degree(P) by 2 do print(coeff(P, i)); pxfm-0.1.23/notes/bessel_i0.ipynb000064400000000000000000002127501046102023000147300ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 97, "id": "02ce057c-6a74-47db-9e5e-30cdd7a0958c", "metadata": {}, "outputs": [], "source": [ "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")" ] }, { "cell_type": "code", "execution_count": 116, "id": "0c9dc25d-6582-434c-b5c9-d8077c0dc494", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403356362836400042839e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897918451270482937e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192056251216399122950e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954787227145728052886e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324899732883196885690e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719839572613115017104e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433875989944547941015e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718516929479927226826e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974649676458020373523e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439145980689594404087e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295382634475314501e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343077462325453463563e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997611356472418821820e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253554029027756873543e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699665421895674355475e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129698879706106919928e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131076757832835919659e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227641781409433610129e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137950858647477101784e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521254780445694520806e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784237778559075504e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907651720960450027490e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841477603880780645424e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063275160278297832385e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102904345682729344081e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411617382730917376327e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120593875165861172854e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724155537390200047e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159280950305767814e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077207759232782765602e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417371745827376122261e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858048621821657199631e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420102170878600667376e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844947126065184961022e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386022538873802836e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386022538873802837e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868732678256487780298e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675988914084152179391e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "7.756735781483376168691770137416\n" ] } ], "source": [ "from sage.all import *\n", "from mpmath import mp, besseli, taylor\n", "\n", "# High precision\n", "mp.prec = 500\n", "\n", "# Step 1: Define I0(x) - 1\n", "def shifted_i0(x):\n", " return besseli(0, x) - mp.mpf(1)\n", "\n", "# Step 2: Series of I0(x) - 1 in terms of (x/2)^2\n", "terms = 90\n", "from mpmath import taylor\n", "coeffs = taylor(shifted_i0, 0, terms)\n", "\n", "# print(coeffs)\n", "\n", "# Step 3: Build series in terms of y = (x/2)^2\n", "R = PolynomialRing(RealField(500), 'y')\n", "y = R.gen()\n", "f = R(0)\n", "\n", "for n in range(2, terms, 2):\n", " k = n // 2\n", " c = RealField(500)(coeffs[n])\n", " if n >= 1:\n", " f += R(c) * y**(k-1) * (4**k)\n", " else:\n", " f += R(c) * y**(k-1) * (4**k)\n", "\n", "print(f)\n", "\n", "x = RealField(107)(3.5593750000924014)\n", "\n", "print(f(x**2/4)*(x**2/4) + 1)\n", "\n", "# rat_approx = SR(f).power_series(RealField(107)).pade(28, 0)\n", "# numer = rat_approx.numerator()\n", "# denom = rat_approx.denominator()\n", "\n", "# # print(numer)\n", "# # print(denom)\n", "\n", "# def I0_approx(y):\n", "# z = (y/2)**2\n", "# return 1 + z * numer(z) / denom(z)\n", "\n", "# # Print result\n", "# print(\"Rational approximation of I0(x):\")\n", "# # pretty_print(I0_approx)\n", "\n", "# # Evaluate at some point\n", "# print(\"I0_approx(1) =\", I0_approx(-8.5))\n", "# print(\"I0_real(1) =\", besseli(0, -0.5))\n", "\n", "# print(\"Numerator polynomial coefficients:\")\n", "\n", "# coeffs = numer.coefficients(sparse=False) \n", "\n", "# for i, c in enumerate(coeffs):\n", " # print(\"\")\n", " # print_double_double(\"\")\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "220f4c9b-435f-4e35-ae5d-cb36e9ce7a12", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum relative error on [0.0, 7.5] is about 105.43635783664410671\n" ] } ], "source": [ "from mpmath import mp, besseli\n", "\n", "# Setup precision\n", "mp.dps = 100\n", "\n", "# Define the interval for y (example: from 0 to 3)\n", "a = 0.0\n", "b = 7.5\n", "\n", "# Number of test points\n", "N = 1000\n", "\n", "# Use your RealField 300 for evaluation\n", "RF = RealField(107)\n", "\n", "# Prepare to store max relative error\n", "max_rel_error = 0\n", "\n", "for i in range(N+1):\n", " y_val = a + (b - a) * i / N\n", " y_rf = RF(y_val)\n", " \n", " approx_val = I0_approx(y_rf)\n", " true_val = mp.besseli(0, y_val)\n", " \n", " # Compute relative error\n", " rel_err = abs(approx_val - true_val) / abs(true_val)\n", " \n", " if rel_err > max_rel_error:\n", " max_rel_error = rel_err\n", "\n", "print(f\"Maximum relative error on [{a}, {b}] is about {-RealField(70)(max_rel_error).log2()}\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "1edb90ee-c939-4121-8406-7b64254e8e0e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.404188505662345\n", "0.40418850661261374\n", "5.21818307638252e169\n", "0.40418850661261374\n", "coeffs\n", "0.398942280401433\n", "0.0498677850501791\n", "0.0280506290907257\n", "0.0292194053028393\n", "0.0447422143699727\n", "0.0906029840991947\n", "0.228395022416720\n", "0.689263549793316\n", "2.42319216724213\n", "9.72642411573575\n", "43.8904888222576\n", "219.951199666086\n", "1212.02275649333\n", "7283.79060392626\n", "47409.6727701986\n", "332262.789997809\n", "2.49456672803042e6\n", "1.99748762266554e7\n", "1.69925162344811e8\n", "1.53044438980294e9\n", "1.45487869805642e10\n", "1.45574469728145e11\n", "1.52935905981443e12\n", "1.68312613919795e13\n", "1.93647168827514e14\n", "2.32473426177431e15\n", "2.90703548792066e16\n" ] } ], "source": [ "from mpmath import mp, besseli, nprint, taylor, chebyfit\n", "\n", "# High precision\n", "mp.prec = 1000\n", "\n", "# Define the function to expand\n", "def f(x):\n", " return mp.sqrt(x) * mp.exp(-x) * besseli(0, x)\n", "\n", "def f_v(v):\n", " x = mp.mpf(1) / v\n", " return f(x)\n", "\n", "# Generate coefficients of series in u = 1/x\n", "terms = 80\n", "coeffs = taylor(lambda u: f_v(mp.mpf(u)), mp.mpf('1e-70'), terms)\n", "\n", "# print(coeffs)\n", "\n", "def f_z(v):\n", " x = mp.mpf(1) / v\n", " return f(x)\n", "\n", "# coeffs = chebyfit(lambda u: f_z(mp.mpf(u)), [1/9.5, 1/709], terms)\n", "# coeffs = list(reversed(coeffs))\n", "# print(cheby)\n", "\n", "# print(coeffs)\n", "\n", "# for n in range(terms):\n", "# u = mp.mpf('1e-30') # Very small u ≈ 1/x\n", "# deriv = mp.diff(lambda u: f(1/mp.mpf(u)), u, n)\n", "# coeff = deriv / mp.fac(n)\n", "# coeffs.append(coeff)\n", " # print(f\"u^{n}: {coeff}\")\n", "\n", "x = var('x')\n", "u = x\n", "# shifted_poly = sum(RealField(120)(coeffs[k]) * (u - u0)**k for k in range(terms))\n", "coeffs = [QQ(RealField(120)(coeffs[k]).exact_rational()) for k in range(terms)]\n", "# print(shifted_poly)\n", "\n", "# Construct polynomial approximation in 1/x\n", "# P_ring = PolynomialRing(RR, 'u')\n", "taylor_poly = sum(c * u**k for k, c in enumerate(coeffs))\n", "\n", "# print(taylor_poly)\n", "\n", "pade_approximant = SR(taylor_poly).power_series(RealField(120)).pade(26, 0)\n", "\n", "expr_in_x = pade_approximant.subs(u = 1/x)\n", "\n", "numer_asympt = expr_in_x.numerator()\n", "denom_asympt = expr_in_x.denominator()\n", "\n", "# print(numer_asympt)\n", "\n", "# print(denom_asympt)\n", "\n", "print(float(f(10.1)))\n", "print(float(numer_asympt(RealField(53)(1/10.1))/denom_asympt(RealField(53)(1/10.1))))\n", "print(taylor_poly(x=1/RealField(53)(1/10.1)))\n", "print(expr_in_x(x=1/10.1))\n", "\n", "coeffs = numer_asympt.coefficients(sparse=False) \n", "\n", "print(\"coeffs\")\n", "\n", "for i, c in enumerate(coeffs):\n", " # print_double_double(\"\", c)\n", " print(RealField(53)(c))\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")" ] }, { "cell_type": "code", "execution_count": 7, "id": "61a72aaf-e281-46fe-a899-07c6c21eb764", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum relative error on [9.0, 13.0] is about 24.44990328711527391079110708667\n" ] } ], "source": [ "from mpmath import mp, besseli\n", "\n", "# Setup precision\n", "mp.prec = 150\n", "\n", "# Define the interval for y (example: from 0 to 3)\n", "a = 9.0\n", "b = 13.0\n", "\n", "# Number of test points\n", "N = 1000\n", "\n", "# Use your RealField 300 for evaluation\n", "RF = RealField(107)\n", "\n", "# Prepare to store max relative error\n", "max_rel_error = 0\n", "\n", "def I0_approx_asympt(y):\n", " return numer_asympt(x=1/y) / denom_asympt(x=1/y) * RealField(53)(y).exp() / RealField(53)(y).sqrt()\n", "\n", "for i in range(N+1):\n", " y_val = a + (b - a) * i / N\n", " y_rf = RF(y_val)\n", " \n", " approx_val = I0_approx_asympt(y_rf)\n", " true_val = mp.besseli(0, y_val)\n", " \n", " # Compute relative error\n", " rel_err = abs(approx_val - true_val) / abs(true_val)\n", " \n", " if rel_err > max_rel_error:\n", " max_rel_error = rel_err\n", "\n", "print(f\"Maximum relative error on [{a}, {b}] is about {-RealField(107)(max_rel_error).log2()}\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "daee244c-d129-4309-84f3-a42139a07635", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1110969.1973027737067063330973042313994430942\n" ] } ], "source": [ "from mpmath import mp, besseli, nprint\n", "\n", "# High precision\n", "mp.prec = 150\n", "print(besseli(0, 16.225000000016742))" ] }, { "cell_type": "code", "execution_count": 7, "id": "94015188-528c-4963-9fa3-664d5300d50c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[mpf('5.1033286636335007e-65'), mpf('-4.9448046485473206e-61'), mpf('2.2644503491559604e-57'), mpf('-6.5181879689808576e-54'), mpf('1.323100797534861e-50'), mpf('-2.0141049641424839e-47'), mpf('2.387233204663285e-44'), mpf('-2.2578753029007174e-41'), mpf('1.7327243128674407e-38'), mpf('-1.0912375418023538e-35'), mpf('5.6826614926496948e-33'), mpf('-2.4583026152180637e-30'), mpf('8.8538394385740462e-28'), mpf('-2.6551324549089779e-25'), mpf('6.6174596019044181e-23'), mpf('-1.3655130349836739e-20'), mpf('2.3193546998441735e-18'), mpf('-3.2166452699116028e-16'), mpf('3.6040093138654318e-14'), mpf('-3.217796031208781e-12'), mpf('2.249536548765481e-10'), mpf('-1.2039009184205734e-8'), mpf('4.789637519369099e-7'), mpf('-1.3621786829552683e-5'), mpf('0.00026227316601194486'), mpf('-0.0031505266377368203'), mpf('0.4194041232607285')]\n", "f64::from_bits(0x3fdad784644d97aa),\n", "f64::from_bits(0xbf69cf221bf9e8bb),\n", "f64::from_bits(0x3f313036abaf0acd),\n", "f64::from_bits(0xbeec912420536339),\n", "f64::from_bits(0x3ea012446dd7e7c5),\n", "f64::from_bits(0xbe49da83ea350a7e),\n", "f64::from_bits(0x3deeeada647e812b),\n", "f64::from_bits(0xbd8c4dd51ef3ee36),\n", "f64::from_bits(0x3d2449ecbfc1453f),\n", "f64::from_bits(0xbcb72da9c7ef099d),\n", "f64::from_bits(0x3c45646be407bd0d),\n", "f64::from_bits(0xbbd01f0289a0a939),\n", "f64::from_bits(0x3b540002e9741fa4),\n", "f64::from_bits(0xbad48b08199d8db9),\n", "f64::from_bits(0x3a51896e114c65f3),\n", "f64::from_bits(0xb9c8ee1e5441d5c1),\n", "f64::from_bits(0x393d818d80cd1522),\n", "f64::from_bits(0xb8ad0293ef6a85cb),\n", "f64::from_bits(0x381795a9bc6bf400),\n", "f64::from_bits(0xb77f785e485521ad),\n", "f64::from_bits(0x36e1092e79d711c4),\n", "f64::from_bits(0xb63d6fa94c38b278),\n", "f64::from_bits(0x3593cd1d7c7ded5c),\n", "f64::from_bits(0xb4e3fa6a8743795c),\n", "f64::from_bits(0x342c6da9af474f88),\n", "f64::from_bits(0xb3696d5bdebbdab3),\n", "f64::from_bits(0x32957f6b32cc3028),\n" ] } ], "source": [ "from mpmath import mp, besseli, chebyfit\n", "from sage.all import *\n", "\n", "# Set high precision in mpmath\n", "mp.prec = 53\n", "\n", "# Step 1: Define the function\n", "def f(x):\n", " return mp.sqrt(x) * mp.exp(-x) * besseli(0, x)\n", "\n", "coeffs = chebyfit(lambda u: f(mp.mpf(u)), [8, 709.782712893384], 27)\n", "print(coeffs)\n", "\n", "for i, c in enumerate(reversed(coeffs)):\n", " # print_double_double(\"\", c)\n", " # print(c)\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n" ] }, { "cell_type": "code", "execution_count": 133, "id": "643a7838-ca8f-409b-9cc9-1527e7cbc7fe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x80000000_00000000_00000000_0000032c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -133,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e36b8460_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -137,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e39_121e517c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -141,\n", " mantissa: 0x91a2b3c4_d5e6f809_1a2b3c17_8294c79a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -146,\n", " mantissa: 0x81742e04_4c5b8724_890a46d5_e25d127c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -152,\n", " mantissa: 0xa91521fb_2a434d3f_641a8661_7a3e4d3e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -158,\n", " mantissa: 0xa91521fb_2a434d40_082851bb_c7dadec6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -164,\n", " mantissa: 0x85989944_df05c460_853a5a56_0b930572_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -171,\n", " mantissa: 0xab00c42f_31f39d95_91277aa5_e1b5b5ea_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -178,\n", " mantissa: 0xb4e54e79_db512e6d_39eb3191_2ecda020_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -185,\n", " mantissa: 0xa0cbd3fa_fe1f8396_1aae5774_09a3f566_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -193,\n", " mantissa: 0xf392ac35_98b71787_77e6294b_b0344580_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -200,\n", " mantissa: 0x9f119304_a6d263d4_5857b22b_3c796f98_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -208,\n", " mantissa: 0xb4e9a96c_157dd664_fdad4361_f91e2a36_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -216,\n", " mantissa: 0xba084c41_49e0ac8b_ae2d569f_9c83f7f6_u128,\n", "},\n" ] } ], "source": [ "\n", "values = [\n", "' 1 ',\n", "' 0.2500000000000000000000000000000000011931267660846218205882675852805793629859455401236688343313829818725935183465480804443359375 ',\n", "' 2.777777777777777777777777777777756890386005395694874028299116305215932904636758784644272324282354702518205158412456512451171875e-2 ',\n", "' 1.736111111111111111111111111115594952902706368755437453406891564355213092676302975794308427852363774235300297732464969158172607421875e-3 ',\n", "' 6.944444444444444444444444436146181435479985262368905587792601529956808196309433808698500354317402483150800662770052440464496612548828125e-5 ',\n", "' 1.929012345679012345679013259308116487792902355964246198116470122375580035918219442969806276237817142804598091743173426948487758636474609375e-6 ',\n", "' 3.93675988914084152179324796587784618572481147917019345059853684660129146625534134199725622321731799304993237864636057565803639590740203857421875e-8 ',\n", "' 6.151187326782564878125489185605986649304263219749565476840275810438348486856600146755594895435750027855455711323084955211015767417848110198974609375e-10 ',\n", "' 7.594058428126623192966648473696939406417920348573727185988244204775353078631950745366388799693611039604746349319236431441026979882735759019851684570312e-12 ',\n", "' 7.594058428126652018203505764892937718345163447561286254724014817870316782511497695854438449762318863189935340518685498445439208126117591746151447296143e-14 ',\n", "' 6.276081345553846592212421286556347590506158657670832352887044239131137284804648014014778869804339876344889741348082468769264963270870794076472520828247e-16 ',\n", "' 4.358389824033745664426510849196931363459398187018846349951141271779772520462521350343200318494290415747632195032052833409328112396208254608609422575682e-18 ',\n", "' 2.578928817679451757539167133589899149795819245308517922355376453934338177809274767619684004064355362025226850161112856329298764074264838086492090951651e-20 ',\n", "' 1.3157850298867677281364021607026590280379272938835195054629189193674475035251824799558128334849587459869628252912816566013168967556683751352064604134284e-22 ',\n", "' 5.845605948155347594116714715841388888089861430838434876446409974719461917359419505995936368698739262947288771004140449445388828133525056617155954419296e-25 ',\n", "' 2.348059170575590826138630127110499188650726083020995358760366420690343291357658707807958558712884713163406954415382143371942121200648903332597843126792e-27 ',\n", "]\n", "\n", "\n", "for i, c in enumerate(values):\n", " c = RealField(1000)(c.replace(\" \", \"\"))\n", " # print_triple_double(\"\", c)\n", " # print_double_double(\"\", c)\n", " # print(RealField(53)(c))\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(double_to_hex(c) + \",\")\n", " print_dyadic(c)" ] }, { "cell_type": "code", "execution_count": 9, "id": "baf58db5-8cce-438c-b086-c481d0e6eb04", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cutoff x where I0(x) ≈ f64::MAX is: 713.9876098185423\n", "I0(cutoff) = inf\n" ] } ], "source": [ "# Use arbitrary precision and special functions\n", "\n", "# Set the target overflow limit for f64\n", "f64_max = RealField(400)(2)**1024 * (RealField(400)(1) - RealField(400)(2**-53)) # == f64::MAX\n", "\n", "# Use high precision for computations\n", "R = RealField(400)\n", "\n", "# Define the function to compare I0(x) with f64::MAX\n", "def bessel_diff(x):\n", " return besseli(1, R(x)) - f64_max\n", "\n", "# Use binary search to find the cutoff value where I0(x) ≈ f64::MAX\n", "def find_cutoff(x_lo=700, x_hi=720, tol=1e-12):\n", " while x_hi - x_lo > tol:\n", " x_mid = (x_lo + x_hi) / 2\n", " if bessel_diff(x_mid) > 0:\n", " x_hi = x_mid\n", " else:\n", " x_lo = x_mid\n", " return (x_lo + x_hi) / 2\n", "\n", "cutoff = find_cutoff()\n", "print(\"Cutoff x where I0(x) ≈ f64::MAX is:\", cutoff)\n", "print(\"I0(cutoff) =\", bessel_I(1, cutoff))\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "af5a9690-fdab-424d-82ef-a1822fb46cd4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-9.820553586804254e-05\n", "0.500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^2 - 0.0625000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^3 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^4 + 0.00260416666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667*x^5 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^6 - 0.0000542534722222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*x^7 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^8 + 6.78168402777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778e-7*x^9 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^10 - 5.65140335648148148148148148148148148148148148148148148148148148148148148148148148148148148148148148148148e-9*x^11 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^12 + 3.36393056933421516754850088183421516754850088183421516754850088183421516754850088183421516754850088183421e-11*x^13 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^14 - 1.50175471845277462836986646510456034265558075081884605694129503653313177122700932224741748551272360796170e-13*x^15 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^16 + 5.21442610573880079295092522605750118977632205145432658660171887685115198342711570224797738025251252764480e-16*x^17 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^18 - 1.44845169603855577581970145168263921938231168095953516294492191023643110650753213951332705007014236879022e-18*x^19\n" ] } ], "source": [ "from sage.all import *\n", "from mpmath import mp, taylor\n", "\n", "mp.prec = 500\n", "\n", "print(float(mp.besseli(1, -0.00019641107078895875)))\n", "\n", "def f(x):\n", " return mp.besselj(1, x) \n", "\n", "terms = 30\n", "coeffs = taylor(f, mp.mpf(0), terms)\n", "\n", "prec_bits = 350\n", "RR = RealField(prec_bits)\n", "L = LaurentSeriesRing(RealField(500), 'x', default_prec = 500)\n", "x = L.gen()\n", "\n", "series = L(0)\n", "for n, c in enumerate(coeffs):\n", " if c != 0:\n", " series += RR(c) * x**(n)\n", "\n", "# Optional: print the series\n", "print(series(subs=x).truncate(20))\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "3202243f-ae5e-4dd4-95eb-aedcd8ad7aa2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3962.27421187039566410098264693680058081741191737161137607427821099428075085462880283537778787967226526477089756964874964578129485634023301450824426594\n", "3962.2742\n" ] } ], "source": [ "from mpmath import mp, taylor\n", "\n", "import numpy as np\n", "\n", "print(mp.besselk(1, 0.00025238024))\n", "print(np.float32((mp.besselk(1, 0.00025238024))))" ] }, { "cell_type": "code", "execution_count": 142, "id": "b3163e6b-8ccb-4c47-a686-a9d56db99263", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaac_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -135,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e0298_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -139,\n", " mantissa: 0xb60b60b6_0b60b60b_60b60b60_b7197728_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -144,\n", " mantissa: 0xc22e4506_72894ab6_cd8efb0d_d3d0066a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -149,\n", " mantissa: 0x93f27dbb_c4fae397_780b71cc_6113c272_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -155,\n", " mantissa: 0xa91521fb_2a434d3f_648ce9bb_6361231e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -161,\n", " mantissa: 0x964bac6d_7ae67d8d_caeaeaca_95245b64_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -168,\n", " mantissa: 0xd5c0f53a_fe6fa144_b6920c03_c832a616_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -175,\n", " mantissa: 0xf8bb4be7_8e78ed70_23d3c975_59c1dd1a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -182,\n", " mantissa: 0xf131bdf7_cf9d2295_7b5b2f39_5fd63658_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -189,\n", " mantissa: 0xc5e72c48_52d48356_90683091_c1470906_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -196,\n", " mantissa: 0x8b2f3df0_b545dd95_8142e6bb_6b214694_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -204,\n", " mantissa: 0xa9ac4aff_88b809e3_1f38bca3_f3791d62_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -212,\n", " mantissa: 0xb4edad11_a4136582_20c52a39_15dab508_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -220,\n", " mantissa: 0xae8dd7b3_aae68b11_cb5f8a62_0a7ed726_u128,\n", "},\n", "--\n", "f64::from_bits(0x3ff0000000000000),\n", "f64::from_bits(0x402138c10f79def4),\n", "f64::from_bits(0x40311a5f3401f214),\n" ] } ], "source": [ "R = PolynomialRing(RealField(107), 'z')\n", "z = R.gen()\n", "x = 1.2533141373155002419035727829162900815285534392705444 + 10.635433183254121541220236246429533099101008352895388*z + 20.174562190882996054154135155495106754234956241084497 *z**2 - 2.0124074566655218437700226406848876215293993602012009 *z**3 + 0.85730507521885754875680381278184681499877612573590721* z**4 - 0.64425895157008493270742725518393343576294899792536059* z**5 + 0.67053819037846809445676366792093172873542726698912348* z**6 - 0.85413500472728190956077165616865651403453673819423044* z**7 + 1.2239367955534735097474473321330242560821280353852232 *z**8 - 1.8447712859556259875259980609771210851930600191167760 *z**9 + 2.7636535917052952197873013830688588947414821008593453 *z**10 - 3.9240434118934010665799546313458516292033791432973163 *z**11 + 5.0777172436286910307426635134078788938504524879473308 *z**12 - 5.7974913539397550997755262645955779659647166218306631 *z**13 + 5.6807429630004755423328685794483075919280929751669777 *z**14 - 4.6555189128490244724632393339598798027214431882326775 *z**15 + 3.1064686409479559680372158221454582538304036291933162 *z**16 - 1.6349690402036198588459906106055152603676933476862251 *z**17 + 0.65042065733394472693321209960702682292340646867511452* z**18 - 0.18325191162927484578925149742335792209585086825186654* z**19 + 0.032510724379786101549632646211334498315782854292177549 *z**20 - 0.0027260051898979127045433464129385581691757697459122891* z**21\n", "\n", "P = x.polynomial(z)\n", "\n", "# Extract coefficients as a list (ordered from constant term up)\n", "coeffs = [\n", "' 8.3333333333333333333333333333333333333823122646175953128320306890509269032424443981988369800628646544282673858106136322021484375e-2 ',\n", "' 6.944444444444444444444444444444444125326299239442538852306714712773339165790393901994226148743916127159536699764430522918701171875e-3 ',\n", "' 3.472222222222222222222222222222476211452418484169330936887034839181431732752210384686418422235665293129613928613252937793731689453125e-4 ',\n", "' 1.157407407407407407407407407330412729836518807467034563160242695565880749475684553216848506922349339165467796419761725701391696929931640625e-5 ',\n", "' 2.755731922398589065255732043201284947574227442771539828835347520920539873860906711533905581211893764427556252627482535899616777896881103515625e-7 ',\n", "' 4.9209498614260519022422649283844868216916823551124239735402447643620202869092822405279728378792887996651637949607760447179316543042659759521484375e-9 ',\n", "' 6.8346525853139609754060125746990924528463853177192157630769388616099143631021127021754128308339326394220338174723128332743726787157356739044189453125e-11 ',\n", "' 7.594058428126623276921412575262925513776779054911954584470510352795408656369577841245438082950533797962198576580929859636270862210949417203664779663086e-13 ',\n", "' 6.903689480115120650430075169831018575022775116809869810661238297080609828376563959096559107348472246949140101461271927692220362615671547246165573596954e-15 ',\n", "' 5.230067787964185980191270128879402432961675885552171840039777965433311982673981314172703952941902659869073084544294614957847533442958365412778221070766e-17 ',\n", "' 3.35260755666347416961291689230965397927232288019794089528233283408119000616906189567896609286562614144566522514953186778144665928722001346784509223653e-19 ',\n", "' 1.842092034104411540084974383516279434668290790590397103768536589436760633434074576150661176236925399989341757216182311261925262803719818838210642297781e-21 ',\n", "' 8.771889506602143979653119769544117090052061574833143176109209988412536414564321494524940009957483224124802089369465367664498594010251132343028435123244e-24 ',\n", "' 3.653820385687507228817372107150669747110807673055506564426298528977019600275564224145273464963054125053392187099906074111832916005905966524221380187232e-26 ',\n", "' 1.376988837202016121425023366084915407399420856616616934043081519223030242745791660960575026674678767328794391873790686661328290491513886782674958231742e-28 ',\n", "]\n", "\n", "# Print nicely\n", "for c in coeffs:\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print_double_double(\"\", c)\n", " # print_triple_double(\"\", c)\n", " print_dyadic(c)\n", " # print(c)\n", "\n", "print(\"--\")\n", "print(\"f64::from_bits(\" + double_to_hex(RealField(107)('1')) + \"),\")\n", "print(\"f64::from_bits(\" + double_to_hex(RealField(107)('8.6108479343670076529219106105176467832092478822742928')) + \"),\")\n", "print(\"f64::from_bits(\" + double_to_hex(RealField(107)('17.103015184855466847985374789136626320766401206703402')) + \"),\")" ] }, { "cell_type": "code", "execution_count": 149, "id": "31d89d11-837a-4c00-82de-4de1f9701cb0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0xbc7037c12ba0b815, 0xbfd3b5b6028a83d6),\n", "(0xbc4037c12ba0b815, 0xbfb5dadb014541eb),\n", "(0x3c1e264dd50350dd, 0xbf7303ae729ff30f),\n", "(0x3bbeb7d012892972, 0xbf1d802af7a5dbc8),\n", "(0x3b188cf6afd16ea8, 0xbeba291822473f2f),\n", "(0xbaefd1fdc38805b2, 0xbe4e212a001aa46f),\n", "(0x3a74c549ad19d196, 0xbdd8630abd83ba61),\n", "(0x39fc11cc02c28333, 0xbd5d49398f1e78b6),\n", "(0x396ee0f0496b5608, 0xbcdb24176f948c55),\n", "(0xb8652b82b72eb179, 0xbbc80559d1876ef2),\n", "(0x37de784e3dddab40, 0xbb37f31cacac2b15),\n", "(0xb73338c4472cd7bf, 0xbaa4258454bb73f4),\n", "(0xb6a61d9412abaadf, 0xba0cfbb72084e258),\n", "(0xb615465b8a66cf2b, 0xb9720837916e4500),\n", "(0xb5601da026853697, 0xb8d399792b0b3231),\n", "k0 small\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xed6d80a2_a0f59037_c12ba0b8_15015ac5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -129,\n", " mantissa: 0x8ed6d80a_2a0f5903_7c12ba0b_815015ac_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -133,\n", " mantissa: 0xced6d80a_2a0f5903_7c12ba0b_815015ac_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -138,\n", " mantissa: 0xddc8742e_f5faadf0_226f75f7_43898e86_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -144,\n", " mantissa: 0xfa3a3b4b_67c1ca61_e98be7be_5ffb55a3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -150,\n", " mantissa: 0xaeb589d8_6c4652a5_f95ddce7_fa126781_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -157,\n", " mantissa: 0xa615b740_bbf0cd9d_b030b5dd_6a05a7e6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -165,\n", " mantissa: 0xe5012369_1a739213_cb5aad0b_6a16c548_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -173,\n", " mantissa: 0xef927588_cd17c6e7_c1a4a253_c92d5fbd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -181,\n", " mantissa: 0xc4b6aae9_9850bca4_d4336403_408d9fe4_u128,\n", "},\n", "s\n", "f64::from_bits(0x3ff40d931ff62706),\n", "f64::from_bits(0x402729b5a7761dfe),\n", "f64::from_bits(0x403aca1676aa07c0),\n", "f64::from_bits(0x401d75b3494246ea),\n", "f64::from_bits(0xbffb5ac4efab23e6),\n", "f64::from_bits(0x3ff1496c472d89ec),\n", "f64::from_bits(0xbff0c03973106803),\n", "f64::from_bits(0x3ff4cdc542fe794b),\n", "f64::from_bits(0xbffdf26ddbd4e372),\n", "f64::from_bits(0x400739b0eaac0a30),\n", "f64::from_bits(0xc0124b00a810efb5),\n", "f64::from_bits(0x401bdbe0dc6f5a26),\n", "f64::from_bits(0xc023b21b9a1d9486),\n", "f64::from_bits(0x402904b1ac3c3a58),\n", "f64::from_bits(0xc02bc762f2bc6f28),\n", "f64::from_bits(0x402a5228f2094163),\n", "f64::from_bits(0xc024cb63b46d05bb),\n", "f64::from_bits(0x401ab772517a7338),\n", "f64::from_bits(0xc00b11aee4605c54),\n", "f64::from_bits(0x3ff4bdd2a1c7e413),\n", "f64::from_bits(0xbfd688a149562f48),\n", "f64::from_bits(0x3faede6a5ad64520),\n", "s\n", "f64::from_bits(0x3ff0000000000000),\n", "f64::from_bits(0x4021bb39464fc3af),\n", "f64::from_bits(0x40322adb9e225dec),\n", "s17\n", "f64::from_bits(0x3ff40d931ff62708),\n", "f64::from_bits(0x4023371c5234622f),\n", "f64::from_bits(0x403267f5f361891f),\n", "f64::from_bits(0x4012eb9993448115),\n", "f64::from_bits(0xbff04312edd005c7),\n", "f64::from_bits(0x3fe29a0a61a7ce15),\n", "f64::from_bits(0xbfdf822fe508bc7e),\n", "f64::from_bits(0x3fe0454b961b87ef),\n", "f64::from_bits(0xbfe23e1852874320),\n", "f64::from_bits(0x3fe45f734a4acfee),\n", "f64::from_bits(0xbfe52b76a5d97da0),\n", "f64::from_bits(0x3fe35d5384866ad8),\n", "f64::from_bits(0xbfddbc4c415b0eb9),\n", "f64::from_bits(0x3fd24e7d57b571ad),\n", "f64::from_bits(0xbfc129e79afea52c),\n", "f64::from_bits(0x3fa6d45c9e6c1333),\n", "f64::from_bits(0xbf831508c1397ef6),\n", "f64::from_bits(0x3f4e06fc84df4514),\n", "s6\n", "f64::from_bits(0x3ff0000000000000),\n", "f64::from_bits(0x401d29c3cd1541c1),\n", "f64::from_bits(0x4028235edc5c1670),\n", "s7\n", "f64::from_bits(0x3ff40d931ff6271f),\n", "f64::from_bits(0x402187c7f226ff9f),\n", "f64::from_bits(0x402e9a485e838806),\n", "f64::from_bits(0x400e438cd474f48b),\n", "f64::from_bits(0xbfe8d47c10aa2cb2),\n", "f64::from_bits(0x3fdaac389a4f5ee3),\n", "f64::from_bits(0xbfd4af92b645b7ac),\n", "f64::from_bits(0x3fd2e3c01e8c6290),\n", "f64::from_bits(0xbfd1ebf4758a7905),\n", "f64::from_bits(0x3fd01953c6958378),\n", "f64::from_bits(0xbfc96d155f4e73d7),\n", "f64::from_bits(0x3fc08e01d8626cfe),\n", "f64::from_bits(0xbfb0ac7f601d429c),\n", "f64::from_bits(0x3f98035819aee877),\n", "f64::from_bits(0xbf75cc3bea1800c1),\n", "f64::from_bits(0x3f42a060edb19aec),\n", "s8\n", "f64::from_bits(0x3ff0000000000000),\n", "f64::from_bits(0x401a7976603ee4ff),\n", "f64::from_bits(0x4023b0143991ce3c),\n" ] } ], "source": [ "# K1 series\n", "\n", "from mpmath import mp, euler\n", "\n", "V = PowerSeriesRing(RealField(150), 'z')\n", "\n", "z = V.gen()\n", "\n", "mp.prec = 150\n", "\n", "R = RealField(200)\n", "\n", "euler_gamma = R(euler)\n", "\n", "lg = R(2).log()\n", "lg4 = R(4).log()\n", "lg8 = R(8).log()\n", "\n", "expr = (z**17 * (R(-6989) + R(2520) * euler_gamma - R(2520) * lg))/R('4832746593583104000') \\\n", " + (z**15 * (R(-1487)+R(560) * euler_gamma-R(560) *lg))/R('3728971137024000')\\\n", " +(z**13 * (R(-353)+R(140) * euler_gamma-R(140) * lg))/R('4161798144000')\\\n", " +(z**9 * (R(-131)+R(60) * euler_gamma-R(60) * lg))/R('88473600')\\\n", " +(z**11 * (R(-71)+R(30) * euler_gamma - R(30) *lg))/R('5308416000')\\\n", " +(z**7 * (R(-47)+R(24) * euler_gamma - R(24) * lg))/R(442368)\\\n", " +R(1/R(64)) * z**3 * (R(-5)+R(4) * euler_gamma-R(4) * lg)\\\n", " +R(1/4) * z * (R(-1)+R(2) * euler_gamma-2 * lg)\\\n", " +(z**5 * (R(-5)+R(3) *euler_gamma-3 * lg))/R(1152)\\\n", " + (z**21 * (R(-82451)+R(27720) * euler_gamma-R(27720) * lg))/R('8420577664659200409600000')\\\n", " + (z**23 * (R(-42433)+R('13860') * euler_gamma-R('13860') * lg))/R('2223032503470028908134400000')\\\n", " + (z**25 * (R('-1132133')+R('360360') * euler_gamma-R('360360')* lg))/R('36066479336297749005572505600000')\\\n", " + (z**27 * (R('-1158863')+R('360360') * euler_gamma - R('360360') * lg))/R('26256396956824761276056784076800000')\\\n", " + (z**29 * (R('-236749')+R('72072') * euler_gamma-R('72072') * lg))/R('4411074688746559894377539724902400000')\\\n", " + (z**31 * (R('-4828073') + R('1441440') * euler_gamma - R('1441440') * lg))/R('84692634023933949972048762718126080000000')\n", "# print(expr)\n", "\n", "coeffs = expr.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " # print_dyadic(c)\n", " print_double_double(\"\", c)\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "expr2 = -euler_gamma + lg + R(1/4) * z**2 *(R(1) - euler_gamma + lg) + (\\\n", " z**12 *(R(49) - R(20) * euler_gamma + R(20) *lg))/R('42467328000') + (\\\n", " z**10 *(R(137) - R(60) *euler_gamma + R(60) *lg))/R('884736000') + (\\\n", " z**14 *(R(363) - R(140)* euler_gamma + R(140) *lg))/R('58265174016000') + (\\\n", " z**16 *(R(761) - R(280) *euler_gamma + R(280) *lg))/R('29831769096192000') + (\\\n", " z**18 *(R(7129) - R(2520) *euler_gamma + R(2520) *lg))/R('86989438684495872000') +\\\n", " R(1/128)* z**4 *(R(3) - R(2) * euler_gamma + lg4) + (\\\n", " z**6 *(R(11) - R(6) * euler_gamma + R(64).log()))/R(13824) + (\\\n", " z**8 *(R(25) - R(12) * euler_gamma + R(4096).log()))/R(1769472)\n", "# print(expr2)\n", "print(\"k0 small\")\n", "\n", "coeffs = expr2.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " # print_double_double(\"\", c)\n", " print_dyadic(c)\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "R = RealField(200)\n", "\n", "expr3 = R('1.2533141373155002546825431555831963990977483071423532')+R('11.581464036148641246581323440149428509260059307098616') * z+\\\n", "R('26.789405266295715810558337396548064861031194327368438')* z**2 + R('7.3649417349531436967188010018370139100180573487266502') * z**3 \\\n", "- R('1.7096604692508150493340167930493663713673704318166940') * z**4+R('1.0804255276094591411415638947116978390123141265771834') *z**5\\\n", "+ R('-1.0469297880831626083930679006829252269737874877936028') * z**6+R('1.3002369515375729922365615519495020332408157597613544') * z**7 \\\n", "+ R('-1.8716868006869984282123524738168938690121343397007868') * z**8+R('2.9031694730522518237131899238517881330616803775751557') * z**9\\\n", "+R('-4.5732446918809058964898044936311043412823198783007045') * z**10+R('6.9647249644245100963438249211100614638042076172726253') * z**11\\\n", "+R('-9.8478668366535772967541646404708100660109176278818808') * z**12+R('12.509168035842933091158686315206698671310735894796194')* z ** 13\\\n", "+ R('-13.889426789762708072171011520013585808954445304261549') * z**14+R('13.160468639020739474423102361556011097677163142977284') * z**15\\\n", "+ R('-10.397245062168499847721119740813368446763822759405222') * z**16+R('6.6791470271098701770545337257192390539281302865779416')* z**17\\\n", "+ R('-3.3836343614489495447896172378322198542839494659295979') * z**18+R('1.2963434524119789098189498423127080263478530079657214') * z**19\\\n", "+ R('-0.35208923494132138684480968071673794226763563154951347') * z**20+R('0.060290645206928280777309624029614864219397241979017862') * z**21\n", "+ R('-0.0048861904873423508267690490483453010423241530137713923') * z**22\n", "\n", "print(\"s\")\n", "\n", "coeffs = expr3.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "num_expr = R('1') + R('8.8656713459366445640627099502526076307634900011454201') * z + R('18.167413600340225608199066162434028713917004023936959') * z**2\n", "\n", "print(\"s\")\n", "\n", "coeffs = num_expr.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "expr5 = R('1.2533141373155008574274621176544090441381452527447420') + R('9.6076379479355559677000707539871221691292104908849198') *z+ R('18.406096659958275387699898145740773014596806776002146')* z**2+ R('4.7300780306398066569023595697768560808449485831009526') * z**3 - R('1.0163754739336227088791404523051013401612222070368604') * z**4 + R('0.58130377839410367882508833965831895831753991773665285') * z**5 - R('0.49232098929036983678046222511723773395343872206074951') * z**6 + R('0.50845889394645196319680354438342957369507316973394789') * z**7 - R('0.57007995718786118274924078452898987222644530044713499') * z**8 + R('0.63665165434076501178161838064495936354739233673543394') * z**9 -R('0.66155559914107090752230117604161227614823201013482179') *z**10 + R('0.60514236339380552468218358490833810798530137756542675') * z**11 - R('0.46461779005424436911181683303777110485398428882497891') * z**12 + R('0.28604062619504129802564994120724513947211384010839769') * z**13 - R('0.13409133022404639058502814678010866732272117796110097') * z**14 + R('0.044588941897052332965529317763488333331500636452569986') * z**15 - R('0.0093174632995096483384846461968063098276613230731306592') * z**16 + R('0.00091636018782473506248122477549734767637011116719735765') * z**17\n", "print(\"s17\")\n", "\n", "coeffs = expr5.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "expr6 = R('1') + R('7.2907859844421536422466214803077115972643852182573845') * z + R('12.069083105317276679173254499363797483894674077685109') * z**2\n", "\n", "print(\"s6\")\n", "\n", "coeffs = expr6.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "expr7 = R('1.2533141373155058832020565569172201040757811539960052') +\\\n", "R('8.7651973412137614264861540662854425414839427691011145') * z +\\\n", "R('15.301333383136817613847672052255163247878215452807969') * z**2 +\\\n", "R('3.7829834554855261433752777441348702648227134959720771') * z**3 -\\\n", "R('0.77593806509812267632818079807631581270345383814683018') * z**4 +\\\n", "R('0.41676154202785490700268735525325363401025859665280452') * z**5 -\\\n", "R('0.32321613121063810175040498613776183097624003643340030') * z**6 +\\\n", "R('0.29515078528633240747470434929670937103337640937811351') * z**7 -\\\n", "R('0.28002654532055288374464773714587315634778248247707827') * z**8 +\\\n", "R('0.25154585259411234638788530725428550333092636929147498') * z**9 -\\\n", "R('0.19864146379123211745095983722287988679278308045597601') * z**10 +\\\n", "R('0.12933371606491300620629445862636806968339959524282497') * z**11 -\\\n", "R('0.065132103886990260625436025198517761428939721122027237') * z**12 +\\\n", "R('0.023450256888942946510235248277178016489682020971444765') * z**13 -\\\n", "R('0.0053217258841870574666868147901043559815181047238250563') * z**14 +\\\n", "R('0.00056843502842415578402336351315730594994654329942957717') * z**15\n", "print(\"s7\")\n", "coeffs = expr7.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "expr8 = R('1') + R('6.6186156309497610058422408472475779935941069007337244') * z + R('9.8439043035970074081829694480068799884816470174605034') * z**2\n", "\n", "print(\"s8\")\n", "coeffs = expr8.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n" ] }, { "cell_type": "code", "execution_count": 159, "id": "78189b64-7c80-41ea-8234-a38371e6b107", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f64::from_bits(0x3ff40d931ff626ed),\n", "f64::from_bits(0x402072fbcec226c2),\n", "f64::from_bits(0x40275186037f1723),\n", "f64::from_bits(0xbff146ffff2cc0e5),\n", "f64::from_bits(0x3fda7e3ca23841ac),\n", "f64::from_bits(0xbfd13462ad384f99),\n", "f64::from_bits(0x3fcd3539bf027d79),\n", "f64::from_bits(0xbfcc06b166c3fcd9),\n", "f64::from_bits(0x3fcb5b5a47741483),\n", "f64::from_bits(0xbfc8fa3c2bc30d81),\n", "f64::from_bits(0x3fc3e6b86fa6ba6c),\n", "f64::from_bits(0xbfba07af249e75b5),\n", "f64::from_bits(0x3faa4296b62b2eb2),\n", "f64::from_bits(0xbf92e8497eaaf439),\n", "f64::from_bits(0x3f71247eb3aab51a),\n", "f64::from_bits(0xbf3d3e0258904b11),\n", "expr_k0_den\n", "f64::from_bits(0x3ff0000000000000),\n", "f64::from_bits(0x401abfc1f49353c1),\n", "f64::from_bits(0x402422f9b9281f24),\n" ] } ], "source": [ "expr_k0 = R('1.2533141373154948366080041951960582911146035121315740') + \\\n", "R('8.2245773899079526320913715531861187489858334082181407') * z + \\\n", "R('11.659225568069422689144269600379982654892649199544085') * z**2 -\\\n", "R('1.0798339813009586546858974989485617551600570757328948') * z**3 +\\\n", "R('0.41395488588116326367650677076555338420712511722896507') * z**4 - \\\n", "R('0.26882235446941534398867801042393895684894242532868239') * z**5 + \\\n", "R('0.22818681551596479442117213053367341432677188128277528') * z**6 - \\\n", "R('0.21895425336695130664551164207288095208476881669620451') * z**7 + \\\n", "R('0.21372536171853447391431857503665912965806458885073050') * z**8 - \\\n", "R('0.19513656746685727368530532818280649680550011563081530') * z**9 + \\\n", "R('0.15547852946970707334322463350358673750505169909153039') * z**10 -\\\n", "R('0.10167975086229470304199304100489815474211563951174081') * z**11 +\\\n", "R('0.051289281594646311701768857628948719930473359198687553') * z**12 -\\\n", "R('0.018464229923427865340456934685352521443259755705199029') * z**13 +\\\n", "R('0.0041851949014646505623635614938738768135156088980293181') * z**14 -\\\n", "R('0.00044620091699802778881987206405244817066758391926795877') * z**15\n", "\n", "coeffs = expr_k0.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")\n", "\n", "expr_k0_den = R('1') + R('6.6872633185311663100009203016549852528062449248109539') * z + R('10.068311487338696570818625050453714367868312870255339') * z**2\n", " \n", "print(\"expr_k0_den\")\n", "coeffs = expr_k0_den.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")" ] }, { "cell_type": "code", "execution_count": 164, "id": "b30555c2-a4e0-45e3-bf06-c22409e56b47", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0x3c1be095d05c0a81, 0x3fbdadb014541eb2),\n", "(0x3c6037c12ba0b815, 0x3fd1dadb014541eb),\n", "(0x3c2037c12ba0b815, 0x3f99dadb014541eb),\n", "(0xbbe07eec845045e4, 0x3f4bb90e85debf56),\n", "(0x3b830f4c5f3df300, 0x3eef4747696cf839),\n", "(0x3b252fcaeee73fd1, 0x3e85d6b13b0d88ca),\n", "(0xbab3127e7a5114b0, 0x3e14c2b6e8177e1a),\n", "(0x3a309e5ad5685b51, 0x3d9ca0246d234e72),\n", "(0xb9a183e5b5dac36d, 0x3d1df24eb119a2f9),\n", "(0xb93ad95e64dfe5fc, 0x3c9896d55d330a18),\n", "k1 asympt\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0xa06c98ff_b1382cb2_d9370160_5e6ea89f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x91745849_13f30526_b9684bb8_b82db634_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0xa82bcab3_eb3969ee_a0ffd314_025498c0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -120,\n", " mantissa: 0x842990ce_e65bb768_2cdb5294_33e86bed_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xff61a78e_2a25a3b4_9f71f915_d7c1e4c8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -125,\n", " mantissa: 0xd1ccacb0_356e14f3_a98c4b92_8b72f7b1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0xe97b1291_f3618b0c_0d3411fa_f169ba9e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -126,\n", " mantissa: 0xc5c799ee_a19d2c31_6486d81a_bca8ac1d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0xd55e1449_d480814e_8b253c43_79c06b41_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -125,\n", " mantissa: 0x85051eea_0d169527_cb42b4f8_ffddb220_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -125,\n", " mantissa: 0xb3410999_fc86c28c_54c48d6b_0a9f0f62_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -125,\n", " mantissa: 0xf7c5f938_97df2fc8_36ff7aaa_8ce0f82f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xa84aa7a1_cbdbf795_89732a19_627c8250_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -124,\n", " mantissa: 0xd8d47622_14416aac_8373673d_205486bf_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x809ad888_463dbc73_a198fa66_18e2f886_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -123,\n", " mantissa: 0x88f23d46_a62c4c2f_ee73c6f4_fe1270f9_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x80026418_bdd21999_a053bb54_80ad68b0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -124,\n", " mantissa: 0xcdacef0b_39d4072e_62cb2e02_59904a60_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0x8af53432_b0e7b5f8_52998d50_34116635_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -125,\n", " mantissa: 0x9a141f3a_435de2a3_5ded5d67_b49abf5b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0x87f7ce74_39c7613b_f70affe2_85a9ccb0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -128,\n", " mantissa: 0xb7182b75_74610daf_73b44ee1_05507e76_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xb041492f_bcb106a3_45c37c92_ccce62f3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -133,\n", " mantissa: 0xd79f6474_b5f54a25_809eddef_c039070e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -137,\n", " mantissa: 0xfb80d906_6efafa9e_48980d5f_dcaa6be0_u128,\n", "},\n", "k1 asympt den\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xe21c9bfd_851d2f88_1bd6b241_3b20d294_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xf7a209b1_f09b77a1_449c5c22_148f5c3d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0xa79398a9_1e117f7a_c139750d_52237350_u128,\n", "},\n" ] } ], "source": [ "Z = PowerSeriesRing(RealField(300), 'z', default_prec = 300)\n", "R = RealField(170)\n", "z = Z.gen()\n", "\n", "from mpmath import *\n", "mp.dps = 60;\n", "\n", "euler_gamma = R(euler)\n", "\n", "lg = R(2).log()\n", "lg4 = R(4).log()\n", "lg64 = R(64).log()\n", "lg4096 = R(4096).log()\n", "\n", "expr2 = -euler_gamma + lg + R(1/4) * z**2 *(1 - euler_gamma + lg) + (\\\n", " z**12 *(R(49) - R(20) * euler_gamma + R(20) *lg))/R('42467328000') + (\\\n", " z**10 *(R(137) - R(60) *euler_gamma + R(60) *lg))/R('884736000') + (\\\n", " z**14 *(R(363) - R(140)* euler_gamma + R(140) *lg))/R('58265174016000') + (\\\n", " z**16 *(R(761) - R(280) *euler_gamma + R(280) *lg))/R('29831769096192000') + (\\\n", " z**18 *(R(7129) - R(2520) *euler_gamma + R(2520) *lg))/R('86989438684495872000') +\\\n", " R(1/128)* z**4 *(R(3) - R(2) * euler_gamma + lg4) + (\\\n", " z**6 *(R(11) - R(6) * euler_gamma + R(64).log()))/R(13824) + (\\\n", " z**8 *(R(25) - R(12) * euler_gamma + R(4096).log()))/R(1769472)\n", "\n", "coeffs = expr2.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print_double_double(\"\", c)\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", " # print(f\"z^{i}: {c}\")1.25331413731550025097574185194058307743736824945827587299663 + \n", "\n", "expr3 = R('1.25331413731550025121927282596719844509479202793343596081659') +\\\n", "R('18.1818090161526720433056569747515378514630065641474625981014') * z +\\\n", "R('84.0855308746947292990799286725009214888553349291444140660290') * z**2 +\\\n", "R('132.162365847816287381044941763470816630213463932078033240530') * z**3 +\\\n", "R('31.9226828676807644427339830797111472671372253510654795457144') * z**4 -\\\n", "R('6.55623468795551166985522946155773048406824737626044144871123') * z**5 +\\\n", "R('3.64813675168036216906333568031312648295984485156865732661545') * z**6 -\\\n", "R('3.09030769637907344287942414087144964418293628150871931378425') * z**7 +\\\n", "R('3.33386714181870765265684414717381480790589837093132038622747') * z**8 -\\\n", "R('4.15687509263144029996675634899519359876131330016912373219164') * z**9 +\\\n", "R('5.60168914866900308748492484302032849837652046070612403967421') * z**10 -\\\n", "R('7.74291668942803388088083086973577048045063529950220281515214') * z**11 +\\\n", "R('10.5182262725991203709271656214076983768897923475996777051390') * z**12 -\\\n", "R('13.5518704730239628983580812834313096171287792612392021785201') * z**13 +\\\n", "R('16.0756083151279354000726821130423204859625333785087750230562') * z**14 -\\\n", "R('17.1182809371435152577732819586801963660470433312228530729236') * z**15 +\\\n", "R('16.0011674817017251371454409588419263278595693541151351864594') * z**16 -\\\n", "R('12.8547201574813259441920569388886787474288736479192357179690') * z**17 +\\\n", "R('8.68486423302827636350417719675952558710622021096282923741362') * z**18 -\\\n", "R('4.81495629672548049328728197240253790905840957706216081678396') * z**19 +\\\n", "R('2.12449990606466172694756924925308136959633096070223397071382') * z**20 -\\\n", "R('0.715212551284256837854636761671218490310899339423567201757157') * z**21 +\\\n", "R('0.172124045885696320404925832426986371003557469307869009460024') * z**22 -\\\n", "R('0.0263211214093518652429028546952441524255064789438934805575092') * z**23 +\\\n", "R('0.00191881798965983631900602829845520749528121908949103217489718') * z**24\n", "print(\"k1 asympt\")\n", "\n", "coeffs = expr3.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print_dyadic(c)\n", " # print(c)\n", " # print_double_double(\"\", c)\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n", "\n", "expr4 = R('1') + R('14.1319847014545522182859614183872365899195687422959996226761') * z +\\\n", "R('61.9082401087861097277037880035610946116051551544124209371854') * z**2 +\\\n", "R('83.7882740830616503293819459356854835383521002198942068063204') * z**3\n", "print(\"k1 asympt den\")\n", "\n", "coeffs = expr4.list() # This gives all coefficients up to the current precision\n", "for i, c in enumerate(coeffs):\n", " if c != 0:\n", " print_dyadic(c)\n", " # print_double_double(\"\", c)\n", " # print(c)\n", " # print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")" ] }, { "cell_type": "code", "execution_count": null, "id": "c7094def-9e7d-4dbe-b1d2-296b93334da5", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_i0_exp.sollya000064400000000000000000000010011046102023000157470ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = exp(x); w = 1; p = remez(f, 6, d, w); pf = fpminimax(f, [|0,1,2,3,4,5,6|], [|107...|], d, absolute, floating, 0, p); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = hexadecimal; print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/exp(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; pxfm-0.1.23/notes/bessel_i0f.ipynb000064400000000000000000000664761046102023000151120ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 2, "id": "9ddfec27-d362-4b8d-8647-380e53799df0", "metadata": {}, "outputs": [], "source": [ "from sage.all import * \n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "e8ffd290-4cf4-4259-9052-5819f0835540", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.70265284158458111246639178380860921965281806355772639932174388328913237632303651273240661304359005444739555445283608842518250882276959e-126*y^48 + 6.48906947264457925103180667292447073638641617060210108477150706377720683555161066707050827791765972072819672624125944830886320368346979e-123*y^47 + 1.49508160649731105943772825744179805766343028570672408993135522749426845491109109769304510723222879965577652572598617689036208212867144e-119*y^46 + 3.30263526875256013029794172068893190937851750112615351465836369753483901689860023480393664187599341843961034532870346475080983942223518e-116*y^45 + 6.98837622868041723571044468097777992024494303238294083701709758398371935975743809684512993420960207341821549071553653141271362021744968e-113*y^44 + 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403358e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192055e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954770e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324896e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719840e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433873e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718507e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974669e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439148e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343076e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997612e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253552e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699661e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129699e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131080e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227650e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137953e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521257e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907652e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841478e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063274e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102908e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411625e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120597e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "Rational approximation of I0(x):\n", "\n", "I0_approx(1) = 683.1619269890404\n", "I0_real(1) = 683.16192699011560928271735903808393139159560065281983029181009891311086332634936800911797290661919018640520067130607713308665087223552\n", "Numerator polynomial coefficients:\n", "1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779\n", "0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112\n", "0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447\n", "1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6\n", "3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8\n", "6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10\n", "7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12\n", "7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14\n", "6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16\n", "4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18\n", "2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20\n", "1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22\n", "5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25\n", "2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27\n", "7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30\n" ] } ], "source": [ "from sage.all import *\n", "from mpmath import mp, besseli, taylor\n", "\n", "# High precision\n", "mp.prec = 450\n", "\n", "# Step 1: Define I0(x) - 1\n", "def shifted_i0(x):\n", " return besseli(0, x) - mp.mpf(1)\n", "\n", "# Step 2: Series of I0(x) - 1 in terms of (x/2)^2\n", "terms = 100\n", "from mpmath import taylor\n", "coeffs = taylor(shifted_i0, 0, terms)\n", "\n", "# print(coeffs)\n", "\n", "# Step 3: Build series in terms of y = (x/2)^2\n", "R = PolynomialRing(RealField(450), 'y')\n", "y = R.gen()\n", "f = R(0)\n", "\n", "for n in range(2, terms, 2):\n", " k = n // 2\n", " c = RealField(450)(coeffs[n])\n", " if n >= 1:\n", " f += R(c) * y**(k-1) * (4**k)\n", " else:\n", " f += R(c) * y**(k-1) * (4**k)\n", "\n", "print(f)\n", "\n", "rat_approx = SR(f).power_series(RealField(450)).pade(16, 0)\n", "numer = rat_approx.numerator()\n", "denom = rat_approx.denominator()\n", "\n", "print(numer)\n", "print(denom)\n", "\n", "def I0_approx(y):\n", " z = (y/2)**2\n", " return 1 + z * numer(z) / denom(z)\n", "\n", "# Print result\n", "print(\"Rational approximation of I0(x):\")\n", "pretty_print(I0_approx)\n", "\n", "# Evaluate at some point\n", "print(\"I0_approx(1) =\", I0_approx(-8.5))\n", "print(\"I0_real(1) =\", besseli(0, -8.5))\n", "\n", "print(\"Numerator polynomial coefficients:\")\n", "\n", "coeffs = numer.coefficients(sparse=False) \n", "\n", "for i, c in enumerate(coeffs):\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n" ] }, { "cell_type": "code", "execution_count": 200, "id": "4d6b20ea-430a-424e-8909-09498e92c629", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum relative error on [0.0, 7.5] is about 44.373857022462585146\n" ] } ], "source": [ "from mpmath import mp, besseli\n", "\n", "# Setup precision\n", "mp.dps = 100\n", "\n", "# Define the interval for y (example: from 0 to 3)\n", "a = 0.0\n", "b = 7.5\n", "\n", "# Number of test points\n", "N = 1000\n", "\n", "# Use your RealField 300 for evaluation\n", "RF = RealField(53)\n", "\n", "# Prepare to store max relative error\n", "max_rel_error = 0\n", "\n", "for i in range(N+1):\n", " y_val = a + (b - a) * i / N\n", " y_rf = RF(y_val)\n", " \n", " approx_val = I0_approx(y_rf)\n", " true_val = mp.besseli(0, y_val)\n", " \n", " # Compute relative error\n", " rel_err = abs(approx_val - true_val) / abs(true_val)\n", " \n", " if rel_err > max_rel_error:\n", " max_rel_error = rel_err\n", "\n", "print(f\"Maximum relative error on [{a}, {b}] is about {-RealField(70)(max_rel_error).log2()}\")\n" ] }, { "cell_type": "code", "execution_count": 197, "id": "e7bc6247-bee4-4ea9-bf48-6463ecf79852", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "u^0: 0.3989422804014326779399460599842496535260377159074279151857741923208659899625711280778486930461872946378\n", "u^1: 0.04986778505017908474249325754789899174093379923092174697417139487176778314389559541069692253826792737632\n", "u^2: 0.028050629090725735167652457426794441035726732402698397570389399641081804023295032420149456191039220173357\n", "u^3: 0.029219405302839307466304643240569091987399935318391427280347329328272064261664577560878230688342532173713\n", "u^4: 0.04474221436997268955777898514109027958559690918740281381390042662429097603654125305500333888070646372967\n", "u^5: 0.090602984099194696354502445363722736656807222877002925476947114448385232039935411995380932943420719345142\n", "u^6: 0.22839502241671996372697491572475453315602132336429437140075380755137032948594264370588900683313591969677\n", "u^7: 0.68926354979331560481890644692276477897048787031387636612939700526515838644736917148315170278374225263234\n", "u^8: 2.4231921672421251731914679968483822640051228046039656182296279794871908299566482763265603718871246216609\n", "u^9: 9.7264241157357524312824202415542402957534453611326999443900857462883412290243438365802032173471439918162\n", "u^10: 43.890488822257582846161921778918397557163250653730527497975835665233273530615608880812436138144717883392\n", "u^11: 219.95119966608629585406145133427016590318781732984827452419181308104271124643651809421809359583014821616\n", "u^12: 1212.0227564933296927791511370008243046156475150944984540972125509071237454171245836565703282885563303631\n", "u^13: 7283.7906039262601729516295237807700662796485650448527353519302945348175995926994674589427530933600002835\n", "u^14: 47409.672770198604161444089260487038232047099366625266817999792238615326208864767369639210192883083779911\n", "u^15: 332262.78999780855083145399721785517624339168386624205650717667849988042015496411945850601994605894239213\n", "u^16: 2494566.728030422010539275753400245963876591295155432664060670755145942281761073030266652478262009757723\n", "u^17: 19974876.226655364481450524570843983019770666187778523433395278706710985544745187835841315389609388394998\n", "u^18: 169925162.34481126034567286833145763886784620066675533343538431674720727874707034621265214312317389842393\n", "u^19: 1530444389.8029382592975405339847954300063627734479285245742535654135449476458504673157293149869034544452\n", "u^20: 14548786980.564181827447244992168701167781622664034271908639953457369318185420013266613962444048763982021\n", "u^21: 145574469728.14517649963582943703759442819696660093345332469010381899554279740558579567303561745176586193\n", "u^22: 1529359059814.4342690217423554020499528365095505529113032986504358568811410942457080574826668056773211699\n", "u^23: 16831261391979.507580266458374560050898647869128028791618972017971953191716481952555396771570775254785738\n", "u^24: 193647168827514.23044171149709234013745988914989178221284986859048725943067517116518555041832271025114432\n", "u^25: 2324734261774308.3364527465807118998945636776557695103609747832225774898040928147151802891182452031429293\n", "u^26: 29070354879206615.303430740450212167367834140113509335890408468322880056488866717558118609642142458398274\n", "u^27: 378049198405978622.16359700059920788536996955572659929374686071713326162166966034723590191165901476003804\n", "u^28: 5105351898116452375.2003614233632632063863714434358479604494506138767448086786044458393055032034999009645\n", "u^29: 71496932400777386926.836098041114669611980948549466988159015847659187854149997504387027378672426442315307\n", "7.14969324007774e19*x^29 + 5.10535189811645e18*x^28 + 3.78049198405979e17*x^27 + 2.90703548792066e16*x^26 + 2.32473426177431e15*x^25 + 1.93647168827514e14*x^24 + 1.68312613919795e13*x^23 + 1.52935905981443e12*x^22 + 1.45574469728145e11*x^21 + 1.45487869805642e10*x^20 + 1.53044438980294e9*x^19 + 1.69925162344811e8*x^18 + 1.99748762266554e7*x^17 + 2.49456672803042e6*x^16 + 332262.789997809*x^15 + 47409.6727701986*x^14 + 7283.79060392626*x^13 + 1212.02275649333*x^12 + 219.951199666086*x^11 + 43.8904888222576*x^10 + 9.72642411573575*x^9 + 2.42319216724213*x^8 + 0.689263549793316*x^7 + 0.228395022416720*x^6 + 0.0906029840991947*x^5 + 0.0447422143699727*x^4 + 0.0292194053028393*x^3 + 0.0280506290907257*x^2 + 0.0498677850501791*x + 0.398942280401433\n", "2.32473426177431e15*x^25 + 1.93647168827514e14*x^24 + 1.68312613919795e13*x^23 + 1.52935905981443e12*x^22 + 1.45574469728145e11*x^21 + 1.45487869805642e10*x^20 + 1.53044438980294e9*x^19 + 1.69925162344811e8*x^18 + 1.99748762266554e7*x^17 + 2.49456672803042e6*x^16 + 332262.789997809*x^15 + 47409.6727701986*x^14 + 7283.79060392626*x^13 + 1212.02275649333*x^12 + 219.951199666086*x^11 + 43.8904888222576*x^10 + 9.72642411573575*x^9 + 2.42319216724213*x^8 + 0.689263549793316*x^7 + 0.228395022416720*x^6 + 0.0906029840991947*x^5 + 0.0447422143699727*x^4 + 0.0292194053028393*x^3 + 0.0280506290907257*x^2 + 0.0498677850501791*x + 0.398942280401433\n", "1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n", "0.40196089431091836794309497797211594973382565501988328617296010456926730028039730091424506041812792503157\n", "0.401960894310917\n", "0.401960894310918\n", "0.401960894310917\n", "f64::from_bits(0x3fd9884533d43651),\n", "f64::from_bits(0x3fa9884533d43651),\n", "f64::from_bits(0x3f9cb94dda4ebd1b),\n", "f64::from_bits(0x3f9debb118bcafa6),\n", "f64::from_bits(0x3fa6e87396f0767b),\n", "f64::from_bits(0x3fb731c1d5a044c3),\n", "f64::from_bits(0x3fcd3c0c4fecac01),\n", "f64::from_bits(0x3fe60e726e95fd33),\n", "f64::from_bits(0x400362b29331d38a),\n", "f64::from_bits(0x402373eddc9838b8),\n", "f64::from_bits(0x4045f1fb89a88662),\n", "f64::from_bits(0x406b7e703a4839d1),\n", "f64::from_bits(0x4092f0174d7a6a7e),\n", "f64::from_bits(0x40bc73ca6504d760),\n", "f64::from_bits(0x40e7263587555e17),\n", "f64::from_bits(0x4114479b28f52f7f),\n", "f64::from_bits(0x414308335d3019d3),\n", "f64::from_bits(0x41730cadc3a06160),\n", "f64::from_bits(0x41a441b454b08b1a),\n", "f64::from_bits(0x41d6ce2e99736357),\n", "f64::from_bits(0x420b1966f9248372),\n", "f64::from_bits(0x4240f27510301295),\n", "f64::from_bits(0x4276414e74b666f3),\n", "f64::from_bits(0x42ae9daab678d704),\n", "f64::from_bits(0x42e603dfd6b60f47),\n", "f64::from_bits(0x432084aabfbd8fc9),\n" ] } ], "source": [ "from mpmath import mp, besseli, nprint\n", "\n", "# High precision\n", "mp.prec = 350\n", "\n", "# Define the function to expand\n", "def f(x):\n", " return mp.sqrt(x) * mp.exp(-x) * besseli(0, x)\n", "\n", "# Generate coefficients of series in u = 1/x\n", "terms = 30\n", "coeffs = []\n", "\n", "for n in range(terms):\n", " u = mp.mpf('1e-27') # Very small u ≈ 1/x\n", " deriv = mp.diff(lambda u: f(1/u), u, n)\n", " coeff = deriv / mp.fac(n)\n", " coeffs.append(coeff)\n", " print(f\"u^{n}: {coeff}\")\n", "\n", "x = var('x')\n", "u = x\n", "coeffs = [RR(coeffs[k]) for k in range(terms)]\n", "\n", "# Construct polynomial approximation in 1/x\n", "# P_ring = PolynomialRing(RR, 'u')\n", "taylor_poly = sum(c * u**k for k, c in enumerate(coeffs))\n", "\n", "print(taylor_poly)\n", "\n", "pade_approximant = SR(taylor_poly).power_series(RR).pade(25, 0)\n", "\n", "expr_in_x = pade_approximant.subs(u = 1/x)\n", "\n", "numer_asympt = expr_in_x.numerator()\n", "\n", "print(numer_asympt)\n", "print(denom)\n", "\n", "print(f(17.1))\n", "print(numer_asympt(1/17.1))\n", "print(taylor_poly(x=1/17.1))\n", "print(expr_in_x(x=1/17.1))\n", "\n", "coeffs = numer_asympt.coefficients(sparse=False) \n", "\n", "for i, c in enumerate(coeffs):\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")\n" ] }, { "cell_type": "code", "execution_count": 198, "id": "aa4296d8-fc32-4471-8ffa-587d9b3b7ca5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum relative error on [15.0, 20.0] is about 43.635221852039236487\n" ] } ], "source": [ "from mpmath import mp, besseli\n", "\n", "# Setup precision\n", "mp.dps = 100\n", "\n", "# Define the interval for y (example: from 0 to 3)\n", "a = 15.0\n", "b = 20.0\n", "\n", "# Number of test points\n", "N = 1000\n", "\n", "# Use your RealField 300 for evaluation\n", "RF = RealField(53)\n", "\n", "# Prepare to store max relative error\n", "max_rel_error = 0\n", "\n", "def I0_approx_asympt(y):\n", " return numer_asympt(x=1/y) * y.exp() / y.sqrt()\n", "\n", "for i in range(N+1):\n", " y_val = a + (b - a) * i / N\n", " y_rf = RF(y_val)\n", " \n", " approx_val = I0_approx_asympt(y_rf)\n", " true_val = mp.besseli(0, y_val)\n", " \n", " # Compute relative error\n", " rel_err = abs(approx_val - true_val) / abs(true_val)\n", " \n", " if rel_err > max_rel_error:\n", " max_rel_error = rel_err\n", "\n", "print(f\"Maximum relative error on [{a}, {b}] is about {-RealField(70)(max_rel_error).log2()}\")" ] }, { "cell_type": "code", "execution_count": null, "id": "3a4485cd-14cd-4a07-97b2-a4f934b5fcda", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_i0f_mid_polys.ipynb000064400000000000000000000603501046102023000171520ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 2, "id": "0a221503-f226-4492-8b3c-a3721f87f532", "metadata": {}, "outputs": [], "source": [ "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def float_to_hex(f):\n", " packed = struct.pack('>f', float(f)) # pack as 32-bit float (big endian)\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")" ] }, { "cell_type": "code", "execution_count": 3, "id": "325c3233-7bed-4b65-9e1b-c69d37517095", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static I0F_POLYS: [[u64; 39]; 16] = [\n", "[\n", "0x3ff0000000122e26,\n", "0xbe16c9f42ab7e95f,\n", "0x3fd00000037a7917,\n", "0xbe360d45339e182d,\n", "0x3f90000065fdc17a,\n", "0xbe36ecaddb8bc445,\n", "0x3f3c71d7ca969145,\n", "0xbe2430101eb89d74,\n", "0x3edc7312b17256cd,\n", "0xbe02501379d76e32,\n", "0x3e72426d26bff243,\n", "0xbdd30aae13f7fc48,\n", "0x3e00e4a8f9885034,\n", "0xbd9837aff2d93c73,\n", "0x3d9052aac4ad91f6,\n", "0xbd53a06d522b581a,\n", "0x3d31b0d6080cec44,\n", "0xbd04cc72d931fe76,\n", "0x3cda7780286b9606,\n", "0xbcad3d046193778a,\n", "0x3c7ddc8eef7cca70,\n", "0xbc4b676fa26f7b3b,\n", "0x3c16c8881e75930a,\n", "0xbbe110dbad899076,\n", "0x3ba70711d09628c5,\n", "0xbb6be4bfdf437d2e,\n", "0x3b2e3e07c4e25b32,\n", "0xbaed3836820798a7,\n", "0x3aa90736a814ac9c,\n", "0xba62e0d274070e0a,\n", "0x3a18de861ec7b752,\n", "0xb9cc4d45c2c424a9,\n", "0x397b6fed27817a38,\n", "0xb9263cb2b33ad34a,\n", "0x38cd5be67c600e66,\n", "0xb86e61e5720468fa,\n", "0x38072dae09144e7a,\n", "0xb7974616b7657578,\n", "0x3717443dc29a1cf8,\n", "],\n", "[\n", "0x3ff0000001526426,\n", "0xbe58e59af6a26e3c,\n", "0x3fd000003919d1ee,\n", "0xbe753f4aaa2574a1,\n", "0x3f900005c4900ba5,\n", "0xbe737abc05a92a42,\n", "0x3f3c729c1278ddaf,\n", "0xbe5e412f3cd99b00,\n", "0x3edc805c42958ab5,\n", "0xbe3833733d017d06,\n", "0x3e72c03435eee880,\n", "0xbe0630493190f763,\n", "0x3e0668d67f93356b,\n", "0xbdc8e181873d5195,\n", "0x3dab7dcf26c1cf26,\n", "0xbd81c6dbc1aa3e24,\n", "0x3d5a416fcf24110d,\n", "0xbd309b1ba6ec37b4,\n", "0x3d03834f63c4baeb,\n", "0xbcd4933130f1bd02,\n", "0x3ca3ae8a015c8cdf,\n", "0xbc70fe5521e2df12,\n", "0x3c3a834452fb4c3c,\n", "0xbc02a5a09b7298a3,\n", "0x3bc79cc652a7b497,\n", "0xbb8ad7eeee9e8b48,\n", "0x3b4b4f1f3fd9f0c8,\n", "0xbb08c1b6a89d8b39,\n", "0x3ac3e4a36618eca3,\n", "0xba7c260c3942eb9b,\n", "0x3a3163260293c130,\n", "0xb9e28d4bc2fe4dc2,\n", "0x3990db78ab4a523e,\n", "0xb9399a134c6a5659,\n", "0x38dfa784d19a25f1,\n", "0xb87ea83e8f39158d,\n", "0x3815de01c49efbf9,\n", "0xb7a48021a778f1ae,\n", "0x3723140b3e7465ce,\n", "],\n", "[\n", "0x3ff0000015503563,\n", "0xbe97a6503af36990,\n", "0x3fd0000332066278,\n", "0xbeb1ee91a94b0ea4,\n", "0x3f90004969b09291,\n", "0xbead36369649744a,\n", "0x3f3c7b2f3b4a0348,\n", "0xbe94274d25c5754a,\n", "0x3edd0444b2dbf1f4,\n", "0xbe6ca46615539c48,\n", "0x3e7714764761a084,\n", "0xbe3753b960436a31,\n", "0x3e2062ff16617630,\n", "0xbdf73bd45cb251a0,\n", "0x3dd434365539f504,\n", "0xbdad7c7abe87028c,\n", "0x3d84162b745098ff,\n", "0xbd5875dbe9eb71f3,\n", "0x3d2b029bce980aee,\n", "0xbcfae8fe6cdf1c41,\n", "0x3cc83eab8c65f59f,\n", "0xbc93bb448e896f88,\n", "0x3c5d0049fe9e5348,\n", "0xbc2337a4f88dd6bd,\n", "0x3be6ec5d513750d4,\n", "0xbba88c3246ea674d,\n", "0x3b6785712527fe20,\n", "0xbb2414c39b92926b,\n", "0x3ade637c5fc214be,\n", "0xba943dfa41f4aa4a,\n", "0x3a478a2a90daacf1,\n", "0xb9f7a3415d6b3083,\n", "0x39a4355d614831ec,\n", "0xb94cdde47c62066c,\n", "0x38f0c6f449d723b6,\n", "0xb88e88a65d3ceecd,\n", "0x3824722b91fd8eb0,\n", "0xb7b1f8f52d2b671f,\n", "0x372f4a25fac14b45,\n", "],\n", "[\n", "0x3ff000012e7fb9a2,\n", "0xbed3d6eb83533633,\n", "0x3fd000288f7b4e3a,\n", "0xbeeae81834db68ff,\n", "0x3f9003415e16d7c9,\n", "0xbee3996970073b20,\n", "0x3f3cd14561c1d551,\n", "0xbec82f0657ca7daf,\n", "0x3ee0d1cc80214db4,\n", "0xbe9ebbd259fd07c7,\n", "0x3e8ce3d06dcd1851,\n", "0xbe666183e22e8ea8,\n", "0x3e47675eaa1b1fc9,\n", "0xbe23ee293cde2f6c,\n", "0x3dffde45db81e541,\n", "0xbdd69cdf9fd2d945,\n", "0x3dad079fa354d61c,\n", "0xbd80c4b210524b2c,\n", "0x3d517f477c188651,\n", "0xbd207d059b0db452,\n", "0x3cec159dbb3be0b6,\n", "0xbcb59bab2fa641cb,\n", "0x3c7e052760ee1d3f,\n", "0xbc42cd87f2eebe9d,\n", "0x3c0532c35e09c92c,\n", "0xbbc5741a5ddeca9e,\n", "0x3b836cf2a47c4f5b,\n", "0xbb3f574d7e1a75a9,\n", "0x3af6679037c371e7,\n", "0xbaac320f36f176f1,\n", "0x3a5ef7fb82fa5d2c,\n", "0xba0d5d8d12adf40f,\n", "0x39b7b36e2129eb0e,\n", "0xb95ff3aa6b47179a,\n", "0x390184d634b026e4,\n", "0xb89e1012337ab19c,\n", "0x3832f77c268320f6,\n", "0xb7bf61eb8f13dc5b,\n", "0x3739a8eeb1e0bff8,\n", "],\n", "[\n", "0x3ff0000ef6699663,\n", "0xbf0dc8dd33d6b917,\n", "0x3fd001ce0a2408a0,\n", "0xbf222b53d22cc2f9,\n", "0x3f90215be1c786cf,\n", "0xbf17cf9f830c19b1,\n", "0x3f3fe208c7e332dc,\n", "0xbefa6db13698f2e4,\n", "0x3ef1e10547fd2fd4,\n", "0xbece35cd994e0125,\n", "0x3eb3959f2279fce8,\n", "0xbe93c97616e69b12,\n", "0x3e72e6ada0a48849,\n", "0xbe4fb1a7c6d17f70,\n", "0x3e27ecef339edbe5,\n", "0xbe002b3ce4f92d82,\n", "0x3dd3ac08ec1620e2,\n", "0xbda58ff3a44eaf37,\n", "0x3d7555119b671aa3,\n", "0xbd430ff6f45753fc,\n", "0x3d0ec8c889eddf9d,\n", "0xbcd674d9fbb19ca7,\n", "0x3c9d93f386bcd6a3,\n", "0xbc6190074a754345,\n", "0x3c22c4ec7ecfd403,\n", "0xbbe2014c179b6821,\n", "0x3b9ee768c9cc0661,\n", "0xbb57a05703fde021,\n", "0x3b10012aa62a7c2a,\n", "0xbac3155a982d915c,\n", "0x3a73db373558c179,\n", "0xba21d5520b0302fd,\n", "0x39cb42495f454637,\n", "0xb97164eace1eda44,\n", "0x39120cd9436d84b0,\n", "0xb8ad4c2fc498534c,\n", "0x384178c38971916b,\n", "0xb7cb4cb337503290,\n", "0x37450b4ecd6e054d,\n", "],\n", "[\n", "0x3ff000aafad1dcce,\n", "0xbf443ac92708fbcb,\n", "0x3fd012a6f16dfc53,\n", "0xbf565211181486cb,\n", "0x3f9137c55c77ac73,\n", "0xbf4a73ef9cd50801,\n", "0x3f4cc0b1dffe81da,\n", "0xbf2a8cf4fd5154ab,\n", "0x3f1659ed11a99633,\n", "0xbefb718fc44dda3c,\n", "0x3ee013a6fb63c769,\n", "0xbec040b47397668f,\n", "0x3e9d5bd4044ce0d2,\n", "0xbe778983afddb865,\n", "0x3e50e1e02e002243,\n", "0xbe25b609ac13722c,\n", "0x3df91cba55ddb1f0,\n", "0xbdca2c2e2aa5f889,\n", "0x3d989df984ec47dc,\n", "0xbd64e9d6483566d2,\n", "0x3d300db5e1a7856d,\n", "0xbcf643d3ba2d822d,\n", "0x3cbbe05349437637,\n", "0xbc7f777507ad2c59,\n", "0x3c3ff67d515e1b6a,\n", "0xbbfd240f6ff28ff3,\n", "0x3bb7c43ce3cdcdc1,\n", "0xbb7144059f7519f0,\n", "0x3b2639bd5218028f,\n", "0xbad92d4988264ef4,\n", "0x3a88e24a33e194f5,\n", "0xba3539a3976c0f27,\n", "0x39dece549fd4302f,\n", "0xb982a916e32ccac4,\n", "0x39226039ff880cba,\n", "0xb8bc4aa840f004ee,\n", "0x384ffd13684430e2,\n", "0xb7d7abdd9c7f83d2,\n", "0x375142763bbf339f,\n", "],\n", "[\n", "0x3ff006f491510050,\n", "0xbf791a6219692f5d,\n", "0x3fd0b082756e13ac,\n", "0xbf892b3925748cbe,\n", "0x3f9a78f0e9671b4d,\n", "0xbf7b1aa265a55c01,\n", "0x3f6ff067e3a452a7,\n", "0xbf58b7ea1caac870,\n", "0x3f427ac8467d72b0,\n", "0xbf2736cb5ebf61d7,\n", "0x3f09bb12c6562d57,\n", "0xbee8fb1183b3b7b7,\n", "0x3ec57c6b6baa5b37,\n", "0xbea06ecc40cfadd1,\n", "0x3e76770f02d90e58,\n", "0xbe4b89e7e8896a40,\n", "0x3e1e5b69abbe8407,\n", "0xbdee2759b4fec186,\n", "0x3dbb076094216ab1,\n", "0xbd85e1f947f83c03,\n", "0x3d5001d71d5b0960,\n", "0xbd1527ba7543df74,\n", "0x3cd93d0604d6542a,\n", "0xbc9b2512836e7046,\n", "0x3c5a453b8088b351,\n", "0xbc16d17638c5cb65,\n", "0x3bd1ba7bcb5baf8a,\n", "0xbb8889460dc7b1cc,\n", "0x3b3e15427e14b775,\n", "0xbaf03a1c2ebc47fd,\n", "0x3a9e8b3389798cf4,\n", "0xba48cdd1047f624c,\n", "0x39f1224a1c757f63,\n", "0xb993c0feeb0d2d06,\n", "0x393281a3ee1aa892,\n", "0xb8cb1895b45dfa32,\n", "0x385d1ea63c52c93f,\n", "0xb7e47758c4003343,\n", "0x375c5011a2a8f4e7,\n", "],\n", "[\n", "0x3ff0429211969797,\n", "0xbfacb11fa14b2624,\n", "0x3fd605dd2e8f6007,\n", "0xbfba412240209c33,\n", "0x3fb8df3c71684365,\n", "0xbfa9cd7c0930f198,\n", "0x3f9a41dee51e9c55,\n", "0xbf85797e1ed95564,\n", "0x3f6e5c151dfd6886,\n", "0xbf52675f1e83c450,\n", "0x3f3376b4ac827466,\n", "0xbf121242fcca9380,\n", "0x3eedb09f82a84e92,\n", "0xbec5b17f1a1fd0a6,\n", "0x3e9c53b53ff3c647,\n", "0xbe70958da454fc7b,\n", "0x3e41761a6a2fdfb3,\n", "0xbe1090e5092eb5f6,\n", "0x3ddc5d5e98dde546,\n", "0xbda5eead36835bf9,\n", "0x3d6ea4dd6f746ca5,\n", "0xbd33569950b18c36,\n", "0x3cf6081035973990,\n", "0xbcb6a08f92380181,\n", "0x3c74e8e53736ed2c,\n", "0xbc31574c1021231f,\n", "0x3be9b9e3a88a4e41,\n", "0xbba0fec9375db0f2,\n", "0x3b53e3fef27960e3,\n", "0xbb047b2b3088c439,\n", "0x3ab26542e49fb0ef,\n", "0xba5c82484c57f208,\n", "0x3a02c9b016572bf4,\n", "0xb9a4a9060a5a2f32,\n", "0x394274d776dc6dde,\n", "0xb8d9c2236525545d,\n", "0x386a5fd1eb3abff9,\n", "0xb7f1a634eddfee24,\n", "0x3767392e0488425f,\n", "],\n", "[\n", "0x3ff24deae94893f6,\n", "0xbfde6c39287a7eff,\n", "0x3ff039e9c18601e1,\n", "0xbfe981fc001fe317,\n", "0x3fe3e92aa1737dd0,\n", "0xbfd6f829c6eb6dd1,\n", "0x3fc60ceac24d1436,\n", "0xbfb183ceba4266d4,\n", "0x3f97aa317c1415f6,\n", "0xbf7b810b23886f23,\n", "0x3f5bd61ed6f48f77,\n", "0xbf38bdefb423f54e,\n", "0x3f1373de4d9054a3,\n", "0xbeeb353e0c5c8f50,\n", "0x3ec10067c268af4c,\n", "0xbe930d810e005013,\n", "0x3e6332e20b4bfdd4,\n", "0xbe316e78f28820d3,\n", "0x3dfc902e02a68ac8,\n", "0xbdc522aa2540c52e,\n", "0x3d8c42443e00e2a6,\n", "0xbd511084aa4fb94e,\n", "0x3d129a3a0e030a27,\n", "0xbcd247caf2e2f226,\n", "0x3c9029a3356bf863,\n", "0xbc49a5d7872089de,\n", "0x3c02333bfb58afe8,\n", "0xbbb700b1c673c159,\n", "0x3b69c015a3da0849,\n", "0xbb195bd839f4fc90,\n", "0x3ac5c7e707cbf33a,\n", "0xba70233cb2d1afb1,\n", "0x3a145578d8a0ada3,\n", "0xb9b55f35076e6c62,\n", "0x39523e5689672e8d,\n", "0xb8e852519fa95ca4,\n", "0x3877c73f7e4f0dc4,\n", "0xb7fe5e6f84ba9ca4,\n", "0x37730cbaf0d7ca22,\n", "],\n", "[\n", "0x400183a03a809ecd,\n", "0xc00e1d2b98bf1231,\n", "0x40183613c9fe24a0,\n", "0xc017382c60a8f5d6,\n", "0x401101bac1befc43,\n", "0xc0033a40b917b9e0,\n", "0x3ff1a9ab03bac865,\n", "0xbfdaf6de8c5f7b6e,\n", "0x3fc176a972efa213,\n", "0xbfa377a858ed0f53,\n", "0x3f82e46328e32a97,\n", "0xbf601a1e5b791420,\n", "0x3f38472252132c11,\n", "0xbf1047a809829900,\n", "0x3ee3821a910ce987,\n", "0xbeb4f61fac0b9742,\n", "0x3e84406e98b0e83f,\n", "0xbe51a122e5a4b95d,\n", "0x3e1bb21d954f3863,\n", "0xbde3a5c59d1d38e6,\n", "0x3da92f2db8e6c425,\n", "0xbd6d288459a386cc,\n", "0x3d2e78831d4ccc45,\n", "0xbcecb3f3ac791254,\n", "0x3ca85344b1049c86,\n", "0xbc627fbb6d645951,\n", "0x3c1929a107c43860,\n", "0xbbce7a5191dbfaca,\n", "0x3b8058e70db8fa63,\n", "0xbb2ed9d2961bc08a,\n", "0x3ad963185620be07,\n", "0xba8204be772a6948,\n", "0x3a25bee43961f9f2,\n", "0xb9c5e313b5723dd7,\n", "0x3961e31aafe9387d,\n", "0xb8f6d2d5afb31a42,\n", "0x3885593264c8f413,\n", "0xb80a12831ac38506,\n", "0x377f40faab38fd23,\n", "],\n", "[\n", "0x402467ee8f3ddef5,\n", "0xc03bfb208c04f2ca,\n", "0x4044d78d00d05f4e,\n", "0xc043e83d990e09a7,\n", "0x403bec9715f1bcfd,\n", "0xc02e6b8edc07f726,\n", "0x401ad549cfe27298,\n", "0xc003ae2131acd53b,\n", "0x3fe87c0e8a346237,\n", "0xbfca37ad4a11e7a1,\n", "0x3fa8700b5bc85fa0,\n", "0xbf84017751eed48a,\n", "0x3f5cf8afc351113f,\n", "0xbf32a8bb3576a51f,\n", "0x3f0579886332aed9,\n", "0xbed62947a8424807,\n", "0x3ea4902844f5be8b,\n", "0xbe7130fd9fb88a1c,\n", "0x3e39efdbb5bf14de,\n", "0xbe01ab8228ce5d34,\n", "0x3dc5c013f83daef4,\n", "0xbd882e945b8ceb80,\n", "0x3d4843fcc8d4e747,\n", "0xbd05f2abd054f284,\n", "0x3cc1dbfb987f99a1,\n", "0xbc7a14619270439d,\n", "0x3c31073df5dabe38,\n", "0xbbe3ccc038d01453,\n", "0x3b946367beb22958,\n", "0xbb42772f85eb0759,\n", "0x3aed2a982ad3e07d,\n", "0xba93dd57a5c44dbc,\n", "0x3a370074a1ef82b1,\n", "0xb9d63578e6500aa8,\n", "0x39716855e93d3d21,\n", "0xb9054c0f7d8d7572,\n", "0x389317ff355af826,\n", "0xb8165720b015d17b,\n", "0x3789a3afc56079ee,\n", "],\n", "[\n", "0x405104b5815888a3,\n", "0xc068864df1f648f4,\n", "0x40717c17397fdf3b,\n", "0xc070263ae6541e35,\n", "0x4065c874c51a78bc,\n", "0xc056d70cf5489600,\n", "0x40436181a222e658,\n", "0xc02b59cc223c932c,\n", "0x40105e10056d0385,\n", "0xbff0dc284e3ad8cd,\n", "0x3fce3c70e7ee4f93,\n", "0xbfa7cfb8692fa469,\n", "0x3f8095e3abd4e937,\n", "0xbf548d0844971b8d,\n", "0x3f26c068fd4e0228,\n", "0xbef695af1dd4f1ba,\n", "0x3ec42850ec873827,\n", "0xbe9035b0cd757731,\n", "0x3e5785df223ddbee,\n", "0xbe1ed3c392a2722e,\n", "0x3de23f82efa06499,\n", "0xbda383335b752b95,\n", "0x3d62d4a85cfe15d2,\n", "0xbd206134df7dc95d,\n", "0x3cd9a26f017e5e13,\n", "0xbc91ff86086b91d9,\n", "0x3c469979f31ee0e7,\n", "0xbbf9440ba04abb33,\n", "0x3ba903529e01b418,\n", "0xbb55c73abd9e205a,\n", "0x3b0088646fa3f7c1,\n", "0xbaa5a51cfff5df28,\n", "0x3a4815fce973541c,\n", "0xb9e658553bcd4436,\n", "0x3980d33ea61ee03a,\n", "0xb913c50f2726b154,\n", "0x38a1047400321080,\n", "0xb8231bd3d467721f,\n", "0x379508d5e683b5fc,\n", "],\n", "[\n", "0x407cf778b81c1c03,\n", "0xc0945d442043104a,\n", "0x409bf463fcce01b1,\n", "0xc098e4eee8bfc924,\n", "0x40902c8f945f4a3e,\n", "0xc08056f8e0b1e49f,\n", "0x406ab718353b3340,\n", "0xc052292b20400b6f,\n", "0x4034f0a7abe943a3,\n", "0xc014c7c420be49a8,\n", "0x3ff1f36585c3fdc6,\n", "0xbfcb3caabf8e1425,\n", "0x3fa246ad17f00faf,\n", "0xbf75d0b10b329085,\n", "0x3f4743e4e01967c5,\n", "0xbf163f3177b04e51,\n", "0x3ee320729a6a6ddb,\n", "0xbeada1a333d00cb4,\n", "0x3e74b5a147159c0e,\n", "0xbe3a2441b6f9a943,\n", "0x3dfdcf3a5f842025,\n", "0xbdbeb352ad0780b0,\n", "0x3d7c88fa6ba7d8ed,\n", "0xbd37e799260cd8da,\n", "0x3cf203a8f99ee025,\n", "0xbca85c20f5b8b382,\n", "0x3c5d744cb7ed5a8f,\n", "0xbc0fb50ce899f8f6,\n", "0x3bbe3910de07e420,\n", "0xbb695585978a99b0,\n", "0x3b1283936bb441e4,\n", "0xbab754c387327398,\n", "0x3a58fc9f14fbf0f1,\n", "0xb9f64e7c667841cd,\n", "0x399028e69174271c,\n", "0xb92243a5da249046,\n", "0x38ae3c64074e754a,\n", "0xb83051672bfb5265,\n", "0x37a141e845627122,\n", "],\n", "[\n", "0x40a7ab341de9e4e2,\n", "0xc0c0150d19d2f950,\n", "0x40c54b91fa702435,\n", "0xc0c24bfecfec1b70,\n", "0x40b6ef98eee26ce7,\n", "0xc0a65a6a0f3bd82f,\n", "0x4091a0d7c42e5b28,\n", "0xc0771ee81435d952,\n", "0x4059b7999f1d186a,\n", "0xc0389e80a32f4355,\n", "0x401483dc4edf7c68,\n", "0xbfee06f04de3fe5b,\n", "0x3fc36f7d83bcd06d,\n", "0xbf9660ce8070d757,\n", "0x3f670547e66bf3e3,\n", "0xbf353bb629f297b7,\n", "0x3f019bbd1aaffbef,\n", "0xbeca4fd2452b24d0,\n", "0x3e91bca954e6e0fc,\n", "0xbe559830b7d709fa,\n", "0x3e17bfdd647c181b,\n", "0xbdd796f17ed8c8c6,\n", "0x3d95253c5ee32f40,\n", "0xbd5115481f2cbd1c,\n", "0x3d08d43f9ef772fa,\n", "0xbcc0302ce846b57f,\n", "0x3c72dfb0c8066677,\n", "0xbc23970103d11494,\n", "0x3bd200c0f5749017,\n", "0xbb7d18c1c52a9aa5,\n", "0x3b247f613684cf12,\n", "0xbac8e5ce1321b495,\n", "0x3a69b2beadffd5c8,\n", "0xba061b6f9895c8b9,\n", "0x399edc36a9ef693b,\n", "0xb930cc7e1722fe45,\n", "0x38bac7f2cb0059c3,\n", "0xb83bd3f40e6ec114,\n", "0x37ac5188131e94e8,\n", "],\n", "[\n", "0x40d2769021851585,\n", "0xc0e83df38a255bcc,\n", "0x40ef01541c2e9547,\n", "0xc0e9bb6367167d8c,\n", "0x40df27fdbccbd6bf,\n", "0xc0cd543b51f0d76a,\n", "0x40b6572e029a053b,\n", "0xc09c4d227a3052b0,\n", "0x407e67b036fe69ff,\n", "0xc05c1cef0e55888c,\n", "0x4036a05b0b0c5773,\n", "0xc00ffc5fff097153,\n", "0x3fe3fee6c7334238,\n", "0xbfb63c66b28d0337,\n", "0x3f86178440a4377d,\n", "0xbf53ade251e61f54,\n", "0x3f1f858cc00d5b00,\n", "0xbee6be86bb6e5f60,\n", "0x3ead9ce7b9dd3208,\n", "0xbe71688510b1a85f,\n", "0x3e327d0025441a21,\n", "0xbdf1bba30e088b75,\n", "0x3daeb2b511c7d671,\n", "0xbd67f26cfba37009,\n", "0x3d20cd905c311d9c,\n", "0xbcd5279bf262d164,\n", "0x3c87cff1e34e4f91,\n", "0xbc37dc53c11e4b5b,\n", "0x3be52af85699f006,\n", "0xbb90830fd5707579,\n", "0x3b36745a976fafde,\n", "0xbada52ae7d7b39b3,\n", "0x3a7a37e972f3b4f2,\n", "0xba15c32b388fd9ca,\n", "0x39ad4ea08a025aae,\n", "0xb93ec670a9ba39cc,\n", "0x38c7a7d0179eba64,\n", "0xb847b207a4a56f0c,\n", "0x37b73c4a43619d27,\n", "],\n", "[\n", "0x40fb8d0dec775114,\n", "0xc1117de0900b0865,\n", "0x4115a24dfee39911,\n", "0xc1115cd2072081dd,\n", "0x4104544391b87158,\n", "0xc0f2816e798fa2a2,\n", "0x40db430ac55ee27a,\n", "0xc0c0b2a8c7b7fdbc,\n", "0x40a158c7b3770446,\n", "0xc07f04d376db3a0a,\n", "0x405823ebefc5d7f9,\n", "0xc0307fc44cfda8e7,\n", "0x4003f25198160e03,\n", "0xbfd5729917e45f2b,\n", "0x3fa49a85593daddc,\n", "0xbf71bef4c3da6bab,\n", "0x3f3b7bc5bc8758df,\n", "0xbf032c6052a15feb,\n", "0x3ec822c69b62c2a6,\n", "0xbe8b6f7b3cf5dd08,\n", "0x3e4c2b88dc78176b,\n", "0xbe0a1f0ea9ed5b1c,\n", "0x3dc5db93af630f4e,\n", "0xbd807baef6f76ff5,\n", "0x3d365c562b1f77c7,\n", "0xbceb36642de1955d,\n", "0x3c9d9b8ccbc374df,\n", "0xbc4caccfb5c07429,\n", "0x3bf8961542a12c3c,\n", "0xbba288d08cccb22b,\n", "0x3b485b46f5b4bca9,\n", "0xbaeb96dac00f8cf9,\n", "0x3a8a8cb90bf658da,\n", "0xba2549f93928bd58,\n", "0x39bbb11f783640c8,\n", "0xb94c15135ce706fb,\n", "0x38d4d759dc419d9f,\n", "0xb85426966fa27659,\n", "0x37c310d21624aab8,\n", "],\n", "];\n" ] } ], "source": [ "from sage.all import *\n", "from mpmath import mp, chebyfit, besseli\n", "\n", "mp.prec = 350\n", "\n", "def horner_eval(x, coeffs):\n", " result = 0\n", " for c in coeffs:\n", " result = RealField(53)(result) * RealField(53)(x) + RealField(53)(c)\n", " return result\n", "\n", "items = 16\n", "\n", "terms = 39\n", "\n", "print(f\"pub(crate) static I0F_POLYS: [[u64; {terms}]; {items}] = [\")\n", "\n", "for i in range(items):\n", " f = lambda x: besseli(0, x)\n", "\n", " cf = chebyfit(f, [7.5 + i*0.5, 8.0 + i*0.5], terms)\n", "\n", " print(\"[\")\n", "\n", " for c in reversed(cf):\n", " # print(c)\n", " print(double_to_hex(RealField(300)(c)) +\",\")\n", "\n", " print(\"],\")\n", " \n", "print(\"];\")\n", "\n", "# print(cf)\n", "\n", "# Evaluate and test\n", "# x = mp.mpf('8.25')\n", "# print(f\"Exact I0({x}) = {f(x)}\")\n", "# print(f\"Chebyfun I0({x}) ≈ {horner_eval(x, cf)}\")\n", "# err = abs(f(x) - horner_eval(x, cf))\n", "# print(f\"Abs error = {-RealField(70)(err).log2()}\")\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "9b688bdd-347c-4272-8743-f5b19ef8a32d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "244.6962646579708484500544101774564739233990936461021517401582798487201487523268303232062991732192169493\n", "Max relative error = 19.384565016680689984\n", "At x = 14.9967996799679967996799679967996799679967996799679967996799679967996799679967996799679967996799679968\n" ] } ], "source": [ "from mpmath import mp, besseli, linspace, fabs\n", "\n", "print(besseli(0, 7.4015625000126715))\n", "\n", "f = lambda x: besseli(0, x)\n", "cf = chebyfit(f, [14.5, 15.0], 37)\n", "\n", "xs = linspace(14.5, 15.0, 10000)\n", "errors = [fabs(f(x) - horner_eval(x, cf)) for x in xs]\n", "\n", "# Get max error and location\n", "errors = []\n", "for x in xs:\n", " actual = f(x)\n", " approx = horner_eval(x, cf)\n", " rel_err = fabs(approx - actual) / fabs(actual)\n", " errors.append(rel_err)\n", "\n", "# Max error and its location\n", "max_err = max(errors)\n", "x_at_max = xs[errors.index(max_err)]\n", "\n", "print(f\"Max relative error = {-RealField(70)(max_err).log2()}\")\n", "print(f\"At x = {x_at_max}\")\n" ] }, { "cell_type": "code", "execution_count": null, "id": "7976ae85-4f05-4a76-835c-af809b250b4f", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_i1f.ipynb000064400000000000000000000461761046102023000151060ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "960d6d19-fc12-4d8f-94a4-0058a7a09593", "metadata": {}, "outputs": [], "source": [ "from sage.all import * \n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")" ] }, { "cell_type": "code", "execution_count": 58, "id": "92f6c828-0a9c-472a-9a0d-7da0765990d6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5.60925685698021087965722018070400338422594974731955926336123209216158518748673667144688016736989945676635607653560767434477873457206268940519083401459\n", "[mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('0.0'), mpf('0.00520833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333413'), mpf('0.0'), mpf('0.000108506944444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444461'), mpf('0.0'), mpf('0.00000135633680555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555553'), mpf('0.0'), mpf('0.0000000113028067129629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629629646'), mpf('0.0'), mpf('0.0000000000672786113866843033509700176366843033509700176366843033509700176366843033509700176366843033509700176366843033509700176366843033509700176366843033509700069'), mpf('0.0'), mpf('0.000000000000300350943690554925673973293020912068531116150163769211388259007306626354245401864449483497102544721592340639959687578735197782816830435878054925673973324'), mpf('0.0'), mpf('0.00000000000000104288522114776015859018504521150023795526441029086531732034377537023039668542314044959547605050250552896055541558187060832563478066123568769071414574047'), mpf('0.0'), mpf('0.00000000000000000289690339207711155163940290336527843876462336191907032588984382047286221301506427902665410014028473758044598726550519613423787439072565468802976151594603'), mpf('0.0'), mpf('0.00000000000000000000658387134562979898099864296219381463355596218617970528611328141016559593867060063415148659122791985813737724378523908212326789634255830610915854889987749'), mpf('0.0'), mpf('0.000000000000000000000012469453306117043524618641973851921654462049595037320617638790549556052914148864837408118543992272458593517507169013413112249803679087700964315433522496'), mpf('0.0'), mpf('0.0000000000000000000000000199830982469824415458632082914293616257404640946110907333954976755705976188283090343078822820388981708229447230272650851157849417934097771864029383373351'), mpf('0.0'), mpf('0.0000000000000000000000000000274493107788220350904714399607546176177753627673229268315872220818277439819070179042690690687347502346469020920704190729612430519140244192120919482655643'), mpf('0.0'), mpf('0.0000000000000000000000000000000326777509271690893934183809056602590687801937706225319423657405736044571213178784574631774627794645650558358238933560392395750618024100228715380336494876'), mpf('0.0'), mpf('0.0000000000000000000000000000000000340393238824678014514774801100627698633127018443984707732976464308379761680394567265241431903952755885998289832222458742078906893775104404911854517182143'), mpf('0.0'), mpf('0.0000000000000000000000000000000000000312861432743270233929020956893959281831918215481603591666338662048143163309186183148199845499956577101101369331086818696763701189131529783926336872410049'), mpf('0.0'), mpf('0.0000000000000000000000000000000000000000255605745705286138830899474586568040712351483236604241557466227163515656298354724794280919526108314625082818080953283248989951951904844594711059536282664'), mpf('0.0'), mpf('0.0000000000000000000000000000000000000000000186846305340121446513815405399538041456397283067693159033235546172160567469557547364240438250079177357516679883737780152770432713380734352858961649329462'), mpf('0.0'), mpf('0.0000000000000000000000000000000000000000000000122925200881658846390668029868117132537103475702429709890286543534316162808919439055421340953999458787839920976143276416296337311434693653196685295611487'), mpf('0.0'), mpf('7.31697624295588371373023987310221027006568307752557796965991330561405731005472851520365124726187254689523339143709978668430579234730319364265983902449337e-51'), mpf('0.0'), mpf('3.95940272887223144682372287505530858769788045320648158531380590130630806821143317922275500392958471152339469233609295816250313438706882772871203410416374e-54'), mpf('0.0'), mpf('1.95622664469971909428049549162811689115507927529964505203251279708809687164596500949740859877943908672104480846644909000123672647582451962881029352972457e-57'), mpf('0.0'), mpf('8.85972212273423502844427305990994968820235179030636346029217752304391699115020384736145198722572050145400728472123682065777502932891539686961183663824675e-61'), mpf('0.0'), mpf('3.6915508844725979285184471082958123700843132459609847751217406346016320796459182697339383280107168756058363686338486752740729288870480820290049319326037e-64'), mpf('0.0'), mpf('1.41982726325869151096863350319069706541704355613884029812374639792370464601766087297459166461950649061762937255148025972079728034117233924192497382023208e-67'), mpf('0.0'), mpf('5.05636489764491278834983441307228299649944286374230875400194586155165472228511706899783356345978094949298209598105505598574530036030035342565873867603942e-71'), mpf('0.0'), mpf('1.67207833916829126598870185617469675810166761367139839748741595950782232879798844874266982918643549917095968782442296824925439826729509041853794268387529e-74'), mpf('0.0'), mpf('5.14802444325212828198491950792702203849035595342179309571248756006102933743223044563629873517991225114211726546928253771322166954216468724919317328779378e-78'), mpf('0.0'), mpf('1.47931736875061157528302284710546610301447010155798652175646194254627279811270989817135021125859547446612565099692026945782231883395536989919344059994099e-81'), mpf('0.0'), mpf('3.97665959341562251420167432017598414788836048805910355310876866275879784438900510261115648187794482383367110483043083187586644847837465026664903387080843e-85'), mpf('0.0'), mpf('1.00218235721159841587743808472177019856057471977295956479555661863880994062222910852095677466682077213550179053186260883968408479797748242607082506824801e-88'), mpf('0.0'), mpf('2.37259080779260988607348031420873626553166363582613533332281396458051595791247421524847721275289008554806295106975049441213088257096941862232676389263327e-92'), mpf('0.0'), mpf('5.2865214077375443094328884006433517502933681725181268567798885128799375176302901409279795293067960907933666467686062709717711287231938917609776379069367e-96'), mpf('0.0'), mpf('1.1106137411213328381161530253452419643473462547306989194915732169915835121072038111193234305266378342002871106656735863386073799838642629749953020812889e-99'), mpf('0.0'), mpf('2.20359869270105721848443060584373405624473463240218039581661352577695141291111867285580045739412268690533156878109838559247496028544496622022877397081146e-103')]\n", "3.27795319155365450882301786771320700150596675703135078794150359633915771477548518124528208276133735129736680957981809606098543787303701e-79*y^33 + 3.90076429794884886549939126257871633179210044086730743765038927964359768058282736568188567848599144804386650339998353431257267106891404e-76*y^32 + 4.37665754229860842709031699661331972427073669465311894504373677176011659761393230429507573126128240470521821681478152549870653693932156e-73*y^31 + 4.62175036466733049900737474842366562882989794955369360596618603097868312708031251333559997221191421936871043695640929092663410300792356e-70*y^30 + 4.58477636174999185501531575043627630379925876595726405711845654273085366206367001322891517243421890561376075346075801659922103018386017e-67*y^29 + 4.26384201642749242516424364790573696253331065234025557312016458473969390571921311230289111036382358222079750071850495543727555807098996e-64*y^28 + 3.70954255429191840989289197367799115740398026753602234861454318872353369797571540770351526601652651653209382562509931123042973552176127e-61*y^27 + 3.01214855408503774883302828262652881981203197723925014707500906924350936275628091105525439600541953142406018640758064071910894524367015e-58*y^26 + 2.27718430688828853811776938166565578777789617479287311118870685634809307824374836875777232338009716575658950092413096438364636260421463e-55*y^25 + 1.59858338343557855375867410592929036302008311470459692405447221315636134092711135486795617101282821036112582964873993699731974654815867e-52*y^24 + 1.03907919923312605994313816885403873596305402455798800063540693855163487160262238066417151115833833673473178927168095904825783525630314e-49*y^23 + 6.23447519539875635965882901312423241577832414734792800381244163130980922961573428398502906695003002040839073563008575428954701153781882e-47*y^22 + 3.44143030786011351053167361524457629350963492933605625810446778048301469474788532475973604495641657126543168606780733636782995036887599e-44*y^21 + 1.74136373577721743632902684931375560451587527424404446660086069692440543554242997432842643874794678506030843315031051220212195488665125e-41*y^20 + 8.04510045929074455584010404382955089286334376700748543569597641979075311220602648139733014701551414697862496115443456637380343157632878e-39*y^19 + 3.37894219290211271345284369840841137500260438214314388299231009631211630712653112218687866174651594173102248368486251787699744126205809e-36*y^18 + 1.28399803330280283111208060539519632250098966521439467553707783659860419670808182643101389146367605785778854380024775679325902767958207e-33*y^17 + 4.39127327389558568240331567045157142295338465503322979033680620116722635274163984639406750880577211787363681979684732823294587466417069e-31*y^16 + 1.34372962181204921881541459515818085542373570444016831584306269755717126393894179299658465769456626806933286685783528243928143764723623e-28*y^15 + 3.65494457132877387517792769883025192675256111607725781909313053735550583791392167695071026892922024914858539785331196823484551040048255e-26*y^14 + 8.77186697118905730042702647719260462420614667858541876582351328965321401099341202468170464543012859795660495484794872376362922496115812e-24*y^13 + 1.84209206394970203308967556021044697108329080250293794082293779082717494230861652518315797554032700557088704051806923199036213724184320e-21*y^12 + 3.35260755638845770022320951958301348737158926055534705229774677930545839500168207583334751548339515013901441374288600222245908978015463e-19*y^11 + 5.23006778796599401234820685054950104029967924646634140158448497571651509620262403830002212415409643421686248543890216346703618005704123e-17*y^10 + 6.90368948011511209629963304272534137319557660533557065009152016794579992698746373055602920388340729316625848077935085577648775767529442e-15*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386e-13*y^8 + 6.83465258531396097533663671229808795946362083928221494359060496626634192771758909325046891184457322023459589597155734721872288009854147e-11*y^7 + 4.92094986142605190224237843285462333081380700428319475938523557571176618795666414714033761652809271856890904509952128999748047367094986e-9*y^6 + 2.75573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192e-7*y^5 + 0.0000115740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740741*y^4 + 0.000347222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*y^3 + 0.00694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*y^2 + 0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333*y\n", "4.3912732738955856824033156704e-31*y^16 + 1.3437296218120492188154145952e-28*y^15 + 3.6549445713287738751779276988e-26*y^14 + 8.7718669711890573004270264772e-24*y^13 + 1.8420920639497020330896755602e-21*y^12 + 3.3526075563884577002232095196e-19*y^11 + 5.2300677879659940123482068506e-17*y^10 + 6.9036894801151120962996330427e-15*y^9 + 7.5940584281266233059295963470e-13*y^8 + 6.8346525853139609753366367123e-11*y^7 + 4.9209498614260519022423784329e-9*y^6 + 2.7557319223985890652557319224e-7*y^5 + 0.000011574074074074074074074074074*y^4 + 0.00034722222222222222222222222222*y^3 + 0.0069444444444444444444444444444*y^2 + 0.083333333333333333333333333333*y\n" ] } ], "source": [ "from sage.all import *\n", "from mpmath import mp, besseli, taylor\n", "\n", "mp.prec = 500\n", "\n", "def refined_approx(x):\n", " if x == 0:\n", " return 0\n", " p1 = besseli(1, x) / x * 2 - mp.mpf(1)\n", " x_over_two = mp.mpf(x) / 2\n", " x_over_two_sqr = x_over_two * x_over_two\n", " p2 = x_over_two_sqr * mp.mpf(0.5)\n", " p1 = p1 - p2\n", " x_over_two_p4 = x_over_two_sqr * x_over_two_sqr\n", " p1 = p1\n", " return p1\n", "\n", "terms = 70\n", "\n", "coeffs = taylor(lambda x: refined_approx(x), mp.mpf('0'), terms)\n", "\n", "print(refined_approx(5))\n", "print(coeffs)\n", "\n", "# Step 3: Build series in terms of y = (x/2)^2\n", "R = PolynomialRing(RealField(450), 'y')\n", "y = R.gen()\n", "f = R(0)\n", "\n", "for n in range(2, terms, 2):\n", " k = n // 2\n", " c = RealField(450)(coeffs[n])\n", " if n >= 1:\n", " f += R(c) * y**(k-1) * (4**k)\n", " else:\n", " f += R(c) * y**(k-1) * (4**k)\n", "\n", "print(f)\n", "\n", "rat_approx = SR(f).power_series(RealField(100)).pade(16, 0)\n", "numer = rat_approx.numerator()\n", "print(numer)" ] }, { "cell_type": "code", "execution_count": 57, "id": "c36e6fb4-f964-4822-b921-228d3f01034e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f64::from_bits(0x3ff0000000000000),\n", "f64::from_bits(0x3fd0000000000000),\n", "f64::from_bits(0x3f9c71c71c71c71c),\n", "f64::from_bits(0x3f5c71c71c71c738),\n", "f64::from_bits(0x3f123456789aba23),\n", "f64::from_bits(0x3ec02e85c089d88b),\n", "f64::from_bits(0x3e6522a43f5a944f),\n", "f64::from_bits(0x3e0522a440661101),\n", "f64::from_bits(0x3da0b31317b0a80b),\n", "f64::from_bits(0x3d35601a20cd3aa3),\n", "f64::from_bits(0x3cc69c8d6cdb26cf),\n", "f64::from_bits(0x3c541ae81d6d4a08),\n", "f64::from_bits(0x3bde57d7c636c9c3),\n", "f64::from_bits(0x3b648e3d1ac6be91),\n", "f64::from_bits(0x3ae0d5f1ec46f644),\n", "f64::from_bits(0x3a7a0c10368f1ea7),\n", "f64::from_bits(0xb9f6879c496e231c),\n" ] } ], "source": [ "values = [\n", "' 1 ',\n", "' 0.25 ',\n", "' 2.777777777777777623580135468728258274495601654052734375e-2 ',\n", "' 1.73611111111111708626975058677999186329543590545654296875e-3 ',\n", "' 6.9444444444434957615201742253674410676467232406139373779296875e-5 ',\n", "' 1.92901234568737175921969949354828344212364754639565944671630859375e-6 ',\n", "' 3.936759888676649827268097590719786449398043259861879050731658935546875e-8 ',\n", "' 6.1511873441828956828506549147955913270369165957163204438984394073486328125e-10 ',\n", "' 7.59405796954071993550940007343340288313571218026254427968524396419525146484375e-12 ',\n", "' 7.5940671293210007585286363412648594930598293373247287263438920490443706512451171875e-14 ',\n", "' 6.275961133446377019580129016152441639440058107450581825759172716061584651470184326171875e-16 ',\n", "' 4.35959955051298758216272254397780728544635283250481549988109009063919074833393096923828125e-18 ',\n", "' 2.57016360879182038857041181827969219806917743324416265253244684441114031869801692664623260498046875e-20 ',\n", "' 1.3602568196404245484903285697695559574915073549807523587646469927225911789037127164192497730255126953125e-22 ',\n", "' 4.3519323177819898788562312469719088894011000991151465841162815470673230766607275654678232967853546142578125e-25 ',\n", "' 5.26017447655109689551220236016711308401702926604489694949032193847215910752213030576740493415854871273040771484375e-27 ',\n", "' -1.777282201721818351530714197390393454320429252790767397879131152377718644796121549855882904012105427682399749755859375e-29 ',\n", "\n", "]\n", "\n", "for i, c in enumerate(values):\n", " c = RealField(1000)(c.replace(\" \", \"\"))\n", " # print_double_double(\"\", c)\n", " # print(RealField(53)(c))\n", " print(\"f64::from_bits(\" + double_to_hex(c) + \"),\")" ] }, { "cell_type": "code", "execution_count": 53, "id": "eaa65b9f-1bb0-4bfd-8e9b-79a507f94a2f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overflow threshold for I1(x) in float32: x ≈ 91.90626485018107\n" ] } ], "source": [ "from sage.all import *\n", "from mpmath import mp, besseli\n", "\n", "# Set precision\n", "mp.dps = 50 # digits of precision\n", "R = RealField(100)\n", "\n", "# Max float32 value\n", "FLT_MAX = R('3.4028235e38')\n", "\n", "# Wrapper: compute I1(x) using mpmath and compare to FLT_MAX\n", "def f(x):\n", " x_mp = mp.mpf(x)\n", " return float(besseli(1, x_mp)) - float(FLT_MAX)\n", "\n", "# Use Sage's root finder\n", "x0 = find_root(f, 80, 100)\n", "print(f\"Overflow threshold for I1(x) in float32: x ≈ {x0}\")\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "6cfa980f-d2f8-403f-bb8c-f321b0bcf58a", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_j0_asympt.ipynb000064400000000000000000000364371046102023000163340ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 4, "id": "c1f20ccd-2146-4bed-8ba3-f521ada8bac5", "metadata": {}, "outputs": [], "source": [ "from mpmath import mp, mpf, findroot, j0, besselj\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "6b1db06a-265c-4a51-a828-dc66f25a797e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -131,\n", " mantissa: 0x85555555_55555555_55555555_55555555_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xd6999999_99999999_99999999_9999999a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -127,\n", " mantissa: 0xd1ac2492_49249249_24924924_92492492_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xbbcd0fc7_1c71c71c_71c71c71_c71c71c7_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -118,\n", " mantissa: 0x85e8fe45_8ba2e8ba_2e8ba2e8_ba2e8ba3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -113,\n", " mantissa: 0x8b5a8f33_63c4ec4e_c4ec4ec4_ec4ec4ec_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -108,\n", " mantissa: 0xc7661d79_9d59b555_55555555_55555555_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -102,\n", " mantissa: 0xbbced715_c2897a28_78787878_78787878_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -96,\n", " mantissa: 0xe14b19b4_aae3f7fe_be1af286_bca1af28_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -89,\n", " mantissa: 0xa7af7341_db2192db_975e0c30_c30c30c3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -82,\n", " mantissa: 0x97a8f676_b349f6fc_5cefd338_590b2164_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -75,\n", " mantissa: 0xa3d299fb_6f304d73_86e15f12_0fd70a3d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -68,\n", " mantissa: 0xd050b737_cbc044ef_e8807e3c_87f43da1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -60,\n", " mantissa: 0x9a02379b_daa7e492_854f42de_6d3dffe6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -52,\n", " mantissa: 0x83011a39_380e467d_de6b70ec_b92ce0cc_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -45,\n", " mantissa: 0xfe16521f_c79e5d9a_a5bed653_e3844e9a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -36,\n", " mantissa: 0x8b54b13d_3fb3e1c4_15dbb880_0bb32218_u128,\n", "},\n" ] } ], "source": [ "def binomial_like(n, m):\n", " prod = QQ(1)\n", " z = QQ(4)*(n**2)\n", " for k in range(1,m + 1):\n", " prod *= (z - (2*k - 1)**2)\n", " return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))\n", "\n", "R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)\n", "x = R.gen()\n", "\n", "def Pn_asymptotic(n, y, terms=10):\n", " # now y = 1/x\n", " return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )\n", "\n", "def Qn_asymptotic(n, y, terms=10):\n", " return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) )\n", "\n", "P = Pn_asymptotic(0, x, 50)\n", "Q = Qn_asymptotic(0, x, 50)\n", "\n", "R_series = (-Q/P)\n", "\n", "# alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series\n", "\n", "arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)])\n", "alpha_series = arctan_series_Z(R_series)\n", "\n", "# see the series\n", "# print(alpha_series)\n", "\n", "for i in range(alpha_series.prec()):\n", " if i > 44:\n", " break\n", " coeff = alpha_series[i]\n", " if coeff != 0:\n", "# print_dyadic256(RealField(300)(f\"{coeff}\"))\n", " # if i < 16:\n", " # print(f\"\\\"{RealField(300)(f\"{coeff}\")}\\\",\")\n", " print_dyadic(RealField(300)(f\"{coeff}\"))\n", " # else:\n", " # print_double_double(\"\", RealField(300)(coeff))" ] }, { "cell_type": "code", "execution_count": 7, "id": "b5856024-bd23-4775-b1ae-03c7887608e2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x - 0.0625000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^2 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^3 + 0.103515625000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^4 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^5 - 0.542846679687500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^6 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^7 + 5.84869956970214843750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^8 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^9 - 106.886793971061706542968750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^10 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^11 + 2968.14293784275650978088378906250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^12 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^13 - 116538.479696836089715361595153808593750000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^14 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^15 + 6.14845146287880064301134552806615829467773437500000000000000000000000000000000000000000000000000000000000000000000000000e6*x^16 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^17 - 4.19670939155785513879322934371884912252426147460937500000000000000000000000000000000000000000000000000000000000000000000e8*x^18 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^19 + 3.59887580121249399187346220685412845341488718986511230468750000000000000000000000000000000000000000000000000000000000000e10*x^20 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^21 - 3.78794715706818013318150480572832350389944622293114662170410156250000000000000000000000000000000000000000000000000000000e12*x^22 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^23 + 4.80133222145893960583907213182121992423034839703177567571401596069335937500000000000000000000000000000000000000000000000e14*x^24 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^25 - 7.21411473132084814094488804183626623044850445509723613213282078504562377929687500000000000000000000000000000000000000000e16*x^26 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^27 + 1.26789483098064112205788267292172242825708185394451010807870261487551033496856689453125000000000000000000000000000000000e19*x^28\n", "beta series\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -131,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -131,\n", " mantissa: 0xd4000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -128,\n", " mantissa: 0x8af80000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -125,\n", " mantissa: 0xbb288c00_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -121,\n", " mantissa: 0xd5c609dc_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -116,\n", " mantissa: 0xb9824979_31000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -111,\n", " mantissa: 0xe39d3d66_b4b78000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -105,\n", " mantissa: 0xbba2c6ec_fe733d8c_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -99,\n", " mantissa: 0xc81d5cd9_3f0c79ba_6b000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -92,\n", " mantissa: 0x86118ddf_c1ffc100_0ee1b000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -86,\n", " mantissa: 0xdc7ccfa9_930b874d_52df3464_00000000_u128,\n", "},\n" ] } ], "source": [ "#generate b series\n", "def binomial_like(n, m):\n", " prod = QQ(1)\n", " z = QQ(4)*(n**2)\n", " for k in range(1,m + 1):\n", " prod *= (z - (2*k - 1)**2)\n", " return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))\n", "\n", "R = LaurentSeriesRing(RealField(400), 'x',default_prec=400)\n", "x = R.gen()\n", "\n", "def Pn_asymptotic(n, y, terms=10):\n", " # now y = 1/x\n", " return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )\n", "\n", "def Qn_asymptotic(n, y, terms=10):\n", " return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) )\n", "\n", "P = Pn_asymptotic(0, x, 50)\n", "Q = Qn_asymptotic(0, x, 50)\n", "\n", "def sqrt_series(s):\n", " val = S.valuation()\n", " lc = S[val] # Leading coefficient\n", " b = lc.sqrt() * x**(val // 2)\n", "\n", " for _ in range(5):\n", " b = (b + S / b) / 2\n", " b = b\n", " return b\n", "\n", "S = (P**2 + Q**2).truncate(50)\n", "\n", "b_series = sqrt_series(S).truncate(30)\n", "#see the series\n", "print(b_series)\n", "\n", "print(\"beta series\")\n", "for i in range(24):\n", " coeff = b_series[i]\n", " if coeff != 0:\n", " # print(f\"{RealField(300)(f\"{coeff}\")},\")\n", " # print(double_to_hex(RealField(300)(f\"{coeff}\")) + \",\")\n", " print_dyadic(RealField(300)(f\"{coeff}\"))\n", " # print_double_double(\"\", RealField(300)(f\"{coeff}\"))\n" ] }, { "cell_type": "code", "execution_count": null, "id": "0a1ea353-7b85-441c-b5d4-055ab84aad0e", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_j0_taylor.ipynb000064400000000000000000004101441046102023000163200ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 10, "id": "e5f80562-8a96-40c7-93ae-0ff3a0bd464a", "metadata": {}, "outputs": [], "source": [ "from mpmath import mp, mpf, findroot, j0, besselj\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")" ] }, { "cell_type": "code", "execution_count": 11, "id": "ba469006-9beb-443a-90bb-950d92ef2bb9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Zero 1: x ≈ 2.4048255576957727686216318793264573074939733531189268383204\n", "Zero 2: x ≈ 5.5200781102863106495966041128130242000048191809601652765466\n", "Zero 3: x ≈ 8.6537279129110122169541987126609444591156073271620997480225\n", "Zero 4: x ≈ 11.791534439014281613743044911925461814515010486679185542023\n", "Zero 5: x ≈ 14.930917708487785947762593997388678583649734231732812761062\n", "Zero 6: x ≈ 18.071063967910922543147882975618174740290230790039575425635\n", "Zero 7: x ≈ 21.211636629879258959078393350526310414504749137725282245072\n", "Zero 8: x ≈ 24.352471530749302737057944763178904145854465408084454673987\n", "Zero 9: x ≈ 27.493479132040254795877288234607417325353844361837018425873\n", "Zero 10: x ≈ 30.634606468431975117549578926854233032528273435206877073822\n", "Zero 11: x ≈ 33.775820213573568684238546346714724828060649562571856542741\n", "Zero 12: x ≈ 36.917098353664043979769493063272951049055170549696852462216\n", "Zero 13: x ≈ 40.058425764628239294799307373994471729106099867476853029585\n", "Zero 14: x ≈ 43.19979171317673035752407272874342161308565625189307087305\n", "Zero 15: x ≈ 46.34118837166181401868578887911285141975841703844258775975\n", "Zero 16: x ≈ 49.482609897397817173602761533178271245864411865293040568226\n", "Zero 17: x ≈ 52.624051841114996029251285380391570725878683733494822765285\n", "Zero 18: x ≈ 55.765510755019979311683492773461830519932369926465930915003\n", "Zero 19: x ≈ 58.906983926080942132834406634615684273400270359548699654425\n", "Zero 20: x ≈ 62.048469190227169882852500264650949022410942834615153620258\n", "Zero 21: x ≈ 65.189964800206860440636033742512319996694053746324918989288\n", "Zero 22: x ≈ 68.331469329856798270992303839984376971638615401481742195298\n", "Zero 23: x ≈ 71.47298160359373282506307385612969707230287462898831589043\n", "Zero 24: x ≈ 74.614500643701837883820540469335554508372667031659638197943\n", "Extrema (peaks/valleys) of J0(x):\n", "nExtrema: 3.8317059702075123156144358863081609582911078521244950401886\n", "nExtrema: 7.0155866698156187535370499814765222133211799657697498562727\n", "nExtrema: 10.173468135062722077185711776775842874118325466668199285671\n", "nExtrema: 13.323691936314223032393684126947876836246966256828906387054\n", "nExtrema: 16.47063005087763281255246047098955460257890840875283477081\n", "nExtrema: 19.615858510468242021125065884137511712322940855970695228805\n", "nExtrema: 22.760084380592771898053005152182260032194822293609582761429\n", "nExtrema: 25.903672087618382625495855445979875220850924725526971473225\n", "nExtrema: 29.046828534916855066647819883531963887188166731590534232106\n", "nExtrema: 32.189679910974403626622984104460371875478032041055034115317\n", "nExtrema: 35.332307550083865102634479022519015000383928144530784171094\n", "nExtrema: 38.47476623477161511205219755771661236717103805681843387566\n", "nExtrema: 41.617094212814450885863516805060288649321765027325910311976\n", "nExtrema: 44.759318997652821732779352713212144805527050106004245235266\n", "nExtrema: 47.901460887185447121274008722507510606090340432217198664216\n", "nExtrema: 51.043535183571509468733034633224064223940401220527595825313\n", "nExtrema: 54.185553641061320532099966214533888722863601345165535245984\n", "nExtrema: 57.327525437901010745090504243750521990195239019055722165916\n", "nExtrema: 60.469457845347491559398749808383148215264825792836696672175\n", "nExtrema: 63.611356698481232631039762417873623076713264180867051323918\n", "nExtrema: 66.753226734098493415305259750042396239171789203090216697113\n", "nExtrema: 69.895071837495773969730536435499809980997967252113712925054\n", "nExtrema: 73.036895225573834826506117569092051498329725501044154535344\n", "Peak or zero 1: x ≈ 2.4048255576957727686216318793264573074939733531189268383204\n", "Peak or zero 2: x ≈ 3.8317059702075123156144358863081609582911078521244950401886\n", "Peak or zero 3: x ≈ 5.5200781102863106495966041128130242000048191809601652765466\n", "Peak or zero 4: x ≈ 7.0155866698156187535370499814765222133211799657697498562727\n", "Peak or zero 5: x ≈ 8.6537279129110122169541987126609444591156073271620997480225\n", "Peak or zero 6: x ≈ 10.173468135062722077185711776775842874118325466668199285671\n", "Peak or zero 7: x ≈ 11.791534439014281613743044911925461814515010486679185542023\n", "Peak or zero 8: x ≈ 13.323691936314223032393684126947876836246966256828906387054\n", "Peak or zero 9: x ≈ 14.930917708487785947762593997388678583649734231732812761062\n", "Peak or zero 10: x ≈ 16.47063005087763281255246047098955460257890840875283477081\n", "Peak or zero 11: x ≈ 18.071063967910922543147882975618174740290230790039575425635\n", "Peak or zero 12: x ≈ 19.615858510468242021125065884137511712322940855970695228805\n", "Peak or zero 13: x ≈ 21.211636629879258959078393350526310414504749137725282245072\n", "Peak or zero 14: x ≈ 22.760084380592771898053005152182260032194822293609582761429\n", "Peak or zero 15: x ≈ 24.352471530749302737057944763178904145854465408084454673987\n", "Peak or zero 16: x ≈ 25.903672087618382625495855445979875220850924725526971473225\n", "Peak or zero 17: x ≈ 27.493479132040254795877288234607417325353844361837018425873\n", "Peak or zero 18: x ≈ 29.046828534916855066647819883531963887188166731590534232106\n", "Peak or zero 19: x ≈ 30.634606468431975117549578926854233032528273435206877073822\n", "Peak or zero 20: x ≈ 32.189679910974403626622984104460371875478032041055034115317\n", "Peak or zero 21: x ≈ 33.775820213573568684238546346714724828060649562571856542741\n", "Peak or zero 22: x ≈ 35.332307550083865102634479022519015000383928144530784171094\n", "Peak or zero 23: x ≈ 36.917098353664043979769493063272951049055170549696852462216\n", "Peak or zero 24: x ≈ 38.47476623477161511205219755771661236717103805681843387566\n", "Peak or zero 25: x ≈ 40.058425764628239294799307373994471729106099867476853029585\n", "Peak or zero 26: x ≈ 41.617094212814450885863516805060288649321765027325910311976\n", "Peak or zero 27: x ≈ 43.19979171317673035752407272874342161308565625189307087305\n", "Peak or zero 28: x ≈ 44.759318997652821732779352713212144805527050106004245235266\n", "Peak or zero 29: x ≈ 46.34118837166181401868578887911285141975841703844258775975\n", "Peak or zero 30: x ≈ 47.901460887185447121274008722507510606090340432217198664216\n", "Peak or zero 31: x ≈ 49.482609897397817173602761533178271245864411865293040568226\n", "Peak or zero 32: x ≈ 51.043535183571509468733034633224064223940401220527595825313\n", "Peak or zero 33: x ≈ 52.624051841114996029251285380391570725878683733494822765285\n", "Peak or zero 34: x ≈ 54.185553641061320532099966214533888722863601345165535245984\n", "Peak or zero 35: x ≈ 55.765510755019979311683492773461830519932369926465930915003\n", "Peak or zero 36: x ≈ 57.327525437901010745090504243750521990195239019055722165916\n", "Peak or zero 37: x ≈ 58.906983926080942132834406634615684273400270359548699654425\n", "Peak or zero 38: x ≈ 60.469457845347491559398749808383148215264825792836696672175\n", "Peak or zero 39: x ≈ 62.048469190227169882852500264650949022410942834615153620258\n", "Peak or zero 40: x ≈ 63.611356698481232631039762417873623076713264180867051323918\n", "Peak or zero 41: x ≈ 65.189964800206860440636033742512319996694053746324918989288\n", "Peak or zero 42: x ≈ 66.753226734098493415305259750042396239171789203090216697113\n", "Peak or zero 43: x ≈ 68.331469329856798270992303839984376971638615401481742195298\n", "Peak or zero 44: x ≈ 69.895071837495773969730536435499809980997967252113712925054\n", "Peak or zero 45: x ≈ 71.47298160359373282506307385612969707230287462898831589043\n", "Peak or zero 46: x ≈ 73.036895225573834826506117569092051498329725501044154535344\n", "Peak or zero 47: x ≈ 74.614500643701837883820540469335554508372667031659638197943\n", "\n" ] } ], "source": [ "# searching for zeros and extremas\n", "R120 = RealField(120)\n", "\n", "zeros = []\n", "\n", "mp.prec = 200\n", "\n", "step = mpf(\"0.01\")\n", "epsilon = mpf(\"1e-35\")\n", "x = mpf(\"0.0\")\n", "\n", "def j0_prime(x):\n", " return diff(lambda t: besselj(0, t), x)\n", "\n", "previous_zero = R120(0)\n", "j0_zeros = []\n", "\n", "while x < mpf(\"76.0\"):\n", " f1 = besselj(0, x)\n", " f2 = besselj(0, x + step)\n", " if f1 * f2 < 0:\n", " zero = findroot(lambda t: j0(t), (x, x + step), solver='bisect', tol=mp.mpf(\"1e-41\"))\n", " previous_zero = zero\n", " j0_zeros.append(zero)\n", " if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon:\n", " zeros.append(previous_zero)\n", " x += step\n", "\n", "j0_extrema = []\n", "\n", "x = mpf(\"0.0\")\n", "while x < mpf(\"76.0\"):\n", " d1 = mp.diff(lambda t: j0(t), x)\n", " d2 = mp.diff(lambda t: j0(t), x + step)\n", " if d1 * d2 < 0:\n", " extremum = findroot(lambda t: mp.diff(lambda u: j0(u), t), (x, x + step), solver='bisect', tol=mp.mpf(\"1e-41\"))\n", " j0_extrema.append(extremum)\n", " x += step\n", "\n", "# Print results\n", "for i, z in enumerate(j0_zeros):\n", " print(f\"Zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"Extrema (peaks/valleys) of J0(x):\")\n", "for e in j0_extrema:\n", " print(f\"nExtrema: {e}\")\n", "\n", "j0_zeros.extend(j0_extrema)\n", "\n", "j0_zeros = sorted(j0_zeros)\n", "\n", "# Print results\n", "for i, z in enumerate(j0_zeros):\n", " print(f\"Peak or zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"\")\n", "\n", "# print(\"pub(crate) static J0_ZEROS: [(u64, u64); 48] = [\")\n", "# print(f\"(0x0, 0x0),\")\n", "# for z in j0_zeros:\n", "# k = split_double_double(z)\n", "# hi = double_to_hex(k[1])\n", "# lo = double_to_hex(k[0])\n", "# print(f\"({lo}, {hi}),\")\n", " \n", "# print(\"];\")\n", "\n", "# print(\"pub(crate) static J0_ZEROS_RATIONAL128: [DyadicFloat128; 48] = [\")\n", "# print(f\"DyadicFloat128 {{ sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0u128, }},\")\n", "# for z in j0_zeros:\n", "# print_dyadic(z)\n", " \n", "# print(\"];\")" ] }, { "cell_type": "code", "execution_count": 7, "id": "29fd1991-208e-4c8a-9d77-d46ae2a12320", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static J0F_COEFFS: [[u64;14]; 47] = [\n", "[\n", "0xbca69de51bcc0120,\n", "0xbfe09cdb3655127d,\n", "0x3fbba1deea029925,\n", "0x3facfae8643687e7,\n", "0xbf81bb1cbe1caeb6,\n", "0xbf61f992590d3f89,\n", "0x3f315382bbf1a06b,\n", "0x3f06ed3ba591e6da,\n", "0xbed232c8d8aba5cc,\n", "0xbea1cceb52db45ee,\n", "0x3e68006b6b5682ca,\n", "0x3e329cc1da0793f0,\n", "0xbdf5dbb0053da32b,\n", "0xbdc04e14e5d96539,\n", "],\n", "[\n", "0xbfd9c6cf582cbf7f,\n", "0x3cb1d608597b5d8f,\n", "0x3fc9c6cf582cbf55,\n", "0xbf91f06d14e12b29,\n", "0xbf8b589d1da0f7e4,\n", "0x3f50f9103d00ae93,\n", "0x3f38644561ce9290,\n", "0xbefa2a034c749192,\n", "0xbed83a0686fd1dd2,\n", "0x3e96a5085d7844b5,\n", "0x3e6ebfcaacd49b87,\n", "0xbe2964b9932b57f3,\n", "0xbdfad73cf4701511,\n", "0x3db5acbea609d3e5,\n", "],\n", "[\n", "0xbc6a1105f9dbcdd5,\n", "0x3fd5c6e60a097826,\n", "0xbf9f8f72e7a8471e,\n", "0xbfab2150cb41ece4,\n", "0x3f72f7ffe901b59c,\n", "0x3f627e31fe9ddafb,\n", "0xbf26f641f369bbbd,\n", "0xbf0863f485fc7e89,\n", "0x3ecad77cbbb32bcd,\n", "0x3ea32e705af41964,\n", "0xbe62d9d2bb447e35,\n", "0xbe341f0e4f4dc44a,\n", "0x3df198b51eee9749,\n", "0x3dbec8f104a030ca,\n", "],\n", "[\n", "0x3fd33518b3874e8a,\n", "0xbca7f56ee546a569,\n", "0xbfc33518b3874e3b,\n", "0x3f7d34125d59fb96,\n", "0x3f880c83bdee71b4,\n", "0xbf4483c20f2abbd1,\n", "0xbf36ffa5fc0ccc0f,\n", "0x3ef2ccf7bbc1d620,\n", "0x3ed796a6caa245fc,\n", "0xbe91e85738cfdd42,\n", "0xbe6e69b581df4be3,\n", "0x3e2550287122730e,\n", "0x3dfab73cc2e87ac7,\n", "0xbdb250809ed630ba,\n", "],\n", "[\n", "0x3c684670459725e1,\n", "0xbfd15f7977a772d5,\n", "0x3f900f7fcf183c65,\n", "0x3fa68b984ec64b1d,\n", "0xbf648e63600c54a1,\n", "0xbf60e0d6038721a4,\n", "0x3f1d7960512fb682,\n", "0x3f07800bc7410c66,\n", "0xbec3324799a7e0fb,\n", "0xbea30e8df2325ca1,\n", "0x3e5cecefe3d75abb,\n", "0x3e3458cbaa06ef8d,\n", "0xbdec4dd6cf551d07,\n", "0xbdbefa0975b65713,\n", "],\n", "[\n", "0xbfcff654544ebcd1,\n", "0x3ca0ffc636e7373a,\n", "0x3fbff654544ebc20,\n", "0xbf70c17ff72b1352,\n", "0xbf84b0c5d5d9e7c9,\n", "0x3f394154be849b76,\n", "0x3f34e12c2fdccc3a,\n", "0xbee9f32fcfbab067,\n", "0xbed63c53e4cc158b,\n", "0x3e8adbb88b7826d7,\n", "0x3e6d5f825ac22ee0,\n", "0xbe20f17a50351084,\n", "0xbdfa326458f60fce,\n", "0x3dae0e0c6fa040ee,\n", "],\n", "[\n", "0xbc648b5c145d146f,\n", "0x3fcdc13e66ac2e78,\n", "0xbf842ff0cdc58194,\n", "0xbfa38d1dd8992ef5,\n", "0x3f5a55e9b344ea02,\n", "0x3f5e2e16f97e7f5f,\n", "0xbf13dfc37714f92e,\n", "0xbf05ce7f4a51d917,\n", "0x3ebbb177bc7895b4,\n", "0x3ea2346df84ab988,\n", "0xbe56125b44798bd5,\n", "0xbe33d7cc75fbdd4e,\n", "0x3de68bc84d67bb0a,\n", "0x3dbe749161c75b7f,\n", "],\n", "[\n", "0x3fcbf3337873a7d8,\n", "0xbc999eb31028b75f,\n", "0xbfbbf3337873a725,\n", "0x3f66604d91f94ba7,\n", "0x3f8251858010ffd8,\n", "0xbf314bc11a41832e,\n", "0xbf32e7decc933381,\n", "0x3ee293b4d39e1d9e,\n", "0x3ed4a66fbc1f8e7c,\n", "0xbe843cb02661be36,\n", "0xbe6bdd61e41af9d3,\n", "0x3e1ab24db7abbdd7,\n", "0x3df940cc3ecafe33,\n", "0xbda870435d8d1863,\n", "],\n", "[\n", "0x3c6110461d393f0c,\n", "0xbfca701d0f967501,\n", "0x3f7c54b930fef3e4,\n", "0x3fa17798aa09f194,\n", "0xbf52a21514062f70,\n", "0xbf5b541f829ca99f,\n", "0x3f0cc0bd9fd11443,\n", "0x3f041f3b06c79efa,\n", "0xbeb4b22fc3292c98,\n", "0xbea1223e5773d27c,\n", "0x3e5118e5cf14a591,\n", "0x3e32ffb6478c2281,\n", "0xbde20a2b34bd7e9f,\n", "0xbdbd77afc051bc6c,\n", "],\n", "[\n", "0xbfc925c6fca08f54,\n", "0x3c941bba0a9908a3,\n", "0x3fb925c6fca08ea3,\n", "0xbf6049377403d97d,\n", "0xbf809463bbcfb70d,\n", "0x3f297b35471ddd4a,\n", "0x3f314dd43fc4bda8,\n", "0xbedbf665e54737fe,\n", "0xbed32caf8123dd12,\n", "0x3e7f510484fa37ba,\n", "0x3e6a42a3b8b1effd,\n", "0xbe1544b8d56d77a8,\n", "0xbdf81cfb72892ddb,\n", "0x3da3f5749b01c5c3,\n", "],\n", "[\n", "0xbc5c64a3611bf4cb,\n", "0x3fc8077f56c9b782,\n", "0xbf75467eb535dac4,\n", "0xbf9fd7c3ad6f5a3e,\n", "0x3f4c1b47c806f9c6,\n", "0x3f59166c7d3ee8f7,\n", "0xbf05f01522f72552,\n", "0xbf02aa939ff2e34a,\n", "0x3eb0129642c0eedc,\n", "0x3ea01716d7274ce0,\n", "0xbe4b21ada69ec1ec,\n", "0xbe320ffbd6f367e8,\n", "0x3ddd441699eaa4df,\n", "0x3dbc46351a30e033,\n", "],\n", "[\n", "0x3fc70c511227d5aa,\n", "0xbc903dd711e6b7a7,\n", "0xbfb70c511227d4fe,\n", "0x3f5910ebe1f1fa45,\n", "0x3f7e7dc08e6ff244,\n", "0xbf23bd7d15b0a88f,\n", "0xbf300357a101d595,\n", "0x3ed5ec733cb20d5b,\n", "0x3ed1e5d1fa4386ae,\n", "0xbe78f423a07fedeb,\n", "0xbe68c089aeb3a360,\n", "0x3e1143a2a87b28be,\n", "0x3df6f2d06548607b,\n", "0xbda07d7d6f49ddb9,\n", "],\n", "[\n", "0x3c57d1baaf487c60,\n", "0xbfc62d93aa9d05bb,\n", "0x3f70ba9ce88926ac,\n", "0x3f9d7073daebb038,\n", "0xbf462813c7f32d76,\n", "0xbf574a948d055ffc,\n", "0x3f01695764ad01fd,\n", "0x3f0170ab5ed77aa3,\n", "0xbea9c8e2cba34328,\n", "0xbe9e4d88f9ebcadb,\n", "0x3e460ec3e9bbfca2,\n", "0x3e312751ad8cf2c9,\n", "0xbdd825b2017389c1,\n", "0xbdbb0b4f2fdaca95,\n", "],\n", "[\n", "0xbfc5664e13b70621,\n", "0x3c8adfee580612ab,\n", "0x3fb5664e13b7057b,\n", "0xbf540ee3940b2f9d,\n", "0xbf7c5e1ad9fa40ad,\n", "0x3f1fb8a98f136a0c,\n", "0x3f2de9be57a255f8,\n", "0xbed1bec95e73b04b,\n", "0xbed0cf25bf302fd8,\n", "0x3e746784408bf531,\n", "0x3e676640f349bd8a,\n", "0xbe0c944164ad511b,\n", "0xbdf5d837e7a07aba,\n", "0x3d9ba3ab0edd6dab,\n", "],\n", "[\n", "0xbc543722dc20f623,\n", "0x3fc4b2a2ebf61ecd,\n", "0xbf6b3297fdae7373,\n", "0xbf9b8105d59b1125,\n", "0x3f420a3f8c10a2c5,\n", "0x3f55d18d69de4109,\n", "0xbefc79db490d157b,\n", "0xbf00679c92947f5d,\n", "0x3ea53ac3d1de0eb7,\n", "0x3e9ca750128116cf,\n", "0xbe4252ac12ff61fa,\n", "0xbe3051067c8a6420,\n", "0x3dd4435be57e146d,\n", "0x3db9dcd0ca8a2a1d,\n", "],\n", "[\n", "0x3fc40f90793605bb,\n", "0xbc86a24c27e99837,\n", "0xbfb40f907936051b,\n", "0x3f5085775a554a25,\n", "0x3f7aa0ce0420ebfd,\n", "0xbf1a32a28e65afde,\n", "0xbf2c26ebc916e22b,\n", "0x3ecd740098d21c07,\n", "0x3ecfc1baf78438dd,\n", "0xbe710c76235f5aa1,\n", "0xbe663455427d9c57,\n", "0x3e08141f4d843200,\n", "0x3df4d5216dec0df1,\n", "0xbd977e29b16d5fdb,\n", "],\n", "[\n", "0x3c5158813dc387f0,\n", "0xbfc37aac8c1aeabb,\n", "0x3f66ac0d2e2f2ac1,\n", "0x3f99e74e754ea6d8,\n", "0xbf3e1c0589dfbd21,\n", "0xbf5496158dc5b2be,\n", "0x3ef7d554035ae72e,\n", "0x3eff0b30f3d1fb7e,\n", "0xbea1d9e26f5a608f,\n", "0xbe9b35eeaebb5fed,\n", "0x3e3f010034c79a0b,\n", "0x3e2f1f31b65b3b40,\n", "0xbdd1445486f07cd4,\n", "0xbdb8c39615e71112,\n", "],\n", "[\n", "0xbfc2f2072e638cf3,\n", "0x3c8361a1f631cd41,\n", "0x3fb2f2072e638c5a,\n", "0xbf4bd42b64fc9353,\n", "0xbf792bb5e1e07ce1,\n", "0x3f161ace339d0b73,\n", "0x3f2aa8d1ce9fa384,\n", "0xbec8ef625b21b762,\n", "0xbece26d28032c92c,\n", "0x3e6d0116b3ae24e4,\n", "0x3e6526a75ee1fb24,\n", "0xbe049a7cd1a8b231,\n", "0xbdf3eac7c4ed94be,\n", "0x3d943b63ca10efa6,\n", "],\n", "[\n", "0xbc4e15276b2257f6,\n", "0x3fc27407dfadee6d,\n", "0xbf6346950bfd8dcc,\n", "0xbf988d48d1d4eb20,\n", "0x3f399e6923aaadf2,\n", "0x3f538984b76c8a40,\n", "0xbef4521949da5854,\n", "0xbefd855d7afc24f7,\n", "0x3e9e8a86b94090aa,\n", "0x3e99f1bce3767a28,\n", "0xbe3aa3a4df470ca3,\n", "0xbe2dc43a0da754d3,\n", "0x3dcdd3f81803822b,\n", "0x3db7c1fb1e948790,\n", "],\n", "[\n", "0x3fc1ff5eec6a01cd,\n", "0xbc80d20b3aa154f7,\n", "0xbfb1ff5eec6a0139,\n", "0x3f47daf64983dfb0,\n", "0x3f77ed5fffc0f26a,\n", "0xbf12f9479636506c,\n", "0xbf296027e938174a,\n", "0x3ec57486d36f86d5,\n", "0x3eccc1196ea00471,\n", "0xbe690ae6942f1564,\n", "0xbe64382bea1931c6,\n", "0x3e01ddd9b1b7300f,\n", "0x3df317ad2d0ae68b,\n", "0xbd91a1072249bec4,\n", "],\n", "[\n", "0x3c4a5ad4fde0c9d8,\n", "0xbfc192f23ce3e050,\n", "0x3f60a668185bfe0f,\n", "0x3f9764141d652022,\n", "0xbf3624437a2d49f0,\n", "0xbf52a184be0d3982,\n", "0x3ef196de0d85b64c,\n", "0x3efc317f84a19048,\n", "0xbe9a80187c3c9493,\n", "0xbe98d3840a83aa5f,\n", "0x3e3730c02a4a94ac,\n", "0x3e2c8d1491c62663,\n", "0xbdca1189016a9692,\n", "0xbdb6d754fe28a395,\n", "],\n", "[\n", "0xbfc12dd57bf18ad9,\n", "0x3c7d8e82da6b051b,\n", "0x3fb12dd57bf18a4a,\n", "0xbf44bebeff7ba93d,\n", "0xbf76d9afe882346d,\n", "0x3f10842d50795e09,\n", "0x3f2841d86abe55fe,\n", "0xbec2b5cab87b5693,\n", "0xbecb86b9f14c3df8,\n", "0x3e65e518bb040851,\n", "0x3e63642ad66ee13c,\n", "0xbdff581d7497507c,\n", "0xbdf2596d87b9a5f8,\n", "0x3d8f0ac4f8bd7787,\n", "],\n", "[\n", "0xbc47483488f843f0,\n", "0x3fc0cf3ed059c573,\n", "0xbf5d242aa5298caf,\n", "0xbf96613d93b0179b,\n", "0x3f33627f261d008d,\n", "0x3f51d69ca0d81e39,\n", "0xbeeed574ad2bb0d3,\n", "0xbefb06384da1c6bc,\n", "0x3e97452b1c4c76e9,\n", "0x3e97d51e823013c9,\n", "0xbe346a18e9324483,\n", "0xbe2b754cf5bbe0eb,\n", "0x3dc70467e00ca1a0,\n", "0x3db601d42e3f412d,\n", "],\n", "[\n", "0x3fc076826cc2c191,\n", "0xbc7a319136b9885b,\n", "0xbfb076826cc2c107,\n", "0x3f4241b03eab1b46,\n", "0x3f75e7f530011e0e,\n", "0xbf0d17978e4af2b0,\n", "0xbf2745b0deaaa29c,\n", "0x3ec0803f899002ed,\n", "0x3eca70060b7e6d91,\n", "0xbe635913c3c95352,\n", "0xbe62a694daaaf841,\n", "0x3dfbc4a0d8050004,\n", "0x3df1ad85820a38f2,\n", "0xbd8b942dd09eb308,\n", "],\n", "[\n", "0x3c44bc1f080e9694,\n", "0xbfc0230b9797a7b2,\n", "0x3f59c8083b2b6f7f,\n", "0x3f957d3203befd1b,\n", "0xbf3127cba226824c,\n", "0xbf5123447144f140,\n", "0x3eeb4fe26c88e56e,\n", "0x3ef9fc5254458847,\n", "0xbe94a44b3f692077,\n", "0xbe96f17d3ebae645,\n", "0x3e3224c9056773e9,\n", "0x3e2a78ba4580cd4b,\n", "0xbdc481589f7c80a5,\n", "0xbdb53f51ba6e502a,\n", "],\n", "[\n", "0xbfbfa8b41711c839,\n", "0x3c776c1e8f7fbdf3,\n", "0x3fafa8b41711c72d,\n", "0xbf403a8d0f113157,\n", "0xbf7511c6dad9e9ce,\n", "0x3f09e040fc7d8bd2,\n", "0x3f266582f59eaade,\n", "0xbebd62a1a025f4b0,\n", "0xbec976fa2e25f4ab,\n", "0x3e61411e4c00a8c3,\n", "0x3e61fc07a47b587f,\n", "0xbdf8d00a9e1b01e2,\n", "0xbdf1119f53145e82,\n", "0x3d88b3165222eaa1,\n", "],\n", "[\n", "0xbc429a344bf53c30,\n", "0x3fbf13faf32c8e0a,\n", "0xbf570558dddb7821,\n", "0xbf94b24d7a9338fa,\n", "0x3f2ea52a2144c44d,\n", "0x3f50834d8f3f71fa,\n", "0xbee86941a2b2f276,\n", "0xbef90e32ce46341a,\n", "0x3e92785e5b786d2a,\n", "0x3e9624822c6837c1,\n", "0xbe304286df6c8e25,\n", "0xbe2993b44677fad8,\n", "0x3dc2692b9cb4de6f,\n", "0x3db48dab755272e9,\n", "],\n", "[\n", "0x3fbe8727daa3daec,\n", "0xbc75105fe04e17a2,\n", "0xbfae8727daa3d9e9,\n", "0x3f3d19c52e0749cd,\n", "0x3f74524d481311c0,\n", "0xbf0735f790cd464b,\n", "0xbf259c8f9e41a823,\n", "0x3eba61a00c8699ad,\n", "0x3ec896d70eee04c2,\n", "0xbe5f04fa0ee2b2df,\n", "0xbe6161b9029aa2c1,\n", "0x3df656dc5e9fcd6d,\n", "0x3df083ab26947d7d,\n", "0xbd8646da85095b0a,\n", "],\n", "[\n", "0x3c40c6e5f0cb085b,\n", "0xbfbe018d99f5da1b,\n", "0x3f54b85897b35dc0,\n", "0x3f93fc44215342e3,\n", "0xbf2b9694d7112c4c,\n", "0xbf4fe6fdc6440535,\n", "0x3ee5fd096c74d7eb,\n", "0x3ef83770c8f9fca0,\n", "0xbe90a6f608ea2259,\n", "0xbe956ad410ba57f4,\n", "0x3e2d5aedc8414c7c,\n", "0x3e28c319213f9f62,\n", "0xbdc0a501a42574f9,\n", "0xbdb3eaef334996a5,\n", "],\n", "[\n", "0xbfbd8293aa55d18f,\n", "0x3c731f5b2ff0d80c,\n", "0x3fad8293aa55d093,\n", "0xbf3a48fe4aff1369,\n", "0xbf73a5ccbc11f183,\n", "0x3f04f91e4204c18c,\n", "0x3f24e72224187971,\n", "0xbeb7dac82ed8c06b,\n", "0xbec7cbd3d4a2512f,\n", "0x3e5c13a012cfa9d9,\n", "0x3e60d55d3c7a1e36,\n", "0xbdf43f07dbc0afd9,\n", "0xbdf001e1c5b3f199,\n", "0x3d8438754303f506,\n", "],\n", "[\n", "0xbc3e721cd5615376,\n", "0x3fbd09b210b30217,\n", "0xbf52c74f6d11fe58,\n", "0xbf9357bfc2be57e6,\n", "0x3f2901e4c492a05d,\n", "0x3f4ee2a36979201d,\n", "0xbee3f0cb91fe387d,\n", "0xbef7748920d95467,\n", "0x3e8e399ed3001c0e,\n", "0x3e94c1b715414ff1,\n", "0xbe2aab03479a9f97,\n", "0xbe2804415514f135,\n", "0x3dbe479692aefaf1,\n", "0x3db3555d82fea6b2,\n", "],\n", "[\n", "0x3fbc96700bf039e1,\n", "0xbc71712327ccc0e1,\n", "0xbfac96700bf038ec,\n", "0x3f37e5647d31307c,\n", "0x3f73095734a194a7,\n", "0xbf0312a4db676954,\n", "0xbf24424a9628de60,\n", "0x3eb5b4a67102dd95,\n", "0x3ec712e41250bc42,\n", "0xbe59918677637160,\n", "0xbe60550f5e9164bb,\n", "0x3df2750c65ef60c0,\n", "0x3def157ced5a6a13,\n", "0xbd8274ea409a4ed7,\n", "],\n", "[\n", "0x3c3bc4a30293d67b,\n", "0xbfbc28612a3bc18a,\n", "0x3f511f52577ff2df,\n", "0x3f92c21da135f4f3,\n", "0xbf26ce18f81fd4cd,\n", "0xbf4df586d8b6aeb3,\n", "0x3ee230fedd1a2b84,\n", "0x3ef6c2a754e321b0,\n", "0xbe8b973110796ae8,\n", "0xbe9426ec6d82a4f4,\n", "0x3e285d2ec3ed03c3,\n", "0x3e2754eefd1cc277,\n", "0xbdbbb13bcfd1095a,\n", "0xbdb2cb6d2f5a71d0,\n", "],\n", "[\n", "0xbfbbbf246914235e,\n", "0x3c6ff848b8004f4e,\n", "0x3fabbf2469142270,\n", "0xbf35d923e8472f22,\n", "0xbf727a96f1740b8b,\n", "0x3f01715e4bcd425f,\n", "0x3f23abacda98c7ab,\n", "0xbeb3dc30debc954f,\n", "0xbec6698cb2175b00,\n", "0x3e57691976ae1f76,\n", "0x3e5fbe7a90c59bea,\n", "0xbdf0ea1d3534d622,\n", "0xbdee39eb617c4576,\n", "0x3d80ee68d9ec5553,\n", "],\n", "[\n", "0xbc396e9c97e8f53c,\n", "0x3fbb5a6219b35e14,\n", "0xbf4f645fdb1a8578,\n", "0xbf923940d01de870,\n", "0x3f24e86a1e60f65a,\n", "0x3f4d1c6a18c716ef,\n", "0xbee0aeec5fff60bb,\n", "0xbef61f7d2f793aca,\n", "0x3e8950f6140dd479,\n", "0x3e939898b4cca68e,\n", "0xbe265f0fa2e22f9c,\n", "0xbe26b33d2f34a7ca,\n", "0x3db9731a4bc752ba,\n", "0x3db24bcd6b2996ce,\n", "],\n", "[\n", "0x3fbaf9cb49c4f934,\n", "0xbc6d6d35ce7e44b9,\n", "0xbfaaf9cb49c4f84c,\n", "0x3f3413b75ce0f622,\n", "0x3f71f7a8fec644b8,\n", "0xbf000844274ab940,\n", "0xbf23215daac1a429,\n", "0x3eb242e9f204ac2f,\n", "0x3ec5cdc3d7570c8d,\n", "0xbe5589d6656d4bd3,\n", "0xbe5ee52f2093b13f,\n", "0x3def25a4c863585f,\n", "0x3ded6edb90588bb5,\n", "0xbd7f34526b242536,\n", "],\n", "[\n", "0x3c37650e44849b1d,\n", "0xbfba9d1835947d6f,\n", "0x3f4cea253049a1d9,\n", "0x3f91bb71f665dc68,\n", "0xbf23427f47955327,\n", "0xbf4c54a7bd6e5c2f,\n", "0x3edebe9e62f23b54,\n", "0x3ef58924f95f83e9,\n", "0xbe875643b068495f,\n", "0xbe93152fe242208c,\n", "0x3e24a270e811a32a,\n", "0x3e261d90f63d69a9,\n", "0xbdb77dbf375b3033,\n", "0xbdb1d55983193fd8,\n", "],\n", "[\n", "0xbfba4407e04298d1,\n", "0x3c6b2fc36b7bca2c,\n", "0x3faa4407e04297ee,\n", "0xbf3288694b34d1f5,\n", "0xbf717f0266da7e64,\n", "0x3efd9a9a1d244e54,\n", "0x3f22a1c915f39e35,\n", "0xbeb0dd9e9cd3be0d,\n", "0xbec53dd8bf4c31dc,\n", "0x3e53e6ebf97ad18c,\n", "0x3e5e1c0952edd05e,\n", "0xbdeccc874da25bb3,\n", "0xbdecb26ccd2d18eb,\n", "0x3d7cdf4dbb3c6f9d,\n", "],\n", "[\n", "0xbc359685a4f3dcbc,\n", "0x3fb9ee5ee937fc88,\n", "0xbf4abf28ad5bf0d6,\n", "0xbf9147481084ad98,\n", "0x3f21d137345ad0c1,\n", "0x3f4b9c10ddf55248,\n", "0xbedc72c9d23eafc6,\n", "0xbef4fe0b3595e36e,\n", "0x3e859a1afaceaec9,\n", "0x3e929b65a8c65855,\n", "0xbe231c3162eaeee6,\n", "0xbe25928cb280552e,\n", "0x3db5c4ff841acff7,\n", "0x3db167146fe195c5,\n", "],\n", "[\n", "0x3fb99be744018c90,\n", "0xbc694d1606868f19,\n", "0xbfa99be744018bb2,\n", "0x3f312d4e1c1cc8e5,\n", "0x3f710f5ca51ef993,\n", "0xbefb714174938907,\n", "0xbf222b9fa834b14b,\n", "0x3eaf47107520863c,\n", "0x3ec4b861783e33d4,\n", "0xbe5276456457a7e2,\n", "0xbe5d612d705e69ee,\n", "0x3deabad16a1c7f4d,\n", "0x3dec0302ce313ca1,\n", "0xbd7ad13436da91d1,\n", "],\n", "[\n", "0x3c33fe4be92d3d54,\n", "0xbfb94c6f54aef04b,\n", "0x3f48d6371f01895c,\n", "0x3f90db975fd7dbd2,\n", "0xbf208bd163414db7,\n", "0xbf4af0d3d4cc449e,\n", "0x3eda6c8e7a6a50d9,\n", "0x3ef47cddcd0777cf,\n", "0xbe8412382d315a8f,\n", "0xbe922a214336182c,\n", "0x3e21c37df131e495,\n", "0x3e25110597bc5108,\n", "0xbdb43f276f813535,\n", "0xbdb10022868bfde2,\n", "],\n", "[\n", "0xbfb8ffc9bd24fe07,\n", "0x3c67889977473d30,\n", "0x3fa8ffc9bd24fd2f,\n", "0xbf2ff51b38ef3764,\n", "0xbf70a7a725d36032,\n", "0x3ef988128742f09f,\n", "0x3f21bdc845f948f5,\n", "0xbead1b60b68e1dce,\n", "0xbec43c2ce2f40a20,\n", "0x3e512fdc8d93240a,\n", "0x3e5cb30713086e1b,\n", "0xbde8e53a40557273,\n", "0xbdeb5f3c07e7903e,\n", "0x3d78fd3f37268235,\n", "],\n", "[\n", "0xbc3292fab12602d5,\n", "0x3fb8b5ccad12d631,\n", "0xbf4724d018597ba3,\n", "0xbf907764ae2b1e77,\n", "0x3f1ed6acc18c1a89,\n", "0x3f4a51693df22314,\n", "0xbed8a0ec5fd8948c,\n", "0xbef4047f31589663,\n", "0x3e82b667a039f6a4,\n", "0x3e91c073e21e1306,\n", "0xbe209143960c8785,\n", "0xbe2497fb13bc2530,\n", "0x3db2e4699f6adc63,\n", "0x3db09fc4db2b9fa9,\n", "],\n", "[\n", "0x3fb86e51be0a9153,\n", "0xbc65fa6f95d443a0,\n", "0xbfa86e51be0a907f,\n", "0x3f2dd3c244b5713f,\n", "0x3f7046fc5a20f248,\n", "0xbef7d51accd8d1f8,\n", "0xbf2157556b6a5aec,\n", "0x3eab2d01d207a4bc,\n", "0x3ec3c837e1b45aa2,\n", "0xbe500d3d097d314b,\n", "0xbe5c103c5b331300,\n", "0x3de742b129024e6b,\n", "0x3deac5e6c8a70206,\n", "0xbd775bdd14ccde28,\n", "],\n", "[\n", "0x3c314cbdbd279267,\n", "0xbfb829356999a096,\n", "0x3f45a280e033e683,\n", "0x3f9019dba8336dd6,\n", "0xbf1cd4559d92616b,\n", "0xbf49bc85774f69b2,\n", "0x3ed70706561ca508,\n", "0x3ef393fc6c586d81,\n", "0xbe818009f70f6704,\n", "0xbe915d911e7ad3a2,\n", "0x3e1eff8fd0ef6949,\n", "0x3e24268fd4573ff9,\n", "0xbdb1ae6de683a236,\n", "0xbdb0455820923c5a,\n", "],\n", "[\n", "0xbfb7e656efb009ad,\n", "0x3c649ee393402ee6,\n", "0x3fa7e656efb008de,\n", "0xbf2bec6b33f0062e,\n", "0xbf6fd932c269835b,\n", "0x3ef6504d7e1cd7db,\n", "0x3f20f77ce56ff037,\n", "0xbea972e583ac028d,\n", "0xbec35ba4e79f8507,\n", "0x3e4e1250b982c251,\n", "0x3e5b77a3c340d6b3,\n", "0xbde5cbcf474ee83d,\n", "0xbdea35fa30652af1,\n", "0x3d75e5f83583c368,\n", "],\n", "[\n", "0xbc375f30b05ffab2,\n", "0x3fb7a597e9550932,\n", "0xbf44486c0b011f0f,\n", "0xbf8f848eec0e0c40,\n", "0x3f1b077fae02763b,\n", "0x3f49310d6e6682f5,\n", "0xbed597a5bccfeb73,\n", "0xbef32a855d113180,\n", "0x3e8069b8fa206f26,\n", "0x3e9100c89784eeac,\n", "0xbe1d14a175c009c5,\n", "0xbe23bbc9bff27ef1,\n", "0x3db0950fae2cbe6f,\n", "0x3dafc6492b94025c,\n", "],\n", "];\n" ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = (zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(j0_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 500;\n", "bessel_j0 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_j0(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RR(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "degree = 13\n", "\n", "print(f\"pub(crate) static J0F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print(\"[\")\n", " for c in coeffs:\n", " print(double_to_hex(c) + \",\")\n", " print(\"],\")\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 13, "id": "443d542b-4733-4993-a432-470be6506fef", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) const J0_MACLAURIN_SERIES: [u64; 9] = [\n", "0x3ff0000000000000,\n", "0xbfd0000000000000,\n", "0x3f90000000000000,\n", "0xbf3c71c71c71c71c,\n", "0x3edc71c71c71c71c,\n", "0xbe723456789abcdf,\n", "0x3e002e85c0898b71,\n", "0xbd8522a43f65486a,\n", "0x3d0522a43f65486a,\n", "];\n", "poly [mpf('1.0'), mpf('0.0'), mpf('-0.25'), mpf('0.0'), mpf('0.015625'), mpf('0.0'), mpf('-0.00043402777777777777782'), mpf('0.0'), mpf('6.7816840277777777785e-6'), mpf('0.0'), mpf('-6.7816840277777777822e-8'), mpf('0.0'), mpf('4.7095027970679012323e-10'), mpf('0.0'), mpf('-2.4028075495244394055e-12'), mpf('0.0'), mpf('9.3859669903298414278e-15'), mpf('0.0'), mpf('-2.8969033920771115517e-17')]\n" ] } ], "source": [ "# Maclaurin series for j0 \n", "def print_expansion_at_0_f():\n", " print(f\"pub(crate) const J0_MACLAURIN_SERIES: [u64; 9] = [\")\n", " from mpmath import mp, j0, taylor\n", " mp.prec = 60\n", " poly = taylor(lambda val: j0(val), 0, 18)\n", " z = 0\n", " for i in range(0, 18, 2):\n", " print(f\"{double_to_hex(poly[i])},\")\n", " print(\"];\")\n", "\n", " print(f\"poly {poly}\")\n", "\n", "print_expansion_at_0_f()" ] }, { "cell_type": "code", "execution_count": 16, "id": "5a9c22ba-b1b7-4f86-ba13-fb32dca636af", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static J0F_COEFFS: [[u64; 15]; 47] = [\n", "[\n", "0x0000000000000000,\n", "0xbfe09cdb36551280,\n", "0x3fbba1deea029494,\n", "0x3facfae864368d70,\n", "0xbf81bb1cbe1a4071,\n", "0xbf61f992590d12bd,\n", "0x3f315382ba06cc47,\n", "0x3f06ed3b9f07eb28,\n", "0xbed232c77d228ab6,\n", "0xbea1cce302821846,\n", "0x3e67ff99166c20b8,\n", "0x3e32951bd4726a93,\n", "0xbdf5c2c38b2a278c,\n", "0xbdbbdc468c1a817a,\n", "0x3d7cd41cf248a22e,\n", "],\n", "[\n", "0xbfd9c6cf582cbf7f,\n", "0x0000000000000000,\n", "0x3fc9c6cf582cbf7f,\n", "0xbf91f06d14e11e02,\n", "0xbf8b589d1da13905,\n", "0x3f50f9103cf5b152,\n", "0x3f386445621cc085,\n", "0xbefa2a033ccf2705,\n", "0xbed83a06e30c4109,\n", "0x3e96a4fd997104b3,\n", "0x3e6ec03c7b7d1357,\n", "0xbe295db03343bc40,\n", "0xbdfb1e242e3fafb5,\n", "0x3db3fa9bccb27cd1,\n", "0x3d8195cae4f67f9d,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fd5c6e60a097823,\n", "0xbf9f8f72e7a848e0,\n", "0xbfab2150cb41e8c1,\n", "0x3f72f7ffe90256bb,\n", "0x3f627e31fe9a9779,\n", "0xbf26f641f41956f7,\n", "0xbf0863f481a43036,\n", "0x3ecad77d748a06db,\n", "0x3ea32e6d99c6af7d,\n", "0xbe62da37e38435b9,\n", "0xbe341d72d9392e0e,\n", "0x3df1d0433d9a0e49,\n", "0x3dbe2f3389aa5f69,\n", "0xbd78498ffdebdd63,\n", "],\n", "[\n", "0x3fd33518b3874e8a,\n", "0x0000000000000000,\n", "0xbfc33518b3874e8a,\n", "0x3f7d34125d59d8ff,\n", "0x3f880c83bdeee5b0,\n", "0xbf4483c20f1cb1cf,\n", "0xbf36ffa5fc8cad74,\n", "0x3ef2ccf7b21fff81,\n", "0x3ed796a751f89051,\n", "0xbe91e850e4c28d2e,\n", "0xbe6e6a49ae425df4,\n", "0x3e254c4387ef6820,\n", "0x3dfb084d1fe8eb88,\n", "0xbdb177e06f2957d2,\n", "0xbd8198853f2794c4,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfd15f7977a772d4,\n", "0x3f900f7fcf183e0d,\n", "0x3fa68b984ec6493c,\n", "0xbf648e63600d8418,\n", "0xbf60e0d60385a6f0,\n", "0x3f1d796052775aab,\n", "0x3f07800bc550673c,\n", "0xbec3324842f7d51c,\n", "0xbea30e8cc35f2086,\n", "0x3e5ceda479a13c54,\n", "0x3e34582cb217a0ff,\n", "0xbdecade19f5ddb10,\n", "0xbdbedafbed1c0039,\n", "0x3d743c230e74f083,\n", "],\n", "[\n", "0xbfcff654544ebcd1,\n", "0x0000000000000000,\n", "0x3fbff654544ebcd1,\n", "0xbf70c17ff72afae7,\n", "0xbf84b0c5d5da6789,\n", "0x3f394154be70ed46,\n", "0x3f34e12c3067bef4,\n", "0xbee9f32fc25ad134,\n", "0xbed63c5475439cb2,\n", "0x3e8adbafdf1415b1,\n", "0x3e6d601d278516f5,\n", "0xbe20eedcab593552,\n", "0xbdfa84fedb589fe9,\n", "0x3dacf8e343fe2283,\n", "0x3d81702cfaaee589,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fcdc13e66ac2e77,\n", "0xbf842ff0cdc58463,\n", "0xbfa38d1dd8992e04,\n", "0x3f5a55e9b346edc1,\n", "0x3f5e2e16f97d0a81,\n", "0xbf13dfc3782af205,\n", "0xbf05ce7f496656d0,\n", "0x3ebbb178da9c4ac0,\n", "0x3ea2346d74940be8,\n", "0xbe5612f2e799b732,\n", "0xbe33d79882e5df9f,\n", "0x3de6dbc112bdb279,\n", "0x3dbe88c4d898d665,\n", "0xbd70ad880fc1e195,\n", "],\n", "[\n", "0x3fcbf3337873a7d8,\n", "0x0000000000000000,\n", "0xbfbbf3337873a7d8,\n", "0x3f66604d91f926ee,\n", "0x3f8251858011816b,\n", "0xbf314bc11a32c246,\n", "0xbf32e7decd1f73a5,\n", "0x3ee293b4c9a24966,\n", "0x3ed4a6704d05ad0b,\n", "0xbe843ca9b71b6996,\n", "0xbe6bddfbf35630ba,\n", "0x3e1aae76737061da,\n", "0x3df992424643ff64,\n", "0xbda7aad4b0989ad6,\n", "0xbd81051e84a7a86a,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfca701d0f967500,\n", "0x3f7c54b930fef892,\n", "0x3fa17798aa09f11f,\n", "0xbf52a2151407dd09,\n", "0xbf5b541f829bfb41,\n", "0x3f0cc0bda19ffe34,\n", "0x3f041f3b0662f49e,\n", "0xbeb4b230b114b149,\n", "0xbea1223e2bd0689f,\n", "0x3e511963968a437f,\n", "0x3e32ffb8dedaa0e5,\n", "0xbde24c47f1c46f88,\n", "0xbdbda527540ac89a,\n", "0x3d6b75eeb2587be0,\n", "],\n", "[\n", "0xbfc925c6fca08f55,\n", "0x0000000000000000,\n", "0x3fb925c6fca08f55,\n", "0xbf6049377403bcb4,\n", "0xbf809463bbd0367f,\n", "0x3f297b354706c53c,\n", "0x3f314dd4404e5fcc,\n", "0xbedbf665d5afcb1e,\n", "0xbed32cb00ee8c1f3,\n", "0x3e7f50fa815b542a,\n", "0x3e6a4339e5f906ee,\n", "0xbe1541c07333f998,\n", "0xbdf86c0bb112e485,\n", "0x3da35fba37d1f6f7,\n", "0x3d80700770cc15dd,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc8077f56c9b782,\n", "0xbf75467eb535deaa,\n", "0xbf9fd7c3ad6f59e0,\n", "0x3f4c1b47c809c5eb,\n", "0x3f59166c7d3eaa7c,\n", "0xbf05f0152478f5f6,\n", "0xbf02aa939fd9fc9b,\n", "0x3eb0129708ec2410,\n", "0x3ea01716dc9f2e1b,\n", "0xbe4b227eef409a9c,\n", "0xbe32101c49d611c3,\n", "0x3dddb1e8b7adba5e,\n", "0x3dbc80aab1d9322c,\n", "0xbd66c2b17ab71886,\n", "],\n", "[\n", "0x3fc70c511227d5aa,\n", "0x0000000000000000,\n", "0xbfb70c511227d5aa,\n", "0x3f5910ebe1f1cbcd,\n", "0x3f7e7dc08e70e99a,\n", "0xbf23bd7d159e09a5,\n", "0xbf300357a187375c,\n", "0x3ed5ec73302455b1,\n", "0x3ed1e5d2836c8d99,\n", "0xbe78f41b94dfba1f,\n", "0xbe68c11aada79ae8,\n", "0x3e1141423452a28d,\n", "0x3df73ef6f4772772,\n", "0xbda007403efd2c9a,\n", "0xbd7f93ab6667901d,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc62d93aa9d05bb,\n", "0x3f70ba9ce88929f2,\n", "0x3f9d7073daebb02c,\n", "0xbf462813c7f58733,\n", "0xbf574a948d05638e,\n", "0x3f01695765f13bbf,\n", "0x3f0170ab5eeb0e4e,\n", "0xbea9c8e418a20315,\n", "0xbe9e4d893dce335e,\n", "0x3e460f73a6ccb16f,\n", "0x3e312782f0f2448a,\n", "0xbdd881d5842ec670,\n", "0xbdbb4c521a316133,\n", "0x3d63132da6b9ef80,\n", "],\n", "[\n", "0xbfc5664e13b70622,\n", "0x0000000000000000,\n", "0x3fb5664e13b70622,\n", "0xbf540ee3940b092f,\n", "0xbf7c5e1ad9fb2f40,\n", "0x3f1fb8a98ef4a243,\n", "0x3f2de9be58a373e2,\n", "0xbed1bec95415e630,\n", "0xbed0cf264341409e,\n", "0x3e74677d9e214cd4,\n", "0x3e6766cc63507104,\n", "0xbe0c905882b94f65,\n", "0xbdf62157963573dc,\n", "0x3d9ae2e0cbb67b06,\n", "0x3d7e456a1c8dbf40,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc4b2a2ebf61ece,\n", "0xbf6b3297fdae7902,\n", "0xbf9b8105d59b114c,\n", "0x3f420a3f8c12a1ff,\n", "0x3f55d18d69de6cfb,\n", "0xbefc79db4b341e8e,\n", "0xbf00679c92c303b2,\n", "0x3ea53ac4ecd4be2d,\n", "0x3e9ca7507840c04b,\n", "0xbe4253415f09767a,\n", "0xbe305141505c9f00,\n", "0x3dd4919940f05339,\n", "0x3dba20de95780e25,\n", "0xbd602fff3daabeb6,\n", "],\n", "[\n", "0x3fc40f90793605bb,\n", "0x0000000000000000,\n", "0xbfb40f90793605bb,\n", "0x3f5085775a5529c9,\n", "0x3f7aa0ce0421d1a8,\n", "0xbf1a32a28e4bc82e,\n", "0xbf2c26ebca0e46de,\n", "0x3ecd7400876206d0,\n", "0x3ecfc1bbf57e3ae2,\n", "0xbe710c7090487d3e,\n", "0xbe6634db39e4a305,\n", "0x3e0810d7e4efab49,\n", "0x3df51b513b3c4cf1,\n", "0xbd96dd877beb3775,\n", "0xbd7d06057acf98a1,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc37aac8c1aeabb,\n", "0x3f66ac0d2e2f2f87,\n", "0x3f99e74e754ea71f,\n", "0xbf3e1c0589e32bb1,\n", "0xbf5496158dc5f7ff,\n", "0x3ef7d55405348ca9,\n", "0x3eff0b30f4506228,\n", "0xbea1d9e3629b98ec,\n", "0xbe9b35ef28e9de24,\n", "0x3e3f0200e2650870,\n", "0x3e2f1fb225e849cb,\n", "0xbdd187928a64d042,\n", "0xbdb908ba84482af1,\n", "0x3d5bd0a97427e582,\n", "],\n", "[\n", "0xbfc2f2072e638cf4,\n", "0x0000000000000000,\n", "0x3fb2f2072e638cf4,\n", "0xbf4bd42b64fc5bed,\n", "0xbf792bb5e1e159fc,\n", "0x3f161ace3386dfd7,\n", "0x3f2aa8d1cf8db852,\n", "0xbec8ef624c36fc32,\n", "0xbece26d3747fe829,\n", "0x3e6d010d2bdb6fa2,\n", "0x3e65272828ae4057,\n", "0xbe0497b03c4482e4,\n", "0xbdf42e35495a0b9f,\n", "0x3d93b2e62efa9ef3,\n", "0x3d7bdc7867dae011,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc27407dfadee6d,\n", "0xbf6346950bfd91f1,\n", "0xbf988d48d1d4eb7b,\n", "0x3f399e6923ada922,\n", "0x3f538984b76cdf4a,\n", "0xbef452194b75f3c7,\n", "0xbefd855d7b8f0243,\n", "0x3e9e8a88601ff296,\n", "0x3e99f1bd69b16e6b,\n", "0xbe3aa483fce054e3,\n", "0xbe2dc4c02391c504,\n", "0x3dce48dc1b4db792,\n", "0x3db807112e6636fd,\n", "0xbd582c0e5f51b3f0,\n", "],\n", "[\n", "0x3fc1ff5eec6a01cd,\n", "0x0000000000000000,\n", "0xbfb1ff5eec6a01cd,\n", "0x3f47daf64983af9d,\n", "0x3f77ed5fffc1c774,\n", "0xbf12f947962314a1,\n", "0xbf296027ea1d6e5c,\n", "0x3ec57486c67fbc78,\n", "0x3eccc11a59e13739,\n", "0xbe690ade515567ae,\n", "0xbe6438a7e22c9734,\n", "0x3e01db6d29a7d048,\n", "0x3df3588cd299009a,\n", "0xbd912b3d3f46a11d,\n", "0xbd7aca95934e0ad6,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc192f23ce3e051,\n", "0x3f60a668185c01b1,\n", "0x3f9764141d652089,\n", "0xbf3624437a2fe76a,\n", "0xbf52a184be0d9891,\n", "0x3ef196de0eeef190,\n", "0x3efc317f854112ad,\n", "0xbe9a8019ef772196,\n", "0xbe98d38497beea33,\n", "0x3e37318410813eeb,\n", "0x3e2c8d9d45d76323,\n", "0xbdca782c1acc5d80,\n", "0xbdb71bbb74f830ea,\n", "0x3d5539502b6b0d41,\n", "],\n", "[\n", "0xbfc12dd57bf18ada,\n", "0x0000000000000000,\n", "0x3fb12dd57bf18ada,\n", "0xbf44bebeff7b7f02,\n", "0xbf76d9afe88301fa,\n", "0x3f10842d50687949,\n", "0x3f2841d86b9b92f4,\n", "0xbec2b5caad1f2b9a,\n", "0xbecb86bad42fc220,\n", "0x3e65e5117a965bcf,\n", "0x3e6364a25cc7309d,\n", "0xbdff53dcc9459e76,\n", "0xbdf297f421bb27bc,\n", "0x3d8e3c9c7289c65b,\n", "0x3d79cfbae2bdc016,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc0cf3ed059c573,\n", "0xbf5d242aa529931c,\n", "0xbf96613d93b0180b,\n", "0x3f33627f261f5116,\n", "0x3f51d69ca0d88394,\n", "0xbeeed574afab70fd,\n", "0xbefb06384e48ee5b,\n", "0x3e97452c65235728,\n", "0x3e97d51f133b6843,\n", "0xbe346ac67a7e0c7c,\n", "0xbe2b75d66a8d7fbb,\n", "0x3dc75f5a5db478ef,\n", "0x3db64531ca4ef464,\n", "0xbd52ceac14a86c69,\n", "],\n", "[\n", "0x3fc076826cc2c191,\n", "0x0000000000000000,\n", "0xbfb076826cc2c191,\n", "0x3f4241b03eaaf5d9,\n", "0x3f75e7f53001e4b1,\n", "0xbf0d17978e2d0336,\n", "0xbf2745b0df80666a,\n", "0x3ec0803f7f7fe323,\n", "0x3eca7006e6ad9cfe,\n", "0xbe63590d57d48525,\n", "0xbe62a7084b42b890,\n", "0x3dfbc0dd5a22c9a6,\n", "0x3df1e9e4e20477cd,\n", "0xbd8ade1de2460eb2,\n", "0xbd78ea3bc5e51ddd,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc0230b9797a7b3,\n", "0x3f59c8083b2b753a,\n", "0x3f957d3203befd90,\n", "0xbf3127cba22892de,\n", "0xbf51234471455a6c,\n", "0x3eeb4fe26ec3e489,\n", "0x3ef9fc5254f1086c,\n", "0xbe94a44c6506c43f,\n", "0xbe96f17dd184ad59,\n", "0x3e3225640a6a9328,\n", "0x3e2a7943505d15ed,\n", "0xbdc4d296ecea7b61,\n", "0xbdb58177059b1ee7,\n", "0x3d50cd71be5428ab,\n", "],\n", "[\n", "0xbfbfa8b41711c83a,\n", "0x0000000000000000,\n", "0x3fafa8b41711c83a,\n", "0xbf403a8d0f110fe1,\n", "0xbf7511c6dadaaa12,\n", "0x3f09e040fc62c87e,\n", "0x3f266582f66d8d4c,\n", "0xbebd62a18e287536,\n", "0xbec976fb023f0f79,\n", "0x3e6141188eda6cd5,\n", "0x3e61fc77546c2a70,\n", "0xbdf8ccadf7842b28,\n", "0xbdf14c0515097baa,\n", "0x3d8810b7fe5b7aae,\n", "0x3d78181478442ce9,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fbf13faf32c8e0a,\n", "0xbf570558dddb7d46,\n", "0xbf94b24d7a933972,\n", "0x3f2ea52a21487a11,\n", "0x3f50834d8f3fdd5b,\n", "0xbee86941a4b43bea,\n", "0xbef90e32cef3e900,\n", "0x3e92785f6385b273,\n", "0x3e962482bf9d2bb8,\n", "0xbe3043125386ac84,\n", "0xbe29943c303e31c2,\n", "0x3dc2b2457a1921b4,\n", "0x3db4ce82afcbf544,\n", "0xbd4e3dcde42d462d,\n", "],\n", "[\n", "0x3fbe8727daa3daed,\n", "0x0000000000000000,\n", "0xbfae8727daa3daed,\n", "0x3f3d19c52e070d9f,\n", "0x3f74524d4813cc25,\n", "0xbf0735f790b535f3,\n", "0xbf259c8f9f0a3484,\n", "0x3eba619ffc5a3ad0,\n", "0x3ec896d7dc819faf,\n", "0xbe5f04efbdfeacf4,\n", "0xbe6162253f3024f4,\n", "0x3df653d736c3ef75,\n", "0x3df0bc406f716b40,\n", "0xbd85b5420be0cc44,\n", "0xbd77573e801c99fe,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfbe018d99f5da1b,\n", "0x3f54b85897b36265,\n", "0x3f93fc442153435d,\n", "0xbf2b9694d71486e3,\n", "0xbf4fe6fdc644ddde,\n", "0x3ee5fd096e4523fb,\n", "0x3ef83770c9a84498,\n", "0xbe90a6f6f7e05f1b,\n", "0xbe956ad4a35eb0ad,\n", "0x3e2d5bea474ca54f,\n", "0x3e28c39f68d21b3c,\n", "0xbdc0e73408ce7d88,\n", "0xbdb42a6dedaa1a20,\n", "0x3d4b640f953cb953,\n", "],\n", "[\n", "0xbfbd8293aa55d18f,\n", "0x0000000000000000,\n", "0x3fad8293aa55d18f,\n", "0xbf3a48fe4afedcc8,\n", "0xbf73a5ccbc12a67b,\n", "0x3f04f91e41eee9bc,\n", "0x3f24e72224db2c0e,\n", "0xbeb7dac8202ad4fb,\n", "0xbec7cbd49c315be0,\n", "0x3e5c1396b62b0f84,\n", "0x3e60d5c64a9c427f,\n", "0xbdf43c4a5d5a74a1,\n", "0xbdf038cb3f5e324b,\n", "0x3d83b473da8d9c7c,\n", "0x3d76a5d59f9a81dd,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fbd09b210b30217,\n", "0xbf52c74f6d120291,\n", "0xbf9357bfc2be5860,\n", "0x3f2901e4c495acea,\n", "0x3f4ee2a36979f905,\n", "0xbee3f0cb93a497a4,\n", "0xbef7748921871bcc,\n", "0x3e8e39a085fc522a,\n", "0x3e94c1b7a6b2509f,\n", "0xbe2aabe92ddd7d73,\n", "0xbe2804c5ad3234f3,\n", "0x3dbec02b4af63bb7,\n", "0x3db3938387c8ea5e,\n", "0xbd48f3df4c861285,\n", "],\n", "[\n", "0x3fbc96700bf039e2,\n", "0x0000000000000000,\n", "0xbfac96700bf039e2,\n", "0x3f37e5647d30fea8,\n", "0x3f73095734a24496,\n", "0xbf0312a4db537d5b,\n", "0xbf24424a96e62373,\n", "0x3eb5b4a6639fb7be,\n", "0x3ec712e4d44c4a74,\n", "0xbe59917dedf003d7,\n", "0xbe6055757b098917,\n", "0x3df2728cdc02e18c,\n", "0x3def80393fe2fc80,\n", "0xbd81fcaa37a8b374,\n", "0xbd760225681cd60a,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfbc28612a3bc18b,\n", "0x3f511f52577ff6ba,\n", "0x3f92c21da135f56c,\n", "0xbf26ce18f8229e00,\n", "0xbf4df586d8b786e1,\n", "0x3ee230fede9c5ad4,\n", "0x3ef6c2a7558fc928,\n", "0xbe8b97329e667f58,\n", "0xbe9426ecfd66cd08,\n", "0x3e285e012a388a8c,\n", "0x3e27557143798fcd,\n", "0xbdbc1f9f6fa068be,\n", "0xbdb30842b25be60a,\n", "0x3d46d9757263a003,\n", "],\n", "[\n", "0xbfbbbf246914235f,\n", "0x0000000000000000,\n", "0x3fabbf246914235f,\n", "0xbf35d923e8470178,\n", "0xbf727a96f174b6d1,\n", "0x3f01715e4bbb00e7,\n", "0x3f23abacdb5106b5,\n", "0xbeb3dc30d27849d7,\n", "0xbec6698d6ee99eb9,\n", "0x3e576911a4642dff,\n", "0x3e5fbf415682210b,\n", "0xbdf0e7d3674631fb,\n", "0xbdeea1cbf2d9d28f,\n", "0x3d80805ad6510626,\n", "0x3d756aaba545a661,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fbb5a6219b35e14,\n", "0xbf4f645fdb1a8c89,\n", "0xbf923940d01de8e9,\n", "0x3f24e86a1e6384ff,\n", "0x3f4d1c6a18c7ed95,\n", "0xbee0aeec61621923,\n", "0xbef61f7d30244338,\n", "0x3e8950f781c1c41c,\n", "0x3e93989942e07175,\n", "0xbe265fd114ee2251,\n", "0xbe26b3bd4dfd4b81,\n", "0x3db9d8a1bbe00799,\n", "0x3db2875c16e44880,\n", "0xbd4505775bc7f118,\n", "],\n", "[\n", "0x3fbaf9cb49c4f935,\n", "0x0000000000000000,\n", "0xbfaaf9cb49c4f935,\n", "0x3f3413b75ce0cc1b,\n", "0x3f71f7a8fec6eba8,\n", "0xbf0008442739ebfc,\n", "0xbf23215dab7537c6,\n", "0x3eb242e9e6bab199,\n", "0x3ec5cdc48f5d75eb,\n", "0xbe5589cf32f43f3a,\n", "0xbe5ee5f0d63c1125,\n", "0x3def216eedb0f95e,\n", "0x3dedd414a7d8c980,\n", "0xbd7e69fdff844763,\n", "0xbd74de15be6889e6,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfba9d1835947d70,\n", "0x3f4cea253049a85b,\n", "0x3f91bb71f665dcdf,\n", "0xbf23427f4797ae90,\n", "0xbf4c54a7bd6f30c1,\n", "0x3edebe9e65809919,\n", "0x3ef58924fa089950,\n", "0xbe87564501e7bcdc,\n", "0xbe9315306e5bb42b,\n", "0x3e24a32382dea2a5,\n", "0x3e261e0ee5367a22,\n", "0xbdb7db8537582634,\n", "0xbdb20facb4a9bb8b,\n", "0x3d436bd6f0001ffb,\n", "],\n", "[\n", "0xbfba4407e04298d1,\n", "0x0000000000000000,\n", "0x3faa4407e04298d1,\n", "0xbf3288694b34ab21,\n", "0xbf717f0266db2149,\n", "0x3efd9a9a1d05433b,\n", "0x3f22a1c916a2d5a1,\n", "0xbeb0dd9e92661e07,\n", "0xbec53dd972d8f232,\n", "0x3e53e6e553aac740,\n", "0x3e5e1cc65033998a,\n", "0xbdecc8a3f36b4e82,\n", "0xbded152ceac3373c,\n", "0x3d7c249e1f309fe3,\n", "0x3d745b3c1804be30,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fb9ee5ee937fc89,\n", "0xbf4abf28ad5bf6da,\n", "0xbf9147481084ae0f,\n", "0x3f21d137345cfee5,\n", "0x3f4b9c10ddf62464,\n", "0xbedc72c9d49c6d7a,\n", "0xbef4fe0b363ccc66,\n", "0x3e859a1c336b7506,\n", "0x3e929b6632cc324d,\n", "0xbe231cd6e7991df9,\n", "0xbe25930872001f69,\n", "0x3db61befbaafa006,\n", "0x3db1a038446ec46c,\n", "0xbd42030319ffc086,\n", "],\n", "[\n", "0x3fb99be744018c90,\n", "0x0000000000000000,\n", "0xbfa99be744018c90,\n", "0x3f312d4e1c1ca4c3,\n", "0x3f710f5ca51f98b0,\n", "0xbefb71417476a570,\n", "0xbf222b9fa8dfd762,\n", "0x3eaf471061b7dd7e,\n", "0x3ec4b862279de756,\n", "0xbe52763f34a53566,\n", "0xbe5d61e605e8e69a,\n", "0x3deab7331a682502,\n", "0x3dec637428f3fda4,\n", "0xbd7a236ad0b3eb49,\n", "0xbd73e11cef6eae93,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfb94c6f54aef04b,\n", "0x3f48d6371f018ef0,\n", "0x3f90db975fd7dc47,\n", "0xbf208bd1634353c9,\n", "0xbf4af0d3d4cd140d,\n", "0x3eda6c8e7c9d023e,\n", "0x3ef47cddcdac15d7,\n", "0xbe8412394fc50e0a,\n", "0xbe922a21cb1edfe9,\n", "0x3e21c417dedcf50f,\n", "0x3e25117f3061daaa,\n", "0xbdb49009a6c8ef27,\n", "0xbdb13823dda87c57,\n", "0x3d40c350b60502a2,\n", "],\n", "[\n", "0xbfb8ffc9bd24fe08,\n", "0x0000000000000000,\n", "0x3fa8ffc9bd24fe08,\n", "0xbf2ff51b38eef42c,\n", "0xbf70a7a725d3fbc4,\n", "0x3ef988128728122a,\n", "0x3f21bdc846a09e43,\n", "0xbead1b60a4812ac4,\n", "0xbec43c2d8e698c10,\n", "0x3e512fd6ccdafecc,\n", "0x3e5cb3bb8802e835,\n", "0xbde8e1dd09a92324,\n", "0xbdebbd84404b6237,\n", "0x3d785bcfd7db3db0,\n", "0x3d736ed760739d88,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fb8b5ccad12d632,\n", "0xbf4724d0185980d2,\n", "0xbf907764ae2b1eeb,\n", "0x3f1ed6acc18fdf29,\n", "0x3f4a51693df2efbb,\n", "0xbed8a0ec61e4df7b,\n", "0xbef4047f31fae045,\n", "0x3e82b668af276950,\n", "0x3e91c07467ed6403,\n", "0xbe2091d32eea7f0f,\n", "0xbe24987294de7d1e,\n", "0x3db32fe6ab220655,\n", "0x3db0d6b127f8ac22,\n", "0xbd3f4d16b8cb00ea,\n", "],\n", "[\n", "0x3fb86e51be0a9153,\n", "0x0000000000000000,\n", "0xbfa86e51be0a9153,\n", "0x3f2dd3c244b53279,\n", "0x3f7046fc5a218a86,\n", "0xbef7d51accbfba76,\n", "0xbf2157556c0e1b1a,\n", "0x3eab2d01c12c8227,\n", "0x3ec3c838897d0a1e,\n", "0xbe500d37aa536a8b,\n", "0xbe5c10ecf088eac6,\n", "0x3de73f8d1af57f4c,\n", "0x3deb2227fe94022c,\n", "0xbd76c5390bcf017b,\n", "0xbd7303a6ded9ee03,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfb829356999a097,\n", "0x3f45a280e033eb59,\n", "0x3f9019dba8336e48,\n", "0xbf1cd4559d95e619,\n", "0xbf49bc857750335e,\n", "0x3ed70706580693f9,\n", "0x3ef393fc6cf8481f,\n", "0xbe81800af4665cb3,\n", "0xbe915d91a2289a30,\n", "0x3e1f009c83572407,\n", "0x3e2427054565b344,\n", "0xbdb1f5167f464cc6,\n", "0xbdb07b3a2cb21729,\n", "0x3d3d4f453474d39c,\n", "],\n", "[\n", "0xbfb7e656efb009ae,\n", "0x0000000000000000,\n", "0x3fa7e656efb009ae,\n", "0xbf2bec6b33efcb49,\n", "0xbf6fd932c26aad94,\n", "0x3ef6504d7e054d50,\n", "0x3f20f77ce6105150,\n", "0xbea972e573db9593,\n", "0xbec35ba58bf2f993,\n", "0x3e4e1246a53112c6,\n", "0x3e5b7850b3bc8175,\n", "0xbde5c8dcec477a4e,\n", "0xbdea905348b4924d,\n", "0x3d7558a1f12cdd3f,\n", "0x3d729edf3b2865f3,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fb7a597e9550934,\n", "0xbf44486c0b012534,\n", "0xbf8f848eec0e0e6b,\n", "0x3f1b077fae06adc6,\n", "0x3f49310d6e6842c6,\n", "0xbed597a5befbd70e,\n", "0xbef32a855e4e113b,\n", "0x3e8069ba0b1a612d,\n", "0x3e9100c97ba8e22d,\n", "0xbe1d15b5350404fa,\n", "0xbe23bc775cca4413,\n", "0x3db0da51f94c98f0,\n", "0x3db0252dc33a4d7a,\n", "0xbd3b84d751a36bd2,\n", "],\n", "];\n" ] } ], "source": [ "# Taylor series for f32\n", "mp.prec = 60\n", "print(f\"pub(crate) static J0F_COEFFS: [[u64; 15]; {len(j0_zeros)}] = [\")\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffsf(poly):\n", " print(\"[\")\n", " for i in range(0, 15):\n", " coeff = poly[i]\n", " print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(j0_zeros)):\n", " k_range = j0_zeros[i]\n", " range_diff = k_range - prev_zero\n", " g_c = 1\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, j0, taylor\n", " poly = taylor(lambda val: j0(val), x0, 15)\n", " # print(poly)\n", " print_taylor_coeffsf(poly)\n", " prev_zero = j0_zeros[i]\n", "\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 14, "id": "26ad8aaa-176f-4c8c-956f-f300611f6fae", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static J0_COEFFS: [[(u64, u64); 24]; 47] = [\n", "[\n", "(0xb5be985fa7f83cc3, 0xb91cba5b78f9bcd0),\n", "(0xbc8ac8cc3d6bafa4, 0xbfe09cdb36551280),\n", "(0xbc5b50b1160e9078, 0x3fbba1deea029494),\n", "(0x3c4bc98bcfdc7a7f, 0x3facfae864368d70),\n", "(0xbc1a87a5518aec0c, 0xbf81bb1cbe1a4071),\n", "(0x3bcf770ef9886bfc, 0xbf61f992590d12bd),\n", "(0x3ba05114c54b25ab, 0x3f315382ba06cc47),\n", "(0x3ba2b401cd6c68ec, 0x3f06ed3b9f07eb28),\n", "(0xbb46fe17c9b10921, 0xbed232c77d228ab6),\n", "(0x3b479fbd07230860, 0xbea1cce302821846),\n", "(0x3ac3ee3080fdf4d2, 0x3e67ff99166c20b8),\n", "(0x3ad99d2c20223b95, 0x3e32951bd4726a93),\n", "(0xba982691b667ba5c, 0xbdf5c2c38b2a278c),\n", "(0x3a44e89952bc724c, 0xbdbbdc468c1a817a),\n", "(0x3a0ebde93f245a29, 0x3d7cd41cf248a22e),\n", "(0x39aeeb56633d8ce6, 0x3d3f70b0201c12a4),\n", "(0xb98e8ed54af59db8, 0xbcfd22d8ef70f1aa),\n", "(0x394a95ebfce4a435, 0xbcbbaa352d8622af),\n", "(0xb91ff1b0b50e7818, 0x3c773612afd5db30),\n", "(0xb8dd29c3a1d1250e, 0x3c3382933550f440),\n", "(0xb8840afcc88fadb8, 0xbbede7dcd5e6dab6),\n", "(0x384023453882217b, 0xbba68bbe41057f40),\n", "(0x37e0c3131ee8f030, 0x3b5fce24eb23551c),\n", "(0x379a6895f9086a05, 0x3b15bc1becd9a431),\n", "],\n", "[\n", "(0x3c62de1143765a96, 0xbfd9c6cf582cbf7f),\n", "(0xb56eab9a5fff323e, 0x38d9a91f973ec303),\n", "(0xbc52de1143765a96, 0x3fc9c6cf582cbf7f),\n", "(0xbc3b84c5dde43674, 0xbf91f06d14e11e02),\n", "(0x3c27767d9698b536, 0xbf8b589d1da13905),\n", "(0x3beae1afe6c3eeda, 0x3f50f9103cf5b152),\n", "(0x3bd3e8ae8dea10a7, 0x3f386445621cc085),\n", "(0x3b8a8905b308cb21, 0xbefa2a033ccf2705),\n", "(0xbb6859e8c0ae37ce, 0xbed83a06e30c4109),\n", "(0xbb3d54a069e9c64a, 0x3e96a4fd997104b3),\n", "(0x3af989d32babfca4, 0x3e6ec03c7b7d1357),\n", "(0xbab1ecf377bfa04f, 0xbe295db03343bc40),\n", "(0xba90b0b6e5fe7551, 0xbdfb1e242e3fafb5),\n", "(0x3a3fd469738e9f05, 0x3db3fa9bccb27cd1),\n", "(0xba1b0f91d98a1070, 0x3d8195cae4f67f9d),\n", "(0xb9ba66f04112da4a, 0xbd3762afe2a5cc10),\n", "(0xb99f157bfc6eaf25, 0xbd017a40c9422e17),\n", "(0x39512dfe72026e3a, 0x3cb52a10c3c6a274),\n", "(0x390b50bb7a057314, 0x3c7b78e32c0ddf7a),\n", "(0x38b2f2ab795ef554, 0xbc2e86449ded35db),\n", "(0x3886128863c137b0, 0xbbf180413173c4a1),\n", "(0x3830411cc8598621, 0x3ba1f599693c21d5),\n", "(0x38061e9b17fc3c4e, 0x3b62704bba47e657),\n", "(0x37ba5ced95be86b1, 0xbb119329ee1d3fb9),\n", "],\n", "[\n", "(0xb5bc6f55d4dac0c2, 0xb916caed64280f3e),\n", "(0xbc6af17f78e58353, 0x3fd5c6e60a097823),\n", "(0xbc22c1940b65933b, 0xbf9f8f72e7a848e0),\n", "(0x3c39226a6968a5d4, 0xbfab2150cb41e8c1),\n", "(0xbc0ead94b776cda6, 0x3f72f7ffe90256bb),\n", "(0xbbdc44bdbe1112fc, 0x3f627e31fe9a9779),\n", "(0xbbc64599a8123499, 0xbf26f641f41956f7),\n", "(0xbb948616b6922642, 0xbf0863f481a43036),\n", "(0x3b680f8935f5af0c, 0x3ecad77d748a06db),\n", "(0x3b3cc25f06059d1b, 0x3ea32e6d99c6af7d),\n", "(0xbac3305a73e5ec68, 0xbe62da37e38435b9),\n", "(0xbad5c613351595f6, 0xbe341d72d9392e0e),\n", "(0xba9c8106c7bc6fb7, 0x3df1d0433d9a0e49),\n", "(0x3a54e8ace2031b36, 0x3dbe2f3389aa5f69),\n", "(0x3a1a0f5d1cba1387, 0xbd78498ffdebdd63),\n", "(0x39c72f8fafe52f38, 0xbd410477aeae347a),\n", "(0x398287fc3bba485f, 0x3cf911a8d781ae91),\n", "(0x395788d424859469, 0x3cbde68af47fa3dd),\n", "(0xb914472b326b8d7e, 0xbc744b3881dbc1de),\n", "(0x38d8ef43414cc878, 0xbc350be81f6c25f7),\n", "(0x388738457ea68eb1, 0x3bea7a3cd386daef),\n", "(0x381867e5c9a67b59, 0x3ba845cae670510a),\n", "(0xb7fd1902fcb38c68, 0xbb5c71de4246f315),\n", "(0xb7bbe92f443184c2, 0xbb175a569f596544),\n", "],\n", "[\n", "(0x3c7af22d033ee0a4, 0x3fd33518b3874e8a),\n", "(0xb5a1c201a4cbcd4f, 0x390f8a0b194e92aa),\n", "(0xbc6af22d033ee0a5, 0xbfc33518b3874e8a),\n", "(0xbc006437c8a4bc6d, 0x3f7d34125d59d8ff),\n", "(0x3c276d8715df682d, 0x3f880c83bdeee5b0),\n", "(0x3be68431910b0ef3, 0xbf4483c20f1cb1cf),\n", "(0xbbb05a9f39ef055c, 0xbf36ffa5fc8cad74),\n", "(0x3b913c3053e04d46, 0x3ef2ccf7b21fff81),\n", "(0x3b34763d026d3263, 0x3ed796a751f89051),\n", "(0x3b28d27038a5d6ff, 0xbe91e850e4c28d2e),\n", "(0xbb0dacba8ae06269, 0xbe6e6a49ae425df4),\n", "(0x3abf3eddd6df5c90, 0x3e254c4387ef6820),\n", "(0xba918835ce9eaca7, 0x3dfb084d1fe8eb88),\n", "(0x3a5d71d0cc12f311, 0xbdb177e06f2957d2),\n", "(0x3a128331bef5dabb, 0xbd8198853f2794c4),\n", "(0xb9d9afdf19b00f9a, 0x3d350c2b4db26303),\n", "(0x399d5420c79c50f5, 0x3d0183edbb8ef55e),\n", "(0x3950904a54f66bdd, 0xbcb376d167cfd12b),\n", "(0x3900fa2cc4b5e6f2, 0xbc7b8a653f1cd809),\n", "(0x38c18dc8b4e37444, 0x3c2c8b097fe47227),\n", "(0x38721faa0c98eabc, 0x3bf189c13e615d1f),\n", "(0x384e91176ed97cac, 0xbba1041440ddec2d),\n", "(0x380179051848c349, 0xbb6276b7a23c8925),\n", "(0x37b217667c662a42, 0x3b10d45d32f264a5),\n", "],\n", "[\n", "(0xb5a271a164439dcf, 0x39091ad14f5534e3),\n", "(0x3c70b85158068ef8, 0xbfd15f7977a772d4),\n", "(0x3c1371b46642ace0, 0x3f900f7fcf183e0d),\n", "(0xbc44d97f9ccedb81, 0x3fa68b984ec6493c),\n", "(0x3c042ebf64ab2f7d, 0xbf648e63600d8418),\n", "(0xbbeee6fe26323549, 0xbf60e0d60385a6f0),\n", "(0x3baeef0ba4a3d132, 0x3f1d796052775aab),\n", "(0xbba7aac08a2ef0bb, 0x3f07800bc550673c),\n", "(0xbb5a88016ef7845c, 0xbec3324842f7d51c),\n", "(0xbb4a5fc6166e08e4, 0xbea30e8cc35f2086),\n", "(0x3ae456e8b4cd8ab1, 0x3e5ceda479a13c54),\n", "(0xbad32f77090cf486, 0x3e34582cb217a0ff),\n", "(0xba896f49e7d71906, 0xbdecade19f5ddb10),\n", "(0x3a21bb7dfbc8d1d7, 0xbdbedafbed1c0039),\n", "(0x3a0e246bb345d838, 0x3d743c230e74f083),\n", "(0xb9ef2b99a0d63f0b, 0x3d41820d4a50e7ac),\n", "(0x39930eba3f48ee4f, 0xbcf56d4abfa3f75e),\n", "(0xb9404cba8724060b, 0xbcbee1c963b55043),\n", "(0x38e5999953118f29, 0x3c71b059736ac012),\n", "(0xb8670d7b409cc9b1, 0x3c35c975cfa56031),\n", "(0x38874e8a77d0b989, 0xbbe76ff93efd4a1a),\n", "(0xb846172c476991f2, 0xbba9288634dcae38),\n", "(0xb7c3ad53cba7bf5d, 0x3b597e272f8ae371),\n", "(0xb793a523f540949e, 0x3b183832a1cf9585),\n", "],\n", "[\n", "(0xbc5052a3a2541c57, 0xbfcff654544ebcd1),\n", "(0xb59d2cb904ed26e5, 0xb8f8cdeedd7089d9),\n", "(0x3c4052a3a2541c57, 0x3fbff654544ebcd1),\n", "(0xbc1261ff874d8f29, 0xbf70c17ff72afae7),\n", "(0x3c123a275590a85f, 0xbf84b0c5d5da6789),\n", "(0xbbda98843bd20bfa, 0x3f394154be70ed46),\n", "(0x3bd7d4055bf0fe2a, 0x3f34e12c3067bef4),\n", "(0x3b83b9ba50d44e92, 0xbee9f32fc25ad134),\n", "(0x3b7dd3415a058d7b, 0xbed63c5475439cb2),\n", "(0xbb2e30b182db0623, 0x3e8adbafdf1415b1),\n", "(0xbb03faa98b08aa74, 0x3e6d601d278516f5),\n", "(0xba8bdda43ca62c5a, 0xbe20eedcab593552),\n", "(0x3a9e2fad33581bf9, 0xbdfa84fedb589fe9),\n", "(0xba43dc502b3bc37b, 0x3dacf8e343fe2283),\n", "(0x3a20042e6b66d5ce, 0x3d81702cfaaee589),\n", "(0x399e7a30f53ca26c, 0xbd320271d8cd44dc),\n", "(0x39a5f9316e1c5efa, 0xbd01797e5eacddfb),\n", "(0xb9547c274818e871, 0x3cb10ed3b5c9be93),\n", "(0x390484c268c0ce85, 0x3c7b98f45921983a),\n", "(0x38c24e5982383c83, 0xbc297cbf7079afbf),\n", "(0x389b277576e91bd0, 0xbbf1a00382f67f4b),\n", "(0xb81f48467ddb418e, 0x3b9ed8b7eb419122),\n", "(0x37fcd9d0b0e535bf, 0x3b629700d2c00fd9),\n", "(0x379a08401f2ad096, 0xbb0ee1e52f6de1ed),\n", "],\n", "[\n", "(0x35857c582b5ea1c9, 0x390bee0ed8c1329b),\n", "(0xbc56d72d40e790b3, 0x3fcdc13e66ac2e77),\n", "(0xbc17a0058564dc78, 0xbf842ff0cdc58463),\n", "(0xbc4ea7eea5885b06, 0xbfa38d1dd8992e04),\n", "(0xbbe0000f328100a7, 0x3f5a55e9b346edc1),\n", "(0xbbf1ad5da35cf264, 0x3f5e2e16f97d0a81),\n", "(0x3bba0bf2d8b00c54, 0xbf13dfc3782af205),\n", "(0x3baf5778b0601b70, 0xbf05ce7f496656d0),\n", "(0x3b554dd7e814f538, 0x3ebbb178da9c4ac0),\n", "(0x3b4faa40f4ef4735, 0x3ea2346d74940be8),\n", "(0x3afda3f1a9c16a33, 0xbe5612f2e799b732),\n", "(0x3ab1ff4f9f08910e, 0xbe33d79882e5df9f),\n", "(0xba8b82d54967fe42, 0x3de6dbc112bdb279),\n", "(0x3a54c5a3f521e570, 0x3dbe88c4d898d665),\n", "(0x3a0aab5610ed8408, 0xbd70ad880fc1e195),\n", "(0x39ecb4a2ad16ceb5, 0xbd4180d64e2c4131),\n", "(0xb99c77042f820598, 0x3cf22094137f7e15),\n", "(0xb94dafad35b07003, 0x3cbf18a8509fa48c),\n", "(0x390d0551dfd7b655, 0xbc6e8dc12bc24aba),\n", "(0x38c7f144bd8a3779, 0xbc360ce090718b01),\n", "(0x3887e3ff32f169c4, 0x3be4947b20d26a23),\n", "(0x384fdb50bbf01aa8, 0x3ba98e129bc0f8a1),\n", "(0xb7f91bc574623289, 0xbb56b091d8385139),\n", "(0x37b564d63f3376cc, 0xbb18aa3f6c83b7e7),\n", "],\n", "[\n", "(0x3c6c8c66d2e42062, 0x3fcbf3337873a7d8),\n", "(0xb540e662913e9721, 0xb8b8ae14acc03cc2),\n", "(0xbc5c8c66d2e42062, 0xbfbbf3337873a7d8),\n", "(0x3bfaea5f3639483f, 0x3f66604d91f926ee),\n", "(0xbc24192692d7c9db, 0x3f8251858011816b),\n", "(0xbbdcdb12750487fd, 0xbf314bc11a32c246),\n", "(0x3bd50548750ad314, 0xbf32e7decd1f73a5),\n", "(0xbb847a9ca039b976, 0x3ee293b4c9a24966),\n", "(0x3b6e3a426e412d42, 0x3ed4a6704d05ad0b),\n", "(0x3b1253e91cb63be7, 0xbe843ca9b71b6996),\n", "(0x3afbda58c238f16a, 0xbe6bddfbf35630ba),\n", "(0x3aba3f365a5e64b5, 0x3e1aae76737061da),\n", "(0x3a96b049b0e48195, 0x3df992424643ff64),\n", "(0x3a42ad17879fc5b9, 0xbda7aad4b0989ad6),\n", "(0xba22956ea0fa52e3, 0xbd81051e84a7a86a),\n", "(0x39c7f26c2e23f425, 0x3d2e49ae1a0e9424),\n", "(0xb998466ad52efa61, 0x3d013585a9b7473f),\n", "(0xb93c2bb2beb0ccde, 0xbcad5c6820d4c19c),\n", "(0xb90356383e63d305, 0xbc7b5bcfc1f36461),\n", "(0xb8714991402d4264, 0x3c2659e097d2d299),\n", "(0x3893b54f82b6acd5, 0x3bf18eefb530cdde),\n", "(0x380fec88aec6bc4b, 0xbb9b78694703192c),\n", "(0x37fadce1d8598d3f, 0xbb6296435cd2331f),\n", "(0xb7a9cd5a8e59cb5f, 0x3b0bdae97028e6a9),\n", "],\n", "[\n", "(0x35ac59c6428de284, 0x390f184285843311),\n", "(0x3c32010996eec734, 0xbfca701d0f967500),\n", "(0xbc1331fb2bff5c30, 0x3f7c54b930fef892),\n", "(0x3c44240355876f9f, 0x3fa17798aa09f11f),\n", "(0xbbf91cbfe509a337, 0xbf52a2151407dd09),\n", "(0xbbeaf2596bf8cd55, 0xbf5b541f829bfb41),\n", "(0x3b9678567dcb0401, 0x3f0cc0bda19ffe34),\n", "(0x3b7cc73ae3f8a72f, 0x3f041f3b0662f49e),\n", "(0x3b50b073a3604389, 0xbeb4b230b114b149),\n", "(0xbb39f6a1ea249aed, 0xbea1223e2bd0689f),\n", "(0xbad9dcc2b787e5e9, 0x3e511963968a437f),\n", "(0xbade1245aa3f79f6, 0x3e32ffb8dedaa0e5),\n", "(0xba7ddb5234f87c44, 0xbde24c47f1c46f88),\n", "(0x3a4b24f96f04dc6f, 0xbdbda527540ac89a),\n", "(0x3a002159e830fd60, 0x3d6b75eeb2587be0),\n", "(0x39a7a5cb88cfcf0b, 0x3d412dcf9e14b526),\n", "(0x39536a23b6e364bc, 0xbcee8dc94e61fd9e),\n", "(0x39406182c6b2e611, 0xbcbec6e9eeb29dec),\n", "(0xb8fb12be3176058a, 0x3c6a411ab303dfdb),\n", "(0xb8da27a89b185f00, 0x3c35f7175a19426f),\n", "(0x388abe97716ef10a, 0xbbe1f8d987025207),\n", "(0x383e3b32dc10b94d, 0xbba99550856225f2),\n", "(0xb7e9ddb15c3ea3e0, 0x3b5415925aa1431b),\n", "(0x3795803255a3ea0c, 0x3b18c98cea89bbf7),\n", "],\n", "[\n", "(0x3c6e9557ccd1703f, 0xbfc925c6fca08f55),\n", "(0x35a0840c3eb5c8e9, 0x3909bb79105907c8),\n", "(0xbc5e9557ccd1703f, 0x3fb925c6fca08f55),\n", "(0xbbf0bd4a4617bca0, 0xbf6049377403bcb4),\n", "(0xbc1dac1b118bb946, 0xbf809463bbd0367f),\n", "(0xbbbd1ccb5b6a209d, 0x3f297b354706c53c),\n", "(0xbbdfefc73ab9ea4c, 0x3f314dd4404e5fcc),\n", "(0xbb7689ff8e8b648e, 0xbedbf665d5afcb1e),\n", "(0xbb55632e0e751036, 0xbed32cb00ee8c1f3),\n", "(0x3b168e07e41d973b, 0x3e7f50fa815b542a),\n", "(0xbaeb09f8b87a4826, 0x3e6a4339e5f906ee),\n", "(0x3ab370c114b8364e, 0xbe1541c07333f998),\n", "(0x3a95f92ca4cd1f66, 0xbdf86c0bb112e485),\n", "(0x3a3d7a90841bd326, 0x3da35fba37d1f6f7),\n", "(0xba2b575752323f67, 0x3d80700770cc15dd),\n", "(0xb9557a6df0847bf2, 0xbd2963b203086961),\n", "(0x3994060b8e456ec8, 0xbd00c58770231c0a),\n", "(0x3934b091af50e5cb, 0x3ca91e0b939f2d33),\n", "(0xb91ee976639f1136, 0x3c7adb6f69ceb591),\n", "(0xb8b63616ac9c64e9, 0xbc2373e3cab8e402),\n", "(0x387455d8787bd080, 0xbbf156093877495b),\n", "(0x3823f244d844aa0f, 0x3b9842736a626a94),\n", "(0x37f3628fad20886f, 0x3b626f881139ee38),\n", "(0x379bb0027a1cd34e, 0xbb08e814b7cab6b6),\n", "],\n", "[\n", "(0xb59e68fd63ab1a3d, 0xb8fc6246c85a6640),\n", "(0x3c4a4f96a2520bad, 0x3fc8077f56c9b782),\n", "(0xbbf97f76587fd9cb, 0xbf75467eb535deaa),\n", "(0x3c28681fd3a1faac, 0xbf9fd7c3ad6f59e0),\n", "(0x3be0e0f0ccfb4015, 0x3f4c1b47c809c5eb),\n", "(0x3bf6295d17a16103, 0x3f59166c7d3eaa7c),\n", "(0xbba4cf48882a0699, 0xbf05f0152478f5f6),\n", "(0x3ba861e7d6d89ac5, 0xbf02aa939fd9fc9b),\n", "(0xbb5e0f27f02ffdbc, 0x3eb0129708ec2410),\n", "(0x3b4393e44832fa90, 0x3ea01716dc9f2e1b),\n", "(0x3acfaffff96cb541, 0xbe4b227eef409a9c),\n", "(0xbadf064b85fdb242, 0xbe32101c49d611c3),\n", "(0xba4ba7b2c5f1707c, 0x3dddb1e8b7adba5e),\n", "(0x3a5a73ba24830cae, 0x3dbc80aab1d9322c),\n", "(0xba00db3fc0b0c1ba, 0xbd66c2b17ab71886),\n", "(0x39e8d291d0b4d27a, 0xbd40ad5f60b542e8),\n", "(0x3973527417cabd58, 0x3ce9d02ffd593bab),\n", "(0xb950911cb567e2a5, 0x3cbe1eda1d51b8b7),\n", "(0xb8f1f756b53acec7, 0xbc668e76453989dd),\n", "(0x38c7df6bb93ac8ec, 0xbc35a3dd5c2dd312),\n", "(0x387c31c12e84cbf7, 0x3bdf55d5df5603a5),\n", "(0x381a4e01bffe5027, 0x3ba95785174d99bc),\n", "(0xb7f4002fdaa22aa2, 0xbb51bb3ba4b3316a),\n", "(0xb7b1fe1d3a814203, 0xbb18a987773fb87c),\n", "],\n", "[\n", "(0x3c62da0057f84d3c, 0x3fc70c511227d5aa),\n", "(0xb590c69cd835e65a, 0xb8fbdadd24cf38cb),\n", "(0xbc52da0057f84d3c, 0xbfb70c511227d5aa),\n", "(0x3bfe726f70245274, 0x3f5910ebe1f1cbcd),\n", "(0xbc0e61277dedf705, 0x3f7e7dc08e70e99a),\n", "(0x3bb740aaea2c85b5, 0xbf23bd7d159e09a5),\n", "(0x3bc9abf12a21a247, 0xbf300357a187375c),\n", "(0x3b7cab62f60660b1, 0x3ed5ec73302455b1),\n", "(0xbb76a66de44f6f2b, 0x3ed1e5d2836c8d99),\n", "(0xbad13f153900acfb, 0xbe78f41b94dfba1f),\n", "(0xbaff3652c8e5edf0, 0xbe68c11aada79ae8),\n", "(0xbaa209f480ef1062, 0x3e1141423452a28d),\n", "(0x3a9e19c8e523a095, 0x3df73ef6f4772772),\n", "(0xba405794c4ab8e4d, 0xbda007403efd2c9a),\n", "(0xb9c2a7b0a727a022, 0xbd7f93ab6667901d),\n", "(0xb9c5c7ae4a96c60d, 0x3d25638d0e0d9767),\n", "(0xb942fb1c3cc08579, 0x3d003d0592185f1c),\n", "(0x39373a63f1b5e963, 0xbca5832b6c129523),\n", "(0xb916b9966d8ed631, 0xbc7a2e88ff86af9c),\n", "(0x38c0ec56239fb4ce, 0x3c20e8839dc5443a),\n", "(0x3884c544300024fc, 0x3bf0ff71f08432b7),\n", "(0x3829d5c62bdc57b6, 0xbb955cc426feea1c),\n", "(0xb7ff81402cdf65ad, 0xbb6229c7418b10f0),\n", "(0x3773be52416792c2, 0x3b062f08720eaee7),\n", "],\n", "[\n", "(0x35a8346aa8f5b4bb, 0xb909c0fc24f65a67),\n", "(0xbc6444d3d89ac00f, 0xbfc62d93aa9d05bb),\n", "(0xbc1afb8f729be80a, 0x3f70ba9ce88929f2),\n", "(0xbc2f64ee23828a95, 0x3f9d7073daebb02c),\n", "(0x3bd6ad884b57cbba, 0xbf462813c7f58733),\n", "(0xbbc1c5da610ae750, 0xbf574a948d05638e),\n", "(0x3ba7816485085533, 0x3f01695765f13bbf),\n", "(0x3b9157b692bbea45, 0x3f0170ab5eeb0e4e),\n", "(0x3b2715c0e1d13855, 0xbea9c8e418a20315),\n", "(0x3b394c7caa0cf226, 0xbe9e4d893dce335e),\n", "(0xbaee8ffa7c53b5fb, 0x3e460f73a6ccb16f),\n", "(0x3ad92747d94d94d7, 0x3e312782f0f2448a),\n", "(0x3a5745f5f5b1bc73, 0xbdd881d5842ec670),\n", "(0xba53516c45370c96, 0xbdbb4c521a316133),\n", "(0x39f845348a27f4b9, 0x3d63132da6b9ef80),\n", "(0xb9e1395c98d19f4a, 0x3d4019364d86610c),\n", "(0xb973bba720cb85bf, 0xbce5f4ab616b4a7d),\n", "(0xb92365a073b465df, 0xbcbd47ca99f425b7),\n", "(0xb90304c2a5a66771, 0x3c637371b17caa3a),\n", "(0xb8dc112a193fb5f1, 0x3c352a819018d0f2),\n", "(0x387a7ad3dc13170e, 0xbbdb5c2ea7518f33),\n", "(0xb848fe010506d44a, 0xbba8eaf2df7cede6),\n", "(0xb7e6b127ce015440, 0x3b4f4fdfa642b717),\n", "(0xb7a66fe7bcf681da, 0x3b185bcb7268f7c2),\n", "],\n", "[\n", "(0x3c6a47ab4241a9f5, 0xbfc5664e13b70622),\n", "(0xb5ac924d5c123479, 0x3900f098dc38e480),\n", "(0xbc5a47ab4241a9f5, 0x3fb5664e13b70622),\n", "(0x3bddc134f1d74a51, 0xbf540ee3940b092f),\n", "(0xbbffe75afd6ce0fa, 0xbf7c5e1ad9fb2f40),\n", "(0xbbab866102da4707, 0x3f1fb8a98ef4a243),\n", "(0xbbc018bed7b77750, 0x3f2de9be58a373e2),\n", "(0xbb75089b2cae9b03, 0xbed1bec95415e630),\n", "(0x3b447f8eea3cc056, 0xbed0cf264341409e),\n", "(0x3ac71d5b65310e89, 0x3e74677d9e214cd4),\n", "(0x3b026d69949fca90, 0x3e6766cc63507104),\n", "(0xba902c01ede1dfd5, 0xbe0c905882b94f65),\n", "(0xba995672d0443f95, 0xbdf62157963573dc),\n", "(0xba18987abee2ab90, 0x3d9ae2e0cbb67b06),\n", "(0x3a01b88c86e07d4b, 0x3d7e456a1c8dbf40),\n", "(0xb9a82e3122996ca9, 0xbd222e4736637ff5),\n", "(0x397f896eb454c48a, 0xbcff56a09da19f70),\n", "(0xb939b4426eb8647c, 0x3ca28607cce512f7),\n", "(0x38da5f520ae3c80c, 0x3c796a2f3d059107),\n", "(0xb8bff36f14735622, 0xbc1d78e82e3dfe4c),\n", "(0xb8985995658ccf15, 0xbbf096501f12c820),\n", "(0x381ac1859ffca23b, 0x3b92d35996fa684b),\n", "(0xb808697949d6df60, 0x3b61ce65ead2f56a),\n", "(0x37a076885f254fcf, 0xbb03bf2c7d52312b),\n", "],\n", "[\n", "(0x357834c50798eee0, 0xb9046916861c7cbe),\n", "(0xbc6e5d93454f99e3, 0x3fc4b2a2ebf61ece),\n", "(0x3bf37b02bd5f53a6, 0xbf6b3297fdae7902),\n", "(0x3c2eb354a6313bb4, 0xbf9b8105d59b114c),\n", "(0x3bb9bab6138b6903, 0x3f420a3f8c12a1ff),\n", "(0xbbf48ec1e2fa78e5, 0x3f55d18d69de6cfb),\n", "(0x3b0ad2f6c6600043, 0xbefc79db4b341e8e),\n", "(0x3b70c098a1ba083c, 0xbf00679c92c303b2),\n", "(0xbb4af505f8420dfd, 0x3ea53ac4ecd4be2d),\n", "(0x3b3bd880347c15c4, 0x3e9ca7507840c04b),\n", "(0xbadbc0ebcece96aa, 0xbe4253415f09767a),\n", "(0x3a8f2f3402a0f194, 0xbe305141505c9f00),\n", "(0xba73147caddad17a, 0x3dd4919940f05339),\n", "(0x3a20801c08cd53d5, 0x3dba20de95780e25),\n", "(0x3a0aad83cdc61600, 0xbd602fff3daabeb6),\n", "(0xb9cd95539d508286, 0xbd3f01d18581b85a),\n", "(0x3986a1dccaaee4ac, 0x3ce2d78e0d95c2b1),\n", "(0xb9420e56b2382383, 0x3cbc5cc76fc4031e),\n", "(0x390db41e1b715d4d, 0xbc60e00793400a38),\n", "(0xb8d97d5c56eaa5d3, 0xbc349c9cebd4542b),\n", "(0xb87767b6f54f3ae0, 0x3bd7fb7ba24468a5),\n", "(0x384f6e8dcd984b87, 0x3ba861a49c8b4594),\n", "(0xb7a3310c04ca52f6, 0xbb4bb5b1358f5d66),\n", "(0xb7bf2be7dc5aa7d5, 0xbb17ef6c51c02185),\n", "],\n", "[\n", "(0x3c6316f8ffd294bc, 0x3fc40f90793605bb),\n", "(0xb57f9e2ffd50aa0c, 0xb8e84b55d671e3ab),\n", "(0xbc5316f8ffd294bc, 0xbfb40f90793605bb),\n", "(0x3bf7017919c133d4, 0x3f5085775a5529c9),\n", "(0xbbe51eb6f09db1a0, 0x3f7aa0ce0421d1a8),\n", "(0x3bb34ca5aae2a0a8, 0xbf1a32a28e4bc82e),\n", "(0x3b829f8de1c1e358, 0xbf2c26ebca0e46de),\n", "(0xbb655efa83f66d77, 0x3ecd7400876206d0),\n", "(0x3b4cb5b0088841fe, 0x3ecfc1bbf57e3ae2),\n", "(0xbb1b0133a27f94ef, 0xbe710c7090487d3e),\n", "(0x3aef5fb8bc32c77a, 0xbe6634db39e4a305),\n", "(0x3aa91e07a77165aa, 0x3e0810d7e4efab49),\n", "(0x3a839aaf703b3d25, 0x3df51b513b3c4cf1),\n", "(0x3a336ceec537a192, 0xbd96dd877beb3775),\n", "(0xba0a1b2154c0dad9, 0xbd7d06057acf98a1),\n", "(0xb9b49d50f1878b22, 0x3d1f3b007c53631a),\n", "(0x3998369e87f01d70, 0x3cfe341812329072),\n", "(0x394269c561f0abb0, 0xbca0119135f2618c),\n", "(0x390e03cff1d48846, 0xbc789daf7e05bf20),\n", "(0xb89d5c1dd0bd003d, 0x3c19d09c42c2fd20),\n", "(0xb89ec3091d0a20a5, 0x3bf023bdfeef2b62),\n", "(0x383eea157ba50462, 0xbb90a443b12390a2),\n", "(0x380faad5050249de, 0xbb6165e9e44cf4fc),\n", "(0x37ac0bb1b2874365, 0x3b019b4693645186),\n", "],\n", "[\n", "(0xb563251dec0c8419, 0xb90190e21085c59e),\n", "(0x3c5948539688f9cf, 0xbfc37aac8c1aeabb),\n", "(0x3c0e1b9871576e7b, 0x3f66ac0d2e2f2f87),\n", "(0xbc3e2c9f8f0de524, 0x3f99e74e754ea71f),\n", "(0x3bc834f161e5b53a, 0xbf3e1c0589e32bb1),\n", "(0x3bfe8b15bd1b2805, 0xbf5496158dc5f7ff),\n", "(0x3b66422c8ac686b8, 0x3ef7d55405348ca9),\n", "(0x3b9138881216a9f6, 0x3eff0b30f4506228),\n", "(0xbb49c5af94afc68e, 0xbea1d9e3629b98ec),\n", "(0x3b31cbe80255f739, 0xbe9b35ef28e9de24),\n", "(0x3ac5335f73a99784, 0x3e3f0200e2650870),\n", "(0xbacc80c87bd0e106, 0x3e2f1fb225e849cb),\n", "(0xba76daf9021379d3, 0xbdd187928a64d042),\n", "(0xba42b8804ba3e9e1, 0xbdb908ba84482af1),\n", "(0xb9f798e4ea85d67c, 0x3d5bd0a97427e582),\n", "(0x39ae28268a102015, 0x3d3dd98a1888cb0d),\n", "(0x39800b32153c5fbf, 0xbce05368fdb3dbd3),\n", "(0x395973c2e28b46eb, 0xbcbb6e7eba27d4df),\n", "(0xb8fd64860bbe4d9f, 0x3c5d7e5c8f77a962),\n", "(0x388996f5c1af67cd, 0x3c34063c16fd02be),\n", "(0x386cbbfcf555cb4a, 0xbbd52213fb27642b),\n", "(0x384eb9fd51a68df4, 0xbba7c8fd7f555061),\n", "(0xb7c915bb96c79ac0, 0x3b489cfc43bd06a7),\n", "(0x37bcc11a3c54068e, 0x3b177056c238889b),\n", "],\n", "[\n", "(0x3c689d1f48185c7e, 0xbfc2f2072e638cf4),\n", "(0xb5952cb9317551e1, 0x3901222bb44bcf14),\n", "(0xbc589d1f48185c7e, 0x3fb2f2072e638cf4),\n", "(0x3be64a78bbbb198f, 0xbf4bd42b64fc5bed),\n", "(0x3c082c4cf012e7aa, 0xbf792bb5e1e159fc),\n", "(0x3ba0f7052b5160b8, 0x3f161ace3386dfd7),\n", "(0xbbc911bb758a62b7, 0x3f2aa8d1cf8db852),\n", "(0x3b53e6d95cbd37f7, 0xbec8ef624c36fc32),\n", "(0x3b54f1d79d1c68cf, 0xbece26d3747fe829),\n", "(0x3b0b9f4f6af339a7, 0x3e6d010d2bdb6fa2),\n", "(0xbb08db6527b88cec, 0x3e65272828ae4057),\n", "(0x3a509976106e8349, 0xbe0497b03c4482e4),\n", "(0x3a79f5e122b84d8f, 0xbdf42e35495a0b9f),\n", "(0x39cbebe4937d13e3, 0x3d93b2e62efa9ef3),\n", "(0x3a14579198fd4bcf, 0x3d7bdc7867dae011),\n", "(0xb9bf0d7f81848e9e, 0xbd1b1acb454ca400),\n", "(0xb97ccb74999a40d8, 0xbcfd1ce7997b3c0d),\n", "(0xb9380511e3a7c101, 0x3c9c1b1fc8c0e04f),\n", "(0x38cac264c6c80d21, 0x3c77d2b971f6828b),\n", "(0xb8b8eacaf1c3a530, 0xbc16c0313e58129c),\n", "(0xb85cf03733411e25, 0xbbef5c5d17f54410),\n", "(0x3815be1ad7496a82, 0x3b8d8dcf1e84a9c2),\n", "(0xb7e5c044edc6060a, 0x3b60f6f0c4603224),\n", "(0x379126e0d0da66b9, 0xbaff7e6aff22be1e),\n", "],\n", "[\n", "(0xb5627bd5768d6ae9, 0x38cc4a2cf6a18867),\n", "(0xbc389c717cff1eba, 0x3fc27407dfadee6d),\n", "(0x3c01b3998e2560e2, 0xbf6346950bfd91f1),\n", "(0x3c3dd532243e7d0c, 0xbf988d48d1d4eb7b),\n", "(0x3bcf03d11aeaafca, 0x3f399e6923ada922),\n", "(0x3bf2c9a985cf61c7, 0x3f538984b76cdf4a),\n", "(0x3b96fc0cb69470ac, 0xbef452194b75f3c7),\n", "(0xbb929abb7ce27bd1, 0xbefd855d7b8f0243),\n", "(0x3b33da9849a0f970, 0x3e9e8a88601ff296),\n", "(0x3aebb8f5815fd80b, 0x3e99f1bd69b16e6b),\n", "(0x3ac86d0d07634a8b, 0xbe3aa483fce054e3),\n", "(0x3ac5ab23f0a90bfb, 0xbe2dc4c02391c504),\n", "(0x3a69996a456ab65e, 0x3dce48dc1b4db792),\n", "(0x3a30cc58e232dc0c, 0x3db807112e6636fd),\n", "(0x39f6e9562163f106, 0xbd582c0e5f51b3f0),\n", "(0xb9c5c661501e7ee5, 0xbd3cc1592707b4bb),\n", "(0x3966aa764333f3df, 0x3cdc8f29e796ad34),\n", "(0xb95785ee30c62c1f, 0x3cba864ef1faff74),\n", "(0xb8ff8a02ad81ef19, 0xbc59f854cbd9efdc),\n", "(0x384627f385cebec8, 0xbc336efc940e4c98),\n", "(0xb87617b5b0e9289b, 0x3bd2bbd3c0ba4c14),\n", "(0xb84c5ed87745f0e5, 0x3ba72a3898c03cd9),\n", "(0x37e4b8d60a63fdb3, 0xbb45f681005965fc),\n", "(0xb7a7ad15bf5e48a5, 0xbb16e75915fef489),\n", "],\n", "[\n", "(0x3c51f9b16832f362, 0x3fc1ff5eec6a01cd),\n", "(0xb59a05b7856c4a22, 0xb8ff07a73b062717),\n", "(0xbc41f9b16832f362, 0xbfb1ff5eec6a01cd),\n", "(0xbbe5f2ed43d9b503, 0x3f47daf64983af9d),\n", "(0xbc19a4b7b3ed5b9d, 0x3f77ed5fffc1c774),\n", "(0xbbafa9d6f1d224d2, 0xbf12f947962314a1),\n", "(0x3bba27855de20282, 0xbf296027ea1d6e5c),\n", "(0xbb585d6672f6864b, 0x3ec57486c67fbc78),\n", "(0x3b6dbae692eab5c3, 0x3eccc11a59e13739),\n", "(0x3b07ece30b8718ed, 0xbe690ade515567ae),\n", "(0x3afec36878fc6271, 0xbe6438a7e22c9734),\n", "(0x3aac5fba9cf90508, 0x3e01db6d29a7d048),\n", "(0x3a9c694efcaf05a9, 0x3df3588cd299009a),\n", "(0xba304f511d090519, 0xbd912b3d3f46a11d),\n", "(0xba1f96e81c9933ce, 0xbd7aca95934e0ad5),\n", "(0x39a4c6d8ef3baa67, 0x3d17c19e5c2a3a3a),\n", "(0xb98de02178f2e8a7, 0x3cfc15e96b25adba),\n", "(0x3904b1879dbd8e47, 0xbc98c7e06842ee3d),\n", "(0xb8f76e2dea2e96ba, 0xbc770ecfbf61ca0d),\n", "(0x38b68e1efbe2a988, 0x3c142e95d318b6f5),\n", "(0xb874c2ceb9ea4228, 0x3bee73932c419ab8),\n", "(0x37f46e3304b4ae0c, 0xbb8a60b7a857ccc0),\n", "(0x380c4d64ccf85fc7, 0xbb608626d8e04736),\n", "(0xb7990c5c39207c1f, 0x3afc47487352322d),\n", "],\n", "[\n", "(0x35ab7cbed9b6b1f4, 0x390239f235357955),\n", "(0x3c6f5f4b08a76fd4, 0xbfc192f23ce3e051),\n", "(0x3bdee957b8603928, 0x3f60a668185c01b1),\n", "(0x3c39de5fb6906a4e, 0x3f9764141d652089),\n", "(0x3bd0a73bf1673e03, 0xbf3624437a2fe76a),\n", "(0xbbe29f0dad749d08, 0xbf52a184be0d9891),\n", "(0x3b92247582470aeb, 0x3ef196de0eeef190),\n", "(0x3b54bbca179d7e5e, 0x3efc317f854112ad),\n", "(0xbb3c4937a266ae2b, 0xbe9a8019ef772196),\n", "(0x3b1fa8fc16fd89b6, 0xbe98d38497beea33),\n", "(0x3ad1777abda5cdbe, 0x3e37318410813eeb),\n", "(0xbaa199670acf66d4, 0x3e2c8d9d45d76323),\n", "(0x3a61c9a46bc0a86d, 0xbdca782c1acc5d80),\n", "(0xba47414175e77281, 0xbdb71bbb74f830ea),\n", "(0x39fb21ba4fd0050e, 0x3d5539502b6b0d41),\n", "(0x39bde0e950bf1a4a, 0x3d3bbc22cd6ef8b2),\n", "(0xb951eab6630258a6, 0xbcd933a6402470d3),\n", "(0xb90f7f72f87b85f2, 0xbcb9a8f9bcb762d2),\n", "(0xb8f0fd489e307f2b, 0x3c5709caa1708994),\n", "(0xb8bf22055786ef23, 0x3c32db59b73d17f0),\n", "(0xb84510913d0bb141, 0xbbd0b5801d4ebd68),\n", "(0xb83e3fe31926f1ed, 0xbba68b53041d22be),\n", "(0xb7ecd50940caefad, 0x3b43b217fd3ffb23),\n", "(0x37a50bcc9d97c7ac, 0x3b165a991dfc9832),\n", "],\n", "[\n", "(0x3c6e71c482be67bd, 0xbfc12dd57bf18ada),\n", "(0x35745b4d4ccbb68f, 0x38d7a991cf97ce2e),\n", "(0xbc5e71c482be67bd, 0x3fb12dd57bf18ada),\n", "(0x3bd11b1ac52dc1e2, 0xbf44bebeff7b7f02),\n", "(0xbc1286f932bea2b2, 0xbf76d9afe88301fa),\n", "(0x3b859ae0593310ce, 0x3f10842d50687949),\n", "(0xbbc5025e938d5cb6, 0x3f2841d86b9b92f4),\n", "(0x3b45bc90ed56ac34, 0xbec2b5caad1f2b9a),\n", "(0xbb3771ef99211bfa, 0xbecb86bad42fc220),\n", "(0x3ac3d72243d64739, 0x3e65e5117a965bcf),\n", "(0x3b07539fc5e6a80e, 0x3e6364a25cc7309d),\n", "(0x3a51d7761a4ff87d, 0xbdff53dcc9459e76),\n", "(0x3a99aab279c470e8, 0xbdf297f421bb27bc),\n", "(0xba27ed296e5c55e5, 0x3d8e3c9c7289c65b),\n", "(0xba1d2b7fc29cc174, 0x3d79cfbae2bdc016),\n", "(0xb99b7a6311b584d8, 0xbd1502858f3b1429),\n", "(0x399664d160d01e32, 0xbcfb20c42e642ccd),\n", "(0x391ef844bb66595d, 0x3c9604b99922c587),\n", "(0xb91aa631f65ad96a, 0x3c7654ba0a2b4ab4),\n", "(0xb8bee3929b6ac229, 0xbc120523ef69f26a),\n", "(0xb88fba8fecf60808, 0xbbed920e28727809),\n", "(0x3816d4cbcfecdce6, 0x3b87ab7af32311cf),\n", "(0xb7f2f0febd96b7f0, 0x3b60169fdd2f6938),\n", "(0x3782a08850768123, 0xbaf9808bbbe92c37),\n", "],\n", "[\n", "(0x359dd81c30ee48fe, 0xb8f151a3aeac900c),\n", "(0x3c53f099a5f56db3, 0x3fc0cf3ed059c573),\n", "(0xbbff3cb9b807fae1, 0xbf5d242aa529931c),\n", "(0x3beb544962a1a242, 0xbf96613d93b0180b),\n", "(0x3bde039e229b4e70, 0x3f33627f261f5116),\n", "(0x3bf7fb39963ccff5, 0x3f51d69ca0d88394),\n", "(0xbb384fc5c48bb913, 0xbeeed574afab70fd),\n", "(0xbb95a44313a48eb8, 0xbefb06384e48ee5b),\n", "(0xbb387c094254f81d, 0x3e97452c65235728),\n", "(0xbaf881554ea8f625, 0x3e97d51f133b6843),\n", "(0xbad89e4d3b4b48e5, 0xbe346ac67a7e0c7c),\n", "(0x3ac74865f688f55b, 0xbe2b75d66a8d7fbb),\n", "(0x3a6411700cfe955c, 0x3dc75f5a5db478ef),\n", "(0xba50702b7e55e69b, 0x3db64531ca4ef464),\n", "(0x39b8d5aa5d138d2b, 0xbd52ceac14a86c69),\n", "(0xb9b1503306d5d1c3, 0xbd3aca497ff206bc),\n", "(0xb972644a7dcc9d17, 0x3cd66b96eb20b32f),\n", "(0xb954b544843ae3aa, 0x3cb8d889b2e2fb84),\n", "(0xb8e75b07f541d7cb, 0xbc5494ff17910999),\n", "(0x38c576f2b4ee6110, 0xbc324dc265486d0f),\n", "(0xb85a9820119b4156, 0x3bcdfc7ea51b3fad),\n", "(0x38430f69314493a8, 0x3ba5eff892c2d831),\n", "(0xb7dc83562058d69b, 0xbb41c095467f781e),\n", "(0x37bbc403c5629dc3, 0xbb15ce2e25be6e38),\n", "],\n", "[\n", "(0x3c61a13e2fee5687, 0x3fc076826cc2c191),\n", "(0xb5391b2ea81aa5bf, 0x38c00dbc5df9a26a),\n", "(0xbc51a13e2fee5687, 0xbfb076826cc2c191),\n", "(0x3be79f62aa488a9d, 0x3f4241b03eaaf5d9),\n", "(0xbc15dbe9d7210c2e, 0x3f75e7f53001e4b1),\n", "(0x3ba5f4ab61cd1e51, 0xbf0d17978e2d0336),\n", "(0xbbb79a683ed1c80a, 0xbf2745b0df80666a),\n", "(0x3b63b64ff7d7f045, 0x3ec0803f7f7fe323),\n", "(0xbb50168184fb2a2f, 0x3eca7006e6ad9cfe),\n", "(0xbb09b47df06e299a, 0xbe63590d57d48525),\n", "(0xbad3c549213b58f2, 0xbe62a7084b42b890),\n", "(0x3a391d2842dc92cf, 0x3dfbc0dd5a22c9a6),\n", "(0xba9fb98847ec903b, 0x3df1e9e4e20477cd),\n", "(0xba2be602f82a15a9, 0xbd8ade1de2460eb2),\n", "(0x3a17881703d93302, 0xbd78ea3bc5e51ddd),\n", "(0x397ca6386538b34a, 0x3d12bb86a88ccf82),\n", "(0x399525cc1707dd4e, 0x3cfa3d6bcad0c3fc),\n", "(0x393d78e1fc33fbc8, 0xbc93b476152074ba),\n", "(0x39110f06e5116481, 0xbc75a59813c6ee3d),\n", "(0x38bc4c43696de6db, 0x3c1030bae23c4e59),\n", "(0xb844d08b5dab4a58, 0x3becba7872c6d35c),\n", "(0x37cead7255599d43, 0xbb855a77ed00896a),\n", "(0x37e2184f9f8c0595, 0xbb5f548425ac1d81),\n", "(0x3797f6a7c6e97b07, 0x3af71a13b7056576),\n", "],\n", "[\n", "(0x357bf96ef321056c, 0x38e8be4b9ac053ef),\n", "(0x3c665439df5bb54c, 0xbfc0230b9797a7b3),\n", "(0x3bd7d914863ddca7, 0x3f59c8083b2b753a),\n", "(0xbc3c455b2fe151b8, 0x3f957d3203befd90),\n", "(0xbbd3de5214e17418, 0xbf3127cba22892de),\n", "(0x3bf0c5ff9d698a77, 0xbf51234471455a6c),\n", "(0xbb8a9c280a18d4c7, 0x3eeb4fe26ec3e489),\n", "(0xbb9cd17c659ae229, 0x3ef9fc5254f1086c),\n", "(0xbb3a46913af4f447, 0xbe94a44c6506c43f),\n", "(0x3b3f5055c4929bc5, 0xbe96f17dd184ad59),\n", "(0x3a9912b1a43a7c95, 0x3e3225640a6a9328),\n", "(0xbab880b364397a7e, 0x3e2a7943505d15ed),\n", "(0x3a4ecbcb0eff2849, 0xbdc4d296ecea7b61),\n", "(0x3a453c61fa23edd4, 0xbdb58177059b1ee7),\n", "(0x39e59e5790859f3e, 0x3d50cd71be5428ab),\n", "(0xb9dab853aa81b7a6, 0x3d39eafac486dfeb),\n", "(0x39594ed10e15fb80, 0xbcd417df1a94b2d2),\n", "(0xb940b5960ba1aada, 0xbcb81583d885c1c9),\n", "(0xb8fa5f714b1f1036, 0x3c52822e3f56f84b),\n", "(0xb8da3a40678675b0, 0x3c31c75f9fd23d85),\n", "(0x38595afb542f1092, 0xbbcb0fe75f5fce5e),\n", "(0xb8206d9263935574, 0xbba55a4472710434),\n", "(0x37b1baa0847432ef, 0x3b4014997c5c3405),\n", "(0xb7baecc415e584a1, 0x3b1544b15eb627ac),\n", "],\n", "[\n", "(0x3c5d7cc4171715a0, 0xbfbfa8b41711c83a),\n", "(0x357640b3baebf195, 0xb8d6a301383ff88d),\n", "(0xbc4d7cc4171715a0, 0x3fafa8b41711c83a),\n", "(0x3bca510f3e4f0ba8, 0xbf403a8d0f110fe1),\n", "(0x3c195ccf34fc85bb, 0xbf7511c6dadaaa12),\n", "(0xbb6fad55e36d2414, 0x3f09e040fc62c87e),\n", "(0x3bb45c7350ce4d8a, 0x3f266582f66d8d4c),\n", "(0xbb2c8a29c78431da, 0xbebd62a18e287536),\n", "(0x3b667f7ad529fbab, 0xbec976fb023f0f79),\n", "(0x3b0f3a432d46b94e, 0x3e6141188eda6cd5),\n", "(0x3afac6e99d820d1b, 0x3e61fc77546c2a70),\n", "(0xba3e756c586379ea, 0xbdf8ccadf7842b28),\n", "(0xba8280b1979ddc28, 0xbdf14c0515097baa),\n", "(0x3a1187e8ad78c9df, 0x3d8810b7fe5b7aae),\n", "(0xba14e29f33da57b3, 0x3d78181478442ce9),\n", "(0xb9b79ebe6761a2d6, 0xbd10d30b1ed6e857),\n", "(0xb995f6bc31063165, 0xbcf96afe82155a3c),\n", "(0x3927bc733591bf77, 0x3c91c038cd6a8753),\n", "(0xb8f984f4b5077d41, 0x3c7501961b5bf1bf),\n", "(0xb8a4dc2a78afb902, 0xbc0d4372ee42b73d),\n", "(0xb88b4f0dd2f40637, 0xbbebee0a131ab576),\n", "(0xb81ffd82b16be530, 0x3b835cde101c242e),\n", "(0x37ec5511ff967fb0, 0x3b5e84462bfb49f0),\n", "(0x378914b866c350ff, 0xbaf50552417f971d),\n", "],\n", "[\n", "(0xb556b1f952a5712e, 0xb8d6808df2a13f7c),\n", "(0x3c581bdf89b0a8b1, 0x3fbf13faf32c8e0a),\n", "(0xbbee91046256d1d1, 0xbf570558dddb7d46),\n", "(0xbc326d6d43908d3c, 0xbf94b24d7a933972),\n", "(0xbbb5423c2da87eef, 0x3f2ea52a21487a11),\n", "(0xbbf33353f135e755, 0x3f50834d8f3fdd5b),\n", "(0x3b8f2ed165228a36, 0xbee86941a4b43bea),\n", "(0xbb93d8441684ef00, 0xbef90e32cef3e900),\n", "(0xbb24c39a94ebc802, 0x3e92785f6385b273),\n", "(0xbaf58f1dccae728c, 0x3e962482bf9d2bb8),\n", "(0xbab1b25f4a923de6, 0xbe3043125386ac84),\n", "(0x3acbae29202faa10, 0xbe29943c303e31c2),\n", "(0xba689e50e7b79f94, 0x3dc2b2457a1921b4),\n", "(0xba5fc1c10645d26a, 0x3db4ce82afcbf544),\n", "(0x39e8d1c21f25be80, 0xbd4e3dcde42d462d),\n", "(0x39cd7cc147b1feaa, 0xbd391cdf33ca55c9),\n", "(0x396660b123953dac, 0x3cd220c06f5ae707),\n", "(0xb95a54474bf84f20, 0x3cb75f9d03ccf4de),\n", "(0x38e97ead5ea85772, 0xbc50be9744b83b69),\n", "(0x38d4e9dad41717fb, 0xbc3148975b0a87db),\n", "(0x38499800271bb705, 0x3bc88e2038a62c01),\n", "(0xb84c766c188201e5, 0x3ba4cb4d904c6a21),\n", "(0x37d9528d3a53acbd, 0xbb3d4587fbb07d3a),\n", "(0x37aa22e47790bf77, 0xbb14bfb26c12f06a),\n", "],\n", "[\n", "(0x3c0020b4016594ac, 0x3fbe8727daa3daed),\n", "(0x357bd9f848327b9d, 0xb8d74664ec9bed14),\n", "(0xbbf020b4016594ac, 0xbfae8727daa3daed),\n", "(0xbbae628434d2d25b, 0x3f3d19c52e070d9f),\n", "(0xbc1361836c532514, 0x3f74524d4813cc25),\n", "(0xbb7cb5b9aae4885e, 0xbf0735f790b535f3),\n", "(0xbbcfed1fabeeb9ac, 0xbf259c8f9f0a3484),\n", "(0xbb45b8692da7d38c, 0x3eba619ffc5a3ad0),\n", "(0x3b69523f4f9b3609, 0x3ec896d7dc819faf),\n", "(0xbaac3c0f5c29d085, 0xbe5f04efbdfeacf4),\n", "(0x3afee241ecc24fbe, 0xbe6162253f3024f4),\n", "(0xba6d1ca080c948cb, 0x3df653d736c3ef75),\n", "(0xba92d3e20a44098b, 0x3df0bc406f716b40),\n", "(0x3a244bdd54062834, 0xbd85b5420be0cc44),\n", "(0x3a0a9968781f3a0f, 0xbd77573e801c99fe),\n", "(0x39a0139e52f2e139, 0x3d0e6b725d3b2ae6),\n", "(0xb99e56935f64b195, 0x3cf8a83e6e4c168c),\n", "(0x392ead92886f9ee6, 0xbc90163396acd7b1),\n", "(0x391d3d6b8efb3080, 0xbc74685be0d8a97e),\n", "(0xb8a6ef909392303e, 0x3c0a9718712afa89),\n", "(0x385c475ef4355891, 0x3beb2d18cd37a98f),\n", "(0x382d92b3e5d0a3a0, 0xbb81a4a7bc85c3b0),\n", "(0x37e8bb074772c480, 0xbb5dbd9c4b52231d),\n", "(0x3792acc4acbf596f, 0x3af335a8be4bc776),\n", "],\n", "[\n", "(0x35982ed3998876be, 0xb8f5dc9ed9d5e051),\n", "(0xbc5a45a53b37a59e, 0xbfbe018d99f5da1b),\n", "(0x3be001e9c4dcf8a1, 0x3f54b85897b36265),\n", "(0xbc32db4ef3821944, 0x3f93fc442153435d),\n", "(0xbbcf201dea326b1a, 0xbf2b9694d71486e3),\n", "(0xbbef8e2381ba7f64, 0xbf4fe6fdc644ddde),\n", "(0x3b87d6d0f34bdbc3, 0x3ee5fd096e4523fb),\n", "(0xbb6b1063264f1631, 0x3ef83770c9a84498),\n", "(0x3b3a40ab832d99d2, 0xbe90a6f6f7e05f1b),\n", "(0xbb3f771b18195677, 0xbe956ad4a35eb0ad),\n", "(0x3ab57ad37dd35a78, 0x3e2d5bea474ca54f),\n", "(0xbac551a8f3695cff, 0x3e28c39f68d21b3c),\n", "(0x3a3d3669caabf1d6, 0xbdc0e73408ce7d88),\n", "(0xba59b3ea5bc5c592, 0xbdb42a6dedaa1a20),\n", "(0xb9ddcafa3dca5d8b, 0x3d4b640f953cb953),\n", "(0x397af903fd708234, 0x3d385e74fde5ce1a),\n", "(0x397d0253626bd0a6, 0xbcd0740945699eba),\n", "(0x39554011a8afef74, 0xbcb6b622427cf222),\n", "(0x38d2f100ca9a88c8, 0x3c4e76f4da90ff0f),\n", "(0x38d40ee48b131878, 0x3c30d15eeed4b2da),\n", "(0xb86bd3c37ebf7704, 0xbbc6647780d4dd5f),\n", "(0x384830339986f999, 0xbba44386be6e1434),\n", "(0x37b288dd01211d3e, 0x3b3ac32d5099a684),\n", "(0xb7bdc2d6cb33959c, 0x3b14400df422e81f),\n", "],\n", "[\n", "(0xbc5cb1f28997ca39, 0xbfbd8293aa55d18f),\n", "(0x35ac5e4a18056845, 0x39005c1969d4e17b),\n", "(0x3c4cb1f28997ca39, 0x3fad8293aa55d18f),\n", "(0x3bb680f417abeace, 0xbf3a48fe4afedcc8),\n", "(0xbc16c091c5e2bd3b, 0xbf73a5ccbc12a67b),\n", "(0xbba33c90d1ef4886, 0x3f04f91e41eee9bc),\n", "(0xbb9b30870eff030b, 0x3f24e72224db2c0e),\n", "(0xbb169834dfa01495, 0xbeb7dac8202ad4fb),\n", "(0x3b6372510d6e3ed7, 0xbec7cbd49c315be0),\n", "(0x3aee3c01a205f644, 0x3e5c1396b62b0f84),\n", "(0x3af43728856e7e95, 0x3e60d5c64a9c427f),\n", "(0x3a8951d1fb56f9e5, 0xbdf43c4a5d5a74a1),\n", "(0x3a9dff3a9a1305b7, 0xbdf038cb3f5e324b),\n", "(0xba2227a6954a8107, 0x3d83b473da8d9c7c),\n", "(0x3a00f6b33cdc63fd, 0x3d76a5d59f9a81dd),\n", "(0xb988bc6d23c00f13, 0xbd0ba9a1977e4129),\n", "(0x398765f6255cb3d1, 0xbcf7f3d211d80ca6),\n", "(0x392695fb30ce2147, 0x3c8d5107593c868e),\n", "(0xb917c43ab17af1b0, 0x3c73d94e8dd594b7),\n", "(0x3898ca359e8db05d, 0xbc08484736827c1c),\n", "(0xb8762b3eb4479bca, 0xbbea7775ae8da32a),\n", "(0x37fbcf628aa86234, 0x3b80264bfaa20223),\n", "(0x37e271fa49b2756e, 0x3b5d00eb74cea235),\n", "(0x379f3f3a922be29c, 0xbaf1a063ed726ac9),\n", "],\n", "[\n", "(0x35854b02b59f20a5, 0xb8e34bc17457894f),\n", "(0x3c5f215e77086bf5, 0x3fbd09b210b30217),\n", "(0x3bfc1f6fd559ad63, 0xbf52c74f6d120291),\n", "(0x3c0587bb3b3049f5, 0xbf9357bfc2be5860),\n", "(0xbbca26f6fb2c1060, 0x3f2901e4c495acea),\n", "(0x3bdfa22468c2245a, 0x3f4ee2a36979f905),\n", "(0xbb819f064e6a387e, 0xbee3f0cb93a497a4),\n", "(0x3b845c631a25decc, 0xbef7748921871bcc),\n", "(0x3af9ba7ee835a985, 0x3e8e39a085fc522a),\n", "(0x3b168e73edf85eb9, 0x3e94c1b7a6b2509f),\n", "(0xbacb21d04553bf28, 0xbe2aabe92ddd7d73),\n", "(0x3ac83c7d3d064b50, 0xbe2804c5ad3234f3),\n", "(0x3a2c4059ace3745e, 0x3dbec02b4af63bb7),\n", "(0x3a5e5f6d54d90428, 0x3db3938387c8ea5e),\n", "(0xb9a027aa900640db, 0xbd48f3df4c861285),\n", "(0xb9a31a1b83cb9055, 0xbd37ae3cd67c3467),\n", "(0x3962c6e3f82d4e4a, 0x3cce075e0968692d),\n", "(0x395097056b18178c, 0x3cb61833a4f480be),\n", "(0x38dbe00af812e106, 0xbc4bda71ed3079b1),\n", "(0xb8dbcc3ff8d7603a, 0xbc30616db3cfc278),\n", "(0x38543a30e58a4f05, 0x3bc483dc2d93ca5e),\n", "(0x383474a59c970c7b, 0x3ba3c2fe3717b507),\n", "(0xb7ce38a86dc4a340, 0xbb3892749970c097),\n", "(0xb7b9f0d1aaa91069, 0xbb13c62adb209305),\n", "],\n", "[\n", "(0xbc49df1f0f8d2108, 0x3fbc96700bf039e2),\n", "(0xb59b9f4f3b516a10, 0xb900369fa71bf644),\n", "(0x3c39df1f0f8d2108, 0xbfac96700bf039e2),\n", "(0xbbb8cb9fe6e6c906, 0x3f37e5647d30fea8),\n", "(0x3c06397704521ddc, 0x3f73095734a24496),\n", "(0xbb56346f9ac2b6d1, 0xbf0312a4db537d5b),\n", "(0x3bc2ab35cecaca9f, 0xbf24424a96e62373),\n", "(0xbb5dc2fd60429a9d, 0x3eb5b4a6639fb7be),\n", "(0xbb533d879080abe9, 0x3ec712e4d44c4a74),\n", "(0xba8a3e2fc66990c5, 0xbe59917dedf003d7),\n", "(0x3b0b520e9010331b, 0xbe6055757b098917),\n", "(0x3a8b72c27ccfb937, 0x3df2728cdc02e18c),\n", "(0x3a7adc897bdb4467, 0x3def80393fe2fc80),\n", "(0xb9fad4f603343968, 0xbd81fcaa37a8b374),\n", "(0x3a03afc083aed050, 0xbd760225681cd60a),\n", "(0x39753518ad0e9b45, 0x3d0949ef9ee5d1b2),\n", "(0xb979524731c89f4a, 0x3cf74c654a2656ac),\n", "(0x391010895dc3b28c, 0xbc8ad88e518a28d9),\n", "(0xb9155499f6d680c6, 0xbc7353b6d93fd106),\n", "(0x38a0ae7b9e53be9c, 0x3c0646e795fc374a),\n", "(0x3872458a3118ee05, 0x3be9cca80299b7b1),\n", "(0xb81bebc11d5a928d, 0xbb7db0b7e5620486),\n", "(0xb7fe8030136a44be, 0xbb5c4e2a3f8819a4),\n", "(0x379be3a580646aab, 0x3af03c8d0fb251d3),\n", "],\n", "[\n", "(0x359ca6ecae51f0ce, 0x38f785cd60d2c1ed),\n", "(0xbc37a2663626dcab, 0xbfbc28612a3bc18b),\n", "(0xbbf422f2d193784d, 0x3f511f52577ff6ba),\n", "(0x3c3976e0041aa23b, 0x3f92c21da135f56c),\n", "(0xbbc90eddb54be50c, 0xbf26ce18f8229e00),\n", "(0xbbed07e9f503136f, 0xbf4df586d8b786e1),\n", "(0xbb8f298c77e80033, 0x3ee230fede9c5ad4),\n", "(0xbb94e2ce3149cc01, 0x3ef6c2a7558fc928),\n", "(0xbb0453950e023ff5, 0xbe8b97329e667f58),\n", "(0x3b301d8210db0b8e, 0xbe9426ecfd66cd08),\n", "(0xbab764b9a347914a, 0x3e285e012a388a8c),\n", "(0x3aca4092574b7b84, 0x3e27557143798fcd),\n", "(0x3a3440e2c63fef00, 0xbdbc1f9f6fa068be),\n", "(0xba5fe0095953ab69, 0xbdb30842b25be60a),\n", "(0xb9d755f288da184b, 0x3d46d9757263a003),\n", "(0xb9bbfc5a456628aa, 0x3d370aced616e601),\n", "(0xb94bab13fb9e7f92, 0xbccb8986f8682a20),\n", "(0x3943b3e29fa75536, 0xbcb584e49cbf1ef2),\n", "(0x38ea081cc361bec5, 0x3c499540a7d48541),\n", "(0xb8c430149fc9b075, 0x3c2ff0b7143f7ffe),\n", "(0xb853ec9906091bb5, 0xbbc2e028bd3c8a70),\n", "(0xb83e36c66c5cd25b, 0xbba34986a6eaad8f),\n", "(0x37c533e5238e3cf1, 0x3b36a6785a72ecd5),\n", "(0x37a56b5d17159660, 0x3b1352244bd5f525),\n", "],\n", "[\n", "(0x3c58fff4515190b5, 0xbfbbbf246914235f),\n", "(0xb538ee4bd006c414, 0xb8bef99392c87f53),\n", "(0xbc48fff4515190b5, 0x3fabbf246914235f),\n", "(0x3b9cd1da1498a8c8, 0xbf35d923e8470178),\n", "(0xbbfbef9e896a9a49, 0xbf727a96f174b6d1),\n", "(0xbb885ae82e4dfd87, 0x3f01715e4bbb00e7),\n", "(0xbbcb52802ba3fd33, 0x3f23abacdb5106b5),\n", "(0xbb5ee3261cd7bab4, 0xbeb3dc30d27849d7),\n", "(0x3b6dfe5ed028776c, 0xbec6698d6ee99eb9),\n", "(0x3aeb6c016c328002, 0x3e576911a4642dff),\n", "(0xbaedb58a3fa04f2e, 0x3e5fbf415682210b),\n", "(0x3a8ffce5bcffc5e8, 0xbdf0e7d3674631fb),\n", "(0x3a850b7e524d421f, 0xbdeea1cbf2d9d28f),\n", "(0x3a0972a562b54d3c, 0x3d80805ad6510626),\n", "(0x3a139fee7249181d, 0x3d756aaba545a661),\n", "(0xb994ba8b6414df04, 0xbd073ab529b32537),\n", "(0x39993a6f276892ca, 0xbcf6b0b8fe737496),\n", "(0x39299d1bde722fbd, 0x3c88b1cfe8649fd4),\n", "(0x391ed1ce51d7dd6c, 0x3c72d6d686eeb22f),\n", "(0xb8a7b2dc61e1a2b3, 0xbc0486115598b4ec),\n", "(0x38788c9ff45e0eaa, 0xbbe92c11b4ee051b),\n", "(0x380d5cd889980784, 0x3b7b6646fc1094e2),\n", "(0xb7d3fbaf9d9205e6, 0x3b5ba50d4ef914aa),\n", "(0x377a30dc81384d5d, 0xbaee055a0471899a),\n", "],\n", "[\n", "(0xb51bc83c3a0e0aea, 0xb8afa7c9add8202e),\n", "(0x3c5d0edcbac85112, 0x3fbb5a6219b35e14),\n", "(0x3be54c0ba9407e4c, 0xbf4f645fdb1a8c89),\n", "(0x3c37a2e3fd65164b, 0xbf923940d01de8e9),\n", "(0x3bb0148b1871872e, 0x3f24e86a1e6384ff),\n", "(0xbbe17bbc96485963, 0x3f4d1c6a18c7ed95),\n", "(0xbb8c8ebe0fad0153, 0xbee0aeec61621923),\n", "(0xbb99391cbe507ac5, 0xbef61f7d30244338),\n", "(0xbaa992f34ae4f53d, 0x3e8950f781c1c41c),\n", "(0x3b3c536bd805608d, 0x3e93989942e07175),\n", "(0x3acb7edf5e20bddc, 0xbe265fd114ee2251),\n", "(0xbab668c775bebb6a, 0xbe26b3bd4dfd4b81),\n", "(0xba547f4392b0f26c, 0x3db9d8a1bbe00799),\n", "(0xba342c15e8cbe561, 0x3db2875c16e44880),\n", "(0xb9e8058b52e08699, 0xbd4505775bc7f118),\n", "(0x399839569d133457, 0xbd3672e2d4f2963b),\n", "(0x39448b9b5bdc1385, 0x3cc95d609dd374b0),\n", "(0x3922fcd538cfb114, 0x3cb4fb4d36b42032),\n", "(0xb8dba4f56475a1e4, 0xbc4798bab4a35bfe),\n", "(0xb8cbc77ae9cc73f8, 0xbc2f2b65eca95481),\n", "(0x38680bd8b9d2b683, 0x3bc16f8b2574d5ff),\n", "(0xb81bbb799c6ddbe9, 0x3ba2d6d14c18aef1),\n", "(0xb778386cee84a709, 0xbb34f49f286455da),\n", "(0x37858cd2c19af21f, 0xbb12e3e607d95973),\n", "],\n", "[\n", "(0xbc5024304247ada3, 0x3fbaf9cb49c4f935),\n", "(0xb59f12f721a3d64f, 0x38fd67b1800cc2aa),\n", "(0x3c4024304247ada3, 0xbfaaf9cb49c4f935),\n", "(0xbbdc12274808bdaf, 0x3f3413b75ce0cc1b),\n", "(0x3c06b1ae600584f2, 0x3f71f7a8fec6eba8),\n", "(0xbbac4403ae7487a8, 0xbf0008442739ebfc),\n", "(0xbbc9d63344ad0f44, 0xbf23215dab7537c6),\n", "(0xbb3addfeaaf586b0, 0x3eb242e9e6bab199),\n", "(0xbb4ca6d60de07627, 0x3ec5cdc48f5d75eb),\n", "(0x3afbb75278987302, 0xbe5589cf32f43f3a),\n", "(0xbafb7ec07d34bce4, 0xbe5ee5f0d63c1125),\n", "(0x3a7c35d35717242c, 0x3def216eedb0f95e),\n", "(0x3a8f8e312b763d9b, 0x3dedd414a7d8c97f),\n", "(0x3a0cada00b33585e, 0xbd7e69fdff844763),\n", "(0x3a13060575a01497, 0xbd74de15be6889e6),\n", "(0x3953d8e70538cd11, 0x3d056e1418ad8cf1),\n", "(0x399662b0ae22d5ef, 0x3cf61fa985a16926),\n", "(0xb91ad31c7ecc6374, 0xbc86cf250611e72c),\n", "(0xb90005c6530d9799, 0xbc7261f414b70fcc),\n", "(0xb88ee36933bdb2e6, 0x3c02fb5ddae9e3c7),\n", "(0xb876a7ccb4b4f8e6, 0x3be895055837a30a),\n", "(0x37c443af13e1d435, 0xbb7960ab422d80c4),\n", "(0xb7d0c27f905f8955, 0xbb5b052425ccb1af),\n", "(0x37393e1ef7ae32d2, 0x3aebd91e8263d1bb),\n", "],\n", "[\n", "(0xb5841211c9e4fbf8, 0x38e6aabd721697ea),\n", "(0x3c508b7cc7933a75, 0xbfba9d1835947d70),\n", "(0xbbcfb3814e43eef7, 0x3f4cea253049a85b),\n", "(0x3c3e993cf753c741, 0x3f91bb71f665dcdf),\n", "(0x3bc6de474edb7971, 0xbf23427f4797ae90),\n", "(0x3bab43046c577e07, 0xbf4c54a7bd6f30c1),\n", "(0xbb74fee4e6b715a1, 0x3edebe9e65809919),\n", "(0xbb914661eec5967d, 0x3ef58924fa089950),\n", "(0xbb1b1ce67962bafd, 0xbe87564501e7bcdc),\n", "(0xbb32d2083a6e1367, 0xbe9315306e5bb42b),\n", "(0x3abb19a5dd98b1c8, 0x3e24a32382dea2a5),\n", "(0xbacf847c762942f2, 0x3e261e0ee5367a22),\n", "(0xba5d25a1687ec831, 0xbdb7db8537582634),\n", "(0x3a40dc676669750a, 0xbdb20facb4a9bb8b),\n", "(0xb9e774de35526b14, 0x3d436bd6f0001ffb),\n", "(0x39c4a236b9d81483, 0x3d35e552618cbf26),\n", "(0x39679d0392cc254a, 0xbcc7754c8d46f92d),\n", "(0x394ad96fb5f59779, 0xbcb47a92b94007d3),\n", "(0xb8ef6b6af098cfd0, 0x3c45d920844ef181),\n", "(0xb8c4d1cfab1f2a0c, 0x3c2e71f74fd91a7e),\n", "(0xb86232b9682bb59c, 0xbbc02a09e0e77777),\n", "(0xb83a4f51c8d25c89, 0xbba26a7e606b3d3b),\n", "(0x37ac0d8d0af00df2, 0x3b33742f43880b52),\n", "(0x37b2cfe1ad3e0ef1, 0x3b127b3f3a3c24de),\n", "],\n", "[\n", "(0xbc55d35a88f1e0a3, 0xbfba4407e04298d1),\n", "(0xb57a12f3e3faa5bd, 0xb8ebd844c546d1fe),\n", "(0x3c45d35a88f1e0a3, 0x3faa4407e04298d1),\n", "(0xbbdfcf49ead39f19, 0xbf3288694b34ab21),\n", "(0x3c1c3cb8ccc39cf1, 0xbf717f0266db2149),\n", "(0x3b7370deeb1fc99d, 0x3efd9a9a1d05433b),\n", "(0xbbc76ae488c15a1a, 0x3f22a1c916a2d5a1),\n", "(0xbb55855b88c468bb, 0xbeb0dd9e92661e07),\n", "(0xbb0d6efd0446126a, 0xbec53dd972d8f232),\n", "(0x3af0ee48a1c77965, 0x3e53e6e553aac740),\n", "(0xbadd40df09e40809, 0x3e5e1cc65033998a),\n", "(0xba32b59db0216721, 0xbdecc8a3f36b4e82),\n", "(0xba8b62a99a7fbe14, 0xbded152ceac3373c),\n", "(0x3a1c9ccca0c04104, 0x3d7c249e1f309fe3),\n", "(0x3a0ef225196657ba, 0x3d745b3c1804be30),\n", "(0xb9afb28e8d2ffa7d, 0xbd03d90bb0238840),\n", "(0xb97d594b3ede144b, 0xbcf598302ab3ac8a),\n", "(0xb92a26a4f451568c, 0x3c85259cd87cdd6c),\n", "(0xb912f6ad38a9745a, 0x3c71f460abad18ae),\n", "(0x388ed6abd853f84f, 0xbc019e5f6867ef21),\n", "(0xb8739b58b6a444ab, 0xbbe806d32d68c464),\n", "(0x380a7ea4b739cc38, 0x3b77958de1803c3e),\n", "(0x37ef37708fa55952, 0x3b5a6deb944c06b2),\n", "(0xb78f61f40b1c77dc, 0xbae9ea1590f503a9),\n", "],\n", "[\n", "(0x357379a2bd7c52ce, 0xb8fbc8219db67734),\n", "(0x3c2748c82bad8c51, 0x3fb9ee5ee937fc89),\n", "(0x3bebaa9c093c19b6, 0xbf4abf28ad5bf6da),\n", "(0x3bf098a110e151ad, 0xbf9147481084ae0f),\n", "(0xbbcb58642b32be0e, 0x3f21d137345cfee5),\n", "(0x3bdbab7a25ecf8c2, 0x3f4b9c10ddf62464),\n", "(0x3b707cd222ddff83, 0xbedc72c9d49c6d7a),\n", "(0x3b9799bc03c5acb7, 0xbef4fe0b363ccc66),\n", "(0x3b2f6ffbbd8a09bd, 0x3e859a1c336b7506),\n", "(0xbb3843707d4c5068, 0x3e929b6632cc324d),\n", "(0xbaa20857a0292715, 0xbe231cd6e7991df9),\n", "(0xbab28b65ed5397d3, 0xbe25930872001f69),\n", "(0xba5cf09bb859c9ae, 0x3db61befbaafa006),\n", "(0xba2fa8cd2c2d9dc1, 0x3db1a038446ec46c),\n", "(0x39d429e8620217b4, 0xbd42030319ffc086),\n", "(0x39d5f3fcc28971f9, 0xbd35611796700e22),\n", "(0xb921b9f1f88c6b8d, 0x3cc5c664f879c556),\n", "(0x395775c1e2792ff0, 0x3cb401eb6a61fbc2),\n", "(0x38ead4ec597eb512, 0xbc444cf4a7922ede),\n", "(0x389608d2d57a3ecf, 0xbc2dc380c95ab35d),\n", "(0xb85138d52c6d34af, 0x3bbe1244da523859),\n", "(0x3811c5c33ebcb580, 0x3ba2042743d87f84),\n", "(0x37c0000bf1ca678b, 0xbb321df42759daa3),\n", "(0xb7b3e51de8fa1afc, 0xbb1217eed90481cc),\n", "],\n", "[\n", "(0x3c5728ab934a26a0, 0x3fb99be744018c90),\n", "(0x359a217cfc0fd73f, 0x38f8cb0a4bb92b1c),\n", "(0xbc4728ab934a26a0, 0xbfa99be744018c90),\n", "(0xbbc84fc91475651a, 0x3f312d4e1c1ca4c3),\n", "(0x3c0f281d89ca12e4, 0x3f710f5ca51f98b0),\n", "(0x3b9fa3d9c46c2f87, 0xbefb71417476a570),\n", "(0xbb82784bcc79df7f, 0xbf222b9fa8dfd762),\n", "(0xbb2378ade6a74c3f, 0x3eaf471061b7dd7e),\n", "(0x3b688d4663776f74, 0x3ec4b862279de756),\n", "(0x3ae406b21b8c7a34, 0xbe52763f34a53566),\n", "(0xbafcf6291cf32841, 0xbe5d61e605e8e69a),\n", "(0x3a86957e31ae2fc6, 0x3deab7331a682502),\n", "(0x3a8a902f91e8c962, 0x3dec637428f3fda4),\n", "(0x39f24e732a100c1c, 0xbd7a236ad0b3eb49),\n", "(0xba105ad2fccf3d78, 0xbd73e11cef6eae93),\n", "(0xb995c95ce2902dca, 0x3d0272cbaef43092),\n", "(0xb995e32a69772db7, 0x3cf519623b4e50ac),\n", "(0xb9292fc5f6cbd421, 0xbc83ac6109d4a7c0),\n", "(0xb916701f83b25b26, 0xbc718d7ac32164f8),\n", "(0xb8a62d82d427d871, 0x3c0068369bb2c654),\n", "(0x388344bf0ff0ace9, 0x3be780d0943d0646),\n", "(0xb7f8d6f94baf1bf3, 0xbb75fc6a10345edb),\n", "(0xb7d82ddcd0a763ae, 0xbb59ded950660f9a),\n", "(0x378e6b4fc0afac52, 0x3ae82fa57e04df35),\n", "],\n", "[\n", "(0xb59824ff875a6f4d, 0xb8fef5ad62580f34),\n", "(0xbc4e31356cad466d, 0xbfb94c6f54aef04b),\n", "(0xbbe68528f64c6571, 0x3f48d6371f018ef0),\n", "(0xbbf705a06948ad50, 0x3f90db975fd7dc47),\n", "(0x3bc06e812fbec708, 0xbf208bd1634353c9),\n", "(0x3beeb410edf15681, 0xbf4af0d3d4cd140d),\n", "(0x3b6d81ec6351ba6b, 0x3eda6c8e7c9d023e),\n", "(0xbb94f5f0c3884299, 0x3ef47cddcdac15d7),\n", "(0xbaee0980702c7029, 0xbe8412394fc50e0a),\n", "(0xbb3fb63544124d21, 0xbe922a21cb1edfe9),\n", "(0xbac10c16da7fd9d1, 0x3e21c417dedcf50f),\n", "(0xbaadc343b535f5ab, 0x3e25117f3061daaa),\n", "(0xba52f41f6480b3af, 0xbdb49009a6c8ef27),\n", "(0xba1394b790b42720, 0xbdb13823dda87c57),\n", "(0x39ecf2b99857d12c, 0x3d40c350b60502a2),\n", "(0x39d16c5f3587dedc, 0x3d34e54a89ae3a78),\n", "(0xb96e84c18fd85bb6, 0xbcc447dde87e69d6),\n", "(0xb92fa9fc1fe799a6, 0xbcb3909fa7a78345),\n", "(0x38e1d450f52eeca1, 0x3c42ec7e57d796d5),\n", "(0x38bc5414c0376e8d, 0x3c2d1f245967f392),\n", "(0x384f6a4fc5c93b04, 0xbbbc0ef954471f60),\n", "(0xb8436aa08a547d96, 0xbba1a364a86e2ed4),\n", "(0xb7c059ecba8db4c0, 0x3b30ebf4b4f1127f),\n", "(0xb792d76142a8ff7b, 0x3b11b9abb3510b7f),\n", "],\n", "[\n", "(0x3c5e213a1a4b3671, 0xbfb8ffc9bd24fe08),\n", "(0x3568e6cd71e05784, 0xb8c846638d0f2565),\n", "(0xbc4e213a1a4b3671, 0x3fa8ffc9bd24fe08),\n", "(0xbbcd36327411471d, 0xbf2ff51b38eef42c),\n", "(0xbc0f532ddb23dab4, 0xbf70a7a725d3fbc4),\n", "(0xbb834bf088b48836, 0x3ef988128728122a),\n", "(0xbbb5bd608899de58, 0x3f21bdc846a09e43),\n", "(0x3b3013850114c517, 0xbead1b60a4812ac4),\n", "(0xbb5a77447ea6fe43, 0xbec43c2d8e698c10),\n", "(0x3ad8023dfb41774f, 0x3e512fd6ccdafecc),\n", "(0xbaf62e671fb10d65, 0x3e5cb3bb8802e835),\n", "(0xba859d9d3a171da7, 0xbde8e1dd09a92324),\n", "(0x3a8ce00fffe0e74e, 0xbdebbd84404b6237),\n", "(0x3a0700486612292d, 0x3d785bcfd7db3db0),\n", "(0x3a131220e196908b, 0x3d736ed760739d88),\n", "(0x399d6eab7135136a, 0xbd01343464751bc4),\n", "(0x399a9e6748bc0bea, 0xbcf4a26ef2219c2c),\n", "(0x3916fec76005e868, 0x3c825c3fff5cf7ca),\n", "(0xb8f4e1647a2b0045, 0x3c712caee4bc257a),\n", "(0xb895bdf1f04f1575, 0xbbfea67f8d5490ce),\n", "(0x388017eb7fef7e93, 0xbbe7025c0acb6ed2),\n", "(0xb80d402134b327c6, 0x3b748e326c33fa45),\n", "(0xb7f36f706b3d34ec, 0x3b595763182ec3fa),\n", "(0xb77ee821070f844b, 0xbae6a29de364d58e),\n", "],\n", "[\n", "(0xb52b322a93406970, 0xb8e11567e5257506),\n", "(0x3c35e8738ef1b9ca, 0x3fb8b5ccad12d632),\n", "(0xbbd18507f867922a, 0xbf4724d0185980d2),\n", "(0x3c1f6ab95e49bd79, 0xbf907764ae2b1eeb),\n", "(0x3bbea971bec7b60e, 0x3f1ed6acc18fdf29),\n", "(0x3bca7600bd731e34, 0x3f4a51693df2efbb),\n", "(0x3b5424c5adeb27a5, 0xbed8a0ec61e4df7b),\n", "(0xbb2fcebf02eeb8d6, 0xbef4047f31fae045),\n", "(0xbb244d41e0ecfe16, 0x3e82b668af276950),\n", "(0x3b3cad4603e7028e, 0x3e91c07467ed6403),\n", "(0xbac9f09027e17c0c, 0xbe2091d32eea7f0f),\n", "(0xbacf61c0a2077065, 0xbe24987294de7d1e),\n", "(0x3a4c64cfb1cdc317, 0x3db32fe6ab220655),\n", "(0xba52d5ac79807dc5, 0x3db0d6b127f8ac22),\n", "(0x39d08853ae95a955, 0xbd3f4d16b8cb00ea),\n", "(0x39c9258c596bcdf2, 0xbd34711e3d50f99d),\n", "(0xb9607956efca23e8, 0x3cc2f28e5de9b115),\n", "(0x394e73cc5f03a293, 0x3cb326098eabb602),\n", "(0x38c9a844bf92f26d, 0xbc41b1699659661e),\n", "(0x38c79ee3937d0522, 0xbc2c84136a790cfd),\n", "(0xb84d287adf77e7fa, 0x3bba415dab11fbcc),\n", "(0x3843b689e4f1e579, 0x3ba147d23398faea),\n", "(0x37b913ca23ec4cc0, 0xbb2fb26f3c616548),\n", "(0x37a819aab969975c, 0xbb1160299cd9ebeb),\n", "],\n", "[\n", "(0x3c5b1c9821974148, 0x3fb86e51be0a9153),\n", "(0xb5720ba7256e1fdc, 0x38ee1da34bfeb8e0),\n", "(0xbc4b1c9821974148, 0xbfa86e51be0a9153),\n", "(0xbbcc79e50a2dc677, 0x3f2dd3c244b53279),\n", "(0xbbe9cfc1363faa0e, 0x3f7046fc5a218a86),\n", "(0x3b47339108bed763, 0xbef7d51accbfba76),\n", "(0x3bbac27d1a98311f, 0xbf2157556c0e1b1a),\n", "(0xbb2e6885549f0df6, 0x3eab2d01c12c8227),\n", "(0xbb685c37a3fcd2ca, 0x3ec3c838897d0a1e),\n", "(0xbaf6ac2b47952135, 0xbe500d37aa536a8b),\n", "(0x3afe13ef178fd248, 0xbe5c10ecf088eac6),\n", "(0x3a640bc972bc618d, 0x3de73f8d1af57f4c),\n", "(0xba7d1502b5443bc9, 0x3deb2227fe94022c),\n", "(0xba0e6bfbee228ee6, 0xbd76c5390bcf017b),\n", "(0xba1975f49279a432, 0xbd7303a6ded9ee03),\n", "(0x399abf56810fc89c, 0x3d0017772c8c0084),\n", "(0x399af156baca0aee, 0x3cf4329cf32bcb6e),\n", "(0xb9219214145d8323, 0xbc812f535b46fd28),\n", "(0x3904bff1857123e5, 0xbc70d1776a208c18),\n", "(0x3888ba3ef05e5fd1, 0x3bfcb5a589ad0a5c),\n", "(0x3871815404beb4a9, 0x3be68adf143f5d78),\n", "(0xb8166a2869445d1c, 0xbb734508c6e2f203),\n", "(0x37edd1f20932a7cc, 0xbb58d702f0f1cb76),\n", "(0xb774cc6cd565f7bf, 0x3ae53cf6ad4248fb),\n", "],\n", "[\n", "(0x3586adcfc24a15bd, 0x38fb4b40fa7659d2),\n", "(0x3c40ee4d5b1b8050, 0xbfb829356999a097),\n", "(0x3be3831592c6b168, 0x3f45a280e033eb59),\n", "(0x3c215c764657672c, 0x3f9019dba8336e48),\n", "(0x3b986e85a6375663, 0xbf1cd4559d95e619),\n", "(0xbbc0173a9412da83, 0xbf49bc857750335e),\n", "(0xbb63dae6774006f7, 0x3ed70706580693f9),\n", "(0x3b838496a72af1a4, 0x3ef393fc6cf8481f),\n", "(0xbaf56d91a42ef902, 0xbe81800af4665cb3),\n", "(0xbb2c21f37756b0a2, 0xbe915d91a2289a30),\n", "(0x3aa04b0681616769, 0x3e1f009c83572407),\n", "(0x3ab8eb4169a44614, 0x3e2427054565b344),\n", "(0xba4aede413980977, 0xbdb1f5167f464cc6),\n", "(0xba42c3010298ffea, 0xbdb07b3a2cb21729),\n", "(0xb9d5250b5c48f994, 0x3d3d4f453474d39c),\n", "(0x39d7de25bab32cb7, 0x3d3403dd864ce1b5),\n", "(0xb959c7b70a761729, 0xbcc1c096935c0515),\n", "(0x3949cfca62e35a95, 0xbcb2c193ec80c816),\n", "(0x38d72ce5fb9c0118, 0x3c40967d8ee82f54),\n", "(0x38b2d922c1971637, 0x3c2bf18fd1afe1de),\n", "(0x385409db53827004, 0xbbb8a21d0c689575),\n", "(0x384dc5f7e6e04311, 0xbba0f11083b9c847),\n", "(0x37ce8f2e696187cf, 0x3b2dc3272d23ffd6),\n", "(0xb7b0e86cfd0bfa4f, 0x3b110b1caef3d73d),\n", "],\n", "[\n", "(0x3c21907f595a082a, 0xbfb7e656efb009ae),\n", "(0xb590e3abdd6e7404, 0x38f3c9c05fc68dd7),\n", "(0xbc11907f595a082a, 0x3fa7e656efb009ae),\n", "(0x3bcce5fd1ce6de53, 0xbf2bec6b33efcb49),\n", "(0x3bcf8f1c9736150f, 0xbf6fd932c26aad94),\n", "(0x3b80b8964c190cdc, 0x3ef6504d7e054d50),\n", "(0xbbb3c0e77f493518, 0x3f20f77ce6105150),\n", "(0x3b3d95fb56d1d86f, 0xbea972e573db9593),\n", "(0x3b44588b63a38eb3, 0xbec35ba58bf2f993),\n", "(0x3ad1cbaf2f9e7b25, 0x3e4e1246a53112c6),\n", "(0xbac8e1b1b14782dd, 0x3e5b7850b3bc8175),\n", "(0xba87c131e73bb3fd, 0xbde5c8dcec477a4e),\n", "(0xba84c1608c9f12fa, 0xbdea905348b4924d),\n", "(0x39e529efb683a910, 0x3d7558a1f12cdd3f),\n", "(0x3a18c3b5cbcd2fee, 0x3d729edf3b2865f3),\n", "(0x399e9dec38211b14, 0xbcfe2f9cdddbe89c),\n", "(0x3991f206b8c5d3a1, 0xbcf3c947b936c2fd),\n", "(0xb926d15a781493eb, 0x3c8020bb8706a05b),\n", "(0x391b89b4941b2fbc, 0x3c707b5bb2f1e971),\n", "(0x3875331d8b43e31b, 0xbbfaf6220e4137a4),\n", "(0x388fbf932efdfa5c, 0xbbe619cedd775137),\n", "(0xb7f15f7042e6e287, 0x3b721c04bebc0bb5),\n", "(0x37f3601b48c231f4, 0x3b585d398a9b6f0b),\n", "(0x378dd18a95cb152b, 0xbae3f99b23077622),\n", "],\n", "[\n", "(0x352bf89ec4e05302, 0x38c2beead70ae7d0),\n", "(0xbc529270d2a71e91, 0x3fb7a597e9550934),\n", "(0xbbd42472048d4fe5, 0xbf44486c0b012534),\n", "(0xbc2ac52ac4327de6, 0xbf8f848eec0e0e6b),\n", "(0x3b684f34372ed852, 0x3f1b077fae06adc6),\n", "(0xbbce518d0a756962, 0x3f49310d6e6842c6),\n", "(0x3b230b8888fa2afa, 0xbed597a5befbd70e),\n", "(0x3b9e1e12047ef68f, 0xbef32a855e4e113b),\n", "(0xbb1d73ebaa41845b, 0x3e8069ba0b1a612d),\n", "(0xbb3a5058b2aec6be, 0x3e9100c97ba8e22d),\n", "(0xbab085381e3747da, 0xbe1d15b5350404fa),\n", "(0x3ac28b1288705592, 0xbe23bc775cca4413),\n", "(0x3a5ffd971088266f, 0x3db0da51f94c98f0),\n", "(0x3a5dfce6ace7ab08, 0x3db0252dc33a4d7a),\n", "(0xb9dc3fdc25aa9e9a, 0xbd3b84d751a36bd2),\n", "(0x39b47e26246286bb, 0xbd339ce8224cc6de),\n", "(0x395a80d541531404, 0x3cc0ad1ba9d01451),\n", "(0xb95b7f3b36aa04cc, 0x3cb262b8db934833),\n", "(0x38dc5e49fddd8fdf, 0xbc3f2ec77da02f0e),\n", "(0x38a348be97d223b5, 0xbc2b66ebaf597acc),\n", "(0x385369dda16c7b7d, 0x3bb72b1780503c41),\n", "(0x3840d18df6c3b214, 0x3ba09ec633447fba),\n", "(0xb7afbf9889f21003, 0xbb2c0312119c246e),\n", "(0xb7bc1892f4c2e089, 0xbb10ba3b452a59bb),\n", "],\n", "];\n" ] } ], "source": [ "# J0 coeffs\n", "mp.prec = 180\n", "def print_taylor_coeffs(poly):\n", " print(\"[\")\n", " for i in range(0, 24):\n", " coeff = poly[i]\n", " print_double_double(\"\", coeff)\n", " # print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "def print_taylor_coeffs_dyad(poly):\n", " print(\"[\")\n", " for i in range(0, 24):\n", " coeff = poly[i]\n", " print_dyadic(coeff)\n", " print(\"],\")\n", "\n", "print(f\"pub(crate) static J0_COEFFS: [[(u64, u64); 24]; {len(j0_zeros)}] = [\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(j0_zeros)):\n", " k_range = j0_zeros[i]\n", " range_diff = k_range - prev_zero\n", "\n", " mp.prec = 180\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, j0, taylor\n", " poly = taylor(lambda val: j0(val), x0, 24)\n", " print_taylor_coeffs(poly)\n", " # print(poly)\n", " prev_zero = j0_zeros[i]\n", "\n", "print(\"];\")\n", "\n", "# print(f\"pub(crate) static J0_COEFFS_RATIONAL128: [[DyadicFloat128; 24]; {len(j0_zeros)}] = [\")\n", "\n", "# prev_zero = 0\n", "\n", "# for i in range(0, len(j0_zeros)):\n", "# k_range = j0_zeros[i]\n", "# range_diff = k_range - prev_zero\n", "\n", "# mp.prec = 180\n", "# x0 = mp.mpf(k_range)\n", "# from mpmath import mp, j0, taylor\n", "# poly = taylor(lambda val: j0(val), x0, 24)\n", "# print_taylor_coeffs_dyad(poly)\n", "# # print(poly)\n", "# prev_zero = j0_zeros[i]\n", "\n", "# print(\"];\")" ] }, { "cell_type": "code", "execution_count": 17, "id": "d48973f7-ca04-4ff7-aeba-4b9daf339ec8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "];\n" ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = (zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(j0_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 500;\n", "bessel_j0 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_j0(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "def print_remez_coeffs(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " print_dyadic(coeff)\n", " # print_double_double(\"\", coeff)\n", " print(\"],\")\n", "\n", "degree = 23\n", "\n", "print(f\"pub(crate) static J0_COEFFS_RATIONAL128_REMEZ: [[(u64, u64); {degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_remez_coeffs(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "da023288-fa9d-4df1-a3bc-6e1f0feb77b4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "const J0_MACLAURIN_SERIES: [(u64, u64); 12] = [\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -129,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -133,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -139,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -145,\n", " mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -151,\n", " mantissa: 0x91a2b3c4_d5e6f809_1a2b3c4d_5e6f8092_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -158,\n", " mantissa: 0x81742e04_4c5b8724_8909fcb6_8cd4e410_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -166,\n", " mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -174,\n", " mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -182,\n", " mantissa: 0x85989944_df05c4ef_b7cce721_23e1b391_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -191,\n", " mantissa: 0xab00c42f_31f2e799_3d2f3c53_6120e5d8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -200,\n", " mantissa: 0xb4e54e79_dbfa9c23_29738e18_bb602809_u128,\n", "},\n", "];\n", "[mpf('1.0'), mpf('0.0'), mpf('-0.25'), mpf('0.0'), mpf('0.015625'), mpf('0.0'), mpf('-0.00043402777777777777777777777777777777777777777777777777781'), mpf('0.0'), mpf('0.0000067816840277777777777777777777777777777777777777777777783'), mpf('0.0'), mpf('-0.000000067816840277777777777777777777777777777777777777777777811'), mpf('0.0'), mpf('0.00000000047095027970679012345679012345679012345679012345679012355'), mpf('0.0'), mpf('-0.0000000000024028075495244394053917863441672965482489292013101536921'), mpf('0.0'), mpf('0.0000000000000093859669903298414273116654069035021415973796926177878599'), mpf('0.0'), mpf('-0.000000000000000028969033920771115516394029033652784387646233619190703257'), mpf('0.0'), mpf('7.2422584801927788790985072584131960969115584047976758145e-20'), mpf('0.0'), mpf('-1.4963343967340452229542370368622305985354459514044784741e-22'), mpf('0.0'), mpf('2.597802772107717400962217077885817011346260332299441796e-25')]\n" ] } ], "source": [ "mp.prec = 180\n", "def print_expansion_at_0():\n", " print(f\"const J0_MACLAURIN_SERIES: [(u64, u64); 12] = [\")\n", " from mpmath import mp, j0, taylor\n", " poly = taylor(lambda val: j0(val), 0, 24)\n", " # print(poly)\n", " real_i = 0\n", " for i in range(0, 24, 2):\n", " print_dyadic(DD(poly[i]))\n", " # print_double_double(\"\", DD(poly[i]))\n", " real_i = real_i + 1\n", " print(\"];\")\n", " print(poly)\n", "\n", "print_expansion_at_0()" ] }, { "cell_type": "code", "execution_count": null, "id": "74ae22c1-3114-4010-9d4e-be9bb7fb0e20", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_j1_asympt.ipynb000064400000000000000000001174171046102023000163330ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 2, "id": "4a50b3ce-5d3f-43f3-9454-0127987c07e5", "metadata": {}, "outputs": [], "source": [ "def binomial_like(n, m):\n", " prod = QQ(1)\n", " z = QQ(4)*(n**2)\n", " for k in range(1,m + 1):\n", " prod *= (z - (2*k - 1)**2)\n", " return prod / (QQ(2)**(2*m) * (ZZ(m).factorial()))\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "2ee599ca-7277-4cb7-9398-406dd856826e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "alpha series coefficients\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -129,\n", " mantissa: 0xc0000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xa8000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -129,\n", " mantissa: 0xbde66666_66666666_66666666_66666666_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0x97a436db_6db6db6d_b6db6db6_db6db6db_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -123,\n", " mantissa: 0xf4fdfa00_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -118,\n", " mantissa: 0xa4cbdaac_a2e8ba2e_8ba2e8ba_2e8ba2e9_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -113,\n", " mantissa: 0xa548a0ca_934ec4ec_4ec4ec4e_c4ec4ec5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -108,\n", " mantissa: 0xe68da9c0_b5760666_66666666_66666666_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -102,\n", " mantissa: 0xd5204aea_0c9a8879_69696969_69696969_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -96,\n", " mantissa: 0xfc04982f_88dce9e0_ca50d794_35e50d79_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -89,\n", " mantissa: 0xb973404f_6b0c58ff_c5b90000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -82,\n", " mantissa: 0xa62db02b_c1cfc563_44ea32e9_0b21642d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -75,\n", " mantissa: 0xb220e7ff_443c1584_7e85f4e0_55eb851f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -68,\n", " mantissa: 0xe10a255c_ca5e68cc_00c2d6c0_acdc8000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -60,\n", " mantissa: 0xa573790c_5186f23b_5db502ea_d9fa5432_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -52,\n", " mantissa: 0x8c0ffedc_407a7015_453df84e_9c3f1d39_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -44,\n", " mantissa: 0x874226ed_c298a17a_d8c49a4e_dc9281a5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -36,\n", " mantissa: 0x93cab36c_9ab9495c_310fa9cd_4b065359_u128,\n", "},\n", "beta series\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -127,\n", " mantissa: 0x80000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -130,\n", " mantissa: 0xc0000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -130,\n", " mantissa: 0xc6000000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0xce280000_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -125,\n", " mantissa: 0xf7adb400_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -120,\n", " mantissa: 0x84c306ea_00000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -116,\n", " mantissa: 0xdd74dbd0_37000000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -110,\n", " mantissa: 0x84388ea0_e0a14000_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -105,\n", " mantissa: 0xd5b80b26_45f372f4_00000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -99,\n", " mantissa: 0xe082af12_794bf6f1_e1000000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -92,\n", " mantissa: 0x94a06149_f30146bc_fe8ed000_00000000_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -86,\n", " mantissa: 0xf212edfc_42a62526_4fac2b0c_00000000_u128,\n", "},\n" ] } ], "source": [ "from scipy.special import j1\n", "from scipy.optimize import brentq\n", "from sage.all import *\n", "import struct\n", "\n", "var('n m x Z')\n", "\n", "DD = RealField(200)\n", "\n", "def triple_double_split(x):\n", " f64 = RealField(53)\n", " hi = f64(x) \n", " rem1 = x - RealField(300)(hi)\n", " med = f64(rem1) \n", " rem2 = rem1 - RealField(300)(med)\n", " lo = f64(rem2) \n", " return (lo, med, hi)\n", "\n", "def dyadic256_from(sign, exponent, mantissa):\n", " R = RealField(256)\n", " mant = Integer(mantissa)\n", " val = QQ(sign * mant) * QQ(1) / (2 ** -exponent) # = mant * 2^exponent\n", " return R(val)\n", "\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")\n", "\n", "def print_dyadic256(value):\n", " (s, m, e) = RealField(256)(value).sign_mantissa_exponent();\n", " mask_128 = (1 << 128) - 1\n", " lo = m & mask_128\n", " hi = m >> 128\n", " print(\"DyadicFloat256 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: u256 {{\")\n", " print(f\" hi: {format_dyadic_hex(hi)},\")\n", " print(f\" lo: {format_dyadic_hex(lo)},\")\n", " print(f\" }}\")\n", " print(\"},\")\n", "\n", "# Expansion for P_n(x)\n", "def Pn_asymptotic(n, x, terms=10):\n", " return sum( (-1)**m * binomial_like(n, 2*m) / ((RealField(500)(2)*RealField(500)(x))**(2*m)) for m in range(0, terms) )\n", "\n", "# Expansion for Q_n(x)\n", "def Qn_asymptotic(n, x, terms=10):\n", " return sum( (-1)**m * binomial_like(n, 2*m + 1) / ((RealField(500)(2)*RealField(500)(x))**(2*m + 1)) for m in range(terms) )\n", "\n", "def double_to_hex(f):\n", " # Converts Python float (f64) to hex string\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " from sage.rings.real_mpfr import RRtoRR\n", " f = RRtoRR(RealField(190), RealField(53))\n", " x_hi = f(x) # convert to f64\n", " x_lo = f(x - RealField(190)(x_hi))\n", " return (float(x_lo),float(x_hi))\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = triple_double_split(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)\n", "x = R.gen()\n", "\n", "def Pn_asymptotic(n, y, terms=10):\n", " # now y = 1/x\n", " return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) )\n", "\n", "def Qn_asymptotic(n, y, terms=10):\n", " return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) )\n", "\n", "P = Pn_asymptotic(1, x, 50)\n", "Q = Qn_asymptotic(1, x, 50)\n", "\n", "R_series = (-Q/P)\n", "\n", "arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)])\n", "\n", "alpha0_computed = arctan_series_Z(R_series)\n", "# print(alpha0_computed)\n", "print(\"alpha series coefficients\")\n", "for i in range(alpha0_computed.prec()):\n", " if i > 36:\n", " break\n", " coeff = alpha0_computed[i]\n", " if coeff != 0:\n", "# print_dyadic256(RealField(300)(f\"{coeff}\"))\n", " # if i < 16:\n", " # print(f\"\\\"{RealField(300)(f\"{coeff}\")}\\\",\")\n", " print_dyadic(RealField(300)(f\"{coeff}\"))\n", " # else:\n", " # print(f\"{double_to_hex(coeff)},\")\n", "\n", "exps = alpha0_computed.exponents()\n", "coeffs = alpha0_computed.coefficients()\n", "\n", "def sqrt_series(s):\n", " val = S.valuation()\n", " lc = S[val] # Leading coefficient\n", " b = lc.sqrt() * x**(val // 2)\n", " \n", " for _ in range(5):\n", " b = (b + S / b) / 2\n", " b = b\n", " return b\n", "\n", "S = (P**2 + Q**2).truncate(50)\n", "\n", "b = sqrt_series(S).truncate(30)\n", "\n", "# print(b)\n", "\n", "print(\"beta series\")\n", "for i in range(24):\n", " coeff = b[i]\n", " if coeff != 0:\n", " # print(double_to_hex(RealField(300)(f\"{coeff}\")) + \",\")\n", " print_dyadic(RealField(300)(f\"{coeff}\"))\n", " # print_double_double(\"\", RealField(300)(f\"{coeff}\"))\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "090ac030-e8b3-4e92-9589-3f0847559bed", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n=4, term=3.13e-7, bits ≈ 21.605667854578722504886316284327550652688482798793625630461\n", "n=5, term=1.76e-9, bits ≈ 29.084035309158744625346903596501636816843960639507303201141\n", "n=6, term=6.95e-12, bits ≈ 37.066445269076355483588360030665051088819626370998150518448\n", "n=7, term=2.04e-14, bits ≈ 45.477698527797840636745292557292991611672713719688681861948\n", "n=8, term=4.63e-17, bits ≈ 54.262169110103542561390263404062298995271395924040831437387\n", "n=9, term=8.35e-20, bits ≈ 63.377029366044802934482165550823669465071947231094656460192\n", "n=10, term=1.23e-22, bits ≈ 72.788282624766288087639098077451609987925034579785187803693\n", "n=11, term=1.49e-25, bits ≈ 82.468283940515960732523514204298974820714506152916839821812\n", "n=12, term=1.54e-28, bits ≈ 92.394110372067204126108796843184474710791398268665810993690\n", "n=13, term=1.35e-31, bits ≈ 102.54644533342712734725773116524352200028669281554162043191\n", "n=14, term=1.03e-34, bits ≈ 112.90878899166766609181037864306224060099199486359102715095\n", "n=15, term=6.80e-38, bits ≈ 123.46688363871842234633146545163390473875307790791179837964\n", "n=16, term=3.97e-41, bits ≈ 134.20828549913223830037547227826641723580353876329337639872\n", "n=17, term=2.06e-44, bits ≈ 145.12203909838290668033273187175694560390807898663624736989\n", "n=18, term=9.54e-48, bits ≈ 156.19842520650953134148891877322465715077654769370072642687\n", "n=19, term=3.97e-51, bits ≈ 167.42876267987072769352389463029490584544572099485310775876\n" ] } ], "source": [ "from math import pi, factorial\n", "\n", "x = DD(pi) / 128\n", "target_error = 2**-240\n", "\n", "for n in range(4, 20):\n", " term = x**(2*n+1) / factorial(2*n+1)\n", " print(f\"n={n}, term={term:.2e}, bits ≈ {-abs(term).log2() if term != 0 else 999}\")\n", " if term < target_error:\n", " break\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "eca32373-ba9a-4350-a030-8370410dbe17", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0x0000000000000000, 0x3ff0000000000000),\n", "(0x0000000000000000, 0xbfe0000000000000),\n", "(0x3c45555555555555, 0x3fa5555555555555),\n", "(0x3bef49f49f49f49f, 0xbf56c16c16c16c17),\n", "(0x3b3a01a01a01a01a, 0x3efa01a01a01a01a),\n", "(0xbb3cbbc05b4fa99a, 0xbe927e4fb7789f5c),\n", "(0xbac2aec959e14c06, 0x3e21eed8eff8d898),\n", "(0xba305d6f8a2efd1f, 0xbda93974a8c07c9d),\n", "(0x39a1d8656b0ee8cb, 0x3d2ae7f3e733b81f),\n", "(0xb94eec01221a8b0b, 0xbca6827863b97d97),\n", "(0x387ea72b4afe3c2f, 0x3c1e542ba4020225),\n", "(0x383aebcdbd20331c, 0xbb90ce396db7f853),\n", "(0xb789ada5fcc1ab14, 0x3aff2cf01972f578),\n", "(0x37071c37ebd16540, 0xba688e85fc6a4e5a),\n" ] } ], "source": [ "roll = false\n", "for i in range(0, 28, 2):\n", " if roll:\n", " print_double_double(\"\", -RealField(300)(1)/RealField(300)(factorial(i)))\n", " else:\n", " print_double_double(\"\", RealField(300)(1)/RealField(300)(factorial(i)))\n", " roll = not roll" ] }, { "cell_type": "code", "execution_count": 73, "id": "7a62032f-775a-4476-99f4-6ff952f7be48", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static SIN_K_PI_OVER_128_F256: [DyadicFloat256; 65] = [\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: 0,\n", " mantissa: u256 {\n", " hi: 0x0_u128,\n", " lo: 0x0_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -261,\n", " mantissa: u256 {\n", " hi: 0xc90aafbd_1b33efc9_c539edcb_fda0cf2c_u128,\n", " lo: 0x4ca5f3c3_54a11581_9e635806_dbd038d5_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -260,\n", " mantissa: u256 {\n", " hi: 0xc8fb2f88_6ec09f37_6a17954b_2b7c5171_u128,\n", " lo: 0x216769fc_da0d0ebf_36fc97b1_fef1fdeb_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -259,\n", " mantissa: u256 {\n", " hi: 0x96a90496_70cfae65_f7757409_4d3c35c4_u128,\n", " lo: 0x12930f6d_ba22f08a_dc9c4943_ba9bd204_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -259,\n", " mantissa: u256 {\n", " hi: 0xc8bd35e1_4da15f0e_c7396c89_4bbf7389_u128,\n", " lo: 0x81840854_6ee849ec_d5f082ff_07df518_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -259,\n", " mantissa: u256 {\n", " hi: 0xfab272b5_4b9871a2_704729ae_56d78a37_u128,\n", " lo: 0x1213a3bd_376798f7_864535f8_9d091487_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -258,\n", " mantissa: u256 {\n", " hi: 0x96408374_7309d113_000a89a1_1e07c1fe_u128,\n", " lo: 0x7f850122_f9e1b840_f1bdc9c1_ac652e22_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -258,\n", " mantissa: u256 {\n", " hi: 0xaf10a224_59fe32a6_3feef3bb_58b1f10c_u128,\n", " lo: 0x8f568ae3_70780d07_70cbee14_1e9d4ed6_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -258,\n", " mantissa: u256 {\n", " hi: 0xc7c5c1e3_4d3055b2_5cc8c00e_4fccd84f_u128,\n", " lo: 0xce539634_4a5cbc74_e50e1d9e_25505307_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -258,\n", " mantissa: u256 {\n", " hi: 0xe05c1353_f27b17e5_0ebc61ad_e6ca83cc_u128,\n", " lo: 0xb26e0071_a479c6ee_04edc5b9_c415799d_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -258,\n", " mantissa: u256 {\n", " hi: 0xf8cfcbd9_0af8d57a_4221dc4b_a772598d_u128,\n", " lo: 0x5600217e_70891ecd_db3bb977_b9b4b553_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0x888e9315_8fb3bb04_984156f5_53344305_u128,\n", " lo: 0xee6a6256_8eee784c_d4dc74c1_fb5c711c_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0x94a03176_acf82d45_ae4ba773_da6bf753_u128,\n", " lo: 0x8e0a682e_37ed1502_38ac3d47_ca109385_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xa09ae4a0_bb300a19_2f895f44_a303cc0a_u128,\n", " lo: 0xf6141485_e8b8837a_c912a50b_e56fd2a0_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xac7cd3ad_58fee7f0_811f9539_84eff83e_u128,\n", " lo: 0x342af9db_36a9c8a9_c3cb6eab_70522ab1_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xb8442987_d22cf576_9cc3ef36_746de3b7_u128,\n", " lo: 0xdeea8efe_bb770256_56fa1d40_0a4367b4_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xc3ef1535_754b168d_3122c2a5_9efddc37_u128,\n", " lo: 0x7be3eb69_567bc498_74782b20_c4e31ee3_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xcf7bca1d_476c516d_a81290bd_baad62e4_u128,\n", " lo: 0x2dfd8b0d_c011c592_ed9183a4_39f71a88_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xdae8804f_0ae6015b_362cb974_182e3030_u128,\n", " lo: 0x83ce50f3_e5985153_655ff4d3_8d27a27_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xe63374c9_8e22f0b4_2872ce1b_fc7ad1cc_u128,\n", " lo: 0xb4b928a7_f4494a68_97edc1ca_ecd3ac71_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xf15ae9c0_37b1d8f0_6c48e9e3_420b0f1d_u128,\n", " lo: 0xad155b05_3b5941a1_950339da_70b97314_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xfc5d26df_c4d5cfda_27c07c91_1290b8d1_u128,\n", " lo: 0x6ab5c209_ae2f4097_a6f50ff4_8b9d0717_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0x839c3cc9_17ff6cb4_bfd79717_f2880abe_u128,\n", " lo: 0xd6bc7fe5_7653aec3_2d3bfe70_d9ab409a_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0x88f59aa0_da591421_b892ca83_61d8c84c_u128,\n", " lo: 0x1ddc902c_4a28d838_5c00d180_c7655a2a_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0x8e39d9cd_73464364_bba4cfec_bff54867_u128,\n", " lo: 0x7ca7d749_adfba33e_ca996068_c296fd79_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0x93682a66_e896f544_b1782191_1e71c16e_u128,\n", " lo: 0x44b562fe_29a53a66_7ad1253f_5ec14ff0_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0x987fbfe7_0b81a708_19cec845_ac87a5c6_u128,\n", " lo: 0x6b714df5_a5e72d4f_1d9ce3a2_743a1804_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0x9d7fd149_0285c9e3_e25e3954_9638ae67_u128,\n", " lo: 0x87424855_daf5d9f3_21f5f9a3_921b151f_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xa2679928_48eeb0c0_3b5167ee_359a234d_u128,\n", " lo: 0xc381700b_df757600_04c7b378_b215b01e_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xa73655df_1f2f489e_149f6e75_993468a2_u128,\n", " lo: 0x9aab00f4_88eea6ad_3d517247_a54a9ea9_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xabeb49a4_6764fd15_1becda80_89c1a94c_u128,\n", " lo: 0x2fd0f385_9abecff4_64742ca4_28c80c16_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xb085baa8_e966f6da_e4cad00d_5c94bcd1_u128,\n", " lo: 0xa642438d_ce55e433_c0570800_fb967a6c_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xb504f333_f9de6484_597d89b3_754abe9f_u128,\n", " lo: 0x1d6f60ba_893ba84c_ed17ac85_83339915_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xb96841bf_7ffcb21a_9de1e3b2_2b8bf4db_u128,\n", " lo: 0x43b1297e_ff842a9f_d1ab4f85_1f6104b6_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xbdaef913_557d76f0_ac85320f_528d6d5c_u128,\n", " lo: 0x9c677149_abc2caaf_e0bd3568_6bed05f0_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xc1d8705f_fcbb6e90_bdf0715c_b8b20bd6_u128,\n", " lo: 0xd785c0cf_c7c2e7a2_164c59c4_fc989f35_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xc5e40358_a8ba05a7_43da25d9_9267326a_u128,\n", " lo: 0xd47437d3_710b81d7_9bcdaef0_2b673f06_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xc9d1124c_931fda7a_8335241b_e1693225_u128,\n", " lo: 0x4bfc4d9a_bfeb5f9f_3e33f423_0b848c8b_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xcd9f023f_9c3a059e_23af31db_7179a4a9_u128,\n", " lo: 0x9d02f0e6_caa17d3d_c881a550_27476af7_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xd14d3d02_313c0eed_744fea20_e8abef91_u128,\n", " lo: 0xe386cbda_4f76d559_39d956bc_fe9a5d9a_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xd4db3148_750d1819_f630e8b6_dac83e68_u128,\n", " lo: 0xb4691d2f_99ec9eaa_ac08e58a_7cd39544_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xd84852c0_a80ffcdb_24b9fe00_663574a3_u128,\n", " lo: 0xdd2c2b52_901fe500_17b15cb0_a701425c_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xdb941a28_cb71ec87_2c19b632_53da43fb_u128,\n", " lo: 0xb67292cb_df4cb882_f8ae9c38_d38a778a_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xdebe0563_7ca94cfb_4b19aa71_fec3ae6c_u128,\n", " lo: 0xd4a25796_6e116379_86a3422b_18230d42_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xe1c5978c_05ed8691_f4e8a837_2f8c580f_u128,\n", " lo: 0xfdea3ff0_dc053327_82c4fe35_f8f29ceb_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xe4aa5909_a08fa7b4_122785ae_67f5515c_u128,\n", " lo: 0x8743f3fe_219a6a8f_27902aa3_6084a51c_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xe76bd7a1_e63b9786_12512952_9d48a92f_u128,\n", " lo: 0x2f1bb328_2663e451_09de14ef_ea575874_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xea09a68a_6e49cd62_15ad45b4_a1b5e823_u128,\n", " lo: 0x3d5705f1_0a9a7f6f_2397ea24_d5049427_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xec835e79_946a3145_7e610231_ac1d6180_u128,\n", " lo: 0xf0a83d3c_d0dae9b5_db897c23_84083747_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xeed89db6_6611e307_86f8c20f_b664b01a_u128,\n", " lo: 0xfc4facdf_d3d64e3f_b6a4dec4_98e3fbc3_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xf1090827_b43725fd_67127db3_5b287315_u128,\n", " lo: 0x89dab2e0_fe03a229_894c0e9a_ac77bfe5_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xf3144762_47088f74_a5486bdc_455d56a2_u128,\n", " lo: 0x6cc90b7d_06c506d8_511aacdc_d3b8eb9a_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xf4fa0ab6_316ed2ec_163c5c7f_03b718c5_u128,\n", " lo: 0x5ee4b099_89a11728_8e77ee63_670fa091_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xf6ba073b_424b19e8_2c791f59_cc1ffc22_u128,\n", " lo: 0xb06854a7_d3139b87_f2f68677_a56efb24_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xf853f7dc_9186b952_c7adc6b4_988891ba_u128,\n", " lo: 0x95a1acb3_43363fb2_6d193284_5f3813dd_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xf9c79d63_272c4628_4504ae08_d19b2980_u128,\n", " lo: 0x79b567a6_7cde8b61_61e63b20_928c47b0_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xfb14be7f_bae58156_2172a361_fd2a722e_u128,\n", " lo: 0xc5f40e3f_d8f18ae1_b1997321_b48e8b1c_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xfc3b27d3_8a5d49ab_256778ff_cb5c1769_u128,\n", " lo: 0x246ddc4e_63f59390_b859505a_0b301225_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xfd3aabf8_4528b50b_eae6bd95_1c1dabbd_u128,\n", " lo: 0xa19702d6_d140d729_62b81762_1ff0f760_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xfe132387_0cfe9a3d_90cd1d95_9db674ee_u128,\n", " lo: 0xcc9d5d78_7e81f867_92ae1e5d_881f153b_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xfec46d1e_89292cf0_41390efd_c726e9ef_u128,\n", " lo: 0x5a2c976d_196a3567_b2681b46_8efba362_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xff4e6d68_0c41d0a9_0f668633_f1ab8589_u128,\n", " lo: 0x91cf862e_7fad71ee_964aad96_d95ae9fb_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xffb10f1b_cb6bef1d_421e8eda_af59453d_u128,\n", " lo: 0xcf53e4ba_a403250b_5750700a_6df26524_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xffec4304_266865d9_56575523_66961732_u128,\n", " lo: 0x568fb692_82182f32_ef6f30da_8fe307e9_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -255,\n", " mantissa: u256 {\n", " hi: 0x80000000_00000000_00000000_00000000_u128,\n", " lo: 0x0_u128,\n", " }\n", "},\n", "];\n" ] } ], "source": [ " R = RealField(300)\n", " π = R.pi()\n", "\n", " # Generate array entries\n", " print(\"pub(crate) static SIN_K_PI_OVER_128_F256: [DyadicFloat256; 65] = [\")\n", " for k in range(65):\n", " value = R(k) * π / R(128)\n", " print_dyadic256(value.sin())\n", "\n", " print(\"];\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "5657fc03-92b3-4f59-889a-07e3800ea1b9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "76.17869958464145757175388613060650100521941417\n" ] } ], "source": [ "p = var('p')\n", "p = (DD(24) + DD(1/4)) * DD.pi()\n", "# Define the expression\n", "def expr():\n", " return p - (3/(8*p)) + (3/(128*p**3)) - (1179/(5120*p**5)) + (1951209/(1146880*p**7)) - (223791831/(9175040*p**9))\n", "print(expr())\n" ] }, { "cell_type": "code", "execution_count": 28, "id": "3e60b97f-4437-4f62-a606-263d1346be8f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7.095540780574083299999999999988596799011215001e-17\n", "5.572824697374581798277133995318844970172780013e-17\n", "5.74848927250931e-18\n" ] }, { "data": { "text/plain": [ "mpf('5.940128391303172e-16')" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z = DD('76.178699584641464070955407805740833') - DD('76.178699584641464')\n", "print(z)\n", "print(z / DD(4)*DD.pi())\n", "from mpmath import mp, j1, taylor, expm1\n", "mp.j1(mp.mpf('76.178699584641464'))" ] }, { "cell_type": "code", "execution_count": 94, "id": "4578c806-feb9-421b-bb3c-9c626b9ab95b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.318309886183790671537767526745028724068919291480912897495334688117793595268453070180227605532506171912145685453515916073785823692229157305755934821463399678458479933874818155146155492793850615377434785792434795323386724780483447258023664760228445399511431880923780173805347912240978821873875688171057446199892886800497344695478919221796646193566149812333972925609398897304375763149573133928482077991748278697219967736198399924885751170342357716862235037534321093095073976\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -257,\n", " mantissa: u256 {\n", " hi: 0xa2f9836e_4e441529_fc2757d1_f534ddc0_u128,\n", " lo: 0xdb629599_3c439041_fe5163ab_debbc562_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Neg,\n", " exponent: -514,\n", " mantissa: u256 {\n", " hi: 0x91b7238b_7b645a3f_f36da22b_ec5cdbc6_u128,\n", " lo: 0x3c429c69_dacb1822_efb9415a_28976f6_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Neg,\n", " exponent: -772,\n", " mantissa: u256 {\n", " hi: 0xb31c7eca_5d040df6_33714e33_e566305b_u128,\n", " lo: 0x1bdd03a2_1036be27_003b4001_0fd33f81_u128,\n", " }\n", "},\n", "DyadicFloat256 {\n", " sign: DyadicSign::Pos,\n", " exponent: -256,\n", " mantissa: u256 {\n", " hi: 0xcc42299e_a1b28468_7e59e280_5d5c717f_u128,\n", " lo: 0xa7053e60_a24e0db1_808e3690_04c73a5d_u128,\n", " }\n", "},\n" ] } ], "source": [ "b1 = RealField(1568)\n", "twopi = b1(1) / b1.pi()\n", "print(twopi)\n", "c0 = RealField(256)(twopi)\n", "c1 = RealField(256)(twopi - b1(c0))\n", "c2 = twopi - b1(c0) - b1(c1)\n", "\n", "print_dyadic256(c0)\n", "print_dyadic256(c1)\n", "print_dyadic256(c2)\n", "\n", "print_dyadic256((b1(2)/b1.pi()).sqrt())\n" ] }, { "cell_type": "code", "execution_count": null, "id": "95ea2563-1f93-4187-b1ac-56285f76a0de", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_log.ipynb000064400000000000000000000437201046102023000152000ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 10, "id": "00076770-242c-48f8-82b1-575cb869098d", "metadata": {}, "outputs": [], "source": [ "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "5b503c18-8357-4318-891b-7185dc2ec91a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0x3c6bc60efafc6f6e, 0xbfd5ff3070a793d4),\n", "(0x3c78ebcb7dee9a3d, 0xbfd5a42ab0f4cfe2),\n", "(0x3c6819cf7e308ddb, 0xbfd548a2c3add263),\n", "(0x3c742a87d977dc5e, 0xbfd4ec973260026a),\n", "(0x3c69ffc341f177dc, 0xbfd49006804009d1),\n", "(0x3c729931715ac903, 0xbfd432ef2a04e814),\n", "(0x3c70bcfb6082ce6d, 0xbfd404308686a7e4),\n", "(0x3c6c68651945f97c, 0xbfd3a64c556945ea),\n", "(0x3c64dd4c580919f8, 0xbfd347dd9a987d55),\n", "(0x3c78f4cdb95ebdf9, 0xbfd2e8e2bae11d31),\n", "(0xbc77ad24c13f040e, 0xbfd2895a13de86a3),\n", "(0x3c776f5eb09628af, 0xbfd22941fbcf7966),\n", "(0x3c7c9fdf9a0c4b07, 0xbfd1f8ff9e48a2f3),\n", "(0xbc79d3d1b0e4d147, 0xbfd1980d2dd4236f),\n", "(0xbc77b66298edd24a, 0xbfd136870293a8b0),\n", "(0xbc589fa0ab4cb31d, 0xbfd1058bf9ae4ad5),\n", "(0xbc77dcfde8061c03, 0xbfd0a324e27390e3),\n", "(0x3c628ec217a5022d, 0xbfd0402594b4d041),\n", "(0x3c6caaae64f21acb, 0xbfcfb9186d5e3e2b),\n", "(0xbc2c5f6dfd018c37, 0xbfcf550a564b7b37),\n", "(0x3c46e03a39bfc89b, 0xbfce8c0252aa5a60),\n", "(0x3c461578001e0162, 0xbfce27076e2af2e6),\n", "(0xbc66e443597e4d40, 0xbfcd5c216b4fbb91),\n", "(0x3c64f689f8434012, 0xbfcc8ff7c79a9a22),\n", "(0x3c673dee38a3fb6b, 0xbfcc2968558c18c1),\n", "(0xbc6ba27fdc19e1a0, 0xbfcb5b519e8fb5a4),\n", "(0x3c5398cff3641985, 0xbfcaf3c94e80bff3),\n", "(0xbc493711b07a998c, 0xbfca23bc1fe2b563),\n", "(0xbc6575e31f003e0c, 0xbfc9bb362e7dfb83),\n", "(0x3c6569d851a56770, 0xbfc8e928de886d41),\n", "(0x3c6bf7fdbfa08d9a, 0xbfc87fa06520c911),\n", "(0xbc4be36b2d6a0608, 0xbfc7ab890210d909),\n", "(0x3c5b264062a84cdb, 0xbfc740f8f54037a5),\n", "(0x3c6caae268ecd179, 0xbfc6d60fe719d21d),\n", "(0x3c5bc60efafc6f6e, 0xbfc5ff3070a793d4),\n", "(0x3c565d22aa8ad7cf, 0xbfc59338d9982086),\n", "(0xbc668981bcc36756, 0xbfc4ba36f39a55e5),\n", "(0xbc69f4f6543e1f88, 0xbfc44d2b6ccb7d1e),\n", "(0x3c5ab3a8e7d81017, 0xbfc3dfc2b0ecc62a),\n", "(0x3c06b9c7d96091fa, 0xbfc303d718e47fd3),\n", "(0xbc6301771c407dbf, 0xbfc29552f81ff523),\n", "(0xbc6f547bf1809e88, 0xbfc2266f190a5acb),\n", "(0xbc6a28813e3a7f07, 0xbfc14785846742ac),\n", "(0xbc69a5dc5e9030ac, 0xbfc0d77e7cd08e59),\n", "(0xbc550c647eb86499, 0xbfc0671512ca596e),\n", "(0xbc585f325c5bbacd, 0xbfbf0a30c01162a6),\n", "(0x3c361578001e0162, 0xbfbe27076e2af2e6),\n", "(0xbc5790dd951d90fa, 0xbfbd4313d66cb35d),\n", "(0xbc35d617ef8161b1, 0xbfbc5e548f5bc743),\n", "(0xbc5942f48aa70ea9, 0xbfba926d3a4ad563),\n", "(0x3c42099e1c184e8e, 0xbfb9ab42462033ad),\n", "(0x3c24a697ab3424a9, 0xbfb8c345d6319b21),\n", "(0x3c5eeedfcdd94131, 0xbfb7da766d7b12cd),\n", "(0x3c5388458ec21b6a, 0xbfb60658a93750c4),\n", "(0xbc5a49e39a1a8be4, 0xbfb51b073f06183f),\n", "(0xbc4ddd4f935996c9, 0xbfb42edcbea646f0),\n", "(0x3c5b599f227becbb, 0xbfb341d7961bd1d1),\n", "(0x3c1c125963fc4cfd, 0xbfb253f62f0a1417),\n", "(0x3c379da3e8c22cda, 0xbfb16536eea37ae1),\n", "(0xbc485f325c5bbacd, 0xbfaf0a30c01162a6),\n", "(0xbc21e3c53257fd47, 0xbfad276b8adb0b52),\n", "(0x3c3eb9759c130499, 0xbfab42dd711971bf),\n", "(0xbc4f5a0e80520bf2, 0xbfa95c830ec8e3eb),\n", "(0xbc418d3ca87b9296, 0xbfa77458f632dcfc),\n", "(0x3c4ce55c2b4e2b72, 0xbfa58a5bafc8e4d5),\n", "(0x3c45bfa937f551bb, 0xbfa39e87b9febd60),\n", "(0x3c3e9ae889bac481, 0xbfa1b0d98923d980),\n", "(0xbc333e3f04f1ef23, 0xbf9f829b0e783300),\n", "(0x3bf0ae69229dc868, 0xbf9b9fc027af9198),\n", "(0x3c35b602ace3a510, 0xbf97b91b07d5b11b),\n", "(0x3c10cb5a902b3a1c, 0xbf93cea44346a575),\n", "(0x3c183092c59642a1, 0xbf8fc0a8b0fc03e4),\n", "(0x3c116d7687d3df21, 0xbf87dc475f810a77),\n", "(0x3bce44b7e3711ebf, 0xbf7fe02a6b106789),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3bec14b9f9377a1d, 0x3f78121214586b54),\n", "(0xbc2c5517f64bc223, 0x3f841929f96832f0),\n", "(0x3c2806208c04c220, 0x3f8c317384c75f06),\n", "(0xbc2cd7b66e01c26d, 0x3f9228fb1fea2e28),\n", "(0xbbf8ed4d357c9c97, 0x3f963d6178690bd6),\n", "(0x3c1ec1a5f86d41f9, 0x3f9a55f548c5c43f),\n", "(0x3c375b44595cab18, 0x3f9e72bf2813ce51),\n", "(0x3c4c05cf1d753622, 0x3fa0415d89e74444),\n", "(0xbc4947f792615916, 0x3fa252f32f8d183f),\n", "(0xbc4cdd6f7f4a137e, 0x3fa466aed42de3ea),\n", "(0x3c40413e6505e603, 0x3fa67c94f2d4bb58),\n", "(0x3c3a8be97660a23d, 0x3fa894aa149fb343),\n", "(0x3c2a353bb42e0add, 0x3faaaef2d0fb10fc),\n", "(0x3c3e5cf3a0f56f72, 0x3fabbcebfc68f420),\n", "(0x3c44e6c986f44c55, 0x3fadda8adc67ee4e),\n", "(0xbc4cd9f1f95c2eed, 0x3faffa6911ab9301),\n", "(0xbc5a4a128d192686, 0x3fb10e45b3cae831),\n", "(0xbc5cc0fbce104eaa, 0x3fb2207b5c78549e),\n", "(0xbc5d15d38d2fa3f7, 0x3fb2aa04a44717a5),\n", "(0x3c47a976d3b5b45f, 0x3fb3bdf5a7d1ee64),\n", "(0x3c5769f42c7842cc, 0x3fb4d3115d207eac),\n", "(0xbc545f9d61c68c1b, 0x3fb55e10050e0384),\n", "(0xbc59acd8b33f8fdc, 0x3fb674f089365a7a),\n", "(0x3c5abca5b4fdb880, 0x3fb78d02263d82d3),\n", "(0x3c3b9f2dffbeed43, 0x3fb8197e2f40e3f0),\n", "(0xbc5478a85704ccb7, 0x3fb9335e5d594989),\n", "(0xbc55b5ca203e4259, 0x3fba4e7640b1bc38),\n", "(0x3c537d8f39bee659, 0x3fbadc77ee5aea8c),\n", "(0xbc4cdc9f6f5f38c7, 0x3fbbf968769fca11),\n", "(0x3c49daf7df76ad2a, 0x3fbd179788219364),\n", "(0x3c5401fa71733019, 0x3fbda727638446a2),\n", "(0xbc4a2bf991780d3f, 0x3fbec739830a1120),\n", "(0xbc59361574fb24e2, 0x3fbf57bc7d9005db),\n", "(0x3c639e2d3f8b7d10, 0x3fc03cdc0a51ec0d),\n", "(0xbc6dd7009902bf32, 0x3fc08598b59e3a07),\n", "(0xbc50e63a5f01c691, 0x3fc1178e8227e47c),\n", "(0xbc62d56ff61c2bfb, 0x3fc160c8024b27b1),\n", "(0x3c462c9ef939ac5d, 0x3fc1f3b925f25d41),\n", "(0xbc66e38161051d69, 0x3fc23d712a49c202),\n", "(0xbc5499a3f25af95f, 0x3fc2d1610c86813a),\n", "(0xbc5c4716bdfc0cc9, 0x3fc31b994d3a4f85),\n", "(0x3c370d6cdf05266c, 0x3fc3b08b6757f2a9),\n", "(0xbc6d87e6a354d056, 0x3fc3fb45a59928cc),\n", "(0xbc50d5604930f135, 0x3fc4913d8333b561),\n", "(0xbc6927d47803c5f4, 0x3fc4dc7b897bc1c8),\n", "(0x3c64f4d710fec38e, 0x3fc5737cc9018cdd),\n", "(0xbc21f5b44c0df7e7, 0x3fc5bf406b543db2),\n", "(0xbc3d34f0f4621bed, 0x3fc6574ebe8c133a),\n", "(0x3c696332bd4b341f, 0x3fc6a399dabbd383),\n", "(0xbc68de59c21e166c, 0x3fc6f0128b756abc),\n", "(0x3c5ef8f6ebcfb201, 0x3fc7898d85444c73),\n", "(0xbc4ac5f0c075b847, 0x3fc7d6903caf5ad0),\n", "(0x3c6d685f35eea2a0, 0x3fc871213750e994),\n", "(0x3c555aa8b6997a40, 0x3fc8beafeb38fe8c),\n", "(0x3c6054473941ad99, 0x3fc90c6db9fcbcd9),\n", "(0x3c6f47dfd871f87f, 0x3fc9a8778debaa38),\n", "(0x3c435a19605e67ef, 0x3fc9f6c407089664),\n", "(0x3c5df207dc5c34c6, 0x3fca454082e6ab05),\n", "(0x3c6ab5ca9eaa088a, 0x3fcae2ca6f672bd4),\n", "(0xbc66353ab386a94d, 0x3fcb31d8575bce3d),\n", "(0x3c3a0ee735d9f0ec, 0x3fcb811730b823d2),\n", "(0x3c3dd355f6a516d7, 0x3fcbd087383bd8ad),\n", "(0xbc68e58b2c57a4a5, 0x3fcc6ffbc6f00f71),\n", "(0x3c653d154280394f, 0x3fccc000c9db3c52),\n", "(0x3c660629242471a2, 0x3fcd1037f2655e7b),\n", "(0x3c5aa11d49f96cb9, 0x3fcdb13db0d48940),\n", "(0x3c5fea48dd7b81d1, 0x3fce020cc6235ab5),\n", "(0x3c42276041f43042, 0x3fce530effe71012),\n", "(0xbc6d33919ab94074, 0x3fcea4449f04aaf5),\n", "(0xbc527c77ded76aad, 0x3fcf474b134df229),\n", "(0x3c6f665066f980a2, 0x3fcf991c6cb3b379),\n", "(0x3c28de00938b4c40, 0x3fcfeb2233ea07cd),\n", "(0xbc418290bd2932e2, 0x3fd01eae5626c691),\n", "(0xbc70779634061cbc, 0x3fd047e60cde83b8),\n", "(0x3c643c2e68684d53, 0x3fd09aa572e6c6d4),\n", "(0x3c5162c79d5d11ee, 0x3fd0c42d676162e3),\n", "(0xbc692b49ef282b09, 0x3fd0edd060b78081),\n", "(0xbc60e63a5f01c691, 0x3fd1178e8227e47c),\n", "(0x3c1e0936abd4fa6e, 0x3fd14167ef367783),\n", "(0x3c766fbd28b40935, 0x3fd16b5ccbacfb73),\n", "(0xbc612aeb84249223, 0x3fd1bf99635a6b95),\n", "(0x3c7512c3749a1e4e, 0x3fd1e9e1678899f4),\n", "(0x3c6f7ae91aeba60a, 0x3fd214456d0eb8d4),\n", "(0x3c3bb75d1addf870, 0x3fd23ec5991eba49),\n", "(0x3c7e0efadd9db02b, 0x3fd269621134db92),\n", "(0xbc6856e61c515740, 0x3fd2941afb186b7c),\n", "(0xbc782dad7fd86088, 0x3fd2bef07cdc9354),\n", "(0xbc73d69909e5c3dc, 0x3fd314f1e1d35ce4),\n", "(0xbc5cd55b8a4746c0, 0x3fd3401e12aecba1),\n", "(0xbc5324f0e883858e, 0x3fd36b6776be1117),\n", "(0xbc5ce2b31b31e8b0, 0x3fd396ce359bbf54),\n", "(0xbc72ad27e50a8ec6, 0x3fd3c25277333184),\n", "(0x3c783d680d3c1084, 0x3fd3edf463c1683e),\n", "(0x3c60dbb243827392, 0x3fd419b423d5e8c7),\n", "(0xbc72b125247b0fa5, 0x3fd44591e0539f49),\n", "(0x3c38fb4c14c56eef, 0x3fd4718dc271c41b),\n", "(0xbc69964a168ccaca, 0x3fd49da7f3bcc41f),\n", "(0xbc5123615b147a5d, 0x3fd4c9e09e172c3c),\n", "(0xbc758cb3124b9245, 0x3fd4f637ebba9810),\n", "(0xbc68f7e9b38a6979, 0x3fd522ae0738a3d8),\n", "(0xbc7aacfdbbdab914, 0x3fd54f431b7be1a9),\n", "(0xbc60908d15f88b63, 0x3fd57bf753c8d1fb),\n", "(0xbc5e6c2bdfb3e037, 0x3fd5a8cadbbedfa1),\n", "(0xbc76541148cbb8a2, 0x3fd5d5bddf595f30),\n", "(0xbc56e8920c09b73f, 0x3fd602d08af091ec),\n", "(0x3c6dc18ce51fff99, 0x3fd630030b3aac49),\n" ] } ], "source": [ "values = [ 0x3ff6900000000000,\n", " 0x3ff6700000000000,\n", " 0x3ff6500000000000,\n", " 0x3ff6300000000000,\n", " 0x3ff6100000000000,\n", " 0x3ff5f00000000000,\n", " 0x3ff5e00000000000,\n", " 0x3ff5c00000000000,\n", " 0x3ff5a00000000000,\n", " 0x3ff5800000000000,\n", " 0x3ff5600000000000,\n", " 0x3ff5400000000000,\n", " 0x3ff5300000000000,\n", " 0x3ff5100000000000,\n", " 0x3ff4f00000000000,\n", " 0x3ff4e00000000000,\n", " 0x3ff4c00000000000,\n", " 0x3ff4a00000000000,\n", " 0x3ff4800000000000,\n", " 0x3ff4700000000000,\n", " 0x3ff4500000000000,\n", " 0x3ff4400000000000,\n", " 0x3ff4200000000000,\n", " 0x3ff4000000000000,\n", " 0x3ff3f00000000000,\n", " 0x3ff3d00000000000,\n", " 0x3ff3c00000000000,\n", " 0x3ff3a00000000000,\n", " 0x3ff3900000000000,\n", " 0x3ff3700000000000,\n", " 0x3ff3600000000000,\n", " 0x3ff3400000000000,\n", " 0x3ff3300000000000,\n", " 0x3ff3200000000000,\n", " 0x3ff3000000000000,\n", " 0x3ff2f00000000000,\n", " 0x3ff2d00000000000,\n", " 0x3ff2c00000000000,\n", " 0x3ff2b00000000000,\n", " 0x3ff2900000000000,\n", " 0x3ff2800000000000,\n", " 0x3ff2700000000000,\n", " 0x3ff2500000000000,\n", " 0x3ff2400000000000,\n", " 0x3ff2300000000000,\n", " 0x3ff2100000000000,\n", " 0x3ff2000000000000,\n", " 0x3ff1f00000000000,\n", " 0x3ff1e00000000000,\n", " 0x3ff1c00000000000,\n", " 0x3ff1b00000000000,\n", " 0x3ff1a00000000000,\n", " 0x3ff1900000000000,\n", " 0x3ff1700000000000,\n", " 0x3ff1600000000000,\n", " 0x3ff1500000000000,\n", " 0x3ff1400000000000,\n", " 0x3ff1300000000000,\n", " 0x3ff1200000000000,\n", " 0x3ff1000000000000,\n", " 0x3ff0f00000000000,\n", " 0x3ff0e00000000000,\n", " 0x3ff0d00000000000,\n", " 0x3ff0c00000000000,\n", " 0x3ff0b00000000000,\n", " 0x3ff0a00000000000,\n", " 0x3ff0900000000000,\n", " 0x3ff0800000000000,\n", " 0x3ff0700000000000,\n", " 0x3ff0600000000000,\n", " 0x3ff0500000000000,\n", " 0x3ff0400000000000,\n", " 0x3ff0300000000000,\n", " 0x3ff0200000000000,\n", " 0x3ff0000000000000,\n", " 0x3ff0000000000000,\n", " 0x3fefd00000000000,\n", " 0x3fefb00000000000,\n", " 0x3fef900000000000,\n", " 0x3fef700000000000,\n", " 0x3fef500000000000,\n", " 0x3fef300000000000,\n", " 0x3fef100000000000,\n", " 0x3fef000000000000,\n", " 0x3feee00000000000,\n", " 0x3feec00000000000,\n", " 0x3feea00000000000,\n", " 0x3fee800000000000,\n", " 0x3fee600000000000,\n", " 0x3fee500000000000,\n", " 0x3fee300000000000,\n", " 0x3fee100000000000,\n", " 0x3fedf00000000000,\n", " 0x3fedd00000000000,\n", " 0x3fedc00000000000,\n", " 0x3feda00000000000,\n", " 0x3fed800000000000,\n", " 0x3fed700000000000,\n", " 0x3fed500000000000,\n", " 0x3fed300000000000,\n", " 0x3fed200000000000,\n", " 0x3fed000000000000,\n", " 0x3fece00000000000,\n", " 0x3fecd00000000000,\n", " 0x3fecb00000000000,\n", " 0x3fec900000000000,\n", " 0x3fec800000000000,\n", " 0x3fec600000000000,\n", " 0x3fec500000000000,\n", " 0x3fec300000000000,\n", " 0x3fec200000000000,\n", " 0x3fec000000000000,\n", " 0x3febf00000000000,\n", " 0x3febd00000000000,\n", " 0x3febc00000000000,\n", " 0x3feba00000000000,\n", " 0x3feb900000000000,\n", " 0x3feb700000000000,\n", " 0x3feb600000000000,\n", " 0x3feb400000000000,\n", " 0x3feb300000000000,\n", " 0x3feb100000000000,\n", " 0x3feb000000000000,\n", " 0x3feae00000000000,\n", " 0x3fead00000000000,\n", " 0x3feac00000000000,\n", " 0x3feaa00000000000,\n", " 0x3fea900000000000,\n", " 0x3fea700000000000,\n", " 0x3fea600000000000,\n", " 0x3fea500000000000,\n", " 0x3fea300000000000,\n", " 0x3fea200000000000,\n", " 0x3fea100000000000,\n", " 0x3fe9f00000000000,\n", " 0x3fe9e00000000000,\n", " 0x3fe9d00000000000,\n", " 0x3fe9c00000000000,\n", " 0x3fe9a00000000000,\n", " 0x3fe9900000000000,\n", " 0x3fe9800000000000,\n", " 0x3fe9600000000000,\n", " 0x3fe9500000000000,\n", " 0x3fe9400000000000,\n", " 0x3fe9300000000000,\n", " 0x3fe9100000000000,\n", " 0x3fe9000000000000,\n", " 0x3fe8f00000000000,\n", " 0x3fe8e00000000000,\n", " 0x3fe8d00000000000,\n", " 0x3fe8b00000000000,\n", " 0x3fe8a00000000000,\n", " 0x3fe8900000000000,\n", " 0x3fe8800000000000,\n", " 0x3fe8700000000000,\n", " 0x3fe8600000000000,\n", " 0x3fe8400000000000,\n", " 0x3fe8300000000000,\n", " 0x3fe8200000000000,\n", " 0x3fe8100000000000,\n", " 0x3fe8000000000000,\n", " 0x3fe7f00000000000,\n", " 0x3fe7e00000000000,\n", " 0x3fe7c00000000000,\n", " 0x3fe7b00000000000,\n", " 0x3fe7a00000000000,\n", " 0x3fe7900000000000,\n", " 0x3fe7800000000000,\n", " 0x3fe7700000000000,\n", " 0x3fe7600000000000,\n", " 0x3fe7500000000000,\n", " 0x3fe7400000000000,\n", " 0x3fe7300000000000,\n", " 0x3fe7200000000000,\n", " 0x3fe7100000000000,\n", " 0x3fe7000000000000,\n", " 0x3fe6f00000000000,\n", " 0x3fe6e00000000000,\n", " 0x3fe6d00000000000,\n", " 0x3fe6c00000000000,\n", " 0x3fe6b00000000000,\n", " 0x3fe6a00000000000,]\n", "\n", "# Precision for RealField (e.g., 100 bits)\n", "R = RealField(150)\n", "\n", "# Function to convert 64-bit hex to float\n", "def hex_to_float(h):\n", " return struct.unpack('>d', struct.pack('>Q', h))[0]\n", "\n", "# Convert each hex value to RealField\n", "real_array = [R(hex_to_float(h)) for h in values]\n", "\n", "# Show results\n", "for r in real_array:\n", " print_double_double(\"\", -RealField(120)(r).log())" ] }, { "cell_type": "code", "execution_count": null, "id": "a2fa1753-109b-4bc4-90ee-3abc1b50984c", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_sollya/CMakeLists.txt000064400000000000000000000010461046102023000174120ustar 00000000000000cmake_minimum_required(VERSION 3.31) project(bessel_sollya) set(CMAKE_CXX_STANDARD 20) add_library(bessel_sollya SHARED library.c) find_package(PkgConfig REQUIRED) pkg_check_modules(MPFR REQUIRED IMPORTED_TARGET mpfr) pkg_check_modules(MPFI REQUIRED IMPORTED_TARGET mpfi) include_directories(${MPFR_INCLUDE_DIRS}) link_directories(${MPFR_LIBRARY_DIRS}) add_definitions(${MPFR_CFLAGS_OTHER}) include_directories(/opt/homebrew/include) link_directories(/opt/homebrew/lib) target_link_libraries(bessel_sollya PRIVATE PkgConfig::MPFR PkgConfig::MPFI)pxfm-0.1.23/notes/bessel_sollya/bessel_i0.sollya000064400000000000000000000006221046102023000177430ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i0_approximant = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 500; f = bessel_i0_approximant(1/x); d = [1/9.5, 1/7.5]; w = 1; pf = remez(f, 29, d, 1, 1e-40); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0_big.sollya000064400000000000000000000066131046102023000205720ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i0_approximant = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 500; f = bessel_i0_approximant(1/x); //f = sqrt(1/x) * exp(-1/x) * (2.59780277210771740096221707788581701134626033229944179534141469782417769044768017446002469666505676220698e-25*x^-24 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-23 + 1.49633439673404522295423703686223059853544595140447847411665486594672634969786378048897422527907269503122e-22*x^-22 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-21 + 7.24225848019277887909850725841319609691155840479767581472460955118215553253766069756663525035071184395112e-20*x^-20 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-19 + 2.89690339207711155163940290336527843876462336191907032588984382047286221301506427902665410014028473758045e-17*x^-18 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-17 + 9.38596699032984142731166540690350214159737969261778785588309397833207357016880826404635928445452254976064e-15*x^-16 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-15 + 2.40280754952443940539178634416729654824892920131015369110607205845301083396321491559586797682035777273872e-12*x^-14 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-13 + 4.70950279706790123456790123456790123456790123456790123456790123456790123456790123456790123456790123456790e-10*x^-12 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-11 + 6.78168402777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778e-8*x^-10 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-9 + 6.78168402777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778e-6*x^-8 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-7 + 0.000434027777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778*x^-6 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-5 + 0.0156250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-4 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-3 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-2 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^-1 + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); d = [1/709.3, 1/9.5]; w = 1; pf = remez(f, 29, d, 1, 1e-40); //pf = fpminimax(f, 29, [|107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; pxfm-0.1.23/notes/bessel_sollya/bessel_i0_big_rational.sollya000064400000000000000000000006251046102023000224600ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i0_approximant = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 500; f = bessel_i0_approximant(1/x); d = [1/709.3, 1/9.5]; w = 1; pf = remez(f, 38, d, 1, 1e-40); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; pxfm-0.1.23/notes/bessel_sollya/bessel_i0_mid_interval.sollya000064400000000000000000000006241046102023000225020ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i0_approximant = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 1000; f = bessel_i0_approximant(1/x); d = [1/9.5, 1/7.5]; w = 1; pf = remez(f, 29, d, 1, 1e-40); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; pxfm-0.1.23/notes/bessel_sollya/bessel_i0_small.sollya000064400000000000000000000166431046102023000211450ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 1000; f = 2.70265284158458111246639178380860921965281806355772639932174388328913237632303651273240661304359005444739555445283608842518250882276959e-126*y^48 + 6.48906947264457925103180667292447073638641617060210108477150706377720683555161066707050827791765972072819672624125944830886320368346979e-123*y^47 + 1.49508160649731105943772825744179805766343028570672408993135522749426845491109109769304510723222879965577652572598617689036208212867144e-119*y^46 + 3.30263526875256013029794172068893190937851750112615351465836369753483901689860023480393664187599341843961034532870346475080983942223518e-116*y^45 + 6.98837622868041723571044468097777992024494303238294083701709758398371935975743809684512993420960207341821549071553653141271362021744968e-113*y^44 + 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403358e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192055e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954770e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324896e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719840e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433873e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718507e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974669e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439148e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343076e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997612e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253552e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699661e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129699e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131080e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227650e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137953e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521257e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907652e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841478e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063274e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102908e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411625e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120597e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [0, 3.6]; w = 1; pf = fpminimax(f, 19, [|1, 107, 107, 107, 107, 107, 107, 107, 107, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0_small_rational.sollya000064400000000000000000000165741046102023000230410ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 1000; f = 2.70265284158458111246639178380860921965281806355772639932174388328913237632303651273240661304359005444739555445283608842518250882276959e-126*y^48 + 6.48906947264457925103180667292447073638641617060210108477150706377720683555161066707050827791765972072819672624125944830886320368346979e-123*y^47 + 1.49508160649731105943772825744179805766343028570672408993135522749426845491109109769304510723222879965577652572598617689036208212867144e-119*y^46 + 3.30263526875256013029794172068893190937851750112615351465836369753483901689860023480393664187599341843961034532870346475080983942223518e-116*y^45 + 6.98837622868041723571044468097777992024494303238294083701709758398371935975743809684512993420960207341821549071553653141271362021744968e-113*y^44 + 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403358e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192055e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954770e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324896e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719840e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433873e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718507e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974669e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439148e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343076e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997612e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253552e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699661e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129699e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131080e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227650e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137953e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521257e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907652e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841478e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063274e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102908e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411625e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120597e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [3.6, 7.5]; w = 1; pf = fpminimax(f, 20, [|127...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0_small_rational128.sollya000064400000000000000000000347121046102023000232660ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; //bessel_i0 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); //f = 2.70265284158458111246639178380860921965281806355772639932174388328913237632303651273240661304359005444739555445283608842518250882276959e-126*y^48 + 6.48906947264457925103180667292447073638641617060210108477150706377720683555161066707050827791765972072819672624125944830886320368346979e-123*y^47 + 1.49508160649731105943772825744179805766343028570672408993135522749426845491109109769304510723222879965577652572598617689036208212867144e-119*y^46 + 3.30263526875256013029794172068893190937851750112615351465836369753483901689860023480393664187599341843961034532870346475080983942223518e-116*y^45 + 6.98837622868041723571044468097777992024494303238294083701709758398371935975743809684512993420960207341821549071553653141271362021744968e-113*y^44 + 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403358e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192055e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954770e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324896e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719840e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433873e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718507e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974669e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439148e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343076e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997612e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253552e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699661e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129699e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131080e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227650e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137953e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521257e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907652e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841478e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063274e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102908e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411625e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120597e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; f = 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403356362836400042839e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897918451270482937e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192056251216399122950e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954787227145728052886e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324899732883196885690e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719839572613115017104e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433875989944547941015e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718516929479927226826e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974649676458020373523e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439145980689594404087e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295382634475314501e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343077462325453463563e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997611356472418821820e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253554029027756873543e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699665421895674355475e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129698879706106919928e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131076757832835919659e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227641781409433610129e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137950858647477101784e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521254780445694520806e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784237778559075504e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907651720960450027490e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841477603880780645424e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063275160278297832385e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102904345682729344081e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411617382730917376327e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120593875165861172854e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724155537390200047e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159280950305767814e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077207759232782765602e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417371745827376122261e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858048621821657199631e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420102170878600667376e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844947126065184961022e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386022538873802836e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386022538873802837e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868732678256487780298e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675988914084152179391e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [0, 3.6]; w = 1; pf = fpminimax(f, 19, [|1, 127...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0_tiny.sollya000064400000000000000000000201641046102023000210110ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 2.70265284158458111246639178380861257666767090314492141742019376612723227490919712204860124825253386707264524164169432457930001458769116773235078892509e-126*y^48 + 6.48906947264457925103180667292443959294725588033299171031493749883732484942218249834913259661739193711348407683036401182920833863573829710798701321518e-123*y^47 + 1.49508160649731105943772825744180233822641087834627898497928615079849385556714799384462975131280690715454619900343225029008125627878006693550280880903e-119*y^46 + 3.30263526875256013029794172068892239398732429772185473502721125054795723475681096425420434130761382108339183508453951235735947434525769266582747746234e-116*y^45 + 6.98837622868041723571044468097776216315085374391179237945002198072531619285020082336939929477299960448485254963733461004154729817633651631140977457016e-113*y^44 + 1.41514618630778449023136504789799799764457661319419338645438605814406285817510771834152077583698809085953542537383113170953341002593585100762595947248e-109*y^43 + 2.73972301669187077308792273273051866516556292488434756601615038650736291745897156024840109644841128053896594959840850039234908984830374891715478036414e-106*y^42 + 5.06574785786326905943956913281875569529502510458768076327918137495427268809861428484911587320631211173027836197841741865622978131129678115421334832400e-103*y^41 + 8.93597922127080662085139995029224696377440163729565903368412350667897037670408482857776055742814753501897555132688362247200717423368141131239457700572e-100*y^40 + 1.50213810709562259296512033164412910400435749454578885887153169043841951981871819774611813378955763265534254847551461922370354932682050341138405905701e-96*y^39 + 2.40342097135299614874419253063061395278986621986188678133906070216822151060092516160341709588652933462470030245623366656479952881952861214755796135383e-93*y^38 + 3.65560329742790714223991683908916375128411073581547899818812307202218411494665380076478497325790804158935809867693546819731409437549550733221796193729e-90*y^37 + 5.27869116148589791339443991564473290026508591346027394232895161992320363237604824191047878818156542275247520117537225953163845335450112689713307388739e-87*y^36 + 7.22652820007419424343698824451767740959046235026546413741667222582806812700555555960916955192538165589860688990119360941024887940660548769104104441527e-84*y^35 + 9.36558054729615573949433676489487824931510950664173506226555043948971193383595573558062529566248555737540487085451224135096793152306856583349279283102e-81*y^34 + 1.14728361704377907808805625369962085990307981751034226908036953564103265883079838724450122382042389849365904062095064186011588913783145746137948167889e-77*y^33 + 1.32625986130260861426979302927676231016233787018305645046442745782427250813194573915006754424342288515590587533511802189545768967329943755807300500657e-74*y^32 + 1.44429698895854078093980460888239193208983909477271650872930872857605985305301038352406428858292755606623477416279587234649126627935461412977851943230e-71*y^31 + 1.47896011669354575968235991949556933845999523304726170493881213806188528952628263272864183150891781741182440874270297328280705667005912486889320389868e-68*y^30 + 1.42128067214249747505474788263524127701951195725218183660853723567175217430226149295322888873568760180828632674809080073876118633090458211171560391611e-65*y^29 + 1.27915260492824772754927309437171794520254105920067926944208386807959384242600293866906977717854599789261472865322213339285164937280180921968845086590e-62*y^28 + 1.07576734074465633886893867236662327736009638330339526903473816362904786106176956910206487737467419709517029288824451571976982508888914441989243081438e-59*y^27 + 8.43401595143810569673247919135429703994236385873930033460061728519787737943119842506279796932274258259460676594869824265569120470517722915052726679348e-57*y^26 + 6.14839762859837905291797733049724553148052968040092084427992696837992509086055181602061843064517504568753193441641599492603155397701959190835163365019e-54*y^25 + 4.15631679693250423977255267541615007604117331381898011727083828909390559111374892899358194717429702431205858909862308580345463346252984298014143742488e-51*y^24 + 2.59769799808281514985784542213510216539535076036467189997492712626127836422794033562385659120833681978456757543331577736260944026073622075225462123759e-48*y^23 + 1.49627404689570152631811896314981992678879142477562918767954087477644272729533918785451452449893577926988631875297213419930097162621238322171040510156e-45*y^22 + 7.91528970807826107422284931506250388642318896106216645561138271355354360275050754489220131513388062263501068757085041351648463957000164208448655439295e-43*y^21 + 3.83100021870987835992385906849024268385475902377434031306662942544638784803549754166560164168155063061181847692597194280534766770381103684844533143464e-40*y^20 + 1.68947109645105635672642184920420521896951506765917667381534183007341855867438873179459189624803921972850527484918246605312234612446067307712195483711e-37*y^19 + 6.75788438580422542690568739681685054952726577000779254914345970140978117521578498950638720930462821956474186443160184270915117016534298301984090735772e-35*y^18 + 2.43959626327532537911295315025086850829123224828098104183856368546203860339896565067107616664585983034401863819272099575463929745261367442159955443159e-32*y^17 + 7.90429189301205422832596820681281214371458529854901906069443058500123146458720865314485325421482761114504010394067349188619642363505708726467702263108e-30*y^16 + 2.28434035708048367198620481176890076484124081967388302602067363277653070881190057539413349636914305784003095398152926917235353964502619916743242356461e-27*y^15 + 5.84791131412603820028468431812838595799357649836514054661292449990791861455846547300898175070500622807047924219271492908122506149126706986862700432539e-25*y^14 + 1.31578004567835859506405397157889545598961011643407079517309914026472632496908921310941598148332151368482921211189523927331812558350065955892205238342e-22*y^13 + 2.57892888952958284632554578429462830742298910974527097983340068810940566772858646596924565472539647831009087435363835716373159812064841389656066894531e-20*y^12 + 4.35838982330499501029017237545792685097868301833634446942432307193341835695546132445433383511871784909150542852707133079093182459473609924316406250000e-18*y^11 + 6.27608134555919281481784822065940098085398787436262779642431340799690290020783816936490715745099384145072596297154632338788360357284545898437500000000e-16*y^10 + 7.59405842812662330592959634699787354468668744733377464492781380580578616519452104838961763270130736480645339270267868414521217346191406250000000000000e-14*y^9 + 7.59405842812662330592959634699787074208975879769963279746864722597352360467063729535807411856473958522428802098147571086883544921875000000000000000000e-12*y^8 + 6.15118732678256487780297304106826184862744710789282169814560466984369382926857419468863116818191372203727951273322105407714843750000000000000000000000e-10*y^7 + 3.93675988914084152179390274628368758312156614905140588681318698869996405073188748460072394763642478210385888814926147460937500000000000000000000000000e-8*y^6 + 1.92901234567901234567901234567902050738299879573449977305467325667863216317912504471632217928345198743045330047607421875000000000000000000000000000000e-6*y^5 + 0.0000694444444444444444444444444444440799889514961654375293375073927828511794217367092407755535532487556338310241699218750000000000000000000000000000000000*y^4 + 0.00173611111111111111111111111111110576130571003545596373339460393075744850527319940169945766683667898178100585937500000000000000000000000000000000000000*y^3 + 0.0277777777777777777777777777777776921808913605672954197343136628921191760843711904271913226693868637084960937500000000000000000000000000000000000000000*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [0, 1.0]; w = 1; pf = fpminimax(f, 17, [|107, 107, 107, 107, 107, 107, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0_tiny_rational.sollya000064400000000000000000000201331046102023000226760ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 2.70265284158458111246639178380861257666767090314492141742019376612723227490919712204860124825253386707264524164169432457930001458769116773235078892509e-126*y^48 + 6.48906947264457925103180667292443959294725588033299171031493749883732484942218249834913259661739193711348407683036401182920833863573829710798701321518e-123*y^47 + 1.49508160649731105943772825744180233822641087834627898497928615079849385556714799384462975131280690715454619900343225029008125627878006693550280880903e-119*y^46 + 3.30263526875256013029794172068892239398732429772185473502721125054795723475681096425420434130761382108339183508453951235735947434525769266582747746234e-116*y^45 + 6.98837622868041723571044468097776216315085374391179237945002198072531619285020082336939929477299960448485254963733461004154729817633651631140977457016e-113*y^44 + 1.41514618630778449023136504789799799764457661319419338645438605814406285817510771834152077583698809085953542537383113170953341002593585100762595947248e-109*y^43 + 2.73972301669187077308792273273051866516556292488434756601615038650736291745897156024840109644841128053896594959840850039234908984830374891715478036414e-106*y^42 + 5.06574785786326905943956913281875569529502510458768076327918137495427268809861428484911587320631211173027836197841741865622978131129678115421334832400e-103*y^41 + 8.93597922127080662085139995029224696377440163729565903368412350667897037670408482857776055742814753501897555132688362247200717423368141131239457700572e-100*y^40 + 1.50213810709562259296512033164412910400435749454578885887153169043841951981871819774611813378955763265534254847551461922370354932682050341138405905701e-96*y^39 + 2.40342097135299614874419253063061395278986621986188678133906070216822151060092516160341709588652933462470030245623366656479952881952861214755796135383e-93*y^38 + 3.65560329742790714223991683908916375128411073581547899818812307202218411494665380076478497325790804158935809867693546819731409437549550733221796193729e-90*y^37 + 5.27869116148589791339443991564473290026508591346027394232895161992320363237604824191047878818156542275247520117537225953163845335450112689713307388739e-87*y^36 + 7.22652820007419424343698824451767740959046235026546413741667222582806812700555555960916955192538165589860688990119360941024887940660548769104104441527e-84*y^35 + 9.36558054729615573949433676489487824931510950664173506226555043948971193383595573558062529566248555737540487085451224135096793152306856583349279283102e-81*y^34 + 1.14728361704377907808805625369962085990307981751034226908036953564103265883079838724450122382042389849365904062095064186011588913783145746137948167889e-77*y^33 + 1.32625986130260861426979302927676231016233787018305645046442745782427250813194573915006754424342288515590587533511802189545768967329943755807300500657e-74*y^32 + 1.44429698895854078093980460888239193208983909477271650872930872857605985305301038352406428858292755606623477416279587234649126627935461412977851943230e-71*y^31 + 1.47896011669354575968235991949556933845999523304726170493881213806188528952628263272864183150891781741182440874270297328280705667005912486889320389868e-68*y^30 + 1.42128067214249747505474788263524127701951195725218183660853723567175217430226149295322888873568760180828632674809080073876118633090458211171560391611e-65*y^29 + 1.27915260492824772754927309437171794520254105920067926944208386807959384242600293866906977717854599789261472865322213339285164937280180921968845086590e-62*y^28 + 1.07576734074465633886893867236662327736009638330339526903473816362904786106176956910206487737467419709517029288824451571976982508888914441989243081438e-59*y^27 + 8.43401595143810569673247919135429703994236385873930033460061728519787737943119842506279796932274258259460676594869824265569120470517722915052726679348e-57*y^26 + 6.14839762859837905291797733049724553148052968040092084427992696837992509086055181602061843064517504568753193441641599492603155397701959190835163365019e-54*y^25 + 4.15631679693250423977255267541615007604117331381898011727083828909390559111374892899358194717429702431205858909862308580345463346252984298014143742488e-51*y^24 + 2.59769799808281514985784542213510216539535076036467189997492712626127836422794033562385659120833681978456757543331577736260944026073622075225462123759e-48*y^23 + 1.49627404689570152631811896314981992678879142477562918767954087477644272729533918785451452449893577926988631875297213419930097162621238322171040510156e-45*y^22 + 7.91528970807826107422284931506250388642318896106216645561138271355354360275050754489220131513388062263501068757085041351648463957000164208448655439295e-43*y^21 + 3.83100021870987835992385906849024268385475902377434031306662942544638784803549754166560164168155063061181847692597194280534766770381103684844533143464e-40*y^20 + 1.68947109645105635672642184920420521896951506765917667381534183007341855867438873179459189624803921972850527484918246605312234612446067307712195483711e-37*y^19 + 6.75788438580422542690568739681685054952726577000779254914345970140978117521578498950638720930462821956474186443160184270915117016534298301984090735772e-35*y^18 + 2.43959626327532537911295315025086850829123224828098104183856368546203860339896565067107616664585983034401863819272099575463929745261367442159955443159e-32*y^17 + 7.90429189301205422832596820681281214371458529854901906069443058500123146458720865314485325421482761114504010394067349188619642363505708726467702263108e-30*y^16 + 2.28434035708048367198620481176890076484124081967388302602067363277653070881190057539413349636914305784003095398152926917235353964502619916743242356461e-27*y^15 + 5.84791131412603820028468431812838595799357649836514054661292449990791861455846547300898175070500622807047924219271492908122506149126706986862700432539e-25*y^14 + 1.31578004567835859506405397157889545598961011643407079517309914026472632496908921310941598148332151368482921211189523927331812558350065955892205238342e-22*y^13 + 2.57892888952958284632554578429462830742298910974527097983340068810940566772858646596924565472539647831009087435363835716373159812064841389656066894531e-20*y^12 + 4.35838982330499501029017237545792685097868301833634446942432307193341835695546132445433383511871784909150542852707133079093182459473609924316406250000e-18*y^11 + 6.27608134555919281481784822065940098085398787436262779642431340799690290020783816936490715745099384145072596297154632338788360357284545898437500000000e-16*y^10 + 7.59405842812662330592959634699787354468668744733377464492781380580578616519452104838961763270130736480645339270267868414521217346191406250000000000000e-14*y^9 + 7.59405842812662330592959634699787074208975879769963279746864722597352360467063729535807411856473958522428802098147571086883544921875000000000000000000e-12*y^8 + 6.15118732678256487780297304106826184862744710789282169814560466984369382926857419468863116818191372203727951273322105407714843750000000000000000000000e-10*y^7 + 3.93675988914084152179390274628368758312156614905140588681318698869996405073188748460072394763642478210385888814926147460937500000000000000000000000000e-8*y^6 + 1.92901234567901234567901234567902050738299879573449977305467325667863216317912504471632217928345198743045330047607421875000000000000000000000000000000e-6*y^5 + 0.0000694444444444444444444444444444440799889514961654375293375073927828511794217367092407755535532487556338310241699218750000000000000000000000000000000000*y^4 + 0.00173611111111111111111111111111110576130571003545596373339460393075744850527319940169945766683667898178100585937500000000000000000000000000000000000000*y^3 + 0.0277777777777777777777777777777776921808913605672954197343136628921191760843711904271913226693868637084960937500000000000000000000000000000000000000000*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [0, 1.0]; w = 1; pf = fpminimax(f, 15, [|1, 127...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0f.sollya000064400000000000000000000004721046102023000201140ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i0_approximant = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 1000; f = bessel_i0_approximant(1/x); d = [1/92.3, 1/7.5]; w = 1; pf = remez(f, 13, d, 1, 1e-25); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0f_small.sollya000064400000000000000000000165731046102023000213150ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 1000; f = 2.70265284158458111246639178380860921965281806355772639932174388328913237632303651273240661304359005444739555445283608842518250882276959e-126*y^48 + 6.48906947264457925103180667292447073638641617060210108477150706377720683555161066707050827791765972072819672624125944830886320368346979e-123*y^47 + 1.49508160649731105943772825744179805766343028570672408993135522749426845491109109769304510723222879965577652572598617689036208212867144e-119*y^46 + 3.30263526875256013029794172068893190937851750112615351465836369753483901689860023480393664187599341843961034532870346475080983942223518e-116*y^45 + 6.98837622868041723571044468097777992024494303238294083701709758398371935975743809684512993420960207341821549071553653141271362021744968e-113*y^44 + 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403358e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192055e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954770e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324896e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719840e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433873e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718507e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974669e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439148e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343076e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997612e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253552e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699661e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129699e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131080e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227650e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137953e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521257e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907652e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841478e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063274e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102908e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411625e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120597e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [6, 7.5]; w = 1; pf = fpminimax(f, 13, [|1, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i0f_tiny.sollya000064400000000000000000000165701046102023000211650ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 1000; f = 2.70265284158458111246639178380860921965281806355772639932174388328913237632303651273240661304359005444739555445283608842518250882276959e-126*y^48 + 6.48906947264457925103180667292447073638641617060210108477150706377720683555161066707050827791765972072819672624125944830886320368346979e-123*y^47 + 1.49508160649731105943772825744179805766343028570672408993135522749426845491109109769304510723222879965577652572598617689036208212867144e-119*y^46 + 3.30263526875256013029794172068893190937851750112615351465836369753483901689860023480393664187599341843961034532870346475080983942223518e-116*y^45 + 6.98837622868041723571044468097777992024494303238294083701709758398371935975743809684512993420960207341821549071553653141271362021744968e-113*y^44 + 1.41514618630778449023136504789800043384960096405754551949596226075670317035088121461113881167744441986718863686989614761107450809403358e-109*y^43 + 2.73972301669187077308792273273052883993282746641540812574418293682497733779930603148716473940753239686287720098011894177504024767004897e-106*y^42 + 5.06574785786326905943956913281874782503579798540208962450099425018938309759091685221976760316452740179945994461223992334204941794192055e-103*y^41 + 8.93597922127080662085139995029227116336314764624928609761975385733407178415037732731567005198222633677424734229599122477537517324954770e-100*y^40 + 1.50213810709562259296512033164413078256134511933450499300988062341785746691567842872176413573821224721175097823995612488474056662324896e-96*y^39 + 2.40342097135299614874419253063060925209815219093520798881580899746857194706508548595482261718113959553880156518392979981558490659719840e-93*y^38 + 3.65560329742790714223991683908915667244128948241245135098884548514969793148599502413728520073251332481451718064475722551950464293433873e-90*y^37 + 5.27869116148589791339443991564474223500522201260357975082789288055616381306577681485423982985774924103216280885102943365016470439718507e-87*y^36 + 7.22652820007419424343698824451765211972214893525430067888338535348138826008704845953545432707525871097303088531705929466707548031974669e-84*y^35 + 9.36558054729615573949433676489487714715990502008957367983286741811187918507281480355794880788953528942104802737090884588852982249439148e-81*y^34 + 1.14728361704377907808805625369962245052708836496097277577952625871870520017141981343584872896646807295407838335293633362134490325556295e-77*y^33 + 1.32625986130260861426979302927676355280931414989488452880113235507882321139816130433184113068523709233491461115599440166627470816343076e-74*y^32 + 1.44429698895854078093980460888239550900934310923552925186443313468083847721259766041737499131622319355272201154887790341457315718997612e-71*y^31 + 1.47896011669354575968235991949557300122556734385718195390917952991317860066570000426739199110781255019798733982605097309652291296253552e-68*y^30 + 1.42128067214249747505474788263524565417777021744675185770672152824656463523973770410096370345460786074026583357283498514575851935699661e-65*y^29 + 1.27915260492824772754927309437172108875999319570207667193604937542190817171576393369086733310914707466623925021555148663118266742129699e-62*y^28 + 1.07576734074465633886893867236661743564715427758544648109821752472982477241295746823401942714479268979430720943127880025682462330131080e-59*y^27 + 8.43401595143810569673247919135428069547368953626990041181002539388182621571758655095471230881517468798736852194122579401350504668227650e-57*y^26 + 6.14839762859837905291797733049727062700031967194075740020950851213985131125812059564598527312626234754279165249515360383584517903137953e-54*y^25 + 4.15631679693250423977255267541615494385221609823195200254162775420653948641048952265668604463335334693892715708672383619303134102521257e-51*y^24 + 2.59769799808281514985784542213509683990763506139497000158851734637908717900655595166042877789584584183682947317920239762064458814075784e-48*y^23 + 1.49627404689570152631811896314981577978679779536350272091498599151435421510777622815640697606800720489801377655122058102949128276907652e-45*y^22 + 7.91528970807826107422284931506252547507216033747292939364027589511093379792013624694739290339975811391049287795595687364600888584841478e-43*y^21 + 3.83100021870987835992385906849026232993492560333689782652189353323369195819334594352253816524548292713267855293068312684466830075063274e-40*y^20 + 1.68947109645105635672642184920420568750130219107157194149615504815605815356326556109343933087325797086551124184243125893849872063102908e-37*y^19 + 6.75788438580422542690568739681682275000520876428628776598462019262423261425306224437375732349303188346204496736972503575399488252411625e-35*y^18 + 2.43959626327532537911295315025087301275188036390734988352044788953734797374535547021892639378098450992979823322047073790719215259120597e-32*y^17 + 7.90429189301205422832596820681282856131609237905981362260625116210100743493495172350932151585038981217254627563432519081930257439550724e-30*y^16 + 2.28434035708048367198620481176890745422035069754828613693320658584719114869620104809419391808076265571786587365831998014677844400030159e-27*y^15 + 5.84791131412603820028468431812840308280409778572361251054900885976880934066227468312113643028675239863773663656529914917575281664077211e-25*y^14 + 1.31578004567835859506405397157889069363092200178781281487352699344798210164901180370225569681451928969349074322719230856454438374417372e-22*y^13 + 2.57892888952958284632554578429462575951660712350411311715211290715804491923206313525642116575645780779924185672529692478650699213858047e-20*y^12 + 4.35838982330499501029017237545791753358306603872195116798707081309709591350218669858335177012841369518071873786575180288919681671420107e-18*y^11 + 6.27608134555919281481784822065940124835961509575960968190138197085981811544314884596002654898491572106023498252668259616044341606844937e-16*y^10 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282382e-14*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282398e-12*y^8 + 6.15118732678256487780297304106827916351725875535399344923154446963970773494583018392542202066011589821113630637440161249685059208868731e-10*y^7 + 3.93675988914084152179390274628369866465104560342655580750818846056941295036533131771227009322247417485512723607961703199798437893675991e-8*y^6 + 1.92901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901234567901233e-6*y^5 + 0.0000694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444447*y^4 + 0.00173611111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112*y^3 + 0.0277777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777779*y^2 + 0.250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*y + 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; d = [0, 1]; w = 1; pf = fpminimax(f, 7, [|1, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1_1.sollya000064400000000000000000000121711046102023000201660ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 3.27795319155365450882301786771320700150596675703135078794150359633915771477548518124528208276133735129736680957981809606098543787303701e-79*y^33 + 3.90076429794884886549939126257871633179210044086730743765038927964359768058282736568188567848599144804386650339998353431257267106891404e-76*y^32 + 4.37665754229860842709031699661331972427073669465311894504373677176011659761393230429507573126128240470521821681478152549870653693932156e-73*y^31 + 4.62175036466733049900737474842366562882989794955369360596618603097868312708031251333559997221191421936871043695640929092663410300792356e-70*y^30 + 4.58477636174999185501531575043627630379925876595726405711845654273085366206367001322891517243421890561376075346075801659922103018386017e-67*y^29 + 4.26384201642749242516424364790573696253331065234025557312016458473969390571921311230289111036382358222079750071850495543727555807098996e-64*y^28 + 3.70954255429191840989289197367799115740398026753602234861454318872353369797571540770351526601652651653209382562509931123042973552176127e-61*y^27 + 3.01214855408503774883302828262652881981203197723925014707500906924350936275628091105525439600541953142406018640758064071910894524367015e-58*y^26 + 2.27718430688828853811776938166565578777789617479287311118870685634809307824374836875777232338009716575658950092413096438364636260421463e-55*y^25 + 1.59858338343557855375867410592929036302008311470459692405447221315636134092711135486795617101282821036112582964873993699731974654815867e-52*y^24 + 1.03907919923312605994313816885403873596305402455798800063540693855163487160262238066417151115833833673473178927168095904825783525630314e-49*y^23 + 6.23447519539875635965882901312423241577832414734792800381244163130980922961573428398502906695003002040839073563008575428954701153781882e-47*y^22 + 3.44143030786011351053167361524457629350963492933605625810446778048301469474788532475973604495641657126543168606780733636782995036887599e-44*y^21 + 1.74136373577721743632902684931375560451587527424404446660086069692440543554242997432842643874794678506030843315031051220212195488665125e-41*y^20 + 8.04510045929074455584010404382955089286334376700748543569597641979075311220602648139733014701551414697862496115443456637380343157632878e-39*y^19 + 3.37894219290211271345284369840841137500260438214314388299231009631211630712653112218687866174651594173102248368486251787699744126205809e-36*y^18 + 1.28399803330280283111208060539519632250098966521439467553707783659860419670808182643101389146367605785778854380024775679325902767958207e-33*y^17 + 4.39127327389558568240331567045157142295338465503322979033680620116722635274163984639406750880577211787363681979684732823294587466417069e-31*y^16 + 1.34372962181204921881541459515818085542373570444016831584306269755717126393894179299658465769456626806933286685783528243928143764723623e-28*y^15 + 3.65494457132877387517792769883025192675256111607725781909313053735550583791392167695071026892922024914858539785331196823484551040048255e-26*y^14 + 8.77186697118905730042702647719260462420614667858541876582351328965321401099341202468170464543012859795660495484794872376362922496115812e-24*y^13 + 1.84209206394970203308967556021044697108329080250293794082293779082717494230861652518315797554032700557088704051806923199036213724184320e-21*y^12 + 3.35260755638845770022320951958301348737158926055534705229774677930545839500168207583334751548339515013901441374288600222245908978015463e-19*y^11 + 5.23006778796599401234820685054950104029967924646634140158448497571651509620262403830002212415409643421686248543890216346703618005704123e-17*y^10 + 6.90368948011511209629963304272534137319557660533557065009152016794579992698746373055602920388340729316625848077935085577648775767529442e-15*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386e-13*y^8 + 6.83465258531396097533663671229808795946362083928221494359060496626634192771758909325046891184457322023459589597155734721872288009854147e-11*y^7 + 4.92094986142605190224237843285462333081380700428319475938523557571176618795666414714033761652809271856890904509952128999748047367094986e-9*y^6 + 2.75573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192e-7*y^5 + 0.0000115740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740741*y^4 + 0.000347222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*y^3 + 0.00694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*y^2 + 0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333*y; d = [0, 1]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16|], [|107, 107, 107, 107, 107, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1_big.sollya000064400000000000000000000005051046102023000205650ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i1_approximant_big = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 1000; f = bessel_i1_approximant_big(1/x); d = [1/713.98, 1/7.75]; w = 1; pf = remez(f, 29, d, 1, 1e-36); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1_big_rational.sollya000064400000000000000000000005161046102023000224600ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i1_approximant_big = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); prec = 500; f = bessel_i1_approximant_big(1/x); d = [1/713.98, 1/7.75]; w = 1; pf = remez(f, 40, d); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1_small.sollya000064400000000000000000000122631046102023000211400ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 3.27795319155365450882301786771320700150596675703135078794150359633915771477548518124528208276133735129736680957981809606098543787303701e-79*y^33 + 3.90076429794884886549939126257871633179210044086730743765038927964359768058282736568188567848599144804386650339998353431257267106891404e-76*y^32 + 4.37665754229860842709031699661331972427073669465311894504373677176011659761393230429507573126128240470521821681478152549870653693932156e-73*y^31 + 4.62175036466733049900737474842366562882989794955369360596618603097868312708031251333559997221191421936871043695640929092663410300792356e-70*y^30 + 4.58477636174999185501531575043627630379925876595726405711845654273085366206367001322891517243421890561376075346075801659922103018386017e-67*y^29 + 4.26384201642749242516424364790573696253331065234025557312016458473969390571921311230289111036382358222079750071850495543727555807098996e-64*y^28 + 3.70954255429191840989289197367799115740398026753602234861454318872353369797571540770351526601652651653209382562509931123042973552176127e-61*y^27 + 3.01214855408503774883302828262652881981203197723925014707500906924350936275628091105525439600541953142406018640758064071910894524367015e-58*y^26 + 2.27718430688828853811776938166565578777789617479287311118870685634809307824374836875777232338009716575658950092413096438364636260421463e-55*y^25 + 1.59858338343557855375867410592929036302008311470459692405447221315636134092711135486795617101282821036112582964873993699731974654815867e-52*y^24 + 1.03907919923312605994313816885403873596305402455798800063540693855163487160262238066417151115833833673473178927168095904825783525630314e-49*y^23 + 6.23447519539875635965882901312423241577832414734792800381244163130980922961573428398502906695003002040839073563008575428954701153781882e-47*y^22 + 3.44143030786011351053167361524457629350963492933605625810446778048301469474788532475973604495641657126543168606780733636782995036887599e-44*y^21 + 1.74136373577721743632902684931375560451587527424404446660086069692440543554242997432842643874794678506030843315031051220212195488665125e-41*y^20 + 8.04510045929074455584010404382955089286334376700748543569597641979075311220602648139733014701551414697862496115443456637380343157632878e-39*y^19 + 3.37894219290211271345284369840841137500260438214314388299231009631211630712653112218687866174651594173102248368486251787699744126205809e-36*y^18 + 1.28399803330280283111208060539519632250098966521439467553707783659860419670808182643101389146367605785778854380024775679325902767958207e-33*y^17 + 4.39127327389558568240331567045157142295338465503322979033680620116722635274163984639406750880577211787363681979684732823294587466417069e-31*y^16 + 1.34372962181204921881541459515818085542373570444016831584306269755717126393894179299658465769456626806933286685783528243928143764723623e-28*y^15 + 3.65494457132877387517792769883025192675256111607725781909313053735550583791392167695071026892922024914858539785331196823484551040048255e-26*y^14 + 8.77186697118905730042702647719260462420614667858541876582351328965321401099341202468170464543012859795660495484794872376362922496115812e-24*y^13 + 1.84209206394970203308967556021044697108329080250293794082293779082717494230861652518315797554032700557088704051806923199036213724184320e-21*y^12 + 3.35260755638845770022320951958301348737158926055534705229774677930545839500168207583334751548339515013901441374288600222245908978015463e-19*y^11 + 5.23006778796599401234820685054950104029967924646634140158448497571651509620262403830002212415409643421686248543890216346703618005704123e-17*y^10 + 6.90368948011511209629963304272534137319557660533557065009152016794579992698746373055602920388340729316625848077935085577648775767529442e-15*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386e-13*y^8 + 6.83465258531396097533663671229808795946362083928221494359060496626634192771758909325046891184457322023459589597155734721872288009854147e-11*y^7 + 4.92094986142605190224237843285462333081380700428319475938523557571176618795666414714033761652809271856890904509952128999748047367094986e-9*y^6 + 2.75573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192e-7*y^5 + 0.0000115740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740741*y^4 + 0.000347222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*y^3 + 0.00694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*y^2 + 0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333*y; d = [0, ((7.75)/2)^2]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22, 23|], [|107, 107, 107, 107, 107, 107, 107, 107, 107, 107, D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1_small_rational.sollya000064400000000000000000000121711046102023000230270ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 3.27795319155365450882301786771320700150596675703135078794150359633915771477548518124528208276133735129736680957981809606098543787303701e-79*y^33 + 3.90076429794884886549939126257871633179210044086730743765038927964359768058282736568188567848599144804386650339998353431257267106891404e-76*y^32 + 4.37665754229860842709031699661331972427073669465311894504373677176011659761393230429507573126128240470521821681478152549870653693932156e-73*y^31 + 4.62175036466733049900737474842366562882989794955369360596618603097868312708031251333559997221191421936871043695640929092663410300792356e-70*y^30 + 4.58477636174999185501531575043627630379925876595726405711845654273085366206367001322891517243421890561376075346075801659922103018386017e-67*y^29 + 4.26384201642749242516424364790573696253331065234025557312016458473969390571921311230289111036382358222079750071850495543727555807098996e-64*y^28 + 3.70954255429191840989289197367799115740398026753602234861454318872353369797571540770351526601652651653209382562509931123042973552176127e-61*y^27 + 3.01214855408503774883302828262652881981203197723925014707500906924350936275628091105525439600541953142406018640758064071910894524367015e-58*y^26 + 2.27718430688828853811776938166565578777789617479287311118870685634809307824374836875777232338009716575658950092413096438364636260421463e-55*y^25 + 1.59858338343557855375867410592929036302008311470459692405447221315636134092711135486795617101282821036112582964873993699731974654815867e-52*y^24 + 1.03907919923312605994313816885403873596305402455798800063540693855163487160262238066417151115833833673473178927168095904825783525630314e-49*y^23 + 6.23447519539875635965882901312423241577832414734792800381244163130980922961573428398502906695003002040839073563008575428954701153781882e-47*y^22 + 3.44143030786011351053167361524457629350963492933605625810446778048301469474788532475973604495641657126543168606780733636782995036887599e-44*y^21 + 1.74136373577721743632902684931375560451587527424404446660086069692440543554242997432842643874794678506030843315031051220212195488665125e-41*y^20 + 8.04510045929074455584010404382955089286334376700748543569597641979075311220602648139733014701551414697862496115443456637380343157632878e-39*y^19 + 3.37894219290211271345284369840841137500260438214314388299231009631211630712653112218687866174651594173102248368486251787699744126205809e-36*y^18 + 1.28399803330280283111208060539519632250098966521439467553707783659860419670808182643101389146367605785778854380024775679325902767958207e-33*y^17 + 4.39127327389558568240331567045157142295338465503322979033680620116722635274163984639406750880577211787363681979684732823294587466417069e-31*y^16 + 1.34372962181204921881541459515818085542373570444016831584306269755717126393894179299658465769456626806933286685783528243928143764723623e-28*y^15 + 3.65494457132877387517792769883025192675256111607725781909313053735550583791392167695071026892922024914858539785331196823484551040048255e-26*y^14 + 8.77186697118905730042702647719260462420614667858541876582351328965321401099341202468170464543012859795660495484794872376362922496115812e-24*y^13 + 1.84209206394970203308967556021044697108329080250293794082293779082717494230861652518315797554032700557088704051806923199036213724184320e-21*y^12 + 3.35260755638845770022320951958301348737158926055534705229774677930545839500168207583334751548339515013901441374288600222245908978015463e-19*y^11 + 5.23006778796599401234820685054950104029967924646634140158448497571651509620262403830002212415409643421686248543890216346703618005704123e-17*y^10 + 6.90368948011511209629963304272534137319557660533557065009152016794579992698746373055602920388340729316625848077935085577648775767529442e-15*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386e-13*y^8 + 6.83465258531396097533663671229808795946362083928221494359060496626634192771758909325046891184457322023459589597155734721872288009854147e-11*y^7 + 4.92094986142605190224237843285462333081380700428319475938523557571176618795666414714033761652809271856890904509952128999748047367094986e-9*y^6 + 2.75573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192e-7*y^5 + 0.0000115740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740741*y^4 + 0.000347222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*y^3 + 0.00694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*y^2 + 0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333*y; d = [0, 7.5]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23|], [|127...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1_tiny_rational.sollya000064400000000000000000000121411046102023000226770ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 3.27795319155365450882301786771320700150596675703135078794150359633915771477548518124528208276133735129736680957981809606098543787303701e-79*y^33 + 3.90076429794884886549939126257871633179210044086730743765038927964359768058282736568188567848599144804386650339998353431257267106891404e-76*y^32 + 4.37665754229860842709031699661331972427073669465311894504373677176011659761393230429507573126128240470521821681478152549870653693932156e-73*y^31 + 4.62175036466733049900737474842366562882989794955369360596618603097868312708031251333559997221191421936871043695640929092663410300792356e-70*y^30 + 4.58477636174999185501531575043627630379925876595726405711845654273085366206367001322891517243421890561376075346075801659922103018386017e-67*y^29 + 4.26384201642749242516424364790573696253331065234025557312016458473969390571921311230289111036382358222079750071850495543727555807098996e-64*y^28 + 3.70954255429191840989289197367799115740398026753602234861454318872353369797571540770351526601652651653209382562509931123042973552176127e-61*y^27 + 3.01214855408503774883302828262652881981203197723925014707500906924350936275628091105525439600541953142406018640758064071910894524367015e-58*y^26 + 2.27718430688828853811776938166565578777789617479287311118870685634809307824374836875777232338009716575658950092413096438364636260421463e-55*y^25 + 1.59858338343557855375867410592929036302008311470459692405447221315636134092711135486795617101282821036112582964873993699731974654815867e-52*y^24 + 1.03907919923312605994313816885403873596305402455798800063540693855163487160262238066417151115833833673473178927168095904825783525630314e-49*y^23 + 6.23447519539875635965882901312423241577832414734792800381244163130980922961573428398502906695003002040839073563008575428954701153781882e-47*y^22 + 3.44143030786011351053167361524457629350963492933605625810446778048301469474788532475973604495641657126543168606780733636782995036887599e-44*y^21 + 1.74136373577721743632902684931375560451587527424404446660086069692440543554242997432842643874794678506030843315031051220212195488665125e-41*y^20 + 8.04510045929074455584010404382955089286334376700748543569597641979075311220602648139733014701551414697862496115443456637380343157632878e-39*y^19 + 3.37894219290211271345284369840841137500260438214314388299231009631211630712653112218687866174651594173102248368486251787699744126205809e-36*y^18 + 1.28399803330280283111208060539519632250098966521439467553707783659860419670808182643101389146367605785778854380024775679325902767958207e-33*y^17 + 4.39127327389558568240331567045157142295338465503322979033680620116722635274163984639406750880577211787363681979684732823294587466417069e-31*y^16 + 1.34372962181204921881541459515818085542373570444016831584306269755717126393894179299658465769456626806933286685783528243928143764723623e-28*y^15 + 3.65494457132877387517792769883025192675256111607725781909313053735550583791392167695071026892922024914858539785331196823484551040048255e-26*y^14 + 8.77186697118905730042702647719260462420614667858541876582351328965321401099341202468170464543012859795660495484794872376362922496115812e-24*y^13 + 1.84209206394970203308967556021044697108329080250293794082293779082717494230861652518315797554032700557088704051806923199036213724184320e-21*y^12 + 3.35260755638845770022320951958301348737158926055534705229774677930545839500168207583334751548339515013901441374288600222245908978015463e-19*y^11 + 5.23006778796599401234820685054950104029967924646634140158448497571651509620262403830002212415409643421686248543890216346703618005704123e-17*y^10 + 6.90368948011511209629963304272534137319557660533557065009152016794579992698746373055602920388340729316625848077935085577648775767529442e-15*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386e-13*y^8 + 6.83465258531396097533663671229808795946362083928221494359060496626634192771758909325046891184457322023459589597155734721872288009854147e-11*y^7 + 4.92094986142605190224237843285462333081380700428319475938523557571176618795666414714033761652809271856890904509952128999748047367094986e-9*y^6 + 2.75573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192e-7*y^5 + 0.0000115740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740741*y^4 + 0.000347222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*y^3 + 0.00694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*y^2 + 0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333*y; d = [0, 1.0]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|], [|127...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1f_big.sollya000064400000000000000000000005031046102023000207310ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_i1_approximant_big = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 1000; f = bessel_i1_approximant_big(1/x); d = [1/91.9, 1/7.75]; w = 1; pf = remez(f, 17, d, 1, 1e-25); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_i1f_small.sollya000064400000000000000000000121421046102023000213020ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; f = 3.27795319155365450882301786771320700150596675703135078794150359633915771477548518124528208276133735129736680957981809606098543787303701e-79*y^33 + 3.90076429794884886549939126257871633179210044086730743765038927964359768058282736568188567848599144804386650339998353431257267106891404e-76*y^32 + 4.37665754229860842709031699661331972427073669465311894504373677176011659761393230429507573126128240470521821681478152549870653693932156e-73*y^31 + 4.62175036466733049900737474842366562882989794955369360596618603097868312708031251333559997221191421936871043695640929092663410300792356e-70*y^30 + 4.58477636174999185501531575043627630379925876595726405711845654273085366206367001322891517243421890561376075346075801659922103018386017e-67*y^29 + 4.26384201642749242516424364790573696253331065234025557312016458473969390571921311230289111036382358222079750071850495543727555807098996e-64*y^28 + 3.70954255429191840989289197367799115740398026753602234861454318872353369797571540770351526601652651653209382562509931123042973552176127e-61*y^27 + 3.01214855408503774883302828262652881981203197723925014707500906924350936275628091105525439600541953142406018640758064071910894524367015e-58*y^26 + 2.27718430688828853811776938166565578777789617479287311118870685634809307824374836875777232338009716575658950092413096438364636260421463e-55*y^25 + 1.59858338343557855375867410592929036302008311470459692405447221315636134092711135486795617101282821036112582964873993699731974654815867e-52*y^24 + 1.03907919923312605994313816885403873596305402455798800063540693855163487160262238066417151115833833673473178927168095904825783525630314e-49*y^23 + 6.23447519539875635965882901312423241577832414734792800381244163130980922961573428398502906695003002040839073563008575428954701153781882e-47*y^22 + 3.44143030786011351053167361524457629350963492933605625810446778048301469474788532475973604495641657126543168606780733636782995036887599e-44*y^21 + 1.74136373577721743632902684931375560451587527424404446660086069692440543554242997432842643874794678506030843315031051220212195488665125e-41*y^20 + 8.04510045929074455584010404382955089286334376700748543569597641979075311220602648139733014701551414697862496115443456637380343157632878e-39*y^19 + 3.37894219290211271345284369840841137500260438214314388299231009631211630712653112218687866174651594173102248368486251787699744126205809e-36*y^18 + 1.28399803330280283111208060539519632250098966521439467553707783659860419670808182643101389146367605785778854380024775679325902767958207e-33*y^17 + 4.39127327389558568240331567045157142295338465503322979033680620116722635274163984639406750880577211787363681979684732823294587466417069e-31*y^16 + 1.34372962181204921881541459515818085542373570444016831584306269755717126393894179299658465769456626806933286685783528243928143764723623e-28*y^15 + 3.65494457132877387517792769883025192675256111607725781909313053735550583791392167695071026892922024914858539785331196823484551040048255e-26*y^14 + 8.77186697118905730042702647719260462420614667858541876582351328965321401099341202468170464543012859795660495484794872376362922496115812e-24*y^13 + 1.84209206394970203308967556021044697108329080250293794082293779082717494230861652518315797554032700557088704051806923199036213724184320e-21*y^12 + 3.35260755638845770022320951958301348737158926055534705229774677930545839500168207583334751548339515013901441374288600222245908978015463e-19*y^11 + 5.23006778796599401234820685054950104029967924646634140158448497571651509620262403830002212415409643421686248543890216346703618005704123e-17*y^10 + 6.90368948011511209629963304272534137319557660533557065009152016794579992698746373055602920388340729316625848077935085577648775767529442e-15*y^9 + 7.59405842812662330592959634699787551051513426586912771510067218474037991968621010361163212427174802248288432885728594135413653344282386e-13*y^8 + 6.83465258531396097533663671229808795946362083928221494359060496626634192771758909325046891184457322023459589597155734721872288009854147e-11*y^7 + 4.92094986142605190224237843285462333081380700428319475938523557571176618795666414714033761652809271856890904509952128999748047367094986e-9*y^6 + 2.75573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906525573192e-7*y^5 + 0.0000115740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740740741*y^4 + 0.000347222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*y^3 + 0.00694444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*y^2 + 0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333*y; d = [0, ((7.75)/2)^2]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9,10,11,12,13|], [|D...|], d, relative, floating); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_j0f_at_zero.sollya000064400000000000000000000010021046102023000216260ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; bessel_j0 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j0(x); d = [0, 1.2]; w = 1; pf = remez(f, 21, d); w = 1; or_f = bessel_j0(x); err_p = -log2(dirtyinfnorm(pf*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; //for i from 0 to degree(pf) do { // write(coeff(pf, i)) >> "coefficients.txt"; // write("\n") >> "coefficients.txt"; //};pxfm-0.1.23/notes/bessel_sollya/bessel_j1_at_zero.sollya000064400000000000000000000007711046102023000214750ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; //prec = 1500; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x)/x; d = [0, 0.921]; w = 1; pf = fpminimax(f, [|0,2,4,6,8,10,12,14,16,18,20,22,24|], [|107, 107, 107, 107, 107, D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x); pf1 = pf * x; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_j1_at_zero_fast.sollya000064400000000000000000000007711046102023000225120ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; //prec = 1500; bessel_j1 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x)/x; d = [0, 0.921]; w = 1; pf = fpminimax(f, [|0,2,4,6,8,10,12,14,16,18,20,22,24|], [|107, D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x); pf1 = pf * x; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_j1_small.sollya000064400000000000000000000007121046102023000211350ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x + 74.601095613456402477925006047823); d = [-0.83210, 0.88000]; pf = remez(f, 23, d); w = 1; or_f = bessel_j1(x + 74.601095613456402477925006047823); err_p = -log2(dirtyinfnorm(pf*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_j1f_at_zero.sollya000064400000000000000000000007141046102023000216400ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; //prec = 1500; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x)/x; d = [0, 1.2]; w = 1; pf = fpminimax(f, [|0,2,4,6,8,10,12|], [|D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x); pf1 = pf * x; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_j1f_small.sollya000064400000000000000000000012731046102023000213060ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 500; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x + 10.173468135062722077185711776775842874118326); d = [-0.82, 0.77]; w = 1; pf = remez(f, 21, d); //pf = fpminimax(f, [|0,2,4,6,8,10,12,14,16,18|], [|D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x + 10.173468135062722077185711776775842874118326); err_p = -log2(dirtyinfnorm(pf*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; //for i from 0 to degree(pf) do { // write(coeff(pf, i)) >> "coefficients.txt"; // write("\n") >> "coefficients.txt"; //};pxfm-0.1.23/notes/bessel_sollya/bessel_k0f_big.sollya000064400000000000000000000005741046102023000207420ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_k0_asympt = library("./cmake-build-release/libbessel_sollya.dylib"); prec = 500; f = bessel_k0_asympt(1/x); d = [0.01, 0.02]; w = 1; pf = remez(f, 8, d); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; pxfm-0.1.23/notes/bessel_sollya/bessel_k0f_small.sollya000064400000000000000000000006021046102023000213010ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 300; bessel_k0_approximant = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_k0_approximant(x); d = [0.5; 1.0]; w = 1; pf = remez(f, 10, d); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_k1f_small0.sollya000064400000000000000000000060271046102023000213710ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 300; f = 0.00000000000000000020692167086265082511710020738323417419747309727993 * x^33 * (-5534.4165244481371912715895329923458737737584734314+2520.0000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 *x^2)-2520.0000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000000026817048543799546935176186876867148975992513407479 * x^29 * (-1163.7592276551415980603532295538546386163907718736+560.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-560.00000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000024028075495244394053917863441672965482489292013102 * x^25 * (-272.18980691378539951508830738846365965409769296841+140.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-140.00000000000000000000000000000000000000000000000 * log(x^2))+0.000000011302806712962962962962962962962962962962962962963 * x^17 * (-96.367060105908028363609274595055854137470439843605+60.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-60.000000000000000000000000000000000000000000000000 * log(x^2))+0.00000000018838011188271604938271604938271604938271604938272 * x^21 * (-53.683530052954014181804637297527927068735219921802+30.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-30.000000000000000000000000000000000000000000000000 * log(x^2))+0.0000022605613425925925925925925925925925925925925925926 * x^13 * (-33.146824042363211345443709838022341654988175937442+24.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-24.000000000000000000000000000000000000000000000000 * log(x^2))+0.015625000000000000000000000000000000000000000000000 * x^5 * (-2.6911373403938685575739516396703902758313626562403+4.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-4.0000000000000000000000000000000000000000000000000 * log(x^2))+0.00086805555555555555555555555555555555555555555555556 * x^9 * (-3.2683530052954014181804637297527927068735219921802+3.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-3.0000000000000000000000000000000000000000000000000 * log(x^2))+0.25000000000000000000000000000000000000000000000000 * x * (0.15443132980306572121302418016480486208431867187985+2.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-2.0000000000000000000000000000000000000000000000000 * log(x^2)); d = [0.00001; 0.001]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8|], [|D...|], d, absolute, floating); print(pf); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_k1f_small1.sollya000064400000000000000000000060241046102023000213670ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 300; f = 0.00000000000000000020692167086265082511710020738323417419747309727993 * x^33 * (-5534.4165244481371912715895329923458737737584734314+2520.0000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 *x^2)-2520.0000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000000026817048543799546935176186876867148975992513407479 * x^29 * (-1163.7592276551415980603532295538546386163907718736+560.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-560.00000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000024028075495244394053917863441672965482489292013102 * x^25 * (-272.18980691378539951508830738846365965409769296841+140.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-140.00000000000000000000000000000000000000000000000 * log(x^2))+0.000000011302806712962962962962962962962962962962962962963 * x^17 * (-96.367060105908028363609274595055854137470439843605+60.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-60.000000000000000000000000000000000000000000000000 * log(x^2))+0.00000000018838011188271604938271604938271604938271604938272 * x^21 * (-53.683530052954014181804637297527927068735219921802+30.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-30.000000000000000000000000000000000000000000000000 * log(x^2))+0.0000022605613425925925925925925925925925925925925925926 * x^13 * (-33.146824042363211345443709838022341654988175937442+24.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-24.000000000000000000000000000000000000000000000000 * log(x^2))+0.015625000000000000000000000000000000000000000000000 * x^5 * (-2.6911373403938685575739516396703902758313626562403+4.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-4.0000000000000000000000000000000000000000000000000 * log(x^2))+0.00086805555555555555555555555555555555555555555555556 * x^9 * (-3.2683530052954014181804637297527927068735219921802+3.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-3.0000000000000000000000000000000000000000000000000 * log(x^2))+0.25000000000000000000000000000000000000000000000000 * x * (0.15443132980306572121302418016480486208431867187985+2.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-2.0000000000000000000000000000000000000000000000000 * log(x^2)); d = [0.001; 0.01]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8|], [|D...|], d, absolute, floating); print(pf); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_k1f_small2.sollya000064400000000000000000000060261046102023000213720ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 140; f = 0.00000000000000000020692167086265082511710020738323417419747309727993 * x^33 * (-5534.4165244481371912715895329923458737737584734314+2520.0000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 *x^2)-2520.0000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000000026817048543799546935176186876867148975992513407479 * x^29 * (-1163.7592276551415980603532295538546386163907718736+560.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-560.00000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000024028075495244394053917863441672965482489292013102 * x^25 * (-272.18980691378539951508830738846365965409769296841+140.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-140.00000000000000000000000000000000000000000000000 * log(x^2))+0.000000011302806712962962962962962962962962962962962962963 * x^17 * (-96.367060105908028363609274595055854137470439843605+60.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-60.000000000000000000000000000000000000000000000000 * log(x^2))+0.00000000018838011188271604938271604938271604938271604938272 * x^21 * (-53.683530052954014181804637297527927068735219921802+30.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-30.000000000000000000000000000000000000000000000000 * log(x^2))+0.0000022605613425925925925925925925925925925925925925926 * x^13 * (-33.146824042363211345443709838022341654988175937442+24.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-24.000000000000000000000000000000000000000000000000 * log(x^2))+0.015625000000000000000000000000000000000000000000000 * x^5 * (-2.6911373403938685575739516396703902758313626562403+4.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-4.0000000000000000000000000000000000000000000000000 * log(x^2))+0.00086805555555555555555555555555555555555555555555556 * x^9 * (-3.2683530052954014181804637297527927068735219921802+3.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-3.0000000000000000000000000000000000000000000000000 * log(x^2))+0.25000000000000000000000000000000000000000000000000 * x * (0.15443132980306572121302418016480486208431867187985+2.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-2.0000000000000000000000000000000000000000000000000 * log(x^2)); d = [0.00000001; 1]; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8|], [|D...|], d, relative, floating); print(pf); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_k1f_tiny.sollya000064400000000000000000000060211046102023000211560ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 300; f = 0.00000000000000000020692167086265082511710020738323417419747309727993 * x^33 * (-5534.4165244481371912715895329923458737737584734314+2520.0000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 *x^2)-2520.0000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000000026817048543799546935176186876867148975992513407479 * x^29 * (-1163.7592276551415980603532295538546386163907718736+560.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-560.00000000000000000000000000000000000000000000000 * log(x^2))+0.00000000000024028075495244394053917863441672965482489292013102 * x^25 * (-272.18980691378539951508830738846365965409769296841+140.00000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-140.00000000000000000000000000000000000000000000000 * log(x^2))+0.000000011302806712962962962962962962962962962962962962963 * x^17 * (-96.367060105908028363609274595055854137470439843605+60.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-60.000000000000000000000000000000000000000000000000 * log(x^2))+0.00000000018838011188271604938271604938271604938271604938272 * x^21 * (-53.683530052954014181804637297527927068735219921802+30.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-30.000000000000000000000000000000000000000000000000 * log(x^2))+0.0000022605613425925925925925925925925925925925925925926 * x^13 * (-33.146824042363211345443709838022341654988175937442+24.000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-24.000000000000000000000000000000000000000000000000 * log(x^2))+0.015625000000000000000000000000000000000000000000000 * x^5 * (-2.6911373403938685575739516396703902758313626562403+4.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-4.0000000000000000000000000000000000000000000000000 * log(x^2))+0.00086805555555555555555555555555555555555555555555556 * x^9 * (-3.2683530052954014181804637297527927068735219921802+3.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-3.0000000000000000000000000000000000000000000000000 * log(x^2))+0.25000000000000000000000000000000000000000000000000 * x * (0.15443132980306572121302418016480486208431867187985+2.0000000000000000000000000000000000000000000000000 * log(0.50000000000000000000000000000000000000000000000000 * x^2)-2.0000000000000000000000000000000000000000000000000 * log(x^2)); d = [2^-23; 0.00001]; w = 1; pf = fpminimax(f, [|1,2,3,4,5|], [|D...|], d, absolute, floating); print(pf); w = 1; err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/bessel_sollya/bessel_y0f_small.sollya000064400000000000000000000011471046102023000213240ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 250; bessel_y0 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_y0(x + 10.173468135062722077185711776775842874118326); d = [-0.82, 0.77]; w = 1; pf = remez(f, 27, d); w = 1; or_f = bessel_y0(x + 10.173468135062722077185711776775842874118326); err_p = -log2(dirtyinfnorm(pf*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do { print("'", coeff(pf, i), "',"); }; //for i from 0 to degree(pf) do { // write(coeff(pf, i)) >> "coefficients.txt"; // write("\n") >> "coefficients.txt"; //};pxfm-0.1.23/notes/bessel_sollya/library.h000064400000000000000000000013531046102023000164700ustar 00000000000000#ifndef BESSEL_SOLLYA_LIBRARY_H #define BESSEL_SOLLYA_LIBRARY_H #include int bessel_y1(mpfi_t result, mpfi_t x, int n); int bessel_i0_approximant(mpfi_t result, mpfi_t x, int n); int bessel_i0(mpfi_t result, mpfi_t x, int n); int bessel_i1_approximant_small(mpfi_t result, mpfi_t x, int n); int bessel_i1_approximant_big(mpfi_t result, mpfi_t x, int n); int bessel_j1(mpfi_t result, mpfi_t x, int n); int bessel_j0(mpfi_t result, mpfi_t x, int n); int bessel_y0(mpfi_t result, mpfi_t x, int n); int bessel_k0(mpfi_t result, mpfi_t x, int n); int bessel_k0_approximant(mpfi_t result, mpfi_t x, int n); int bessel_k0_asympt(mpfi_t result, mpfi_t x, int n); int pxfm_gamma(mpfi_t result, mpfi_t x, int n); #endif //BESSEL_SOLLYA_LIBRARY_Hpxfm-0.1.23/notes/bessel_y0_taylor.ipynb000064400000000000000000004517741046102023000163550ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "7a069ab0-9bd6-4940-b375-68f817251b86", "metadata": {}, "outputs": [], "source": [ "from mpmath import mp, mpf, findroot, bessely\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")" ] }, { "cell_type": "code", "execution_count": 2, "id": "15966b0e-5d2d-4020-9d66-302cf344c839", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W = 0.515740866931212572\n", "Z = -0.0580326104859750086\n", "LOG = -0.11252280788079415479644853102767\n", "(0x3c7abc9e3b39803f, 0x3fe62e42fefa39ef),\n", "r = -2.338927928406201408822986214495e-17\n", "t = -2.338927928406210311869215576136051e-17\n", "(0xbc5ddfd831a70821, 0x3fb2e4d699cbd01f),\n", "(0xbc6d93e63489aea6, 0xbfc6bbcb41034286),\n", "(0xbc1b88525c2e130b, 0x3f9075b1bbf41364),\n", "(0x3be097334e26e578, 0xbf41a6206b7b973d),\n", "(0x3b51c64a34c78cda, 0x3ee3e99794203bbd),\n", "(0xbb1c407b0f5b2805, 0xbe7bce4a600d3ea4),\n", "(0xbaa57d1e1e88c9ca, 0x3e0a6ee796b871b6),\n", "(0x3a3b6e7030a77899, 0xbd92393d82c6b2e4),\n", "(0x397fcfedacb03781, 0x3d131085da82054c),\n", "(0xb8e45f51f6118e46, 0xbc8f4ed4b492ebcc),\n", "(0xb89bd46046c3c8de, 0x3c04b7ac8a1b15d0),\n", "(0x37d1a206fb205e32, 0xbb769201941d0d49),\n", "(0x3782f38acbf23993, 0x3ae4987e587ab039),\n", "(0x36b691bdabf5672b, 0xba4ff1953e0a7c5b),\n", "(0x3636e1c8cd260e18, 0x39b55031dc5e1967),\n" ] } ], "source": [ "from sage.all import *\n", "\n", "R = LaurentSeriesRing(RealField(300), 'x',default_prec=300)\n", "x = R.gen()\n", "N = 16 # Number of terms (adjust as needed)\n", "gamma = RealField(300)(euler_gamma)\n", "d2 = RealField(300)(2)\n", "pi = RealField(300).pi()\n", "\n", "# Define J0(x) Taylor expansion at x = 0\n", "def j_series(n, x):\n", " return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)])\n", "\n", "J0_series = j_series(0, x)\n", "\n", "def z_series(x):\n", " return sum([(-1)**m * (x/2)**(ZZ(2)*ZZ(m)) / ZZ(m).factorial()**ZZ(2) * sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) for m in range(1, N)])\n", "\n", "W0 = (d2/pi) * J0_series\n", "Z0 = -gamma * (d2/pi) * J0_series + RealField(300)(2).log() * (d2/pi) * J0_series + (d2/pi) * z_series(x)\n", "\n", "# print(\"W0(x) =\", W0)\n", "# print(\"Z0(x) =\", Z0)\n", "\n", "terms = 30\n", "\n", "from mpmath import mp, bessely, taylor\n", "\n", "def Y0_approx(val):\n", " # Substitute numeric value and convert to high precision real\n", " w = W0.truncate(terms)(val)\n", " z = Z0.truncate(terms)(val)\n", " return RealField(107)(w) * RealField(107)(val).log() - RealField(107)(z)\n", "\n", "mp.prec = 120\n", "\n", "print(\"W = \", RealField(64)(W0.truncate(terms)(0.89357696627916749)))\n", "print(\"Z = \", RealField(64)(Z0.truncate(terms)(0.89357696627916749)))\n", "print(\"LOG = \", RealField(110)(0.89357696627916749).log())\n", "print_double_double(\"\", RealField(110)(2).log())\n", "print(\"r = \", Y0_approx(RealField(100)(0.89357696627916749)))\n", "print(\"t = \", bessely(0, 0.89357696627916749))\n", "\n", "def print_series(z, N):\n", " for i in range(N):\n", " coeff = z[i]\n", " if coeff != 0:\n", " # print(double_to_hex(RealField(300)(coeff)) + \",\")\n", " print_double_double(\"\", RealField(300)(coeff))\n", "\n", "print_series(Z0, 30)\n", "\n", "# W0_series = W0.series(x, 2*N)\n", "# Z0_series_expanded = Z0.series(x, 2*N)\n", "\n", "# print(\"W0(x) power series:\")\n", "# for i in range(0, 2*N):\n", "# coeff = W0_series.coefficient(x, i)\n", "# if coeff != 0:\n", "# print(f\"x^{i}: {coeff}\")" ] }, { "cell_type": "code", "execution_count": 177, "id": "f9f8e3fa-00ee-4d90-bc07-c61358f982ce", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0x3c755555556795ff, 0x3fd5555555555555),\n", "(0xba86f68980000000, 0xbfd0000000000000),\n", "(0xbc699b285263b391, 0x3fc999999999999a),\n", "(0xbc65526cf5c49dc3, 0xbfc5555555555555),\n", "(0xbc34fc756f340748, 0x3fc24924924924aa),\n", "(0xbc52e654a63b293e, 0xbfc0000000000023),\n", "(0xbc5c73c13a9c2171, 0x3fbc71c71c2042d5),\n", "(0xbc3d2af5e7ee68d8, 0xbfb999999934f78b),\n", "(0xbc590d76077808da, 0x3fb74612a55c3e99),\n", "(0xbc3447161ca8047c, 0xbfb5559a592aadc7),\n", "(0x3c18760148059540, 0x3fb3b18880576230),\n", "(0xbc3b2424b7665f98, 0xbfb2496a29cbc904),\n" ] } ], "source": [ "# log coeffs\n", "\n", "print_double_double(\"\", RealField(107)('0.33333333333333333333333333701941430830813680984317'))\n", "print_double_double(\"\", RealField(107)('-0.25000000000000000000000000927469621095374516819563'))\n", "print_double_double(\"\", RealField(107)('0.19999999999999999999736148023407947320974191411113'))\n", "print_double_double(\"\", RealField(107)('-0.166666666666666666661740817355617089084687157682226'))\n", "print_double_double(\"\", RealField(107)('0.142857142857143514208845068731577058039341433616166'))\n", "print_double_double(\"\", RealField(107)('-0.125000000000000975543372027000681903260219080482025'))\n", "print_double_double(\"\", RealField(107)('0.111111111036972084401481914727934733718551705198942'))\n", "print_double_double(\"\", RealField(107)('-9.9999999908474789172229905677506311880264028108553e-2'))\n", "print_double_double(\"\", RealField(107)('9.0912976618933058600055577564907185974457745483036e-2'))\n", "print_double_double(\"\", RealField(107)('-8.333744694635135507057149825265760651408947697174e-2'))\n", "print_double_double(\"\", RealField(107)('7.6927691777549212280402265589168123489454885488853e-2'))\n", "print_double_double(\"\", RealField(107)('-7.1432719425306658106725949877427166499943643429565e-2'))" ] }, { "cell_type": "code", "execution_count": 3, "id": "d09892c2-9003-4c07-8d54-6011ea7a5b22", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Zero 1: x ≈ 3.9576784193148578683756771869174012814186038\n", "Zero 2: x ≈ 7.0860510603017726976236245968203524689715104\n", "Zero 3: x ≈ 10.22234504349641701899204227634218712599406\n", "Zero 4: x ≈ 13.361097473872763478267694585713786426579135\n", "Zero 5: x ≈ 16.500922441528090753421143666489774115751333\n", "Zero 6: x ≈ 19.641309700887939773776045472285980025441517\n", "Zero 7: x ≈ 22.782028047291559316932081968396516662816306\n", "Zero 8: x ≈ 25.922957653180922706872191146269373317052509\n", "Zero 9: x ≈ 29.064030252728398055304718405181344393605068\n", "Zero 10: x ≈ 32.205204116493280650953559661516194096980979\n", "Zero 11: x ≈ 35.346452305214320508799868706358214091282447\n", "Zero 12: x ≈ 38.487756653081537176464556122066562157372007\n", "Zero 13: x ≈ 41.629104466213807963834028403266947835118214\n", "Zero 14: x ≈ 44.770486607221993156366801616102992110196472\n", "Zero 15: x ≈ 47.911896331516480342150305098366009288219297\n", "Zero 16: x ≈ 51.053328552362362084622730461625767074078664\n", "Zero 17: x ≈ 54.19477936108705429869041017135112434866769\n", "Zero 18: x ≈ 57.336245704766280522194469751655579045492095\n", "Zero 19: x ≈ 60.477725164223475733312929993890880111162984\n", "Zero 20: x ≈ 63.61921579772037911632668674172406195191179\n", "Zero 21: x ≈ 66.760716028729644657324380151732884086510259\n", "Zero 22: x ≈ 69.902224563938499423840189433441406124611816\n", "Zero 23: x ≈ 73.043740332392073461652359520761344876173305\n", "Extrema (peaks/valleys) of Y0(x):\n", "nExtrema: 2.1971413260310170351490335626989662730530183\n", "nExtrema: 5.4296810407941351327720051908525841965837575\n", "nExtrema: 8.5960058683311689264296061801639678511029216\n", "nExtrema: 11.749154830839881243399421939922350714301166\n", "nExtrema: 14.897442128336725378844819156429870879807151\n", "nExtrema: 18.043402276727855564304555507889508902163088\n", "nExtrema: 21.188068934142213016142481528685423196935025\n", "nExtrema: 24.331942571356912035992944051850129651414333\n", "nExtrema: 27.475294980449223512212285525410668235700897\n", "nExtrema: 30.61828649164111471576162569644744831027794\n", "nExtrema: 33.761017796109325692471759911249650993879821\n", "nExtrema: 36.903555316142950053588159309844303659060545\n", "nExtrema: 40.045944640266876089064214537312936172020628\n", "nExtrema: 43.188218097393211268477533200127597207456358\n", "nExtrema: 46.330399250701686587724463565243621670014636\n", "nExtrema: 49.472505679924095824128003887609267273294894\n", "nExtrema: 52.614550767172957805120284895640403531617011\n", "nExtrema: 55.756544879208134886631236807492075985298424\n", "nExtrema: 58.898496171433054036050631513576196116955149\n", "nExtrema: 62.040411147670693473712823944067304389825849\n", "nExtrema: 65.18229505809561451746542971638249026690812\n", "nExtrema: 68.324152187403298603979275237541495840929062\n", "nExtrema: 71.465986066986123729425683592774276298807768\n", "nExtrema: 74.607799633511720751283338348407684418490569\n", "Peak or zero 1: x ≈ 2.1971413260310170351490335626989662730530183\n", "Peak or zero 2: x ≈ 3.9576784193148578683756771869174012814186038\n", "Peak or zero 3: x ≈ 5.4296810407941351327720051908525841965837575\n", "Peak or zero 4: x ≈ 7.0860510603017726976236245968203524689715104\n", "Peak or zero 5: x ≈ 8.5960058683311689264296061801639678511029216\n", "Peak or zero 6: x ≈ 10.22234504349641701899204227634218712599406\n", "Peak or zero 7: x ≈ 11.749154830839881243399421939922350714301166\n", "Peak or zero 8: x ≈ 13.361097473872763478267694585713786426579135\n", "Peak or zero 9: x ≈ 14.897442128336725378844819156429870879807151\n", "Peak or zero 10: x ≈ 16.500922441528090753421143666489774115751333\n", "Peak or zero 11: x ≈ 18.043402276727855564304555507889508902163088\n", "Peak or zero 12: x ≈ 19.641309700887939773776045472285980025441517\n", "Peak or zero 13: x ≈ 21.188068934142213016142481528685423196935025\n", "Peak or zero 14: x ≈ 22.782028047291559316932081968396516662816306\n", "Peak or zero 15: x ≈ 24.331942571356912035992944051850129651414333\n", "Peak or zero 16: x ≈ 25.922957653180922706872191146269373317052509\n", "Peak or zero 17: x ≈ 27.475294980449223512212285525410668235700897\n", "Peak or zero 18: x ≈ 29.064030252728398055304718405181344393605068\n", "Peak or zero 19: x ≈ 30.61828649164111471576162569644744831027794\n", "Peak or zero 20: x ≈ 32.205204116493280650953559661516194096980979\n", "Peak or zero 21: x ≈ 33.761017796109325692471759911249650993879821\n", "Peak or zero 22: x ≈ 35.346452305214320508799868706358214091282447\n", "Peak or zero 23: x ≈ 36.903555316142950053588159309844303659060545\n", "Peak or zero 24: x ≈ 38.487756653081537176464556122066562157372007\n", "Peak or zero 25: x ≈ 40.045944640266876089064214537312936172020628\n", "Peak or zero 26: x ≈ 41.629104466213807963834028403266947835118214\n", "Peak or zero 27: x ≈ 43.188218097393211268477533200127597207456358\n", "Peak or zero 28: x ≈ 44.770486607221993156366801616102992110196472\n", "Peak or zero 29: x ≈ 46.330399250701686587724463565243621670014636\n", "Peak or zero 30: x ≈ 47.911896331516480342150305098366009288219297\n", "Peak or zero 31: x ≈ 49.472505679924095824128003887609267273294894\n", "Peak or zero 32: x ≈ 51.053328552362362084622730461625767074078664\n", "Peak or zero 33: x ≈ 52.614550767172957805120284895640403531617011\n", "Peak or zero 34: x ≈ 54.19477936108705429869041017135112434866769\n", "Peak or zero 35: x ≈ 55.756544879208134886631236807492075985298424\n", "Peak or zero 36: x ≈ 57.336245704766280522194469751655579045492095\n", "Peak or zero 37: x ≈ 58.898496171433054036050631513576196116955149\n", "Peak or zero 38: x ≈ 60.477725164223475733312929993890880111162984\n", "Peak or zero 39: x ≈ 62.040411147670693473712823944067304389825849\n", "Peak or zero 40: x ≈ 63.61921579772037911632668674172406195191179\n", "Peak or zero 41: x ≈ 65.18229505809561451746542971638249026690812\n", "Peak or zero 42: x ≈ 66.760716028729644657324380151732884086510259\n", "Peak or zero 43: x ≈ 68.324152187403298603979275237541495840929062\n", "Peak or zero 44: x ≈ 69.902224563938499423840189433441406124611816\n", "Peak or zero 45: x ≈ 71.465986066986123729425683592774276298807768\n", "Peak or zero 46: x ≈ 73.043740332392073461652359520761344876173305\n", "Peak or zero 47: x ≈ 74.607799633511720751283338348407684418490569\n", "\n", "pub(crate) static Y0_ZEROS_RATIONAL128: [DyadicFloat128; 48] = [\n", "DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0u128, },\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0x8c9df6a6_ff921721_70d796f3_2017e155_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0xfd4a9a6c_c2b4de0f_95187fbc_7b23405a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -125,\n", " mantissa: 0xadbff274_3d8173bf_cf758451_d17ddc12_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -125,\n", " mantissa: 0xe2c0ee27_39081734_45adb505_49881acc_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0x89893d73_0b4da147_9cc068d9_0466df5b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xa38eb9ad_23eabc69_6c010dc7_6d6f6ad3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xbbfc89c6_a1903021_f8f0d9c0_c1004d6b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xd5c70e25_0f3a4d04_0fc42f21_b652c247_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xee5bec46_f4245543_edcb5e0e_3f61c303_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x8401e3a0_0190a24b_446fa242_b3576c07_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x9058e34a_f8f1d4bc_236756f0_2443a2d1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x9d2166fa_ff5eb4e8_0da55c08_a2ad07a8_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xa9812a49_0c466a72_3628820a_51d726a6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xb64197eb_bd603b94_ea1019ea_75071211_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xc2a7d181_c10650a9_7baf812d_902b3e46_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xcf62379f_400a2f7e_0fd6a131_fa8945f0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xdbcd6774_67dbe718_767820ae_26dd1f44_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xe883224b_0b627a15_562fd94e_971537db_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xf4f24030_2941dfc3_0b11f705_3d347846_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x80d22107_255f73a5_e3155151_e5d892e3_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x870b483f_c7daacd2_82a82102_617f3d05_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x8d62c464_a213c7cc_45d50ff9_25debfa4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x939d3d9a_d3d7f924_81e87adf_e5728360_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x99f3767a_e59104c7_8457834d_d50a09ba_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xa02f0c1c_9d7da9a8_ffacaac8_460e01b5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xa68433f6_109f9515_8900655b_5e80e9a0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xacc0bc3e_b346d87f_918feb38_b06e7e1f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xb314fa70_f0190b85_d6ddc7c9_8e042c17_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xb952542e_618bedb3_8de1b41f_c6aa4a1f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xbfa5c826_e4d297ca_0422f662_55b48e77_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xc5e3d887_69cafe33_9981aa85_e88e1e1a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xcc369bc2_915b8377_95352db8_354bd3b1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xd2754ccb_daf5504d_ddc5f4bc_dbdd757b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xd8c7743d_a737fc41_cf46ecb7_f33e383f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xdf06b3b3_689eef4b_abdf2ea8_7ffc6b1b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xe55850cb_45910bb1_50f1d21d_b471f3c5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xeb980f61_5f8b71dc_c8dd083c_434699b9_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xf1e930c9_1343a494_74e9bb0d_6a192158_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xf829618a_368ecd4d_cc957993_351501b6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xfe7a13b4_c18097f4_25599c4d_0177b3b7_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x825d55c7_217c758e_c0d144c4_0bcdb6aa_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x85857c92_41dfa6e6_aacb2f94_f7661be1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x88a5f746_87a5e758_f802fa31_68b9cc60_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x8bcdf060_c78705c7_f126991d_5358881d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x8eee95b9_cc31b2ba_1bc86205_b537adc7_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x92166522_0247be75_b0e61b82_f4233602_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -121,\n", " mantissa: 0x95373183_78e841b3_79dbe48b_8f49ccd7_u128,\n", "},\n", "];\n" ] } ], "source": [ "R120 = RealField(120)\n", "\n", "zeros = []\n", "\n", "mp.prec = 150\n", "\n", "step = mpf(\"0.1\")\n", "epsilon = mpf(\"1e-35\")\n", "x = mpf(\"1.25\")\n", "\n", "previous_zero = R120(0)\n", "y0_zeros = []\n", "\n", "while x < mpf(\"76.0\"):\n", " f1 = bessely(0, x)\n", " f2 = bessely(0, x + step)\n", " if f1 * f2 < 0:\n", " zero = findroot(lambda t: bessely(0, t), (x, x + step), solver='secant', tol=mp.mpf(\"1e-41\"))\n", " previous_zero = zero\n", " y0_zeros.append(zero)\n", " if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon:\n", " zeros.append(previous_zero)\n", " x += step\n", "\n", "y0_extrema = []\n", "\n", "x = mpf(\"1.25\")\n", "while x < mpf(\"76.0\"):\n", " d1 = mp.diff(lambda t: bessely(0, t), x)\n", " d2 = mp.diff(lambda t: bessely(0, t), x + step)\n", " if d1 * d2 < 0:\n", " extremum = findroot(lambda t: mp.diff(lambda u: bessely(0, u), t), (x, x + step), solver='secant', tol=mp.mpf(\"1e-41\"))\n", " y0_extrema.append(extremum)\n", " x += step\n", "\n", "# Print results\n", "for i, z in enumerate(y0_zeros):\n", " print(f\"Zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"Extrema (peaks/valleys) of Y0(x):\")\n", "for e in y0_extrema:\n", " print(f\"nExtrema: {e}\")\n", "\n", "y0_zeros.extend(y0_extrema)\n", "\n", "y0_zeros = sorted(y0_zeros)\n", "\n", "# Print results\n", "for i, z in enumerate(y0_zeros):\n", " print(f\"Peak or zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"\")\n", "\n", "# print(\"pub(crate) static Y0_ZEROS: [(u64, u64); 48] = [\")\n", "# print(f\"(0x0, 0x0),\")\n", "# for z in y0_zeros:\n", "# k = split_double_double(z)\n", "# hi = double_to_hex(k[1])\n", "# lo = double_to_hex(k[0])\n", "# print(f\"({lo}, {hi}),\")\n", " \n", "# print(\"];\")\n", "\n", "print(\"pub(crate) static Y0_ZEROS_RATIONAL128: [DyadicFloat128; 48] = [\")\n", "print(f\"DyadicFloat128 {{ sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0u128, }},\")\n", "for z in y0_zeros:\n", " print_dyadic(z)\n", " \n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 113, "id": "b56fcd62-23de-4cc5-bc1d-b8a162f3af12", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y0F_COEFFS: [[u64; 41]; 47] = [\n", "[mpf('0.52078641240226751110715073692607'), mpf('0.0'), mpf('-0.26039320620113375555357536846304'), mpf('0.0395048485830322028364602785614'), mpf('0.0082143493513216024279099048784476'), mpf('0.00095956233402108751324624666282015'), mpf('-0.0012370922221179114212488122443617'), mpf('0.00037074881260917165021899792834161'), mpf('-0.00013335662500684747464830109816763'), mpf('0.00005662236715064509475652994381275'), mpf('-0.00002358699837551760903508966274673'), mpf('0.0000097964034682169090390241456552774'), mpf('-0.0000041036905126218338307613733655675'), mpf('0.0000017300870834862234846237408636078'), mpf('-0.00000073313228183263465617037950680149'), mpf('0.00000031208598237787635042276363091502'), mpf('-0.00000013339044438352910154921218452208'), mpf('0.000000057219051205514850171026599282661'), mpf('-0.00000002462396619372747864989152467005'), mpf('0.000000010627628156707689361120006498825'), mpf('-0.0000000045989070057707728409573379625272'), mpf('0.000000001994839239593058546947191175894'), mpf('-8.6717095952456776554834474872814e-10'), mpf('3.7771565687842002083162911306619e-10'), mpf('-1.6482313365323497970848669030869e-10'), mpf('7.2044676218846789163201632336255e-11'), mpf('-3.1539932955022028060267738432361e-11'), mpf('1.3827554040986096536616843642946e-11'), mpf('-6.0703179384600914491330249325004e-12'), mpf('2.6682051385400796496642634533752e-12'), mpf('-1.1741750035573949903069624065507e-12'), mpf('5.172730216232396724988440928256e-13'), mpf('-2.2811337768270027689991896988382e-13'), mpf('1.0069288888350707009122056291205e-13'), mpf('-4.4487653061604646921371659201182e-14'), mpf('1.9672087375694825673405871491965e-14'), mpf('-8.7058485256468931375712774795299e-15'), mpf('3.8556942807890320993122021161774e-15'), mpf('-1.7088639621125691633685720190179e-15'), mpf('7.5789620088817533016344611167521e-16'), mpf('-3.3635232341051059573800322085719e-16'), mpf('1.4936464286421332686929521327555e-16')]\n", "[\n", "0x3fe0aa48442f014a,\n", "0x0000000000000000,\n", "0xbfd0aa48442f014b,\n", "0x3fa439fac16525f6,\n", "0x3f80d2af4e932386,\n", "0x3f4f71646bea8111,\n", "0xbf5444bda8b664a9,\n", "0x3f384c220672ab82,\n", "0xbf217ab4afac0736,\n", "0x3f0dafb9b8983d86,\n", "0xbef8bb962fa6c505,\n", "0x3ee48b6770c210be,\n", "0xbed1364ddbddf33c,\n", "0x3ebd06aadd881cef,\n", "0xbea8998eefe8caa1,\n", "0x3e94f198aa7c73a8,\n", "0xbe81e742c1cf6acb,\n", "0x3e6eb820636013a9,\n", "0xbe5a709593e5d778,\n", "0x3e46d299b1a6ab0d,\n", "0xbe33c08d3e0a3e4c,\n", "0x3e2122b2a831eedc,\n", "0xbe0dcbb767b405d5,\n", "0x3df9f4d817711bdf,\n", "0xbde6a732ce7db296,\n", "0x3dd3cdb1820544fc,\n", "0xbdc156d9d7a9603b,\n", "0x3dae68388d1e7163,\n", "0xbd9ab29205d3c902,\n", "0x3d8778438a9d4c3f,\n", "0xbd74a8039c9d2a24,\n", "0x3d62332e6179cd25,\n", "0xbd500d53464407ad,\n", "0x3d3c57aff386dbcb,\n", "0xbd290b58b370769d,\n", "0x3d162617d848c516,\n", "0xbd039a947a4277c5,\n", "0x3cf15d5017096190,\n", "0xbcdec8be79807012,\n", "0x3ccb4e5bceebb7f1,\n", "0xbcb83c9af0422255,\n", "],\n", "];\n" ] } ], "source": [ "# Taylor series for f32\n", "mp.prec = 60\n", "terms = 28\n", "print(f\"pub(crate) static Y0F_COEFFS: [[u64; {terms}]; {len(j0_zeros)}] = [\")\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffsf(poly, n):\n", " print(\"[\")\n", " for i in range(0, n):\n", " coeff = poly[i]\n", " print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(y0_zeros)):\n", " k_range = y0_zeros[i]\n", " range_diff = k_range - prev_zero\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, bessely, taylor\n", " poly = taylor(lambda val: bessely(0, val), x0, terms)\n", " # print(poly)\n", " print_taylor_coeffsf(poly, terms)\n", " prev_zero = y0_zeros[i]\n", "\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "423d0efd-5aed-4ece-82b9-9e8c831bcbbd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y0F_COEFFS: [[u64;18]; 47] = [\n", "[\n", "0x3fe0aa48442f014b,\n", "0xbc009e915c2e5f95,\n", "0xbfd0aa48442f0143,\n", "0x3fa439fac165257c,\n", "0x3f80d2af4e929791,\n", "0x3f4f71646c0dc646,\n", "0xbf5444bda7f2ee4c,\n", "0x3f384c21f1d0de42,\n", "0xbf217ab4d69ab0db,\n", "0x3f0dafc989c8ea40,\n", "0xbef8bbefbac0d893,\n", "0x3ee48ac7a622784f,\n", "0xbed1245593770ad0,\n", "0x3ebc28878607b687,\n", "0xbea585c089718cc9,\n", "0x3e8b7ad75bd333d8,\n", "0xbe68a20d8d3d57a5,\n", "0x3e362c70b36d12a4,\n", "],\n", "[\n", "0x3bf75cf88f1b7237,\n", "0xbfd9c34256a12a0c,\n", "0x3faa09c9290367ec,\n", "0x3fadf6d59bf50e4b,\n", "0xbf7c116fdc597e2f,\n", "0xbf61e32bc4eef0b0,\n", "0x3f29982765136b27,\n", "0x3f0ab2c1fd5871c0,\n", "0xbed486371d6e71eb,\n", "0xbe93b212b9208b3e,\n", "0xbe577700c20e01fd,\n", "0x3e545234fb052f6a,\n", "0xbe2f6a5f736d8c82,\n", "0x3e0a8134a3ddd47f,\n", "0xbde9666a74f1504a,\n", "0x3dc63b75b90c0da3,\n", "0xbdaa991122c61028,\n", "0x3d930f1a31e30006,\n", "],\n", "[\n", "0xbfd5c7c556f0c19a,\n", "0xbbc44b457ab6a440,\n", "0x3fc5c7c556f0c19a,\n", "0xbf8564d4b1ed0d7e,\n", "0xbf8a15d92dfe3e28,\n", "0x3f4b438430469f6e,\n", "0x3f37a8924cc2fcab,\n", "0xbef5f69b4a89930d,\n", "0xbed85b940ebd0c07,\n", "0x3e955ac0f4e7f8ab,\n", "0x3e6d563e284b0072,\n", "0xbe23eac267e6cf3c,\n", "0xbe00077161c32b55,\n", "0x3dc04d965b688847,\n", "0xbd45e4f4886f7d51,\n", "0x3d5501605dba787a,\n", "0xbd363e6119f047ec,\n", "0x3d096861e7e8004b,\n", "],\n", "[\n", "0xbb236a0ad5bec7c3,\n", "0x3fd334cca0697a5b,\n", "0xbf95aef611fc4d57,\n", "0xbfa8969c64cbf452,\n", "0x3f6b2f14a95527cb,\n", "0x3f61d35e85fde2a4,\n", "0xbf226dd71e391c65,\n", "0xbf08177e4fe524db,\n", "0x3ec6a9227352b13b,\n", "0x3ea34aa757412911,\n", "0xbe60a2814d2e238a,\n", "0xbe3442a3d67717ae,\n", "0x3defa6c448c9759c,\n", "0x3dbf14eacd6e3a21,\n", "0xbd771434b676ae83,\n", "0xbd406a106470261f,\n", "0x3cf2c5324aed291b,\n", "0x3cc47f208256e17f,\n", "],\n", "[\n", "0x3fd15f993fceab5c,\n", "0xbb597aaa5d4472ea,\n", "0xbfc15f993fceab5c,\n", "0x3f758ef6efbed797,\n", "0x3f86395dfe49fcd4,\n", "0xbf3fb15104a41c03,\n", "0xbf35f88a11d55641,\n", "0x3eef37d226a827fd,\n", "0x3ed6f7bab104d878,\n", "0xbe8f0c45a3868f32,\n", "0xbe6dfe11ded99f62,\n", "0x3e2311adc6046d1a,\n", "0x3dfad34dd085ee0f,\n", "0xbdafdc85833041dc,\n", "0xbd819463fb6a5c22,\n", "0x3d33a4c369438250,\n", "0x3d014560b8776112,\n", "0xbcb2ae15d3a41e47,\n", "],\n", "[\n", "0x3b12ba7db6ce5807,\n", "0xbfcff635cc72b9f1,\n", "0x3f89036451ff57c5,\n", "0x3fa4e667a71556af,\n", "0xbf60325ee41e910c,\n", "0xbf5fe23914fb9128,\n", "0x3f17f84d7c50e49e,\n", "0x3f06afdd57be1e75,\n", "0xbec04053abf415e2,\n", "0xbea2aea9ec4954d7,\n", "0x3e593eb9f19579b5,\n", "0x3e3428a3a4917f21,\n", "0xbde99d8be9e4cd5a,\n", "0xbdbec9815ee61f19,\n", "0x3d7260f619cb637c,\n", "0x3d418f963ce687db,\n", "0xbcf38a6e7195daa0,\n", "0xbcbf332d386dfb1b,\n", "],\n", "[\n", "0xbfcdc14ea14e89f9,\n", "0x3b52ef4e10970973,\n", "0x3fbdc14ea14e89f9,\n", "0xbf6b037fe9cf2a52,\n", "0xbf8367d7d608e4ba,\n", "0x3f34abef5636e4f9,\n", "0x3f33d8a66122924a,\n", "0xbee5cfe92a1a2ead,\n", "0xbed571814a1a8669,\n", "0x3e87414e33ccd6d7,\n", "0x3e6ca7069e37c5b4,\n", "0xbe1e0b3a74e3f35e,\n", "0xbdfa15dd188a976e,\n", "0x3daa33983e3b34b5,\n", "0x3d8141656fbf9e02,\n", "0xbd3089bd5153b08a,\n", "0xbd01345e91fc8d5c,\n", "0x3cb05566655c2807,\n", "],\n", "[\n", "0xbb10bed1f7905ee9,\n", "0x3fcbf32a27594007,\n", "0xbf80bc2d84e65214,\n", "0xbfa26cab38a8b368,\n", "0x3f55f03e47165d72,\n", "0x3f5caaa76e34992d,\n", "0xbf10c5f18c46d00f,\n", "0xbf04f0af7d46cd82,\n", "0x3eb7d1e28094a46b,\n", "0x3ea1ad073122cd33,\n", "0xbe536021c88affe4,\n", "0xbe3371ae6cd96849,\n", "0x3de46ce028e7c109,\n", "0x3dbe235dc856ef66,\n", "0xbd6e401d592ca47a,\n", "0xbd415f37788a98a4,\n", "0x3cf078a1b34fa822,\n", "0x3cbefbc3ca8cda9f,\n", "],\n", "[\n", "0x3fca7022be084d99,\n", "0xbb4ddca3665cb95a,\n", "0xbfba7022be084d99,\n", "0x3f62ee079d020b12,\n", "0x3f8163191c30aa62,\n", "0xbf2d7806ea72fc7a,\n", "0xbf320f95702b1d3e,\n", "0x3ee006108822968d,\n", "0x3ed3e398cbc455aa,\n", "0xbe81bbe181c8bfbe,\n", "0xbe6b0f89b78908bf,\n", "0x3e17c3f85c062f0a,\n", "0x3df902361639d835,\n", "0xbda56494e7b59641,\n", "0xbd80bde23236fbba,\n", "0x3d2bbbd3bb25cf30,\n", "0x3d00d7f96ac5af92,\n", "0xbcabe3861f527a48,\n", "],\n", "[\n", "0x3b0d39acdbc38af2,\n", "0xbfc925c35988ee29,\n", "0x3f7862549367591e,\n", "0x3fa0a4512039d6a2,\n", "0xbf5013b38cfb9292,\n", "0xbf5a24a1215f6684,\n", "0x3f08f91421377f72,\n", "0x3f035d17cec01753,\n", "0xbeb2283a93110ac0,\n", "0xbea099e713932038,\n", "0x3e4e5de01dbe7d10,\n", "0x3e3288585522eec4,\n", "0xbde0730be51a22c7,\n", "0xbdbd174416e1daeb,\n", "0x3d68f810d9b70d7c,\n", "0x3d40f177553ea68b,\n", "0xbcebc58c79d9f1a6,\n", "0xbcbe6305e9d630f0,\n", "],\n", "[\n", "0xbfc80781c32422e7,\n", "0x3b483f69e003254a,\n", "0x3fb80781c32422e7,\n", "0xbf5c6923374d561f,\n", "0xbf7fbe6df840847f,\n", "0x3f264f4711a85f1d,\n", "0x3f309ff42b0d7a58,\n", "0xbed8a60685a59ae7,\n", "0xbed282d26a74a669,\n", "0x3e7bdb57a88d9298,\n", "0x3e697d9c12695952,\n", "0xbe131aa86bece7b9,\n", "0xbdf7d486a4891297,\n", "0x3da197f4a31bb9d7,\n", "0x3d801da2d1e74508,\n", "0xbd2749f32e6b29e4,\n", "0xbd005a3044bf379a,\n", "0x3ca7cdb1346a2761,\n", "],\n", "[\n", "0xbb095b0f9cce8be6,\n", "0x3fc70c4f66cab47f,\n", "0xbf72c6731071e936,\n", "0xbf9e924b85a17361,\n", "0x3f48d6c364d92082,\n", "0x3f58247b02d6b0f6,\n", "0xbf037612593855eb,\n", "0xbf0206da232a2b7e,\n", "0x3eacaf84db86b79e,\n", "0x3e9f367117733794,\n", "0xbe48654affaeff8a,\n", "0xbe3199ec88cf0125,\n", "0x3ddaeb1a0e170f3e,\n", "0x3dbbe67c38767c0a,\n", "0xbd64cda59f058a2d,\n", "0xbd406490f1401c35,\n", "0x3ce7873ddbd2ecb8,\n", "0x3cbd9254c745332c,\n", "],\n", "[\n", "0x3fc62d94d97e859c,\n", "0xbb4423d84fd9daf1,\n", "0xbfb62d94d97e859c,\n", "0x3f565481b55eaefb,\n", "0x3f7d5f857a2a6107,\n", "0xbf21a015a2ccb791,\n", "0xbf2eeb4eafd8612c,\n", "0x3ed3a7b79e4d8384,\n", "0x3ed154ed4598b648,\n", "0xbe767f762ea5d48d,\n", "0xbe680ec1e0075865,\n", "0x3e0f52965769de53,\n", "0x3df6ad7b894b88a3,\n", "0xbd9d4e5bf81e66fd,\n", "0xbd7eeb07104d446e,\n", "0x3d23b37b411dc13d,\n", "0x3cff991c92fdc4d8,\n", "0xbca4681dcbe602f7,\n", "],\n", "[\n", "0x3b0608e1eb7299ca,\n", "0xbfc5664d37c37d7b,\n", "0x3f6e0ee8ec84659a,\n", "0x3f9c6c415c971b4b,\n", "0xbf43ec49cb941f55,\n", "0xbf56853b2d047885,\n", "0x3eff632a9396fcf6,\n", "0x3f00e6afa01af56c,\n", "0xbea7541247ac8e20,\n", "0xbe9d735e8beba89d,\n", "0x3e440e6a7c5b76f7,\n", "0x3e30b9cfae36d52a,\n", "0xbdd66808178f0472,\n", "0xbdbab498e9ad024c,\n", "0x3d618b0d40031fb2,\n", "0x3d3f99bd1527877f,\n", "0xbce4186fe1076e16,\n", "0xbcbca6e4a9f85609,\n", "],\n", "[\n", "0xbfc4b2a38f1ab9b4,\n", "0x3b4106370f2ef866,\n", "0x3fb4b2a38f1ab9b4,\n", "0xbf5225a5c73f2233,\n", "0xbf7b750d89a9b35f,\n", "0x3f1cbdb4f1d5dbc0,\n", "0x3f2cfe933fc6d09a,\n", "0xbed01ef10d839ddf,\n", "0xbed05375a5888b31,\n", "0x3e729afe7eaa78e7,\n", "0x3e66c8fe01244a3c,\n", "0xbe0a2a01eba23e6a,\n", "0xbdf59b32be188f85,\n", "0x3d98c0a83d3ee202,\n", "0x3d7da2dd5a1ff0d5,\n", "0xbd20d5047e87a8a0,\n", "0xbcfe76ab94a96cf5,\n", "0x3ca19e4f3f768bb8,\n", "],\n", "[\n", "0xbb033ddc20ef994b,\n", "0x3fc40f8ffdf09a5f,\n", "0xbf68c37a29c4586f,\n", "0xbf9aab099314b209,\n", "0x3f406f735cc0f6a6,\n", "0x3f552d29a06802e0,\n", "0xbef9fc04c675c0a0,\n", "0xbeffe48825ed3c99,\n", "0x3ea36bd2d58fad6c,\n", "0x3e9be87e2cad35c1,\n", "0xbe40d1fded7d33ea,\n", "0xbe2fdbeb107f2787,\n", "0x3dd2f44ca7722117,\n", "0x3db992136419242c,\n", "0xbd5df6388aabd242,\n", "0xbd3e6bd4176ef817,\n", "0x3ce15380b88a0004,\n", "0x3cbbb4210e2ade39,\n", "],\n", "[\n", "0x3fc37aaceac987b9,\n", "0xbb3d355a175fbb67,\n", "0xbfb37aaceac987b9,\n", "0x3f4e3fdbfd65014a,\n", "0x3f79de7a33bc3a97,\n", "0xbf1801d911fbd06f,\n", "0xbf2b605a5ade3a62,\n", "0x3ecb0a2608144de7,\n", "0x3eceeceb341aa1c8,\n", "0xbe6f623fc7c35376,\n", "0xbe65a9ca94685dee,\n", "0x3e0638ba32c100f7,\n", "0x3df4a1b3dc97031d,\n", "0xbd9530c9cb91ec68,\n", "0xbd7c6deff6c29a1e,\n", "0x3d1d10f27ed0d91c,\n", "0x3cfd5b5110a971f2,\n", "0xbc9eac069b193638,\n", "],\n", "[\n", "0x3b00e83df01ac491,\n", "0xbfc2f206e49909c7,\n", "0x3f64dbf6a9fb80d7,\n", "0x3f99336443318ed1,\n", "0xbf3bb6aa3d4e9e78,\n", "0xbf540aaa5d94bd8d,\n", "0x3ef5f61b66612962,\n", "0x3efe4158391f2c2d,\n", "0xbea07a7a0745b8f1,\n", "0xbe9a8ea97b66fe4d,\n", "0x3e3cb10b3a7e93b8,\n", "0x3e2e6d788791546c,\n", "0xbdd044442a2af39d,\n", "0xbdb8850c7d8525ad,\n", "0x3d59e48a6e2fcf83,\n", "0x3d3d4af5e70dabe3,\n", "0xbcde2a65241d7e39,\n", "0xbcbac578a90cdb0d,\n", "],\n", "[\n", "0xbfc2740819f1caaa,\n", "0x3b395de3b03fa760,\n", "0x3fb2740819f1caaa,\n", "0xbf49b6f37d0a00f9,\n", "0xbf78868d7401bf2e,\n", "0x3f1470a7cbcb436d,\n", "0x3f29fe94ce3d3e66,\n", "0xbec71660e61f123b,\n", "0xbecd6dfcdb022b53,\n", "0x3e6ae79c35d4303c,\n", "0x3e64ac50be35d108,\n", "0xbe0325840c0fab26,\n", "0xbdf3c09642eaf47d,\n", "0x3d925d87f4bac822,\n", "0x3d7b50337a12ad98,\n", "0xbd195a5cf071931d,\n", "0xbcfc4e3bdd8deb9e,\n", "0x3c9aec36c7cd8057,\n", "],\n", "[\n", "0xbafde3378387cd4f,\n", "0x3fc1ff5ebddd3c3a,\n", "0xbf61e2035324643c,\n", "0xbf97f3506d4a1231,\n", "0x3f37c65c9302c53a,\n", "0x3f53117816335151,\n", "0xbef2df9afa521258,\n", "0xbefcd5d4a9d78a10,\n", "0x3e9c672d4d6f090d,\n", "0x3e995e4b10218b56,\n", "0xbe38d22635a19a7c,\n", "0xbe2d24fc943fc6e5,\n", "0x3dcc462d12216cc2,\n", "0x3db78eaf8cc86453,\n", "0xbd569efa1b265a8d,\n", "0xbd3c3c11b66258b3,\n", "0x3cda808e4f387067,\n", "0x3cb9e0f8deb75911,\n", "],\n", "[\n", "0x3fc192f2627a74e3,\n", "0xbb3645a3987074b0,\n", "0xbfb192f2627a74e3,\n", "0x3f4635b38affe698,\n", "0x3f775eceaabf7f86,\n", "0xbf11ac9e0164f7c3,\n", "0xbf28cc464a35b093,\n", "0x3ec4014d9bf38c8d,\n", "0x3ecc1f05a2d81e1e,\n", "0xbe6761d18ebe9900,\n", "0xbe63cb9af0ceb4cf,\n", "0x3e00b3cb584e2702,\n", "0x3df2f5c722e3bf8d,\n", "0xbd9017792eaec1aa,\n", "0xbd7a4a02574df6fb,\n", "0x3d1652dad940d7a4,\n", "0x3cfb525fce2f20bd,\n", "0xbc97d2bda2bb98bd,\n", "],\n", "[\n", "0x3afa988afe4c49f9,\n", "0xbfc12dd55d4be2b3,\n", "0x3f5f1aee31818d19,\n", "0x3f96de64242a8310,\n", "0xbf34afdf89fca61a,\n", "0xbf5238cfc13ac771,\n", "0x3ef0719d13e00e1d,\n", "0x3efb974781a526ac,\n", "0xbe98cc82a70d12de,\n", "0xbe9850ae878c16d4,\n", "0x3e35bba73dc2363a,\n", "0x3e2bfe1396c7d24f,\n", "0xbdc8d7db68570364,\n", "0xbdb6adfbad375234,\n", "0x3d53f4c573239e3d,\n", "0x3d3b40924b9cec60,\n", "0xbcd77b88ddf3cd06,\n", "0xbcb909671eb81963,\n", "],\n", "[\n", "0xbfc0cf3ee98f769b,\n", "0x3b33bcff5c943527,\n", "0x3fb0cf3ee98f769b,\n", "0xbf436f451f6e14fb,\n", "0xbf765d05948a946a,\n", "0x3f0ef55c5a0d16d1,\n", "0x3f27bfec9d15d01e,\n", "0xbec18c549f28e7a1,\n", "0xbecaf7544eea95a1,\n", "0x3e648e81edf6b6c0,\n", "0x3e630341e759775f,\n", "0xbdfd73d2cdd0aab5,\n", "0xbdf23ec233be72a4,\n", "0x3d8c78e7f536eeff,\n", "0x3d795a1608a24a32,\n", "0xbd13d34748616c7a,\n", "0xbcfa685ede39fb91,\n", "0x3c953d75ba0ff04b,\n", "],\n", "[\n", "0xbaf7d336e374344e,\n", "0x3fc0768257dad56a,\n", "0xbf5b602a7beaaa48,\n", "0xbf95ebc22efd092c,\n", "0x3f3236a604142e61,\n", "0x3f517a482faa8d85,\n", "0xbeecfc008907874e,\n", "0xbefa7d7b128ac52d,\n", "0x3e95e419f1b51819,\n", "0x3e97603cea233f99,\n", "0xbe333a0b43111627,\n", "0xbe2af464175ecac5,\n", "0x3dc609ac1d6253eb,\n", "0x3db5e11b59984046,\n", "0xbd51c2262e85ed55,\n", "0xbd3a58213539aed8,\n", "0x3cd4f80a679b93ee,\n", "0x3cb83fa375444bd0,\n", "],\n", "[\n", "0x3fc0230ba90f2871,\n", "0xbb31a4207958473d,\n", "0xbfb0230ba90f2871,\n", "0x3f413164a0864cde,\n", "0x3f7579c1bdbcfc99,\n", "0xbf0b67e1913c668f,\n", "0xbf26d26de4fd8c43,\n", "0x3ebf1b520b063cbf,\n", "0x3ec9f01e7c18d94a,\n", "0xbe624071b17c353c,\n", "0xbe624f8e936aca3d,\n", "0x3dfa356639a676b4,\n", "0x3df19911d0412ad5,\n", "0xbd89677525aa079f,\n", "0xbd787e875d392b57,\n", "0x3d11be245f9c21d5,\n", "0x3cf98faabb17d8d4,\n", "0xbc93119ed524d1f5,\n", "],\n", "[\n", "0x3af57b2a92bacca4,\n", "0xbfbfa8b3f9ae4375,\n", "0x3f5856073b7fa2cd,\n", "0x3f9514e652eb2e96,\n", "0xbf3032298718ea1a,\n", "0xbf50d1153fde431b,\n", "0x3ee9cb455c29d651,\n", "0x3ef982167b1c52b5,\n", "0xbe938191ef689b27,\n", "0xbe968865345b1bd6,\n", "0x3e31296000bb210d,\n", "0x3e2a0403677632fc,\n", "0xbdc3b67c5c27ec16,\n", "0xbdb526035aeb726c,\n", "0x3d4fd977f75a677c,\n", "0x3d398199969ac0ac,\n", "0xbcd2db2724a8c540,\n", "0xbcb7838b8a136198,\n", "],\n", "[\n", "0xbfbf13fb0c0e6fcd,\n", "0x3b2fb8a657120d32,\n", "0x3faf13fb0c0e6fcd,\n", "0xbf3eb3e6fcc47c00,\n", "0xbf74af74cbd77bef,\n", "0x3f087bb1ebeaec78,\n", "0x3f25fe62920314f5,\n", "0xbebbd0f2a6556264,\n", "0xbec9040de83035a2,\n", "0x3e6057f7a76c1f7c,\n", "0x3e61ad6dd4dfaab9,\n", "0xbdf782a6f91b13a7,\n", "0xbdf1027d851ec0eb,\n", "0x3d86d65e028f8e8e,\n", "0x3d77b54a61df8d64,\n", "0xbd0ffa6793d8746b,\n", "0xbcf8c72862ef4d7d,\n", "0x3c913a3849824cc1,\n", "],\n", "[\n", "0xbaf37825e4b1711a,\n", "0x3fbe8727c572a2c2,\n", "0xbf55d1ef092ab395,\n", "0xbf9454e7a7395636,\n", "0x3f2d0cc3a7fa6d3d,\n", "0x3f50398d2cbd02df,\n", "0xbee725b0909f9c17,\n", "0xbef8a022f5fee439,\n", "0x3e9185b1ea975d21,\n", "0x3e95c5711673ea6a,\n", "0xbe2edff650b86504,\n", "0xbe29298da3993db9,\n", "0x3dc1c346aaab062e,\n", "0x3db47ab8b9f6e94a,\n", "0xbd4cc1c87cd4af9d,\n", "0xbd38bb86b43ec34d,\n", "0x3cd1104df3fa9e99,\n", "0x3cb6d47888429c17,\n", "],\n", "[\n", "0x3fbe018dac1c17e3,\n", "0xbb2cbf68b5ed7271,\n", "0xbfae018dac1c17e3,\n", "0x3f3ba21bd15d02a4,\n", "0x3f73f9e0db07e7ef,\n", "0xbf060b77c5e27625,\n", "0xbf253f9b1a5d2273,\n", "0x3eb910b38812c5ec,\n", "0x3ec82ee6dfdfc034,\n", "0xbe5d7cc2a9aa9fae,\n", "0xbe611a57d834f490,\n", "0x3df53d401868b2b6,\n", "0x3df07915b5d7b1b9,\n", "0xbd84aabf5e11aa97,\n", "0xbd76fc66f73ce419,\n", "0x3d0cff2a096a9861,\n", "0x3cf80d87c580ea09,\n", "0xbc8f4ef03ad4ec66,\n", "],\n", "[\n", "0x3af1bbdf10c72747,\n", "0xbfbd82939ab62339,\n", "0x3f53b5a54845670f,\n", "0x3f93a7ff1622def8,\n", "0xbf2a3ebc476a606d,\n", "0xbf4f61adde3a8c61,\n", "0x3ee4ec45da047869,\n", "0x3ef7d3b28159f22c,\n", "0xbe8fb3f21bccfc28,\n", "0xbe95145a876d09d8,\n", "0x3e2bf64cdef37a7c,\n", "0x3e2862204a96b8ac,\n", "0xbdc01c0cf54f6b8d,\n", "0xbdb3dd6c7e6818d8,\n", "0x3d4a1faa7e189d99,\n", "0x3d3804640c4d999d,\n", "0xbccf0f5eda690a07,\n", "0xbcb63189b3dc27d0,\n", "],\n", "[\n", "0xbfbd09b21e36c0bd,\n", "0x3b2a335791a61ca6,\n", "0x3fad09b21e36c0bd,\n", "0xbf390b0e6a475e45,\n", "0xbf7355b904fbf7ee,\n", "0x3f03fc459d1e25a7,\n", "0x3f2492cc61d19de6,\n", "0xbeb6bcf110a02e19,\n", "0xbec76d44f6a8089e,\n", "0x3e5ac61efcb7f75f,\n", "0x3e609436fc7c1966,\n", "0xbdf34eb60c63b887,\n", "0xbdeff662240b32ed,\n", "0x3d82d05e647447d5,\n", "0x3d76520ffbea05d6,\n", "0xbd0a70b3d6b77e3f,\n", "0xbcf7617161d2567e,\n", "0x3c8c991bfcf38c32,\n", "],\n", "[\n", "0xbaf03b145709e9fb,\n", "0x3fbc96700031f601,\n", "0xbf51eb2a07d0f09e,\n", "0xbf930b36eddaa234,\n", "0x3f27dd2dde84b73c,\n", "0x3f4e696553e0b8a5,\n", "0xbee3085aa35a1606,\n", "0xbef7199f24bccad0,\n", "0x3e8cdbab6a75e8e1,\n", "0x3e9472a7cffbdf8d,\n", "0xbe2979f5209f2f88,\n", "0xbe27ab4b017a68c3,\n", "0x3dbd638fb5c45254,\n", "0x3db34c83c71aa648,\n", "0xbd47dc91892a3240,\n", "0xbd375abc2b119f77,\n", "0x3ccc6a16f48d942f,\n", "0x3cb599c2db65d50c,\n", "],\n", "[\n", "0x3fbc2861347b1b39,\n", "0xbb27f93aa95d7811,\n", "0xbfac2861347b1b39,\n", "0x3f36d57bffb37fd5,\n", "0x3f72c060ef553f18,\n", "0xbf023a407b722d31,\n", "0xbf23f55581ec6826,\n", "0x3eb4bfb4daa30262,\n", "0x3ec6bc69099ac792,\n", "0xbe587334098baabf,\n", "0xbe601951f000356a,\n", "0x3df1a61752a7a337,\n", "0x3def0ec9ee45cf6f,\n", "0xbd8137cd564b9118,\n", "0xbd75b4aa3b6c601b,\n", "0x3d083b040a6d9f05,\n", "0x3cf6c19bd64bc967,\n", "0xbc8a3eded96f75bf,\n", "],\n", "[\n", "0x3aedd70a3afed493,\n", "0xbfbbbf246019c0d4,\n", "0x3f506224199140d8,\n", "0x3f927c3416c09898,\n", "0xbf25d279dc87cf68,\n", "0xbf4d86a5f5adbdac,\n", "0x3ee169041634c20c,\n", "0x3ef66f5bd1bedad0,\n", "0xbe8a69b2c7176656,\n", "0xbe93de4eab455284,\n", "0x3e2755eabb6b4563,\n", "0x3e2702fe7b7aa32d,\n", "0xbdbaf1fff2894365,\n", "0xbdb2c697124bdb4b,\n", "0x3d45e717125b6112,\n", "0x3d36bd366d374341,\n", "0xbcca1d9ce8759323,\n", "0xbcb50c32fba6f689,\n", "],\n", "[\n", "0xbfbb5a622198a72c,\n", "0x3b261140492792be,\n", "0x3fab5a622198a72c,\n", "0xbf34ee71cf67c243,\n", "0xbf7237c02b462f6f,\n", "0x3f00b67b6fdfec64,\n", "0x3f2365167d8bc319,\n", "0xbeb3086b7a29712d,\n", "0xbec61a141425984e,\n", "0x3e56712b239ca861,\n", "0x3e5f507367e2287b,\n", "0xbdf0366d05430f3b,\n", "0xbdee38f952d755dd,\n", "0x3d7faa412f355ab7,\n", "0x3d7522cbd2af359c,\n", "0xbd064e7a6cf56505,\n", "0xbcf62cd7c73270a1,\n", "0x3c883112ff8933cd,\n", "],\n", "[\n", "0xbaeb8a30d224cee7,\n", "0x3fbaf9cb42cd08a7,\n", "0xbf4e1c66d7616e37,\n", "0xbf91f90fd1013589,\n", "0x3f240e3eb09b7d6d,\n", "0x3f4cb682ff471274,\n", "0xbee0016819a61da0,\n", "0xbef5d2d1c420645b,\n", "0x3e884b0fe8a7ecd7,\n", "0x3e93559d96bedaf4,\n", "0xbe257a0be6df375d,\n", "0xbe26677c8f23f9e7,\n", "0x3db8d1ada000f3d8,\n", "0x3db24a6de676e9f8,\n", "0xbd4431a53c25281e,\n", "0xbd362a9b74747797,\n", "0x3cc81ad277664852,\n", "0x3cb487f213f494c1,\n", "],\n", "[\n", "0x3fba9d183bc04545,\n", "0xbb24612b590e8e50,\n", "0xbfaa9d183bc04545,\n", "0x3f334779874010dc,\n", "0x3f71ba2299ab88a8,\n", "0xbefecb19f5bdc64d,\n", "0xbf22e052707cc843,\n", "0x3eb18a5da77ee010,\n", "0x3ec5846b622f2fd0,\n", "0xbe54b17e97b8ccc9,\n", "0xbe5e7f7666f84ced,\n", "0x3dedeb50538393d5,\n", "0x3ded72e1f6ccd5a2,\n", "0xbd7d3e0b2d7b598f,\n", "0xbd749b384c86d390,\n", "0x3d049ebe7a682354,\n", "0x3cf5a2123b57dec6,\n", "0xbc8662ce26072b62,\n", "],\n", "[\n", "0x3ae97c92b0497970,\n", "0xbfba4407dac72297,\n", "0x3f4bcba4dec1da44,\n", "0x3f91803c65cafdfb,\n", "0xbf2283df2b3e4a6d,\n", "0xbf4bf695e89259cd,\n", "0x3edd8f3759122cea,\n", "0x3ef54246c8e04206,\n", "0xbe867111bc8e08a2,\n", "0xbe92d72a1f62d131,\n", "0x3e23d9ca3e4f40f9,\n", "0x3e25d74a6df26826,\n", "0xbdb6f4b3a86a00b8,\n", "0xbdb1d6f951aed310,\n", "0x3d42b1828de6ffa0,\n", "0x3d35a1d54468858d,\n", "0xbcc655ad620318bd,\n", "0xbcb40c27591e7a1a,\n", "],\n", "[\n", "0xbfb9ee5eee1a97c6,\n", "0x3b22e5c966133b1c,\n", "0x3fa9ee5eee1a97c6,\n", "0xbf31d55d93e59bd7,\n", "0xbf7146219394a99c,\n", "0x3efc7d32bb646e2e,\n", "0x3f226599aed4f1b4,\n", "0xbeb03ba58ec85e6f,\n", "0xbec4f9e3961b9170,\n", "0x3e5328d4dc364807,\n", "0x3e5dbda7ac1d3f8b,\n", "0xbdebb7c2f5dfce50,\n", "0xbdecbac1e6849bc9,\n", "0x3d7b1c39328db702,\n", "0x3d741cdba002ff38,\n", "0xbd0321f9e5a1aec7,\n", "0xbcf520545c68186a,\n", "0x3c84ca30f2d8fe34,\n", "],\n", "[\n", "0xbae7aaec85700fa6,\n", "0x3fb99be73fa3efcc,\n", "0xbf49c3248da75775,\n", "0xbf91107147eda800,\n", "0x3f212980be9d8520,\n", "0x3f4b44e1221e6051,\n", "0xbedb67b78c1dd966,\n", "0xbef4bc49e9b5bceb,\n", "0x3e84d02ffb8b7772,\n", "0x3e9261c31456c932,\n", "0xbe226b4006e91d9d,\n", "0xbe25512519fb5144,\n", "0x3db5500f2545f2d3,\n", "0x3db16b4e5f84ad48,\n", "0xbd415e211f9e7a0f,\n", "0xbd3521ed4cbd2b27,\n", "0x3cc4c4800c50a30c,\n", "0x3cb39810921b4be9,\n", "],\n", "[\n", "0x3fb94c6f5898708b,\n", "0xbb219499b2c197ca,\n", "0xbfa94c6f5898708b,\n", "0x3f308f4f1b8fb0dc,\n", "0x3f70da931c776c71,\n", "0xbefa7550d2940f2e,\n", "0xbf21f3b978a47cde,\n", "0x3eae28ea0247325a,\n", "0x3ec47930aec7652a,\n", "0xbe51ce32c4f61fb7,\n", "0xbe5d0950e94a9be9,\n", "0x3de9c5a164496f38,\n", "0x3dec0f17151563cb,\n", "0xbd79390150c5d3eb,\n", "0xbd73a6c5157c0de8,\n", "0x3d01d041a270134c,\n", "0x3cf4a6c2b9e9b4e9,\n", "0xbc835f05ebdf3e12,\n", "],\n", "[\n", "0x3ae60bdc6a36e0e5,\n", "0xbfb8ffc9b9a131f6,\n", "0x3f47f724314bb99d,\n", "0x3f90a89c5d1074ba,\n", "0xbf1feeaeb33465e7,\n", "0xbf4a9fba36a7a08e,\n", "0x3ed980034770f358,\n", "0x3ef43fa4bb8cba45,\n", "0xbe835f40f3a33db9,\n", "0xbe91f465ba2910f8,\n", "0x3e212688f6f9e1b4,\n", "0x3e24d3f7e3ce0c1a,\n", "0xbdb3daee33c4651d,\n", "0xbdb106a0ff5e7529,\n", "0x3d40309d2f92ac42,\n", "0x3d34aa09772c258a,\n", "0xbcc35f72aaef208c,\n", "0xbcb32afd4e360d62,\n", "],\n", "[\n", "0xbfb8b5ccb03d459b,\n", "0x3b206ac337f71f68,\n", "0x3fa8b5ccb03d459b,\n", "0xbf2edc98b92fedf3,\n", "0xbf70767d524cea88,\n", "0x3ef8a85a847c89c6,\n", "0x3f2189afaa2bffb7,\n", "0xbeac1d231a69bf1e,\n", "0xbec40139bdbc767b,\n", "0x3e509a6859cb8509,\n", "0x3e5c60fc5f4b173c,\n", "0xbde80ad395bd719c,\n", "0xbdeb6e94ec333a76,\n", "0x3d778adf7d6d4ffb,\n", "0x3d7338227f2ea5d9,\n", "0xbd00a328a2899a4a,\n", "0xbcf4349a4535eb0d,\n", "0x3c821ac1fe027675,\n", "],\n", "[\n", "0xbae4990a795d52df,\n", "0x3fb86e51bb2ee24d,\n", "0xbf465e3bad214eb8,\n", "0xbf9047d6ed159c31,\n", "0x3f1dce4a381ce24d,\n", "0x3f4a05b93842da9a,\n", "0xbed7ce3df60b0e4e,\n", "0xbef3cb50138cce39,\n", "0x3e8216e84a5d9f52,\n", "0x3e918e354c013832,\n", "0xbe2005492fe9c63e,\n", "0xbe245ed4a343a749,\n", "0x3db28e2e71c56d3c,\n", "0x3db0a83f8589bb9d,\n", "0xbd3e46baa33f452c,\n", "0xbd3439690ccae646,\n", "0x3cc2201c8a30e9e6,\n", "0x3cb2c44f88828341,\n", "],\n", "[\n", "0x3fb829356c2fb67c,\n", "0xbb1ebe6fec859455,\n", "0xbfa829356c2fb67c,\n", "0x3f2cd964e5e4caa0,\n", "0x3f70190ce66b97c3,\n", "0xbef70d5fd8bad7b8,\n", "0xbf2126a150469af1,\n", "0x3eaa49ea858153dd,\n", "0x3ec3910f5c157962,\n", "0xbe4f0f4bdbe6f9e5,\n", "0xbe5bc36977db17fb,\n", "0x3de67f295d55fdea,\n", "0x3dead81ba8b0c52f,\n", "0xbd760a13803ef42a,\n", "0xbd72d03bf820c54e,\n", "0x3cff2ad7c1434050,\n", "0x3cf3c92e07a03306,\n", "0xbc80f7d055471199,\n", "],\n", "[\n", "0x3ae34bfa6ed120b4,\n", "0xbfb7e656ed57a0d1,\n", "0x3f44f0cfc62eb61c,\n", "0x3f8fdaba63e9c655,\n", "0xbf1be7bad1c50546,\n", "0xbf4975ac0770c98d,\n", "0x3ed64a6af83ba812,\n", "0x3ef35e6b41b6d769,\n", "0xbe80f12d050da9bf,\n", "0xbe912e744222d16c,\n", "0x3e1e04a8c0124324,\n", "0x3e23f0ed5e3ac1ab,\n", "0xbdb163fd1599c398,\n", "0xbdb04f8ecba977f7,\n", "0x3d3c639575076eb9,\n", "0x3d33cf61a84aa254,\n", "0xbcc101368b088743,\n", "0xbcb26377b4c35c24,\n", "],\n", "[\n", "0xbfb7a597eb76a5e3,\n", "0x3b53aefe167f1294,\n", "0x3fa7a597eb76a5e3,\n", "0xbf2b0bd9eb615315,\n", "0xbf6f831b9629acd2,\n", "0x3ef59d1c40c95bc4,\n", "0x3f20c9d35d4be179,\n", "0xbea8a711bec6b4b0,\n", "0xbec327e42f38db9e,\n", "0x3e4d225aa909ad2f,\n", "0x3e5b2f83a8f0f85c,\n", "0xbde51bef24cad6b5,\n", "0xbdea4ab13337518e,\n", "0x3d74b0547a699854,\n", "0x3d726e6cf385d626,\n", "0xbcfd56db39ddf26a,\n", "0xbcf362be01af446b,\n", "0x3c82edb1a6e2242c,\n", "],\n", "];\n" ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = 2 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(y0_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 500;\n", "bessel_y0 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_y0(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RR(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "degree = 17\n", "\n", "print(f\"pub(crate) static Y0F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print(\"[\")\n", " for c in coeffs:\n", " print(double_to_hex(c) + \",\")\n", " print(\"],\")\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 8, "id": "9147c4ae-8986-4eca-b325-3df047cceabb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y0_COEFFS_RATIONAL128_REMEZ: [[DyadicFloat128; 28]; 47] = [\n", "[\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -128,\n", " mantissa: 0x85524221_780a56b6_c983b3fe_6c874e54_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -216,\n", " mantissa: 0xad336330_151c2c91_1ec49d0e_2d4fd907_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -129,\n", " mantissa: 0x85524221_780a56b6_c983fbd2_e7545155_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -132,\n", " mantissa: 0xa1cfd60b_292fb213_189bc436_c3003cac_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -134,\n", " mantissa: 0x86957a74_991c2d4a_53f763ae_ab84f4a6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -138,\n", " mantissa: 0xfb8b235f_54088566_49f167bf_c032ba14_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -137,\n", " mantissa: 0xa225ed45_b32545de_271ef3ae_ba3f18c2_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -139,\n", " mantissa: 0xc2611033_955c128a_5f7cbc3a_7ed7d315_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -140,\n", " mantissa: 0x8bd5a57d_603910e9_54271936_f142182e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -142,\n", " mantissa: 0xed7dcdc4_c1e2d347_58bb40aa_67675d8a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -143,\n", " mantissa: 0xc5dcb17d_36c0a344_27d0095b_de4e4c91_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -144,\n", " mantissa: 0xa45b3b86_19f08b11_56f33bc4_8611d500_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -145,\n", " mantissa: 0x89b26ede_ebf14345_f8342503_10164207_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -147,\n", " mantissa: 0xe83556e4_f7f59ddc_10e7b6d0_c5ab8adc_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -148,\n", " mantissa: 0xc4cc774d_4914633c_56e47ec0_c341edff_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -149,\n", " mantissa: 0xa78cc5cf_5036caff_f2fe3251_6c3e861f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -150,\n", " mantissa: 0x8f3a247a_fb46ec66_f1fdf086_529555ef_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -152,\n", " mantissa: 0xf5c1a981_e8b36ef3_381d8794_d143697f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -153,\n", " mantissa: 0xd385019e_6045fb57_9565d471_8322b667_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -154,\n", " mantissa: 0xb681850f_1ac4b42e_9b0aeabd_4b30bc23_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -155,\n", " mantissa: 0x9d6afe17_eb06ebc5_679ba694_5165b5df_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -156,\n", " mantissa: 0x865e90b8_4bdc5729_c5a4a68a_1be5232d_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -158,\n", " mantissa: 0xdd2dc7fe_cb628350_bc70a365_de7b54f4_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -159,\n", " mantissa: 0xa71a42fc_0c4c800d_bacf66ec_1dbb3f95_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -161,\n", " mantissa: 0xd76c79a8_96571086_80ac6ba7_49d83bab_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -163,\n", " mantissa: 0xd6ba7507_28a18650_aab8050b_9306c569_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Neg,\n", " exponent: -165,\n", " mantissa: 0x8f0db3ea_ec607145_10459e73_e6e8afc0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -169,\n", " mantissa: 0xbb5d993d_06092240_8f399b3b_5df72934_u128,\n", "},\n", "],\n" ] }, { "ename": "KeyboardInterrupt", "evalue": "", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mKeyboardInterrupt\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 76\u001b[39m\n\u001b[32m 74\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[32m0\u001b[39m, \u001b[38;5;28mlen\u001b[39m(intervals)):\n\u001b[32m 75\u001b[39m interval = intervals[i]\n\u001b[32m---> \u001b[39m\u001b[32m76\u001b[39m \u001b[43mcall_sollya_on_interval\u001b[49m\u001b[43m(\u001b[49m\u001b[43minterval\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minterval\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minterval\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdegree\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 77\u001b[39m coeffs = load_coefficients(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mcoefficients.txt\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 78\u001b[39m print_remez_coeffs(coeffs)\n", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 46\u001b[39m, in \u001b[36mcall_sollya_on_interval\u001b[39m\u001b[34m(a, b, zero, degree)\u001b[39m\n\u001b[32m 44\u001b[39m os.remove(\u001b[33m\"\u001b[39m\u001b[33mcoefficients.txt\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 45\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m46\u001b[39m result = \u001b[43msubprocess\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 47\u001b[39m \u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43msollya\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtmp_interval.sollya\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 48\u001b[39m \u001b[43m \u001b[49m\u001b[43mcheck\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 49\u001b[39m \u001b[43m \u001b[49m\u001b[43mcapture_output\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 50\u001b[39m \u001b[43m \u001b[49m\u001b[43mtext\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\n\u001b[32m 51\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 52\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess.CalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m 53\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/subprocess.py:550\u001b[39m, in \u001b[36mrun\u001b[39m\u001b[34m(input, capture_output, timeout, check, *popenargs, **kwargs)\u001b[39m\n\u001b[32m 548\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m Popen(*popenargs, **kwargs) \u001b[38;5;28;01mas\u001b[39;00m process:\n\u001b[32m 549\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m550\u001b[39m stdout, stderr = \u001b[43mprocess\u001b[49m\u001b[43m.\u001b[49m\u001b[43mcommunicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 551\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m TimeoutExpired \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[32m 552\u001b[39m process.kill()\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/subprocess.py:1209\u001b[39m, in \u001b[36mPopen.communicate\u001b[39m\u001b[34m(self, input, timeout)\u001b[39m\n\u001b[32m 1206\u001b[39m endtime = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 1208\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1209\u001b[39m stdout, stderr = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_communicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mendtime\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1210\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[32m 1211\u001b[39m \u001b[38;5;66;03m# https://bugs.python.org/issue25942\u001b[39;00m\n\u001b[32m 1212\u001b[39m \u001b[38;5;66;03m# See the detailed comment in .wait().\u001b[39;00m\n\u001b[32m 1213\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m timeout \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/subprocess.py:2115\u001b[39m, in \u001b[36mPopen._communicate\u001b[39m\u001b[34m(self, input, endtime, orig_timeout)\u001b[39m\n\u001b[32m 2108\u001b[39m \u001b[38;5;28mself\u001b[39m._check_timeout(endtime, orig_timeout,\n\u001b[32m 2109\u001b[39m stdout, stderr,\n\u001b[32m 2110\u001b[39m skip_check_and_raise=\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[32m 2111\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m( \u001b[38;5;66;03m# Impossible :)\u001b[39;00m\n\u001b[32m 2112\u001b[39m \u001b[33m'\u001b[39m\u001b[33m_check_timeout(..., skip_check_and_raise=True) \u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 2113\u001b[39m \u001b[33m'\u001b[39m\u001b[33mfailed to raise TimeoutExpired.\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m-> \u001b[39m\u001b[32m2115\u001b[39m ready = \u001b[43mselector\u001b[49m\u001b[43m.\u001b[49m\u001b[43mselect\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 2116\u001b[39m \u001b[38;5;28mself\u001b[39m._check_timeout(endtime, orig_timeout, stdout, stderr)\n\u001b[32m 2118\u001b[39m \u001b[38;5;66;03m# XXX Rewrite these to use non-blocking I/O on the file\u001b[39;00m\n\u001b[32m 2119\u001b[39m \u001b[38;5;66;03m# objects; they are no longer using C stdio!\u001b[39;00m\n", "\u001b[36mFile \u001b[39m\u001b[32m/private/var/tmp/sage-10.6-current/venv/lib/python3.12/selectors.py:415\u001b[39m, in \u001b[36m_PollLikeSelector.select\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 413\u001b[39m ready = []\n\u001b[32m 414\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m415\u001b[39m fd_event_list = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_selector\u001b[49m\u001b[43m.\u001b[49m\u001b[43mpoll\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 416\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mInterruptedError\u001b[39;00m:\n\u001b[32m 417\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m ready\n", "\u001b[31mKeyboardInterrupt\u001b[39m: " ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = 2 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.03 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.03 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.03\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(y0_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 200;\n", "bessel_y0 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_y0(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "def print_remez_coeffs(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " print_dyadic(coeff)\n", " # print_double_double(\"\", coeff)\n", " print(\"],\")\n", "\n", "degree = 27\n", "\n", "# print(f\"pub(crate) static Y0_COEFFS: [[(u64, u64); {degree + 1}]; {len(intervals)}] = [\")\n", "# for i in range(0, len(intervals)):\n", "# interval = intervals[i]\n", "# call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", "# coeffs = load_coefficients(f\"coefficients.txt\")\n", "# print_remez_coeffs(coeffs)\n", "# print(\"];\")\n", "\n", "print(f\"pub(crate) static Y0_COEFFS_RATIONAL128_REMEZ: [[DyadicFloat128; {degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_remez_coeffs(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "fe855ef3-0327-46c1-b3f3-d4b5b2575aab", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y0_COEFFS: [[(u64, u64); 28]; 47] = [\n", "[\n", "(0xbc749367c4c05aaa, 0x3fe0aa48442f014b),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c649367c4c05aaa, 0xbfd0aa48442f014b),\n", "(0x3c4098c5b27f9542, 0x3fa439fac16525f6),\n", "(0xbc25adcf3e0230ee, 0x3f80d2af4e932386),\n", "(0xbbe4e773096516dd, 0x3f4f71646bea8111),\n", "(0x3bf3295907be08a9, 0xbf5444bda8b664a9),\n", "(0x3bcc92ed3e7dac0f, 0x3f384c220672ab82),\n", "(0xbbc2b56b5db9ac40, 0xbf217ab4afac0735),\n", "(0x3ba57929ce662323, 0x3f0dafb9b8983d86),\n", "(0xbb9a34080fad5051, 0xbef8bb962fa6c504),\n", "(0xbb70f97215a75a9f, 0x3ee48b6770c210bf),\n", "(0xbb6ac5099b6b7783, 0xbed1364ddbddf33b),\n", "(0x3b5c6a28d5d49339, 0x3ebd06aadd881cef),\n", "(0x3b360737a2bfac90, 0xbea8998eefe8caa1),\n", "(0x3b10ceb1fd02d154, 0x3e94f198aa7c73a8),\n", "(0x3b201bb903ea5d53, 0xbe81e742c1cf6acb),\n", "(0x3b0e3c97eb74692a, 0x3e6eb820636013a9),\n", "(0xbae9e5875024afeb, 0xbe5a709593e5d778),\n", "(0x3a9c3113327b82cf, 0x3e46d299b1a6ab0d),\n", "(0x3ad32a9aab166472, 0xbe33c08d3e0a3e4c),\n", "(0xbab2ec0cd7aefe76, 0x3e2122b2a831eedc),\n", "(0xba7fd1a1eaeba4e2, 0xbe0dcbb767b405d4),\n", "(0xba9f28de864d6d7d, 0x3df9f4d817711be0),\n", "(0xba84e5784f3ba466, 0xbde6a732ce7db295),\n", "(0x3a2ba83b1dceb593, 0x3dd3cdb1820544fc),\n", "(0x3a64cd3a569b8afb, 0xbdc156d9d7a9603b),\n", "(0xba4c3618e715b8ab, 0x3dae68388d1e7164),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc5a4026e436c4d3, 0xbfd9c34256a12a0c),\n", "(0xbc49ded6e8236fd3, 0x3faa09c9290367ef),\n", "(0xbc253b02d2a53d30, 0x3fadf6d59bf50ebd),\n", "(0xbc18dbf118b1a2cc, 0xbf7c116fdc598096),\n", "(0x3bf40db0aa3d7078, 0xbf61e32bc4ef8a41),\n", "(0xbbcbb6264c727077, 0x3f29982765166254),\n", "(0xbb86be82f4783a97, 0x3f0ab2c1fecdcfc4),\n", "(0x3b74540a4df5362c, 0xbed486371e6a663e),\n", "(0xbb38925afac5b2b8, 0xbe93b21684089b4c),\n", "(0x3af8953a9c0487f4, 0xbe5777058741bf97),\n", "(0xbad841f372dee964, 0x3e5452ea00945a70),\n", "(0x3aa79f6248f7f1b0, 0xbe2f6938829664f1),\n", "(0xba9880934623f972, 0x3e0a5a1f3a2a293e),\n", "(0xba74d07ce1ea2db9, 0xbde994e736de8ef8),\n", "(0x3a666975b24e41c6, 0x3dc88ae5c83467bc),\n", "(0x39e7564160acaf67, 0xbda75329361f19bb),\n", "(0x39f36d6ccdec6121, 0x3d8643c7a49b7f43),\n", "(0x39e06cdcecde2c8d, 0xbd655480c70f5929),\n", "(0xb9ee4b7548f46bdb, 0x3d447c1c44c1487e),\n", "(0x398be3f2b0a46b7a, 0xbd23b7d1fbf0fdd0),\n", "(0xb9aeefcda909f8cb, 0x3d0305531056d810),\n", "(0x398546902be387f3, 0xbce2626f5e5dfcac),\n", "(0x395bf1c6ad49bc60, 0x3cc1cd4c7460b8d8),\n", "(0xb91985693844d5c0, 0xbca1445851bfea5f),\n", "(0xb92b3bdde2175982, 0x3c80c63a86aa43b3),\n", "(0xb8ff7f8fe9d70fe2, 0xbc6051ca830eb872),\n", "(0xb8b0d0de6a7a8a72, 0x3c3fcc0fa90bfb3f),\n", "],\n", "[\n", "(0x3c7b8d2a1c496808, 0xbfd5c7c556f0c19a),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc6b8d2a1c496808, 0x3fc5c7c556f0c19a),\n", "(0xbc2b4d44aaadbbec, 0xbf8564d4b1ed0d7e),\n", "(0x3c2e4289c3acba27, 0xbf8a15d92dfe3e27),\n", "(0xbbedbea927b719eb, 0x3f4b438430469ff7),\n", "(0x3bdc1760512f76cc, 0x3f37a8924cc2f914),\n", "(0xbb70219aa771d161, 0xbef5f69b4a8a3c05),\n", "(0xbb77299907aec5c4, 0xbed85b940eb607f9),\n", "(0x3b3d5ae26ad627b8, 0x3e955ac0f5c3162c),\n", "(0xbb0f58c09c1fabd1, 0x3e6d563e18b47eb9),\n", "(0x3a99750b0b40769a, 0xbe23eac3a45e06ef),\n", "(0x3a9e3d09f9f42f26, 0xbe0007671d55a8be),\n", "(0xba495377f5d84985, 0x3dc04e13e8d2ceb5),\n", "(0x3981b2ad63946aa5, 0xbd46e2b306cbb1f3),\n", "(0xb9fbadc4f0bb048c, 0x3d54d18f7c90e926),\n", "(0xb9c8225b40e694f7, 0xbd34980895b5067a),\n", "(0xb998c3893e3c0087, 0x3d0a5b439cef90cb),\n", "(0x3977814f4b07cebf, 0xbce1c9c4c0d530e1),\n", "(0x3952fcdfd498e788, 0x3cb933cc6493bf1c),\n", "(0x393ffe3660f335f2, 0xbc91c67122e8e134),\n", "(0x3904bb25b4c5ee57, 0x3c6904e906c46283),\n", "(0x38cd1dbe18c0ee49, 0xbc41a5ff5486c2fe),\n", "(0xb8a09b2fbba2c634, 0x3c18f24433ae1991),\n", "(0x3898e91198e4959c, 0xbbf1a84c8250ebd5),\n", "(0xb856349e52eccab3, 0x3bc90826d8cc3eff),\n", "(0xb848f5b7e7d4ec81, 0xbba1c456da51d36d),\n", "(0x37f66d77762bebcf, 0x3b7940bb04835b31),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc78d4484b7cd2a6, 0x3fd334cca0697a5b),\n", "(0xbc341c66c86d3ebd, 0xbf95aef611fc4d57),\n", "(0xbc44929b43aab7fb, 0xbfa8969c64cbf452),\n", "(0x3bfab353487eb36f, 0x3f6b2f14a95527cb),\n", "(0x3c0aa67a62fad710, 0x3f61d35e85fde2a3),\n", "(0xbbb270ba54459cab, 0xbf226dd71e391c8b),\n", "(0xbb61863b08bc5950, 0xbf08177e4fe52324),\n", "(0x3b494954a2d7de21, 0x3ec6a9227352f96a),\n", "(0xbb44a5b1e0c3c3e1, 0x3ea34aa7573ef14e),\n", "(0xbb06984676a524bc, 0xbe60a2814d7ac448),\n", "(0xbad9251769eb31a9, 0xbe3442a3d3359ad9),\n", "(0x3a86fc915b18c175, 0x3defa6c509566c72),\n", "(0xba3b534d6e1095ea, 0x3dbf14e5584823db),\n", "(0x3a16e8b19c361860, 0xbd7714c292be3936),\n", "(0x39e500ccc143989e, 0xbd40679cd5855172),\n", "(0xb998a55fa2ea549b, 0x3cf3365d5a786a7b),\n", "(0x395c00dd62ac7e1c, 0x3cc38cf06b47bc6e),\n", "(0x38f0c8bd8691968e, 0xbc82bd5a83b64d59),\n", "(0x38bddc7ea088ddcd, 0x3c326e92cf91d829),\n", "(0x38b27643db6c3b27, 0xbc127116123c3d66),\n", "(0x388c47f57a6d55b0, 0x3be8df4f1bd4a3f7),\n", "(0x3853b5c4a12853b5, 0xbbb9b0c7fab8762b),\n", "(0x381d1068b57233fd, 0x3b8b3b04447f58f8),\n", "(0x37f6b2b5793b64aa, 0xbb5dbd231117d61d),\n", "(0xb7d3a5abcdba22eb, 0x3b3035d90c22fa4e),\n", "(0xb786f2af60849004, 0xbb01a58ba966a549),\n", "(0x376712c78c816e41, 0x3ad33cc7a0e946ec),\n", "],\n", "[\n", "(0x3c61dc672a53c590, 0x3fd15f993fceab5c),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc51dc672a53c590, 0xbfc15f993fceab5c),\n", "(0xbc0d1c390189cb30, 0x3f758ef6efbed797),\n", "(0xbc243ede64b782d9, 0x3f86395dfe49fcd4),\n", "(0xbbbb4484582c2699, 0xbf3fb15104a41c00),\n", "(0xbbd4410e752be535, 0xbf35f88a11d5564f),\n", "(0xbb8b2d9b83a11c89, 0x3eef37d226a824b7),\n", "(0xbb61fb17827843f5, 0x3ed6f7bab104f355),\n", "(0x3b2da2cb75d8087f, 0xbe8f0c45a3824d70),\n", "(0xbac1132bedbb6ebc, 0xbe6dfe11df12c715),\n", "(0xbac5290f391bbfe1, 0x3e2311adc2e753ee),\n", "(0xba92039061518817, 0x3dfad34e18504e16),\n", "(0xba4d6cd9e6f85fe9, 0xbdafdc8061ae8b15),\n", "(0xba189257c63f6446, 0xbd819498ca6cef9b),\n", "(0xb9c8f0f4bb78628c, 0x3d33a291d5991f74),\n", "(0x399127448ae5dbb8, 0x3d016f7ae80cad77),\n", "(0xb958d1b0f5eaa04b, 0xbcb1f8d80deccee6),\n", "(0x3910d158fa5b41a8, 0xbc7c27b5350a923c),\n", "(0x38c3559986f928ac, 0x3c2d08034e70dd4a),\n", "(0xb86c6bb218da7ccb, 0x3befac2006e277e3),\n", "(0x383c518f1fca847d, 0xbb93e926868daea2),\n", "(0x380ef79adc3898ef, 0xbb6dcdf980ddfdf4),\n", "(0x37cea115c120894b, 0x3b2c4665b1564c6a),\n", "(0xb783f5bf36c1dc64, 0xbaec0521ead39203),\n", "(0xb74144c7cd1de85b, 0x3abed64c1afbe47b),\n", "(0x3722cfb0d396394e, 0xba8e04ab2a193e84),\n", "(0xb6f088c0c22460a8, 0x3a5a77e09ed6a09d),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c61e8f568f8c6b9, 0xbfcff635cc72b9f1),\n", "(0x3c0fa6ebe8b75862, 0x3f89036451ff57c5),\n", "(0x3c46345bcf3c5b7d, 0x3fa4e667a71556af),\n", "(0x3c065e386829f03c, 0xbf60325ee41e910c),\n", "(0x3bfde6b6846da9d0, 0xbf5fe23914fb9128),\n", "(0xbbb9c28522c54ab2, 0x3f17f84d7c50e4c4),\n", "(0xbbaeab0290c99b85, 0x3f06afdd57be1e14),\n", "(0xbb2bbdfb6c4ce197, 0xbec04053abf4386a),\n", "(0x3b3787c4b6b6a0b6, 0xbea2aea9ec48d8fd),\n", "(0xbaf17a3632e2edc5, 0x3e593eb9f1ddb4e9),\n", "(0x3ad9f831e08fbb99, 0x3e3428a3a3e30a13),\n", "(0xba49cae682f11d51, 0xbde99d8c42f7a020),\n", "(0xba591eb785e59448, 0xbdbec9805045aa58),\n", "(0xba086b5bad70f23b, 0x3d72613659ce994f),\n", "(0xb9eb4013d9ba0032, 0x3d418f302bdba980),\n", "(0x38e42c05bf9582a5, 0xbcf3bc9ccb704253),\n", "(0x3952d598704c3b46, 0xbcbf0dc4067be8b2),\n", "(0x391246064faa45fa, 0x3c706e491f458956),\n", "(0xb88908e1a67ee56c, 0x3c36013bac769277),\n", "(0x388f595373e53a2e, 0xbbe616b4d62a47f6),\n", "(0x384c63a51904dc22, 0xbba93fb6fa556eab),\n", "(0xb7fb730412560441, 0x3b57963a88acf606),\n", "(0xb7aad1cf0b52dca3, 0x3b1937ef4e3db6a9),\n", "(0x37592af1b29a1e7c, 0xbac8387c0e875a84),\n", "(0xb6f7ae247b07d290, 0xba80a12689ec647c),\n", "(0x36beb9fdadfcf39a, 0x3a1bcc6e30896704),\n", "(0xb697aa9158bd1808, 0x39fd4db12fab6895),\n", "],\n", "[\n", "(0x3c54d14c77bc1691, 0xbfcdc14ea14e89f9),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc44d14c77bc1691, 0x3fbdc14ea14e89f9),\n", "(0x3c00ff03f97580f3, 0xbf6b037fe9cf2a52),\n", "(0xbc2f19a8f5b1379e, 0xbf8367d7d608e4ba),\n", "(0x3bdd892317f291c8, 0x3f34abef5636e4f7),\n", "(0x3bd5ba5b5b609683, 0x3f33d8a661229259),\n", "(0xbb700a3f00979ee5, 0xbee5cfe92a1a2c45),\n", "(0xbb6087e84c57d2ad, 0xbed571814a1aa301),\n", "(0x3b22b6740da6456f, 0x3e87414e33c9bacd),\n", "(0x3afa4836a36f8841, 0x3e6ca7069e73d1d9),\n", "(0x3abe65fd6bda59de, 0xbe1e0b3a705ff247),\n", "(0x3a95774cb23eb7b8, 0xbdfa15dd62cf9f10),\n", "(0xba399fbe055cb8be, 0x3daa33948eada12c),\n", "(0x3a2240f402a7b379, 0x3d81419b1fd428ef),\n", "(0x39cc415e74e0cbc8, 0xbd30882f60b8a775),\n", "(0xb991c41d97727556, 0xbd015e5c0af749d4),\n", "(0x392937d5bb210372, 0x3cafb1e115e08994),\n", "(0x38f58b3c9e456997, 0x3c7b838263708865),\n", "(0x38c5cd0199e8f790, 0xbc27e5d539870f02),\n", "(0xb89a3dc2e116c3ad, 0xbbf19dae392457a1),\n", "(0x383bc230f8650284, 0x3b9d2b72778fe832),\n", "(0x37f13768b14c0c18, 0x3b6298bb7e2277f2),\n", "(0xb7aa1239c7070276, 0xbb0d50baf60db64c),\n", "(0xb773592299e9674f, 0xbad08ad53b850ab4),\n", "(0x3717cc8a5ae6e9ab, 0x3a79141842fa569d),\n", "(0xb6b9bec849ea1c6d, 0x3a38ab0a361907e6),\n", "(0xb67a764f692d7a9b, 0xb9e14491ed3e919d),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c41398cacaa32d4, 0x3fcbf32a27594007),\n", "(0x3bfe5ce4af724b17, 0xbf80bc2d84e65214),\n", "(0x3c4acd5148eb7e9d, 0xbfa26cab38a8b368),\n", "(0x3bfab9a1103e2000, 0x3f55f03e47165d72),\n", "(0xbbc4598141a3f849, 0x3f5caaa76e34992d),\n", "(0xbbbb7ab55e886623, 0xbf10c5f18c46d030),\n", "(0xbb99f58bad5e7aa5, 0xbf04f0af7d46cd48),\n", "(0xbb3040f00afca09c, 0x3eb7d1e28094e21a),\n", "(0xbb3f12dedaa2ba65, 0x3ea1ad0731228479),\n", "(0xbae9fe69a3662740, 0xbe536021c8cb3c34),\n", "(0x3ad92bf3f184780b, 0xbe3371ae6c759181),\n", "(0x3a630cc7c21c0cfc, 0x3de46ce077a8bed7),\n", "(0xba5feb6d0e335e60, 0x3dbe235d3564b639),\n", "(0xb9d7ae1d94bd92ac, 0xbd6e408e259c72fb),\n", "(0xb9c8768c2460ab80, 0xbd415f07ac87e832),\n", "(0xb91b6919f885a208, 0x3cf0a44f77f6a8ef),\n", "(0x393312b132a8d347, 0x3cbefd8ab52f8eb9),\n", "(0x38f1bfe622c31b37, 0xbc6c54ebb5ad3869),\n", "(0xb8a61a375002a1c0, 0xbc360b43cbb5f5e9),\n", "(0xb88cc62cec929222, 0x3be33d74aacb57e2),\n", "(0x3842ffe5c04b22b9, 0x3ba99bfbb3fe627d),\n", "(0x37e1d4df5722a5b0, 0xbb555c0969d70a77),\n", "(0x37b44cfc1475dce9, 0xbb18c29d2318e9b5),\n", "(0xb7682246c98d07a1, 0x3ac3c0750d221b4f),\n", "(0xb717ffcd427c1eee, 0x3a843fa688c2eb51),\n", "(0x369fc06d11ba5fce, 0xba2ef4ae2931c6ca),\n", "(0xb674d5d2266c5526, 0xb9ec57869d64feb9),\n", "],\n", "[\n", "(0x3c57ba12cd0fc91f, 0x3fca7022be084d99),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc47ba12cd0fc91f, 0xbfba7022be084d99),\n", "(0xbc0b3327197c9da3, 0x3f62ee079d020b12),\n", "(0x3c2d0f8f36713120, 0x3f8163191c30aa62),\n", "(0xbbcc7f2dbb383204, 0xbf2d7806ea72fc76),\n", "(0x3bcf9ec581434d38, 0xbf320f95702b1d4e),\n", "(0x3b899e1a0f3c0857, 0x3ee00610882294aa),\n", "(0x3b61505ce3b29a78, 0x3ed3e398cbc472ea),\n", "(0xbae050c77864dd20, 0xbe81bbe181c65162),\n", "(0xbb0c3fb8339198a1, 0xbe6b0f89b7c61f3a),\n", "(0x3ab91b7c8e3c7c3c, 0x3e17c3f85882049b),\n", "(0xba976a7c841dba14, 0x3df90236614c84dc),\n", "(0xba43ab3b18e59a65, 0xbda564920d1387dc),\n", "(0x3a2b1754ca712321, 0xbd80be1811255cfe),\n", "(0x39b342bebee2071b, 0x3d2bb9712586bfac),\n", "(0xb99c92d876d25063, 0x3d0101c31e1df223),\n", "(0xb916e23fb5f67bb8, 0xbcab298cda76e77b),\n", "(0x3918a11b915d1274, 0xbc7b22acc441d872),\n", "(0x38cdcc71612b99d0, 0x3c24dca37a32e97c),\n", "(0x38855c0754c54ab3, 0x3bf176e94ee1fe21),\n", "(0x3836cf20a369d629, 0xbb99d4f0d74e9093),\n", "(0x3802940330562608, 0xbb6287585b150c7c),\n", "(0x37a0f4cbacc81873, 0x3b0a5c015f1f057c),\n", "(0x3779aaaf8d850193, 0x3ad07cc0082a44cf),\n", "(0xb70fd62f89ce46a9, 0xba76909f83007714),\n", "(0xb6d4e9d85e17b208, 0xba38f88423d4ad97),\n", "(0xb66d34e3378a5539, 0x39e072fc561ac2bd),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc65b9c39e42719e, 0xbfc925c35988ee29),\n", "(0xbbdda9c0588bc7cc, 0x3f7862549367591e),\n", "(0x3c4a142ed6a5521f, 0x3fa0a4512039d6a2),\n", "(0x3be94ce533c65cad, 0xbf5013b38cfb9292),\n", "(0xbbea2a14cf0f61af, 0xbf5a24a1215f6684),\n", "(0xbbae7b4c448b42eb, 0x3f08f91421377fad),\n", "(0x3baf72fd0f5209a4, 0x3f035d17cec0172f),\n", "(0x3b3cd242e4f5ce10, 0xbeb2283a93114096),\n", "(0x3b259dda3f9c3cd8, 0xbea099e71392f54e),\n", "(0xbad6dce1bfae1a53, 0x3e4e5de01e2e6566),\n", "(0xbab52eec76dd7e24, 0x3e32885854ea8b06),\n", "(0x3a6795ca81b0c1a2, 0xbde0730c2985fd22),\n", "(0x3a4e06d8277ffd55, 0xbdbd1743cbb2e11a),\n", "(0x3a013448997f1418, 0x3d68f8728745e1e6),\n", "(0x39dd9a182e4412f8, 0x3d40f166cb29a7d1),\n", "(0x398dd4bcf72e3139, 0xbcec10e67c004e3b),\n", "(0xb9542acf7b7def7d, 0xbcbe7aec1ba33e83),\n", "(0xb908d6ed91615a58, 0x3c68543e12c9bf9a),\n", "(0x38a13a9d572a9420, 0x3c35d3939f6d1ed2),\n", "(0x387a4284a63f1993, 0xbbe0c7ba11981a01),\n", "(0x38405b9a6bff4fca, 0xbba97d9177222a00),\n", "(0xb7f4c779b6c742c8, 0x3b52dfb95f4a8634),\n", "(0xb7aba81ffd3b5c41, 0x3b18c04f3759b6eb),\n", "(0x375fa028706c2252, 0xbac1a799c1562309),\n", "(0xb729c62dd7828d2a, 0xba844dc9c3e85489),\n", "(0xb6cf5aac2a393499, 0x3a2bea86b90f9faf),\n", "(0x36614b1df5aeed9d, 0x39ec85971210b79b),\n", "],\n", "[\n", "(0xbc63db68c567283b, 0xbfc80781c32422e7),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c53db68c567283b, 0x3fb80781c32422e7),\n", "(0xbbfab5094c039454, 0xbf5c6923374d561f),\n", "(0xbc032419a9d405db, 0xbf7fbe6df840847f),\n", "(0x3bc0f03bc2e75d6b, 0x3f264f4711a85f1a),\n", "(0x3bbd9972e6c197fd, 0x3f309ff42b0d7a68),\n", "(0xbb61aba5a7ce6455, 0xbed8a60685a597d9),\n", "(0xbafdb153b13f2cf0, 0xbed282d26a74c38e),\n", "(0xbb1d21d4a94b9e91, 0x3e7bdb57a889a4c1),\n", "(0xbb099a040a6939c6, 0x3e697d9c12a60cef),\n", "(0x3a35e114fc2a1213, 0xbe131aa8691738fb),\n", "(0x3a93c999393c858b, 0xbdf7d486eee39a85),\n", "(0x3a223c1c4424f0db, 0x3da197f258214b3d),\n", "(0xba1644a8cbcb4af5, 0x3d801dd7f92195ff),\n", "(0xb9ca37ef1c0ef3fa, 0xbd27480b9efaa860),\n", "(0xb98847e4ec1195cf, 0xbd00833ea1f83461),\n", "(0xb928c4b1729bab7e, 0x3ca73bf7964edc26),\n", "(0x3913ebe30cf0771f, 0x3c7a891d704fef9b),\n", "(0x3881294f9e950341, 0xbc22222dcf094b80),\n", "(0xb898aeadae639677, 0xbbf12db9d21e37ed),\n", "(0x37ea537285a44833, 0x3b96c4638e4cc003),\n", "(0xb7f3ee61741a27e7, 0x3b624ff2a82fc9c9),\n", "(0xb7987ce466329a95, 0xbb0782fd4fc7cb7b),\n", "(0xb75dca0980ad8630, 0xbad05bab97dc88c3),\n", "(0x36f1b4cbf5a58e0a, 0x3a74565e5f91bb35),\n", "(0xb6d553555a830f19, 0x3a38da3118f887bc),\n", "(0x36758225c016dcfa, 0xb9ddea7aa8da61e4),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c64fef53f4893e5, 0x3fc70c4f66cab47f),\n", "(0xbc1e032768318e4d, 0xbf72c6731071e936),\n", "(0x3c2f806b21bc9577, 0xbf9e924b85a17361),\n", "(0xbbe1434be87c6363, 0x3f48d6c364d92082),\n", "(0x3bf5cbe0638f4cef, 0x3f58247b02d6b0f6),\n", "(0xbbaade8b3660fd4e, 0xbf0376125938561d),\n", "(0x3bae81e47dd383cf, 0xbf0206da232a2b6a),\n", "(0x3b424b3c3173e20f, 0x3eacaf84db871510),\n", "(0xbb022e3bac70bc67, 0x3e9f3671177306ca),\n", "(0x3a9f8b17b052db72, 0xbe48654b001006cd),\n", "(0x3ad272b921d7360d, 0xbe3199ec88b18766),\n", "(0x3a6b9a3bf5083c1d, 0x3ddaeb1a849305fb),\n", "(0x3a57cadaf3f1d693, 0x3dbbe67c197c48c0),\n", "(0xb9c7cc3d8d1e5e49, 0xbd64cdfa0bd69898),\n", "(0xb9db4ff4c3ee8f12, 0xbd4064936f97922f),\n", "(0xb9777557537dd027, 0x3ce7c83b5186222f),\n", "(0x395de8595a9345f0, 0x3cbdb73ad7fa8bc8),\n", "(0x38f6136241cc3637, 0xbc64eecbf0b91d4f),\n", "(0xb8d2eab985ecf43c, 0xbc356ab697c0ab6d),\n", "(0x387327e90134d3b9, 0x3bdd4506fe436113),\n", "(0xb837e66ef2a0608f, 0x3ba925d81a8dc397),\n", "(0xb7f15df323201ec3, 0xbb50a89d96a14715),\n", "(0xb7bfc8950449ed4b, 0xbb18875d24cf9582),\n", "(0xb754b1be99b10be3, 0x3abf7e546e402e74),\n", "(0x372718433d137dec, 0x3a84326527427bb9),\n", "(0xb68468a05b2cb0da, 0xba2921298884b92b),\n", "(0x367c4fc25beb34a3, 0xb9ec75a8ffac9550),\n", "],\n", "[\n", "(0xbc6d2f0105f3ce7c, 0x3fc62d94d97e859c),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c5d2f0105f3ce7c, 0xbfb62d94d97e859c),\n", "(0xbbf6c13bde837960, 0x3f565481b55eaefb),\n", "(0x3c17013075a066f9, 0x3f7d5f857a2a6107),\n", "(0x3bc5f065aa6339f5, 0xbf21a015a2ccb78f),\n", "(0xbbc12f349174f010, 0xbf2eeb4eafd8614b),\n", "(0xbb53525d6141be28, 0x3ed3a7b79e4d80fc),\n", "(0xbb662d899f08a704, 0x3ed154ed4598d2f0),\n", "(0xbb0444753ebe791d, 0xbe767f762ea293a1),\n", "(0xbafe11bb6f1d4207, 0xbe680ec1e042ee62),\n", "(0x3aa725a667375b0d, 0x3e0f529652b9de0f),\n", "(0xba97b074118bab16, 0x3df6ad7bd2247f55),\n", "(0x39e3900c76e6a68e, 0xbd9d4e582fb43553),\n", "(0x3a1f5fd82381bd59, 0xbd7eeb6efcbb6228),\n", "(0x39c7389b8d7fe521, 0x3d23b1eabb5c1c2c),\n", "(0x3992974c386cdc2a, 0x3cffe92f0882b440),\n", "(0xb923c49452353597, 0xbca3f20671568bca),\n", "(0xb9002a4da3d3a816, 0xbc79ce30ac166eb5),\n", "(0x38b02f60dd891164, 0x3c1f8db6e94f1a96),\n", "(0x383459153c91e395, 0x3bf0cc90c0607e7d),\n", "(0x383003b333010a99, 0xbb940c6bb9f9a6c4),\n", "(0x37d6a317d4f5ae21, 0xbb61fe382b9ca927),\n", "(0xb76dfd62097696b0, 0x3b04ed907b4ff4b6),\n", "(0xb75abcbe1108a215, 0x3ad0234a19150d32),\n", "(0xb71105a3cea0d529, 0xba7246b54dbf759d),\n", "(0xb6cf812a75ac4069, 0xba3899f3eb5b7cf1),\n", "(0x36688dddcd012369, 0x39db1cda80386890),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c5fe2103f7148bb, 0xbfc5664d37c37d7b),\n", "(0xbc0a0fbbe8bcf9a6, 0x3f6e0ee8ec84659a),\n", "(0xbc383a77d074bd0a, 0x3f9c6c415c971b4b),\n", "(0xbbb06fe5233f06e8, 0xbf43ec49cb941f55),\n", "(0x3bfe14142e1727fe, 0xbf56853b2d047885),\n", "(0xbb98cea461592c41, 0x3eff632a9396fd4e),\n", "(0xbba049885559b2a5, 0x3f00e6afa01af561),\n", "(0x3b452a8549984c17, 0xbea7541247acdf59),\n", "(0x3b3a7242d1da1ee5, 0xbe9d735e8beb8fcc),\n", "(0xbae93d2eb398218a, 0x3e440e6a7cafc096),\n", "(0x3acae709ad00bd19, 0x3e30b9cfae2ab337),\n", "(0x3a72d6de94168a75, 0xbdd668087e67279b),\n", "(0x3a5eab8fef3b6421, 0xbdbab498e6f69c73),\n", "(0x3a0c8ec8094d97ed, 0x3d618b5674894afb),\n", "(0xb9db00611b51a32b, 0x3d3f99da023c7232),\n", "(0x3971efb1b8385b20, 0xbce450b8165c264c),\n", "(0xb934a2a8921ee27a, 0xbcbcd387688c508f),\n", "(0x390195709783e7c1, 0x3c621a103bd0a113),\n", "(0x38dbfdcea4f39167, 0x3c34e540faee9f3c),\n", "(0xb87ade2a66df50ab, 0xbbd999b3cf947860),\n", "(0x3847c3fb15ff4625, 0xbba8a8f1c18bd090),\n", "(0xb7c279575afc11de, 0x3b4d71c32bb0428b),\n", "(0x3797f3b19c608f42, 0x3b18289deefa7196),\n", "(0x3754153d9d2c7699, 0xbabc183d32d93a1f),\n", "(0x371c05c0e3242945, 0xba83f7ae467ae529),\n", "(0xb69ad19453e29618, 0x3a269b7adc6804ef),\n", "(0x367130005d91c163, 0x39ec3a580d0009a9),\n", "],\n", "[\n", "(0xbc5e9088e9ff2518, 0xbfc4b2a38f1ab9b4),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4e9088e9ff2519, 0x3fb4b2a38f1ab9b4),\n", "(0xbbfcc8083276a193, 0xbf5225a5c73f2233),\n", "(0x3c1525fe797e2126, 0xbf7b750d89a9b35f),\n", "(0xbbb08db59499cb94, 0x3f1cbdb4f1d5dbbd),\n", "(0x3bc35c23938c810e, 0x3f2cfe933fc6d0b8),\n", "(0x3b52d453a3ea26cd, 0xbed01ef10d839bbc),\n", "(0x3b71cffb5ca00bc2, 0xbed05375a588a72b),\n", "(0xbb03f71b77aa7082, 0x3e729afe7ea7ba43),\n", "(0x3af336f1341f6d84, 0x3e66c8fe015e6610),\n", "(0x3aa95a6cddd6ccb3, 0xbe0a2a01e7af0241),\n", "(0xba7851970a0eac4f, 0xbdf59b33050d2092),\n", "(0xba24b1969b00bcf7, 0x3d98c0a50e7852d3),\n", "(0x3a16ee76e659ed58, 0x3d7da3426f355690),\n", "(0xb9cdfb48abef1f45, 0xbd20d3b48429ce84),\n", "(0x399e510926654c46, 0xbcfec46e14cd5d9e),\n", "(0xb94d8b3c4e2a8910, 0x3ca13c3da7405de9),\n", "(0xb9199ffbceedc2fd, 0x3c79043b4a0f03df),\n", "(0xb8b7be40ca4f6a7f, 0xbc1b902f4b26eb03),\n", "(0x38971ae8f878f8af, 0xbbf05dbe75075aa3),\n", "(0xb834ec73bf06d543, 0x3b91b0f5dc51ac20),\n", "(0x37f5aae0017b0662, 0x3b619b551575f49b),\n", "(0xb799e67f64663319, 0xbb02a3e0a7397c83),\n", "(0x376711f24f4773dc, 0xbacfb4a185898d2d),\n", "(0x371e5adab87fe639, 0x3a706acbac6f6bd1),\n", "(0xb694af13fd9e3bbb, 0x3a383fb94408a8c0),\n", "(0x367e1f0c9bfb4eba, 0xb9d88b17eec4fb7c),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c5f3474ffad3fd7, 0x3fc40f8ffdf09a5f),\n", "(0x3c047810b9792b13, 0xbf68c37a29c4586f),\n", "(0xbc348471cc77dfe2, 0xbf9aab099314b209),\n", "(0x3be6aa80fcd045e0, 0x3f406f735cc0f6a6),\n", "(0x3bebe02c3928856d, 0x3f552d29a06802e0),\n", "(0x3b89fdf10253d75f, 0xbef9fc04c675c0ed),\n", "(0xbb62f9306dab684a, 0xbeffe48825ed3c8e),\n", "(0x3b43251677276142, 0x3ea36bd2d58ff45b),\n", "(0xbb2af08b6d9ffd1a, 0x3e9be87e2cad2ce7),\n", "(0xbaec807c6c103803, 0xbe40d1fdedc6cb17),\n", "(0xba7064dd3b6b5724, 0xbe2fdbeb107ddccf),\n", "(0x3a75893a2f37955a, 0x3dd2f44d01321684),\n", "(0xba4232fa9e2160b9, 0x3db9921373ea0f26),\n", "(0xb9da39ce7fd7d9d8, 0xbd5df6b83ac56981),\n", "(0x39db340c9865a7cd, 0xbd3e6c005b62bffa),\n", "(0xb9708387feb998a6, 0x3ce1848c91de7162),\n", "(0x39532ac00e2fa8ff, 0x3cbbe5530d0fcf1e),\n", "(0xb8f7971717114a0f, 0xbc5f8540b8b06042),\n", "(0xb8d7787ecd6e687d, 0xbc3451eb9bf040e8),\n", "(0xb8696fbf3607765c, 0x3bd67f1edd448664),\n", "(0xb84ad321b52d14f9, 0x3ba8169212a3f8c0),\n", "(0x37d9b42cb89199fa, 0xbb4a1a0e01aa07e3),\n", "(0x37a4d1d59a34de84, 0xbb17b199c8e398ae),\n", "(0x37565ae964dca96e, 0x3ab91bd224db8139),\n", "(0xb71f2cb70464cd53, 0x3a83a756c81f58e6),\n", "(0x36a634d3a7864fac, 0xba245b460d9907d1),\n", "(0xb68d4c3a3fc04b15, 0xb9ebdf60ca34bcd7),\n", "],\n", "[\n", "(0x3c4997782859a00d, 0x3fc37aaceac987b9),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc3997782859a00d, 0xbfb37aaceac987b9),\n", "(0xbbd05a6eb7d72f47, 0x3f4e3fdbfd65014a),\n", "(0x3c1d91e80a0529b8, 0x3f79de7a33bc3a97),\n", "(0xbbb56ef10c1ebaad, 0xbf1801d911fbd06c),\n", "(0x3bcce92f388f20ea, 0xbf2b605a5ade3a80),\n", "(0xbb539bcd81dca55a, 0x3ecb0a2608144a3d),\n", "(0xbb6b3675770103a2, 0x3eceeceb341ad833),\n", "(0xbaf6cb1030653935, 0xbe6f623fc7be9f9f),\n", "(0xbb0412babffea489, 0xbe65a9ca94a0d7dd),\n", "(0x3a9025c6eebf2e96, 0x3e0638ba2f5f5e6b),\n", "(0xba745bdb1a5b34d9, 0x3df4a1b4217ef864),\n", "(0xba32b235688fed51, 0xbd9530c712e738d4),\n", "(0xba0b5b22087c168f, 0xbd7c6e5208e89146),\n", "(0x39aabbad8d2c58ef, 0x3d1d0eb5303a804a),\n", "(0x3988eb799dd68c33, 0x3cfda6ae03deea14),\n", "(0xb91737db06df4072, 0xbc9e05ef8aaeac6f),\n", "(0xb8ffe2eecdfe0f4b, 0xbc783796c23b134e),\n", "(0x38836225e752dac9, 0x3c183703be1e065f),\n", "(0xb87377273654d7a7, 0x3befd20ef0b9b32e),\n", "(0x381f98f1f5615157, 0xbb8f58105c7413a4),\n", "(0xb7f08f641ff4b998, 0xbb612ee75ce95b31),\n", "(0x37ac304030a2dba7, 0x3b00a4adc945e963),\n", "(0xb760c6584778a1df, 0x3acf0d914ecfdc7d),\n", "(0x36e07d1a751a4b9c, 0xba6d88af68997ed9),\n", "(0x36db1ad813072ac7, 0xba37d36ec5b8b8d2),\n", "(0x3672facc8520936e, 0x39d63a55dc5490c7),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc569479644686c1, 0xbfc2f206e49909c7),\n", "(0x3c0fab1b83d46057, 0x3f64dbf6a9fb80d7),\n", "(0xbc32d9141794e6dc, 0x3f99336443318ed1),\n", "(0xbbd0d543bfdf0729, 0xbf3bb6aa3d4e9e78),\n", "(0x3bebe3f68704392e, 0xbf540aaa5d94bd8d),\n", "(0x3b419d1c00b3671e, 0x3ef5f61b666129a6),\n", "(0x3b7d88846cdeeaef, 0x3efe4158391f2c2b),\n", "(0x3b46369cf5ad9126, 0xbea07a7a0745f74a),\n", "(0xbaff9b34051c76b6, 0xbe9a8ea97b670057),\n", "(0xbac6b3f27d760998, 0x3e3cb10b3affeaff),\n", "(0x3a82ba28da6d4ef2, 0x3e2e6d78879f98a1),\n", "(0xba64a30357ebbef6, 0xbdd044447904054e),\n", "(0xba47c38fca3d087e, 0xbdb8850c99b76d50),\n", "(0x39f0bc2d92a30cdc, 0x3d59e4fa8ff52f90),\n", "(0x39da7eb9dc7c3857, 0x3d3d4b2c1afd964f),\n", "(0x397e3e8ba2460cb7, 0xbcde807e2b0027a1),\n", "(0x394f139f76a41235, 0xbcbaf942a59e1d55),\n", "(0x38e1843405416d9e, 0x3c5ba64c4108b5da),\n", "(0x38d7063d60c6e606, 0x3c33ba614d4a4418),\n", "(0xb86c7ec67073bb42, 0xbbd3e1ce585ffa1f),\n", "(0x37e22b5fc552851b, 0xbba779ee6dc176e6),\n", "(0x37e956c614ab6059, 0x3b473c7bc63c3880),\n", "(0xb7b796c186b6db87, 0x3b172ca465caf995),\n", "(0x37588aab872e21fa, 0xbab681e73200f9aa),\n", "(0x37260574a8f5d812, 0xba83492c838e2b86),\n", "(0x36bb446923624df9, 0x3a225df78223620b),\n", "(0xb680e905ae135da7, 0x39eb6eaa1f93591f),\n", "],\n", "[\n", "(0x3c6b7326e3fbaa70, 0xbfc2740819f1caaa),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc5b7326e3fbaa70, 0x3fb2740819f1caaa),\n", "(0xbbe4b7a0f7878f6f, 0xbf49b6f37d0a00f9),\n", "(0xbc011249d3675d98, 0xbf78868d7401bf2e),\n", "(0x3bb6d7fdfc21dddd, 0x3f1470a7cbcb436a),\n", "(0xbbc5a6b64d367c4b, 0x3f29fe94ce3d3e83),\n", "(0xbb5352a68b13573e, 0xbec71660e61f0f0c),\n", "(0xbb68d34686b724d9, 0xbecd6dfcdb026028),\n", "(0x3af006603a027d68, 0x3e6ae79c35d01bca),\n", "(0xbb0ef1a3dfdf0941, 0x3e64ac50be6ca02e),\n", "(0x3a8def2f9646d0a2, 0xbe03258409210f45),\n", "(0x3a9043cd5dc1ca57, 0xbdf3c09685c05e25),\n", "(0x3a140fbcac25067c, 0x3d925d85992670e2),\n", "(0x3a184f1121e2c362, 0x3d7b509288f452b8),\n", "(0x39b4b4c230260136, 0xbd19586d0c8690d8),\n", "(0x39776fb98c811c8b, 0xbcfc973a175ffbb6),\n", "(0xb9337afd9ae7c0eb, 0x3c9a5d61717a7033),\n", "(0x3907444e5980ecc1, 0x3c776fa9ee1a429f),\n", "(0x38bdaeb8edb9cbf2, 0xbc156907cfeb69d8),\n", "(0xb8705ec9beaf1eac, 0xbbeee74de5fce6e5),\n", "(0x382fdb3ba7577f93, 0x3b8be6f4a0664634),\n", "(0xb80c67b2a3f6b8fa, 0x3b60be8c60df72fe),\n", "(0xb7980c2fe23edbd8, 0xbafdd3c10be941a0),\n", "(0x376107929e229c71, 0xbace5afc740d98d1),\n", "(0xb6ffc39670c4b338, 0x3a6aa1c12cf8bc0c),\n", "(0x36bf0bd26da1ffcc, 0x3a375bd104e008ce),\n", "(0x3671519a4046ccc5, 0xb9d429e651c05e27),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc6be2029a752b31, 0x3fc1ff5ebddd3c3a),\n", "(0xbc04bba52e05ef56, 0xbf61e2035324643c),\n", "(0xbc3a42d5bcad204f, 0xbf97f3506d4a1231),\n", "(0xbbd8ddfdbbecb379, 0x3f37c65c9302c53b),\n", "(0xbbff79e837d220e1, 0x3f53117816335151),\n", "(0x3b97f81238bbf061, 0xbef2df9afa521294),\n", "(0xbb9270fec55a19ce, 0xbefcd5d4a9d78a14),\n", "(0xbb3a3cd8b5652e44, 0x3e9c672d4d6f7766),\n", "(0xbb2736243a1eeac9, 0x3e995e4b102194f0),\n", "(0xbad74d87610e5d51, 0xbe38d22636140e12),\n", "(0x3acf7d99cf14d15d, 0xbe2d24fc9458bf7f),\n", "(0xba609b77f08fc036, 0x3dcc462d9da63971),\n", "(0x3a5ec10df895da79, 0x3db78eafb15964df),\n", "(0xb9d9e108200b834c, 0xbd569f5d498b660b),\n", "(0x39c6a15cc2204e9d, 0xbd3c3c4e5b0fab49),\n", "(0xb9732871d1bbe384, 0x3cdaccaf11834f8d),\n", "(0xb93cb3c7ca476321, 0x3cba161c63abb182),\n", "(0xb8e7d3af6ae5f8f7, 0xbc5870224af67eb4),\n", "(0xb8dc947a17c950f7, 0xbc3324870c0b9f1a),\n", "(0x3835837498a32b18, 0x3bd1adca41a58439),\n", "(0x384e7a933bc23443, 0x3ba6da83c46ff8a1),\n", "(0xb7e2d9939a6b62de, 0xbb44c90654b3ecef),\n", "(0x37b4d48249a8211b, 0xbb16a125665039e4),\n", "(0x3751c4fab8892f89, 0x3ab4403fbdd7d32b),\n", "(0xb723bebaa05fe118, 0x3a82e31c9f4289aa),\n", "(0x36be4670338eb907, 0xba209e5b516e3eb9),\n", "(0x36636814b89df314, 0xb9eaf0173952c775),\n", "],\n", "[\n", "(0xbc4081c2a50ad27b, 0x3fc192f2627a74e3),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c3081c2a50ad27b, 0xbfb192f2627a74e3),\n", "(0xbbed88bdcc1e7819, 0x3f4635b38affe698),\n", "(0x3bfbe434e30d7a64, 0x3f775eceaabf7f86),\n", "(0x3b9ca8671aa55df6, 0xbf11ac9e0164f7c1),\n", "(0x3bc6ba93b83783a0, 0xbf28cc464a35b0af),\n", "(0xbb6979a9d3cf377f, 0x3ec4014d9bf389c3),\n", "(0xbb64740ce7aaa9f5, 0x3ecc1f05a2d85165),\n", "(0x3b05322df74ff9fc, 0xbe6761d18ebb04af),\n", "(0xbb0eb4591c8e1e8d, 0xbe63cb9af103e0f5),\n", "(0x3aa091624db08269, 0x3e00b3cb55bbe5d2),\n", "(0xba9e3e54a390f0cd, 0x3df2f5c763b33667),\n", "(0x3a315b71b511ed17, 0xbd9017771db5a5e9),\n", "(0xba14beedd13cfb94, 0xbd7a4a5e79f39fb9),\n", "(0x39987da2b8e5b9fc, 0x3d165128cc4d99cc),\n", "(0xb995477d64dc86b2, 0x3cfb991575a9daff),\n", "(0x391a0c68aab7bf20, 0xbc9756473a57c932),\n", "(0x391f7919e47d81ac, 0xbc76b070fece822a),\n", "(0x38aea8dff65f4d33, 0x3c130e1f9f1562ad),\n", "(0xb885307e292801c8, 0x3bee01b29bf38fbe),\n", "(0x380c55e014e1fd44, 0xbb88f8681f03bf7f),\n", "(0xb7a97a5de24d257a, 0xbb604e16b9d18563),\n", "(0xb79be9ebe189653a, 0x3afad6e6ca7adff4),\n", "(0xb75781440aba92bc, 0x3acda3ed85696d1e),\n", "(0x36e87609f3833ad8, 0xba6817ad40ddad7a),\n", "(0xb6d43ee7c83c85cd, 0xba36de22ba99ddd2),\n", "(0x3644163dc4acb5e3, 0x39d255cee2696246),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc4e7aa4db2a788a, 0xbfc12dd55d4be2b3),\n", "(0xbbf6da5fa7c968b2, 0x3f5f1aee31818d19),\n", "(0xbc319e43d5f0f1d5, 0x3f96de64242a8310),\n", "(0xbbd5e5667369987f, 0xbf34afdf89fca61a),\n", "(0x3bd951e5980d1eeb, 0xbf5238cfc13ac771),\n", "(0x3b9632bd2bd2db1d, 0x3ef0719d13e00e52),\n", "(0x3b672b1f290673a0, 0x3efb974781a526b4),\n", "(0xbb1d4aa2a151d3bc, 0xbe98cc82a70d752f),\n", "(0xbb3bd18c494b86c6, 0xbe9850ae878c25bb),\n", "(0x3ad9b4f29c25b035, 0x3e35bba73e282ede),\n", "(0x3ac284476c98f69a, 0x3e2bfe1396e83644),\n", "(0x3a4529f3c858a5ed, 0xbdc8d7dbe4a241ab),\n", "(0xba562391a18ff729, 0xbdb6adfbd773748d),\n", "(0xb9fff61487742711, 0x3d53f51dcb398ad3),\n", "(0xb9d0d5d8e6a35200, 0x3d3b40d30be85f3d),\n", "(0xb97f65625ced3453, 0xbcd7bf544872d9cd),\n", "(0xb9476385a2a2b1f8, 0xbcb93f163a09379d),\n", "(0x38f06b1beee10cee, 0x3c55c1ca7d35fe43),\n", "(0x38b8eeb49079a75a, 0x3c3293b43a786b37),\n", "(0xb854b85c8c7227d3, 0xbbcfa1df0227f182),\n", "(0xb80a3744049cba08, 0xbba63d0b33ebfae1),\n", "(0xb7cca2e89550a07c, 0x3b42afdbba3b1d6f),\n", "(0xb799806c5d3ae5db, 0x3b161427fedb2614),\n", "(0x374631901a8ab5ef, 0xbab24bb69b617f29),\n", "(0x3706634bb0b1f240, 0xba827970d7fd5a93),\n", "(0x369d62ccd478840e, 0x3a1e2c0be398bf2f),\n", "(0xb676a35ad46d678c, 0x39ea69a77fc2c19d),\n", "],\n", "[\n", "(0x3c60c06e2860e868, 0xbfc0cf3ee98f769b),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc50c06e2860e868, 0x3fb0cf3ee98f769b),\n", "(0xbbb4697a99d5fadb, 0xbf436f451f6e14fb),\n", "(0x3c194225ed089995, 0xbf765d05948a946a),\n", "(0x3b91ed6777d1acf2, 0x3f0ef55c5a0d16cd),\n", "(0x3bcf058a2a3a8b0d, 0x3f27bfec9d15d038),\n", "(0x3b563856fcc3c915, 0xbec18c549f28e528),\n", "(0x3b59158b4542d2c4, 0xbecaf7544eeac766),\n", "(0x3af5145c85b8d71b, 0x3e648e81edf38b1d),\n", "(0x3afbd8241fda0445, 0x3e630341e78d1014),\n", "(0xba51c1f8c39d84cc, 0xbdfd73d2c942e970),\n", "(0xba8a04a03e6e4b0a, 0xbdf23ec2729d3a6d),\n", "(0x3a229664fb891b84, 0x3d8c78e44cdec8b3),\n", "(0x39dac0cbab30eb59, 0x3d795a6f6107b4e6),\n", "(0xb9ba116bfc433ee0, 0xbd13d1c77de8a03d),\n", "(0x399e9b0cd3f3a20f, 0xbcfaace944141c61),\n", "(0x393126e2b3ac5379, 0x3c94cfcb5e84963e),\n", "(0x390ce3384ec723cf, 0x3c75fbc3b0ec9599),\n", "(0xb8a8a1431d96f0b6, 0xbc11115c48c0688d),\n", "(0x385d6ff29b2308fa, 0xbbed24eb2fb8425b),\n", "(0xb825e6a6df55bdde, 0x3b8677909ec26485),\n", "(0xb7c21d072a134e9c, 0x3b5fbfed070231f3),\n", "(0xb797829f30055e39, 0xbaf8423b3340403e),\n", "(0xb75751d2373f6e38, 0xbacced4275822f9a),\n", "(0x370ed561d6ebcce7, 0x3a65dfcd7ab2578d),\n", "(0x36cf53856f82b22b, 0x3a365e43730aa685),\n", "(0xb61c3bb3f92eb84f, 0xb9d0b87da5a9b4de),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc64353fd6c42f1d, 0x3fc0768257dad56a),\n", "(0x3bf3a4186dcffc49, 0xbf5b602a7beaaa48),\n", "(0x3c16aaef36d826d8, 0xbf95ebc22efd092c),\n", "(0xbb76c80c9b070fe3, 0x3f3236a604142e61),\n", "(0x3beddcf66c5978ce, 0x3f517a482faa8d85),\n", "(0x3b66ad649af93743, 0xbeecfc00890787ae),\n", "(0x3b928f6dcddab568, 0xbefa7d7b128ac538),\n", "(0x3b25a6c98552063d, 0x3e95e419f1b57043),\n", "(0xbaf32b6c630ee4fa, 0x3e97603cea235244),\n", "(0xbad9cee30553553d, 0xbe333a0b436c8824),\n", "(0x3abe7890b4a4106e, 0xbe2af46417845f40),\n", "(0x3a4f7394a3298f16, 0x3dc609ac8cd8177a),\n", "(0xba59cd5f345dc226, 0x3db5e11b87ad3903),\n", "(0x39f73ed5597f6f80, 0xbd51c2756590391a),\n", "(0x399986e8c9348fca, 0xbd3a586483dd891d),\n", "(0xb97cc034606fd4e1, 0x3cd534d22c600964),\n", "(0xb957a2d70318a209, 0x3cb8755ad322c506),\n", "(0x38e4680effc80bb4, 0xbc53809e528c6189),\n", "(0x38d5dd4c01f7d4c2, 0xbc3209a0a78d682e),\n", "(0xb8644847850e1cab, 0x3bcc77842d1f731c),\n", "(0x384c2f3bd9e41480, 0x3ba5a4538092f65b),\n", "(0x37efb4bb53ec98f4, 0xbb40e2a86e6cb3f9),\n", "(0x377521ae7e540c78, 0xbb1588f3efb4ad64),\n", "(0x375fdbdc3816089b, 0x3ab099874d761b53),\n", "(0x37298a0b16897a8b, 0x3a820f23922028f2),\n", "(0x36b4686e1a4ffa47, 0xba1b7c94063b4326),\n", "(0xb682cf52edcbf7b1, 0xb9e9dfbe640c7d02),\n", "],\n", "[\n", "(0x3c61166b7995967a, 0x3fc0230ba90f2871),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc51166b7995967a, 0xbfb0230ba90f2871),\n", "(0x3be85d0df08ff853, 0x3f413164a0864cde),\n", "(0x3c175b99fcae0fa4, 0x3f7579c1bdbcfc99),\n", "(0xbbaa847d3261af11, 0xbf0b67e1913c668b),\n", "(0xbbbdc3b0bfb76e70, 0xbf26d26de4fd8c5d),\n", "(0x3b509cffcaa6fd75, 0x3ebf1b520b063853),\n", "(0x3b56e93d7c515f0c, 0x3ec9f01e7c1909a0),\n", "(0x3aeb43dee8b56e57, 0xbe624071b1796027),\n", "(0x3a99b4c0bd0ff4a5, 0xbe624f8e939ce43c),\n", "(0xba9ac0bb7d806efd, 0x3dfa35663595463f),\n", "(0xba625661d1f74770, 0x3df199120d49d507),\n", "(0x3a1bddfd9246953c, 0xbd896771e1b15e44),\n", "(0x3a1acb7638900b33, 0xbd787ede134ed7a0),\n", "(0x39a9e2e9004bba4f, 0x3d11bccdfbafa1fd),\n", "(0xb995262f16494ab9, 0x3cf9d22a6dc5a57c),\n", "(0x393e65a43ea6fde8, 0xbc92b00e367301bf),\n", "(0xb8e38ef38ce7f9e3, 0xbc755236722b3018),\n", "(0xb8a085f6fce94877, 0x3c0ec2ce49a94662),\n", "(0x38851022a9daf9df, 0x3bec52d2fb48c061),\n", "(0xb8260ec09f1c11bc, 0xbb84522e399fa43a),\n", "(0x37d6e8cbd63da93e, 0xbb5eeb3ee8f96a17),\n", "(0xb780414b4648c1d1, 0x3af60651f3414a8f),\n", "(0xb75a1e55435fe75b, 0x3acc3a2c8e72fa37),\n", "(0x37034c532c4c52e0, 0xba63ef7c46a9be7d),\n", "(0xb6d60fee2f339275, 0xba35deebe060dd5c),\n", "(0x366c4892cbf5f446, 0x39ce97bce469d7a5),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c10417847765c1a, 0xbfbfa8b3f9ae4375),\n", "(0xbbcf334b3619566d, 0x3f5856073b7fa2cd),\n", "(0x3c3664c698368b18, 0x3f9514e652eb2e96),\n", "(0xbbb93b53ec827565, 0xbf3032298718ea1a),\n", "(0x3bfdfbf103edc8e3, 0xbf50d1153fde431b),\n", "(0x3b7c365adad42a66, 0x3ee9cb455c29d6a7),\n", "(0xbb9fa9b04c310c2c, 0x3ef982167b1c52c3),\n", "(0x3b3466b707822fa7, 0xbe938191ef68eab3),\n", "(0x3b31f4e7061400c0, 0xbe968865345b3130),\n", "(0x3adaf50c9fd62c74, 0x3e312960010da387),\n", "(0xbace36911ce663a9, 0x3e2a0403679f6882),\n", "(0x3a4177820d3b2b22, 0xbdc3b67cc0b96c06),\n", "(0xba565f2ed3c28fcc, 0xbdb526038b956efd),\n", "(0xb9d5a1b33bcbb16b, 0x3d4fda06e840fa34),\n", "(0x39d1d67f1bd55539, 0x3d3981de640d0e00),\n", "(0x397c94419a95b1f3, 0xbcd311fc56c4b88a),\n", "(0x39532577b4bca3e2, 0xbcb7b8f62899fc83),\n", "(0xb8f552faebfd4704, 0x3c51977cb27410a2),\n", "(0x38d26b959afd2d20, 0x3c318706eb31dd46),\n", "(0x386ce90ca03d9538, 0xbbc9c2ecf35b9e14),\n", "(0x384b179344e2eb73, 0xbba511e7341e8837),\n", "(0xb7dba680290d429b, 0x3b3eaa190aa91ed0),\n", "(0xb7b49a491a85f98b, 0x3b1501910205c4a9),\n", "(0xb74ebc3f994c58ab, 0xbaae3fe1d152dac7),\n", "(0xb72316bcea29e953, 0xba81a632639f368e),\n", "(0xb698c03bf571184d, 0x3a192191e962f593),\n", "(0xb68c49d86016d888, 0x39e95576c2d368f1),\n", "],\n", "[\n", "(0x3c50db2c50623ec0, 0xbfbf13fb0c0e6fcd),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc40db2c50623ec0, 0x3faf13fb0c0e6fcd),\n", "(0xbbddaa7169324a5a, 0xbf3eb3e6fcc47c00),\n", "(0xbc1a7c91ef9a7da1, 0xbf74af74cbd77bef),\n", "(0xbb8ca4e36c0e29e8, 0x3f087bb1ebeaec75),\n", "(0x3bc0dc1e11076c62, 0x3f25fe629203150e),\n", "(0xbb5990b5b348875c, 0xbebbd0f2a6555e6b),\n", "(0x3b6af9c37c81d002, 0xbec9040de830649e),\n", "(0x3ae759c4b27cdf74, 0x3e6057f7a76993d7),\n", "(0xbaf1d65071810a7a, 0x3e61ad6dd5105c3e),\n", "(0x3a9d40eb62d35800, 0xbdf782a6f5738cdb),\n", "(0x3a8bf5df6e6d389e, 0xbdf1027dc06d4453),\n", "(0xba28e41b1a5587d6, 0x3d86d65b13b16f65),\n", "(0xb9fc75d3c8772d41, 0x3d77b59e9ed7367d),\n", "(0xb9af754c04eface9, 0xbd0ff800f2a49a00),\n", "(0xb991f98cd4e6ac14, 0xbcf907be43054aec),\n", "(0xb933d033de8a73d1, 0x3c90e2e1d8f5ad67),\n", "(0x38eed8fb6a3c50a9, 0x3c74b3a8b0fb5259),\n", "(0x388913f9676a0ac9, 0xbc0be06d96b6ddb7),\n", "(0xb88ea864297f3fc7, 0xbbeb8c227343f289),\n", "(0xb82ff7b2b57b5685, 0x3b8278dcce458371),\n", "(0xb7f78beca367a3df, 0x3b5e1fb52b874a03),\n", "(0x379b7478eaac89e3, 0xbaf41590cb708f7e),\n", "(0xb752fe7b149fbb7c, 0xbacb8ca63f91e577),\n", "(0xb70548503aed227a, 0x3a623cdbe3c71609),\n", "(0x36c12f6cf019ff77, 0x3a3561f0d31660bb),\n", "(0x365d1dc388e61bc9, 0xb9cc13f7faffaf26),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c56a7c2ed8fa844, 0x3fbe8727c572a2c2),\n", "(0x3bfdee3ce04b3d39, 0xbf55d1ef092ab395),\n", "(0x3c206dda20eba87a, 0xbf9454e7a7395636),\n", "(0x3bb99eb39ffae4f4, 0x3f2d0cc3a7fa6d3d),\n", "(0xbbc9d1e5b54f9af7, 0x3f50398d2cbd02df),\n", "(0x3b8aa1f4bf33efdb, 0xbee725b0909f9c66),\n", "(0xbb9b20d87a760067, 0xbef8a022f5fee447),\n", "(0xbb1fcb0c42b0e854, 0x3e9185b1ea97a54b),\n", "(0x3b3ea0aa1deb55ca, 0x3e95c571167401ae),\n", "(0x3acd2759cfccc15b, 0xbe2edff6514e1da9),\n", "(0x3ab2592f6b4b9153, 0xbe29298da3c4fa71),\n", "(0xba62158d0945cb91, 0x3dc1c34705eadfb1),\n", "(0xba424ede84d84b4b, 0x3db47ab8ec529c51),\n", "(0xb9e73e83248604d7, 0xbd4cc24a2f007c3e),\n", "(0xb9c2979e3d03632b, 0xbd38bbcc44e6c225),\n", "(0x39703e1bd29b296c, 0x3cd1420df9bb4359),\n", "(0x395d047d716a7a8d, 0x3cb7095f8b3266bd),\n", "(0xb8cd11469be08694, 0xbc4feb87e4e655cc),\n", "(0x38be1dd0526935fa, 0xbc310c0caf4ba7a9),\n", "(0x385a60dd5e84c9c5, 0x3bc76f4ca221cf39),\n", "(0xb83ecbabc0dd7d07, 0x3ba4868177e6f5ef),\n", "(0x37b8847e584a462d, 0xbb3bf93dc497bf28),\n", "(0xb7bb4e77466271a4, 0xbb147f2c424e92f5),\n", "(0x374a584169fadea4, 0x3aabace093fa5e7e),\n", "(0x370af91e2a607b95, 0x3a813fe3dbef7300),\n", "(0x36a10a818d4db7be, 0xba170f75c4345a45),\n", "(0xb6269b19813edb68, 0xb9e8ccf104c5a0ca),\n", "],\n", "[\n", "(0xbc3b9f1d130797af, 0x3fbe018dac1c17e3),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c2b9f1d130797af, 0xbfae018dac1c17e3),\n", "(0xbbc5edf62333beba, 0x3f3ba21bd15d02a4),\n", "(0x3c138b4f0d3a4110, 0x3f73f9e0db07e7ef),\n", "(0xbba6f23ddcae2db1, 0xbf060b77c5e27622),\n", "(0x3ba86d4e04faa212, 0xbf253f9b1a5d228c),\n", "(0xbb5fddc005e382a4, 0x3eb910b38812c253),\n", "(0xbb40935ad53575b8, 0x3ec82ee6dfdfedeb),\n", "(0x3afa8bf307790c80, 0xbe5d7cc2a9a602ee),\n", "(0x3b0b50784ff133f1, 0xbe611a57d8645358),\n", "(0x3a8673cb487ec434, 0x3df53d401519442d),\n", "(0xba8c03600ffb7a70, 0x3df07915ef87408d),\n", "(0x3a2022a5f15014b6, 0xbd84aabcb6141c76),\n", "(0xba1d37109cce2377, 0xbd76fcb8e2eada15),\n", "(0xb9a95525555a3484, 0x3d0cfcfdb2faeb02),\n", "(0x39997fd3cf0000fa, 0x3cf84c5369d2e33d),\n", "(0x38f88b42ac1a9330, 0xbc8eb11d7e6581b7),\n", "(0x39181a3f66a29421, 0xbc741f9ab4632e3b),\n", "(0xb8abf00ddaa40351, 0x3c0965159407b5ab),\n", "(0x3885289d8a9dc178, 0x3bead0e3cd065e84),\n", "(0xb8220f36807a6153, 0xbb80dee0e94d3838),\n", "(0xb7e15def3c2d10d9, 0xbb5d5e035bd44cab),\n", "(0x379e09d7e4e2053c, 0x3af26452e5cf7372),\n", "(0x375c2b8feb4af0ba, 0x3acae5d15fef7e8f),\n", "(0x370c46b7285b4063, 0xba60bf2894ab39b9),\n", "(0x36bc8ff0c23e41b6, 0xba34e87ee39a6f39),\n", "(0x366a289544183384, 0x39c9daa655367c6d),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c555d27e18add4d, 0xbfbd82939ab62339),\n", "(0xbbe5f2055a671318, 0x3f53b5a54845670f),\n", "(0xbc331ee0af44ab91, 0x3f93a7ff1622def8),\n", "(0xbbb2001fd8691606, 0xbf2a3ebc476a606d),\n", "(0xbbb7a5c728534a7d, 0xbf4f61adde3a8c61),\n", "(0xbb6721b027970bc9, 0x3ee4ec45da0478b0),\n", "(0x3b60295953d04e19, 0x3ef7d3b28159f23c),\n", "(0x3b21dd48380f5e9a, 0xbe8fb3f21bcd7fc4),\n", "(0x3b3047a478eaf94e, 0xbe95145a876d2273),\n", "(0xbac575cc2ab01d93, 0x3e2bf64cdf7c0558),\n", "(0x3a9c7ea365ef1c0c, 0x3e2862204ac427d2),\n", "(0x3a25523941e42ede, 0xbdc01c0d48888811),\n", "(0x3a3766e8ee24e58a, 0xbdb3dd6cb1cbcd8f),\n", "(0x39e11ac6552bc64c, 0x3d4a2020c8b3c20d),\n", "(0x39bbaa3793fd39c4, 0x3d3804a9d711292e),\n", "(0xb965d9ecddfcbd4d, 0xbccf6a1ef9182e2c),\n", "(0xb95ee6d1970be0a7, 0xbcb665c82dfd3111),\n", "(0x38e2ccf8afc7f5eb, 0x3c4d1cbc474ae672),\n", "(0x38baa3fe632e7af8, 0x3c309883728ed041),\n", "(0x386cc2812a2e5111, 0xbbc56bda19c4b049),\n", "(0x3825988783a1ff06, 0xbba4025c7e87cb33),\n", "(0x3798e8afd688bd54, 0x3b39a17a3b2afb39),\n", "(0x37b0dd0e73f34a5f, 0x3b14026125d71009),\n", "(0xb73504f75a230f17, 0xbaa96b8155611361),\n", "(0x36fcaf6a0d9e7292, 0xba80dcfdcb67c11b),\n", "(0x363354ed9306d4a3, 0x3a153c10e4500766),\n", "(0xb6880389022204ec, 0x39e84794b22bad24),\n", "],\n", "[\n", "(0xbc56edd809f4ec43, 0xbfbd09b21e36c0bd),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c46edd809f4ec43, 0x3fad09b21e36c0bd),\n", "(0x3bd1da06fbc186d3, 0xbf390b0e6a475e45),\n", "(0xbc140975d5184af6, 0xbf7355b904fbf7ee),\n", "(0x3b9e3b983f117cfc, 0x3f03fc459d1e25a4),\n", "(0xbbb494c77a177873, 0x3f2492cc61d19dfe),\n", "(0x3b46367d4d299b08, 0xbeb6bcf110a02ad1),\n", "(0x3b6b6ea46d6db74f, 0xbec76d44f6a83523),\n", "(0x3a8030056b81d3a7, 0x3e5ac61efcb3c36c),\n", "(0x3afeb8462b17799c, 0x3e609436fcaa3965),\n", "(0xba99e294aeb8cd7b, 0xbdf34eb6095f969b),\n", "(0xba88db8194acb808, 0xbdeff662945eb368),\n", "(0xba237c1915fc9c0d, 0x3d82d05bf8ff5181),\n", "(0xb9d3e0b801e8758e, 0x3d76525fbb563fe0),\n", "(0xb9a734f42937bddb, 0xbd0a6eb937c7f6c0),\n", "(0x396073f8f8b180ec, 0xbcf79e90468589ab),\n", "(0xb922e469e5eb93e5, 0x3c8c0998b46c2a6d),\n", "(0x38badc48095c4e55, 0x3c73955fe5fb130b),\n", "(0xb8949ebb69e71ffd, 0xbc073ec897598aef),\n", "(0xb88f7564544e1430, 0xbbea20bd7b4d506a),\n", "(0xb7fb326fec2fdde6, 0x3b7ef3962c3d7988),\n", "(0x37e82dd0be2c1482, 0x3b5ca6507646e165),\n", "(0xb7879646e68dbcf8, 0xbaf0e8ca73f2d68d),\n", "(0xb74018d4e9ae2637, 0xbaca463d4098cc93),\n", "(0x36f61d9992deaded, 0x3a5edd93261617c3),\n", "(0xb6dbe7fd3fa3deaf, 0x3a34734a62443d4b),\n", "(0x3623d3bbf119c872, 0xb9c7e1ec2479954a),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4e1f19f10295a1, 0x3fbc96700031f601),\n", "(0x3bd8339df4a4a968, 0xbf51eb2a07d0f09e),\n", "(0xbc39bfe53ec12c8a, 0xbf930b36eddaa234),\n", "(0xbbb206af4ba8d313, 0x3f27dd2dde84b73c),\n", "(0xbbd1f3a6f0dd2e56, 0x3f4e696553e0b8a5),\n", "(0x3b70bebcc672e081, 0xbee3085aa35a1647),\n", "(0x3b964955e62a56d5, 0xbef7199f24bccae1),\n", "(0x3b29acbd0629609d, 0x3e8cdbab6a766176),\n", "(0x3b336b635edd4912, 0x3e9472a7cffbf91e),\n", "(0xbaa919ffba04358e, 0xbe2979f5211c4dae),\n", "(0xbacb3a83d64d312f, 0xbe27ab4b01a902db),\n", "(0xba3d20c26289bb46, 0x3dbd63904e4c487c),\n", "(0x3a3a2263834e8f85, 0x3db34c83fb1c2279),\n", "(0x39d0d1629893175f, 0xbd47dcfdf13e5ccc),\n", "(0x39b38e8b7b2086d0, 0xbd375b01ddacf988),\n", "(0xb96c94f8a51700d8, 0x3cccbd41ea6afd29),\n", "(0xb9596f4635f2eb43, 0x3cb5cd46eaba1e98),\n", "(0xb8ef331fa6111e01, 0xbc4aaded22d1c6ea),\n", "(0xb8c316503d17378d, 0xbc302c0feb2cc9ff),\n", "(0xb86b0bb9dacdd402, 0x3bc3ab0efb0f5a6a),\n", "(0xb83c8dfa9ab81f86, 0x3ba38564ae73cbd4),\n", "(0xb7ce2bd40d6dd04f, 0xbb379494ee2fe052),\n", "(0xb7a9f50c26ffe35d, 0xbb138b6c6bd628fc),\n", "(0xb704cc1a22fd0a79, 0x3aa76f817567d54d),\n", "(0xb72b4eeb7ce6fd0f, 0x3a807ded69c2252a),\n", "(0x36b142adaa59897c, 0xba139e9549f763d8),\n", "(0xb6561aae4c08fc78, 0xb9e7c644065d040a),\n", "],\n", "[\n", "(0xbc5ca34ef67ceca5, 0x3fbc2861347b1b39),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4ca34ef67ceca5, 0xbfac2861347b1b39),\n", "(0x3bbf201ae2302561, 0x3f36d57bffb37fd5),\n", "(0xbc16b4ecac2fa1c2, 0x3f72c060ef553f18),\n", "(0xbb9df91b90d34cd8, 0xbf023a407b722d2e),\n", "(0xbbca3432d200d5db, 0xbf23f55581ec683d),\n", "(0xbb5e04bafba5dc5a, 0x3eb4bfb4daa2ff62),\n", "(0xbb42a29e463f2261, 0x3ec6bc69099af2f7),\n", "(0xbafb52717e21f4f1, 0xbe5873340987d276),\n", "(0xbadb9738396340d1, 0xbe601951f02d2b37),\n", "(0x3a8c2da917c5d2d4, 0x3df1a6174fe55fbe),\n", "(0xba7265752e07ea23, 0x3def0eca5bc0284a),\n", "(0xba1b8d994d0c183a, 0xbd8137cb1fcc55a3),\n", "(0x39c1b1fb4f7e04be, 0xbd75b4f7f2bb19ed),\n", "(0x39961a8be6115ecd, 0x3d083934ed797abc),\n", "(0xb998209f68cee7a8, 0x3cf6fd29fcbcf38b),\n", "(0x38da8f6db73066be, 0xbc89bbe4a386b1fc),\n", "(0x39119e7a973ba60e, 0xbc73143b8f6fa9b5),\n", "(0xb8a42d280d3b7044, 0x3c055f1ef8c6277c),\n", "(0xb8741bc4d5b892a4, 0x3be97b209a81cdd1),\n", "(0x381f56010f66d563, 0xbb7c822a3d227a0b),\n", "(0xb7d326c5dc6baa73, 0xbb5bf86da968d5d8),\n", "(0x37685ec534d88737, 0x3aef3590b082abca),\n", "(0x376f5328f688841e, 0x3ac9ae18938ed4dc),\n", "(0x369b410a6e56968b, 0xba5c8a82558390d1),\n", "(0xb6c5a55f28288a0c, 0xba3402b3aeae6a78),\n", "(0x365785f4c242b76d, 0x39c621268afb8484),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc2986f8b543f277, 0xbfbbbf246019c0d4),\n", "(0xbbf8243dc68faf05, 0x3f506224199140d8),\n", "(0xbc31c8ab4f070de9, 0x3f927c3416c09898),\n", "(0x3bc1400990dffd7c, 0xbf25d279dc87cf69),\n", "(0xbba49f5dbb72a054, 0xbf4d86a5f5adbdac),\n", "(0x3b8c1a134d478d15, 0x3ee169041634c248),\n", "(0x3b908bd4df68b455, 0x3ef66f5bd1bedae1),\n", "(0x3b2340bc492ebacd, 0xbe8a69b2c717d54a),\n", "(0x3b2b327658085637, 0xbe93de4eab456cbd),\n", "(0xba8a52518b85c3bb, 0x3e2755eabbde6915),\n", "(0xbaceee9ff82c0693, 0x3e2702fe7ba9f8c3),\n", "(0xba380d66035d4ef3, 0xbdbaf2007eeae256),\n", "(0x3a5fcfcb227b90a8, 0xbdb2c69746948e55),\n", "(0x39e9a9de8d952335, 0x3d45e77ad9a9daf0),\n", "(0xb9d9fd6d3c1b2712, 0x3d36bd7bc6045cd0),\n", "(0x392032afd924a7d3, 0xbcca6a2a200a32c2),\n", "(0xb959d59bb0713bcd, 0xbcb53ef0001a8fc4),\n", "(0xb8ed4be5f4212c88, 0x3c488eb37fc1d400),\n", "(0xb89d39eabce00ec1, 0x3c2f8c832f51b562),\n", "(0x3840e097e8a92261, 0xbbc22200a03da113),\n", "(0x384c3af44c4ec552, 0xbba30f596dc1d400),\n", "(0xb7dc9bccb090c4a1, 0x3b35c6dd14718296),\n", "(0xb7bce5b1aace9f68, 0x3b131a4eaddd4e23),\n", "(0x3744f32babed55e0, 0xbaa5ae9b0fa87ab5),\n", "(0x372de16b15f9f82a, 0xba8022e41d997f41),\n", "(0x36b5867aa0456426, 0x3a122f7b20539f5a),\n", "(0x368433fa75fa367b, 0x39e74982e085fb06),\n", "],\n", "[\n", "(0x3c497d2b9281abc8, 0xbfbb5a622198a72c),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc397d2b9281abc8, 0x3fab5a622198a72c),\n", "(0x3bd29fd72f6917e5, 0xbf34ee71cf67c243),\n", "(0x3bef69e3e89e3765, 0xbf7237c02b462f6f),\n", "(0xbbaa32f85df10bfa, 0x3f00b67b6fdfec62),\n", "(0xbbcb53a20d4b2f61, 0x3f2365167d8bc330),\n", "(0xbb5df27a7ce0e8f5, 0xbeb3086b7a296e69),\n", "(0xbb64ce30c488f398, 0xbec61a141425c2a6),\n", "(0xbaf5a586401bb54e, 0x3e56712b23991e80),\n", "(0x3afc0839aea10c7b, 0x3e5f50736839e481),\n", "(0x3a894d28c9a59269, 0xbdf0366d02b91b84),\n", "(0xba3b7dda45b64dc6, 0xbdee38f9bda5f6df),\n", "(0x3a0f464a8fd7c7bf, 0x3d7faa3d1cb01e65),\n", "(0xba1e45ca78c915d9, 0x3d752317a2a5b9a2),\n", "(0x39a7d004a800c3b5, 0xbd064cd06847bd1d),\n", "(0xb95179a5ef0f66b7, 0xbcf666eebfeb573d),\n", "(0xb9285e2b929e1519, 0x3c87b8b54f1785bc),\n", "(0xb919589128d0188e, 0x3c729b70ca32ef58),\n", "(0xb8a46a9746bfb343, 0xbc03ba848f791229),\n", "(0x386730f56682d5be, 0xbbe8df65522ba529),\n", "(0x37f2ab030e344d2f, 0x3b7a5b900787f393),\n", "(0xb7bb11ca75f0fcdb, 0x3b5b53fa2dd77bb4),\n", "(0x378eb255c1629783, 0xbaece6fc2aac5380),\n", "(0xb729982419793a6f, 0xbac91d5406064eb8),\n", "(0xb6ebe671ea8254cb, 0x3a5a7a1d77627f77),\n", "(0xb6cf1004e96b1aa1, 0x3a3396e1ce8aa477),\n", "(0xb62a0c13a37cd740, 0xb9c490dcdeea0de1),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c56e5b3d654a3de, 0x3fbaf9cb42cd08a7),\n", "(0x3bd4df22cc118423, 0xbf4e1c66d7616e37),\n", "(0x3c32068ccdde2ecb, 0xbf91f90fd1013589),\n", "(0xbbb9426a5fb5baf4, 0x3f240e3eb09b7d6d),\n", "(0x3bcf4131edb03e4e, 0x3f4cb682ff471274),\n", "(0x3b8c9cd4cf70b38d, 0xbee0016819a61dd8),\n", "(0x3b8325d69b159805, 0xbef5d2d1c420646d),\n", "(0xbb157a8a155b14f1, 0x3e884b0fe8a85355),\n", "(0x3b1d5bbe26d9661b, 0x3e93559d96bef598),\n", "(0x3ac3da55cae73bf1, 0xbe257a0be74997ad),\n", "(0xbaac817776602a6c, 0xbe26677c8f53b6a6),\n", "(0xba48a3adc3758fa2, 0x3db8d1ae21b756a1),\n", "(0xba55e41c080dae7e, 0x3db24a6e1ac65e87),\n", "(0x39d87ea029a22f95, 0xbd4432017034b94c),\n", "(0xb9b0c571c0172220, 0xbd362ae0447c7c88),\n", "(0x392c7ada7dc7ba07, 0x3cc86190e6a87084),\n", "(0xb8cce5846ffd630a, 0x3cb4b9e1622f9586),\n", "(0x38e2a29910f701c9, 0xbc46b1f3e51e7716),\n", "(0x389f461c8b8d14fd, 0xbc2ecd4131542af6),\n", "(0xb865a2f5fd7d4f74, 0x3bc0c7d6edd792f0),\n", "(0xb84d80cbe9f82337, 0x3ba29fe1dfb030da),\n", "(0xb7be1d7b0beadd6d, 0xbb342eb58314dd57),\n", "(0xb7bd13d73eb584cb, 0xbb12aee37e25148e),\n", "(0x3706be9737507cbd, 0x3aa420385af46d51),\n", "(0x37178c7e05bb4a09, 0x3a7f97d766899d96),\n", "(0x36b40aa8f19fb9a4, 0xba10e85b8b8bab6c),\n", "(0xb68622de5eece514, 0xb9e6d19365680b1c),\n", "],\n", "[\n", "(0x3c49a6abbfd839f8, 0x3fba9d183bc04545),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc39a6abbfd839f8, 0xbfaa9d183bc04545),\n", "(0x3b97025ee34cfaec, 0x3f334779874010dc),\n", "(0xbc01fefbfc4e4e9c, 0x3f71ba2299ab88a8),\n", "(0xbb55c0e2a19295ff, 0xbefecb19f5bdc649),\n", "(0xbbcce75d43258257, 0xbf22e052707cc859),\n", "(0xbb5a63ba682d6499, 0x3eb18a5da77edd83),\n", "(0xbb6dd00d54139579, 0x3ec5846b622f592b),\n", "(0xbae5e872e9945332, 0xbe54b17e97b5884a),\n", "(0x3ac6a221a04b77f7, 0xbe5e7f76674dfaab),\n", "(0xba84b342c0e05e8d, 0x3dedeb504ed353c6),\n", "(0x3a86775d5b3d25ee, 0x3ded72e25f190409),\n", "(0xba00d09a917a59f6, 0xbd7d3e076b0201d6),\n", "(0x39c46b750b88e7f8, 0xbd749b825302af88),\n", "(0x39abeb00dd42cc76, 0x3d049d35475fc5c4),\n", "(0x399639c0b0dc546c, 0x3cf5dac9623f7b3a),\n", "(0xb8c1489d884eb85a, 0xbc85f3d5130dc414),\n", "(0xb91861dc55985f01, 0xbc722a4aeb6977eb),\n", "(0x3890153f6d844191, 0x3c02479e3ad06b06),\n", "(0x3880093480726623, 0x3be84cdbd4996301),\n", "(0xb80c8f94083b0211, 0xbb78745ed629d641),\n", "(0x37e3f2458bb649a6, 0xbb5ab87a5deb4183),\n", "(0xb788f6fa139ccbd7, 0x3aeada86a4d62add),\n", "(0x3756d41ddc1f8d52, 0x3ac893b9d1f77835),\n", "(0xb6ee50fc22fbfa2f, 0xba58a3198036b128),\n", "(0x36c2de5121e2e61a, 0xba332fd57127bac6),\n", "(0xb63875952298668b, 0x39c32aa4779bf0be),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c5729f43724612e, 0xbfba4407dac72297),\n", "(0x3be5723d945cf385, 0x3f4bcba4dec1da44),\n", "(0xbc3fe775590d7dac, 0x3f91803c65cafdfb),\n", "(0x3bc90cfa57dbb628, 0xbf2283df2b3e4a6e),\n", "(0x3bc3e3e0391f1e19, 0xbf4bf695e89259cd),\n", "(0x3b630f86ed6a90e0, 0x3edd8f3759122d51),\n", "(0x3b9030fb5fd0d14f, 0x3ef54246c8e04218),\n", "(0xbb1b2983b9c451c8, 0xbe867111bc8e67a4),\n", "(0xbb3a3cef2b75d5c2, 0xbe92d72a1f62ec18),\n", "(0x3acbd165727f6821, 0x3e23d9ca3eb1e22f),\n", "(0xbacc01aecceaa6e4, 0x3e25d74a6e225515),\n", "(0xba59e0bf6ede94ee, 0xbdb6f4b420b2f957),\n", "(0xba5cdfc28e1823b4, 0xbdb1d6f985dc3ec9),\n", "(0x39e7d772f8fce3e1, 0x3d42b1d81101dea8),\n", "(0xb9d82ef548b3e361, 0x3d35a2197089fbfb),\n", "(0xb956841fa8612f5c, 0xbcc6974aff17c78f),\n", "(0x394b2b4bcdaabf0e, 0xbcb43d4892ea1bcf),\n", "(0xb8dd3073293bb4a5, 0x3c450d21b45ffbaf),\n", "(0xb8b6f6e75ed53665, 0x3c2e196b40872c65),\n", "(0x384e654070aa0a0c, 0xbbbf2abd4dc31a0d),\n", "(0x3847ef0270966133, 0xbba23699d6695800),\n", "(0xb7d774e0a1072a6c, 0x3b32c4314fb1b042),\n", "(0x3798dfd4a7af4ecb, 0x3b1248f0b0a01e5c),\n", "(0x374feaa8039e5d21, 0xbaa2bd2ced8351bd),\n", "(0x37162b8b059830f3, 0xba7ef1e8bc571d77),\n", "(0x36a5be76c75f587a, 0x3a0f87929eae0a41),\n", "(0x367e0d8209c727ce, 0x39e65e8aae87b358),\n", "],\n", "[\n", "(0x3c4f5da9526c15aa, 0xbfb9ee5eee1a97c6),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc3f5da9526c15aa, 0x3fa9ee5eee1a97c6),\n", "(0xbbc33100916421b3, 0xbf31d55d93e59bd7),\n", "(0xbbb6887e944ccfcf, 0xbf7146219394a99c),\n", "(0x3b8ca8e50931ec0e, 0x3efc7d32bb646e2a),\n", "(0x3b459561844c2171, 0x3f226599aed4f1ca),\n", "(0x3b2f06633c8a57af, 0xbeb03ba58ec85c12),\n", "(0xbb602686ed9f14f1, 0xbec4f9e3961bb9dd),\n", "(0x3aeea9ee2c50aae8, 0x3e5328d4dc334079),\n", "(0xbaef3a53aa36f2d4, 0x3e5dbda7ac70ff93),\n", "(0x3a77a84a53fa4382, 0xbdebb7c2f187144e),\n", "(0xba64d01b19ecf2c5, 0xbdecbac24c760567),\n", "(0x3a16eec036aa6895, 0x3d7b1c35b65eca4e),\n", "(0xba1d9ece3561eb27, 0x3d741d23f93de7a0),\n", "(0x39ab2aa54e1d2f75, 0xbd03208d806698c2),\n", "(0xb99acf6d8899800a, 0xbcf557c166250d9c),\n", "(0x391934ffa520f9d8, 0x3c84637130a9d7e6),\n", "(0x38f36ddde127bd83, 0x3c71c021934a5bf8),\n", "(0xb89d68e84d698c21, 0xbc00fed119c94fe7),\n", "(0x388e25551faa0fb9, 0xbbe7c2d64524cfa1),\n", "(0x381e8f2946a1a0bb, 0x3b76c3357c3f7adf),\n", "(0x37f7b13ebe2df289, 0x3b5a25665c8bb28a),\n", "(0xb78e1214cb5a34de, 0xbae906c5169421c4),\n", "(0x376f2d89008c8e68, 0xbac810fd94a57b7b),\n", "(0x36d90aeea93b07c4, 0x3a56fd9fc0a89c82),\n", "(0xb6dc9ebd96e6e684, 0x3a32cd7652121959),\n", "(0xb61332c9199d4380, 0xb9c1e8fff9203895),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c422d28ddb0663f, 0x3fb99be73fa3efcc),\n", "(0x3bc06623176e8323, 0xbf49c3248da75775),\n", "(0x3c24e67d5d6f01f8, 0xbf91107147eda800),\n", "(0xbbb9f85d6cd5a102, 0x3f212980be9d8520),\n", "(0xbbc6d7f4255305b6, 0x3f4b44e1221e6051),\n", "(0xbb75ffceb4092099, 0xbedb67b78c1dd9c5),\n", "(0xbb952647474dbc63, 0xbef4bc49e9b5bcfd),\n", "(0xbb07d96f2518a716, 0x3e84d02ffb8bcfd0),\n", "(0x3b3e32d27646b835, 0x3e9261c31456e43c),\n", "(0xbac76119a10d67c2, 0xbe226b400744def1),\n", "(0x3acd5778eebf7e73, 0xbe2551251a2b4223),\n", "(0x3a46fe94a695c8b2, 0x3db5500f9531112d),\n", "(0x3a083f83ad3b6fcc, 0x3db16b4e936f8a96),\n", "(0x39d92e892227b268, 0xbd415e70b28182e4),\n", "(0xb9d311286e6202d4, 0xbd352230c03cb29f),\n", "(0x39694a35e842f6b5, 0x3cc5019095879294),\n", "(0xb95c82d35e7d0a85, 0x3cb3c864dd8bd878),\n", "(0xb8e021ec04623c9c, 0xbc4397af75e324f3),\n", "(0xb8c1d4036b77bcc2, 0xbc2d701c9937cabc),\n", "(0x385d6fca0674878d, 0x3bbd0965d9326e17),\n", "(0xb84fa05c3c3c3a3f, 0x3ba1d319c4fce696),\n", "(0xb77cd5e86688f3b8, 0xbb3180c1f00da609),\n", "(0xb7ba86637aa4bf02, 0xbb11e8305b488b70),\n", "(0x3736c6f17e2a0301, 0x3aa17f7804b40b24),\n", "(0xb7084fe04399b71a, 0x3a7e53bca7936259),\n", "(0x369739312d3bebf0, 0xba0d7a5725978bd4),\n", "(0x3689e9b194e5ecb2, 0xb9e5f05f8d349ae8),\n", "],\n", "[\n", "(0xbc55bbc298d062cd, 0x3fb94c6f5898708b),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c45bbc298d062cd, 0xbfa94c6f5898708b),\n", "(0xbbc91fb79f224deb, 0x3f308f4f1b8fb0dc),\n", "(0x3c11274d5c28ac61, 0x3f70da931c776c71),\n", "(0x3b468ef3cfedd83e, 0xbefa7550d2940f2a),\n", "(0x3bbf74462dfd6402, 0xbf21f3b978a47cf4),\n", "(0xbb46a542136ebd9e, 0x3eae28ea02472df4),\n", "(0xbb6c80d173ca8c69, 0x3ec47930aec78cb8),\n", "(0x3adf057ade51b16d, 0xbe51ce32c4f34e51),\n", "(0x3afb45adc74dd76d, 0xbe5d0950e99c8b39),\n", "(0xba7a6618445563ec, 0x3de9c5a1603e79e8),\n", "(0xba8e2efa815aa6df, 0x3dec0f1778cf9887),\n", "(0xba168e5ec792cc80, 0xbd7938fe13097690),\n", "(0xba1edc43381b3d99, 0xbd73a70bdaedabef),\n", "(0x39ad72e528e9a77a, 0x3d01ceeed28a9bbc),\n", "(0x3981b5050358ac3a, 0x3cf4dcf95c5ca94a),\n", "(0x38e5c074caf95ef8, 0xbc82ff92717657b8),\n", "(0xb8c1517cb6203642, 0xbc715c5a3e02462c),\n", "(0x38848ac21ce9d63b, 0x3bffb3c968d1317c),\n", "(0xb868eaf9f67497e9, 0x3be740ae3a9480c4),\n", "(0xb7e7ce53355d1e7c, 0xbb754054fa0921f1),\n", "(0xb7db46466a3c45dd, 0xbb599a3335285172),\n", "(0x376a7830f0710c1c, 0x3ae763db68405483),\n", "(0x37496d5dfac38e6e, 0x3ac794c6d23aefa1),\n", "(0xb6d0259444fde6bc, 0xba5583129058029b),\n", "(0xb6b49a7445a09fb2, 0xba326f9c89204c85),\n", "(0x3648f301c94c285c, 0x39c0c73ede23db3f),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbbb1d709b3e6aac3, 0xbfb8ffc9b9a131f6),\n", "(0x3bdb4dd57b3641ab, 0x3f47f724314bb99d),\n", "(0xbc3086cbc396cba9, 0x3f90a89c5d1074ba),\n", "(0x3bb8da379d94d744, 0xbf1feeaeb33465e8),\n", "(0xbbef433944c1a75a, 0xbf4a9fba36a7a08e),\n", "(0xbb7f256bdb98dded, 0x3ed980034770f3b2),\n", "(0x3b91b4c8faeaae10, 0x3ef43fa4bb8cba57),\n", "(0xbad948481046b8ce, 0xbe835f40f3a3902b),\n", "(0x3b3e2e9d940a603b, 0xbe91f465ba292c0d),\n", "(0xba98e1101ee20622, 0x3e212688f74f8106),\n", "(0x3ac17030074177fa, 0x3e24d3f7e3fdde95),\n", "(0xba567e7ce0ee9db6, 0xbdb3daee9c38c74a),\n", "(0x3a51aeae4597f6fa, 0xbdb106a132ee69a7),\n", "(0x39ebf6485dd79da8, 0x3d4030e7765d6c75),\n", "(0x39c15870eda63050, 0x3d34aa4c24070ac4),\n", "(0xb958792c38458a32, 0xbcc3987402712b60),\n", "(0xb95ac711e3d7df47, 0xbcb35a87994f9f22),\n", "(0xb8b987c84af86497, 0x3c424aa138f72769),\n", "(0x38cd1d7e8860d6ea, 0x3c2cd07eb7a4b74f),\n", "(0xb85adedac22a5607, 0xbbbb21f2d5c76559),\n", "(0xb8403dbefd803008, 0xbba174fb8123d957),\n", "(0xb7decb7c15886751, 0x3b305ef4d5737c95),\n", "(0xb78dcfe2c3d73d6b, 0x3b118c574d742d02),\n", "(0x3746542ad0f810ba, 0xbaa0621051dc9615),\n", "(0x371434d10d672431, 0xba7dbd00a70ea7c3),\n", "(0x36a3d2f4625f489c, 0x3a0ba13931894290),\n", "(0x367d34b5778ce244, 0x39e586f4fb44eb1c),\n", "],\n", "[\n", "(0x3c5827414357db53, 0xbfb8b5ccb03d459b),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc4827414357db53, 0x3fa8b5ccb03d459b),\n", "(0x3bc829bf4eaf884d, 0xbf2edc98b92fedf3),\n", "(0x3c0a89c9aabf2841, 0xbf70767d524cea88),\n", "(0xbb9b6aea43cf7c69, 0x3ef8a85a847c89c3),\n", "(0x3b9126e1254c1c3f, 0x3f2189afaa2bffcc),\n", "(0xbb239c5c72e2b643, 0xbeac1d231a69bb02),\n", "(0x3b6e89e6ffd32981, 0xbec40139bdbc9d36),\n", "(0xbac65998040abd88, 0x3e509a6859c8e374),\n", "(0x3aded4461012c62e, 0x3e5c60fc5f9b505f),\n", "(0xba80f4ba127543b5, 0xbde80ad391f7224c),\n", "(0xba8175d6b9c314bd, 0xbdeb6e954dd6c922),\n", "(0xba13a59996f17ca1, 0x3d778adc76ca1d1b),\n", "(0x39e11be5ff01d8f8, 0x3d733867c824f37c),\n", "(0xb99156aaeb019d3d, 0xbd00a1ec5f4dca90),\n", "(0xb98d52e6f6ab31a5, 0xbcf469ac872b68fd),\n", "(0xb92873e76419e2d3, 0x3c81c1b6937f11e6),\n", "(0x38ccce25f4bbd867, 0x3c70fe687033cfb9),\n", "(0x3891a388623b4d18, 0xbbfda774598ea00a),\n", "(0xb869e8b9411b1044, 0xbbe6c5c790ba8cb1),\n", "(0x38166a66767c0cb3, 0x3b73e54f8ca945a2),\n", "(0xb7f10320398ad824, 0x3b5916586436314c),\n", "(0x37824e29afdee9e2, 0xbae5eb34af321144),\n", "(0x376cca34b6192949, 0xbac71eb7d8b137e6),\n", "(0xb6e44bfb5b2e06d0, 0x3a542dd9e755ef71),\n", "(0x36d5af611735126d, 0x3a321616f456ec2b),\n", "(0xb6303bf3b5725f15, 0xb9bf82bf12709cef),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c116404635b6173, 0x3fb86e51bb2ee24d),\n", "(0x3be40f7dbe05e2df, 0xbf465e3bad214eb8),\n", "(0xbc3502bddec37518, 0xbf9047d6ed159c31),\n", "(0xbbb68a41509d990f, 0x3f1dce4a381ce24e),\n", "(0x3be0a2f7a61834bb, 0x3f4a05b93842da9a),\n", "(0x3b384a0ade44f859, 0xbed7ce3df60b0ea1),\n", "(0x3b8858267c36b09d, 0xbef3cb50138cce4b),\n", "(0x3b2cb60fbd510cee, 0x3e8216e84a5dec74),\n", "(0x3b2d7337b289cb04, 0x3e918e354c01533b),\n", "(0xbac53c3104a34351, 0xbe2005493039e5f0),\n", "(0x3ac1ef2cc08d8fcc, 0xbe245ed4a3733e9d),\n", "(0xba3577c4c664c7a0, 0x3db28e2ed388f175),\n", "(0xba513618783b7d45, 0x3db0a83fb8aae5cc),\n", "(0x39d2152affe981ca, 0xbd3e4745b1e410b2),\n", "(0xb9cc35474710f93a, 0xbd3439aae872dae3),\n", "(0xb90f376af336ee4d, 0x3cc2557a9d9a51a0),\n", "(0xb9418e01d92d0d8b, 0x3cb2f313647cb524),\n", "(0xb8ee555d5c581be4, 0xbc4120389f39a9c9),\n", "(0x38bceac00481a0f5, 0xbc2c39cb315eebe0),\n", "(0x38543f94ec753f1e, 0x3bb96c5a77539703),\n", "(0xb7f664a9d463aaf9, 0x3ba11bdcff0ddb62),\n", "(0xb7909879d65e235f, 0xbb2eb47c0f406536),\n", "(0x37b323a3eb4616f4, 0xbb1135192cf31d4c),\n", "(0x36df969385034399, 0x3a9ec17139b4fa1e),\n", "(0xb712728ddaed35bd, 0x3a7d2d581a06903c),\n", "(0xb68322eeb5683b7f, 0xba09f599e9b3fcee),\n", "(0xb6584681390e9457, 0xb9e522216f24e570),\n", "],\n", "[\n", "(0xbc5aa58d824fcbf0, 0x3fb829356c2fb67c),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4aa58d824fcbf0, 0xbfa829356c2fb67c),\n", "(0x3bc03ee1c336b408, 0x3f2cd964e5e4caa0),\n", "(0x3c0adae94b604802, 0x3f70190ce66b97c3),\n", "(0xbb6093ba87cf3d05, 0xbef70d5fd8bad7b5),\n", "(0xbbae25e1759c428e, 0xbf2126a150469b05),\n", "(0x3b4f93e54fe01a02, 0x3eaa49ea85815004),\n", "(0xbb4a798f784213ff, 0x3ec3910f5c159f54),\n", "(0x3ab455b6aeed4cdd, 0xbe4f0f4bdbe20c90),\n", "(0xbaf74c179ce6757b, 0xbe5bc3697829b270),\n", "(0x3a883549e84165fc, 0x3de67f2959cd47c2),\n", "(0x3a6dc709a66c6637, 0x3dead81c085abf1e),\n", "(0xb9f0a2a8eed90e0b, 0xbd760a10ab0898ac),\n", "(0x3a0d4bed5455a7cd, 0xbd72d07fd9984920),\n", "(0x399e8c3991730925, 0x3cff2887ab34ba4b),\n", "(0xb99d15049de98d82, 0x3cf3fd2c46f43bfa),\n", "(0x3918217b1630091e, 0xbc80a48214b2d81b),\n", "(0xb90aebeb32b2ec56, 0xbc70a5cd24e7aff5),\n", "(0x387f8e2a60b26930, 0x3bfbd0274fe43cf0),\n", "(0xb87decdf6830646f, 0x3be65191993b3def),\n", "(0xb8169726f5849485, 0xbb72acc84c6c9c30),\n", "(0xb7ecea63d3d7881a, 0xbb5899530e0f85dd),\n", "(0x3783523fe1e47394, 0x3ae4974878ee147d),\n", "(0xb75b7329483fca7c, 0x3ac6ae722e577e49),\n", "(0x36f5f5ad175e3a10, 0xba52f937d6c2c894),\n", "(0x36da45ec2b162935, 0xba31c0af96ec39d1),\n", "(0xb63b5886d2aae802, 0x39bda7e9893ee0e5),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc4ea89f3a43207f, 0xbfb7e656ed57a0d1),\n", "(0x3bed3586339aa922, 0x3f44f0cfc62eb61c),\n", "(0x3c1736dd17549bef, 0x3f8fdaba63e9c655),\n", "(0x3bb8a2f82c46d7d1, 0xbf1be7bad1c50547),\n", "(0x3be9f603d64ca819, 0xbf4975ac0770c98d),\n", "(0xbb716dcdea217bd7, 0x3ed64a6af83ba860),\n", "(0x3b95937b8720b7f0, 0x3ef35e6b41b6d77b),\n", "(0x3b1fd0d91a2328f8, 0xbe80f12d050df219),\n", "(0x3b0b801799b9887e, 0xbe912e744222ec5c),\n", "(0x3a882bc4f09a4762, 0x3e1e04a8c0a89be6),\n", "(0x3ab7f6d6a00158e7, 0x3e23f0ed5e6a0d3b),\n", "(0x3a40220f85fad9d6, 0xbdb163fd7157593b),\n", "(0x3a410e6d9a99af97, 0xbdb04f8efe519654),\n", "(0xb9d5f5b1b377833f, 0x3d3c6417f7a11d41),\n", "(0xb9df5b1599ff1601, 0x3d33cfa2affaf9e4),\n", "(0xb953811266af2ff0, 0xbcc1334e857adc93),\n", "(0xb95d7d93dd11d118, 0xbcb2917ae18b1995),\n", "(0x38e71d9f8e4fabac, 0x3c4013b4389ffe8d),\n", "(0x38b8b37790d4d1d0, 0x3c2bab4c1141eb75),\n", "(0x3858ea4627e8efee, 0xbbb7e1ea8188735c),\n", "(0x381cd9d4b13e954d, 0xbba0c761c695703d),\n", "(0xb7c2ccb36474c65d, 0x3b2cdd9ab5adf543),\n", "(0xb7ad59a9bff1b6e1, 0x3b10e22b0412a059),\n", "(0x37298e06ba0a7eff, 0xba9cefb8354e799e),\n", "(0x371ce2c8c6a65fa1, 0xba7ca4621c89c3ea),\n", "(0x369bfbcde055522b, 0x3a0871d638e71562),\n", "(0x36702a74cab2e18d, 0x39e4c1b3f6f3c4fc),\n", "],\n", "[\n", "(0xbc52d2ff041ff2f6, 0xbfb7a597eb76a5e3),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c42d2ff041ff2f6, 0x3fa7a597eb76a5e3),\n", "(0x3bb9dc564feff08d, 0xbf2b0bd9eb615315),\n", "(0xbc03cbe9e9bac1ac, 0xbf6f831b9629acd2),\n", "(0xbb95cc1ecba38a9d, 0x3ef59d1c40c95ba7),\n", "(0x3bad7b9ad1a36974, 0x3f20c9d35d4be191),\n", "(0xbb39533f46784cb0, 0xbea8a711bec6920b),\n", "(0xbb4180f2a561ac4b, 0xbec327e42f39066e),\n", "(0x3adb23dbc633fe86, 0x3e4d225aa8ded6cd),\n", "(0xbaea1e7c5d2c24a0, 0x3e5b2f83a946aed5),\n", "(0x3a72070bf439257d, 0xbde51bef06eb5d9f),\n", "(0xba7f45169aef013e, 0xbdea4ab19859cce7),\n", "(0xba0912db1823cb9f, 0x3d74b03ce339d83a),\n", "(0x3a007d1a27a09f97, 0x3d726eb2bbaa63c7),\n", "(0xb991c095fa32b480, 0xbcfd433d6a1a8fc3),\n", "(0x3988ca74e8a71011, 0xbcf396dd9428b7d8),\n", "(0xb91f2420c8969cf6, 0x3c7f470853f5d87d),\n", "(0x39129d5b5b244d63, 0x3c705215ddbe7188),\n", "(0xb89ad8ca1c6e4ad7, 0xbbfa26d052836024),\n", "(0xb86057f50da94b85, 0xbbe5e38754f9398d),\n", "(0x381cce919f096c57, 0x3b71923ffdac92d4),\n", "(0x37f2bbe0806d82ac, 0x3b5822a7b984366d),\n", "(0x377a0e974a7e67bc, 0xbae3636b0de0af87),\n", "(0x376c2d3712cd37ea, 0xbac6439959854a9a),\n", "(0xb6f5653a15338763, 0x3a51e12428cdc675),\n", "(0x36bd7966e734f9d4, 0x3a316f2e8a6d63cb),\n", "(0xb64936e1f9cb0f09, 0xb9bbf81db6228424),\n", "],\n", "];\n" ] } ], "source": [ "# Taylor series for f64\n", "mp.prec = 115\n", "terms = 28\n", "print(f\"pub(crate) static Y0_COEFFS: [[(u64, u64); {terms}]; {len(y0_zeros)}] = [\")\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffs(poly, n):\n", " print(\"[\")\n", " for i in range(0, n):\n", " coeff = poly[i]\n", " print_double_double(\"\", RealField(300)(coeff))\n", " # print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(y0_zeros)):\n", " k_range = y0_zeros[i]\n", " range_diff = k_range - prev_zero\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, bessely, taylor, chebyfit\n", " poly = taylor(lambda val: bessely(0, val), x0, terms)\n", " print_taylor_coeffs(poly, terms)\n", " prev_zero = y0_zeros[i]\n", "\n", "print(\"];\")\n", "\n", "# Taylor series for f64\n", "# mp.prec = 140\n", "# terms = 28\n", "# print(f\"pub(crate) static Y0_COEFFS_RATIONAL128: [[DyadicFloat128; {terms}]; {len(y0_zeros)}] = [\")\n", "\n", "# def get_constant_term(poly, y):\n", "# for term in poly.operands():\n", "# if term.is_constant():\n", "# return term\n", "\n", "# def print_taylor_dyadic_cef(poly, n):\n", "# print(\"[\")\n", "# for i in range(0, n):\n", "# coeff = poly[i]\n", "# print_dyadic(coeff)\n", "# # print(f\"{double_to_hex(coeff)},\")\n", "# print(\"],\")\n", "\n", "# prev_zero = 0\n", "\n", "# for i in range(0, len(y0_zeros)):\n", "# k_range = y0_zeros[i]\n", "# range_diff = k_range - prev_zero\n", "\n", "# x0 = mp.mpf(k_range)\n", "# from mpmath import mp, bessely, taylor, chebyfit\n", "# poly = taylor(lambda val: bessely(0, val), x0, terms)\n", "# print_taylor_dyadic_cef(poly, terms)\n", "# prev_zero = y0_zeros[i]\n", "\n", "# print(\"];\")" ] }, { "cell_type": "code", "execution_count": null, "id": "c3c42cf8-be7b-430d-891e-580eedb381e5", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/bessel_y1_taylor.ipynb000064400000000000000000003764741046102023000163610ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "1ecf1ea6-afd7-4cda-996e-c7e05a9b9efd", "metadata": {}, "outputs": [], "source": [ "from mpmath import mp, mpf, findroot, bessely\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_mid = DR(x - DD(x_hi))\n", " x_lo = x - DD(x_hi) - DD(x_mid)\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x):\n", " splat = split_triple_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")" ] }, { "cell_type": "code", "execution_count": 2, "id": "c834fde6-eb89-4b57-89fb-0517f909c256", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W = 0.256973952516943105\n", "Z = 0.138065597292926445\n", "LOG = -0.11252280788079415479644853102767\n", "(0x3c7abc9e3b39803f, 0x3fe62e42fefa39ef),\n", "Y1 approx = -0.87942080249719479722972442056\n", "Y1 full = -0.87942080249719479722972442056\n", "Y1 full expanded = -0.87942080249719479722972442056\n", "Y1 = -0.87942080249719479722972442056326109\n", "0.318309886183790671537767526745028724068919291480912897495334688117793595268453070180227606*x + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^2 - 0.0397887357729738339422209408431285905086149114351141121869168360147241994085566337725284507*x^3 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^4 + 0.00165786399054057641425920586846369127119228797646308800778820150061350830868985974052201878*x^5 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^6 - 0.0000345388331362620086304001222596602348165059995096476668289208645961147564310387445942087246*x^7 + 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*x^8 + 4.31735414203275107880001528245752935206324993870595835361510807451434455387984307427609057e-7*x^9\n", "(0x3c61d7eb2e54cda1, 0x3fc91866143cbc8a),\n", "(0xbc2f9f7a0ce54a40, 0xbfabd3975c75b4a7),\n", "(0xbbf7659313f45e8c, 0x3f6835b97894be5b),\n", "(0x3b9cbcd40f1be7b9, 0xbf12c7dbffcde97d),\n", "(0xbb495d78778645b4, 0x3eb0a780ac776eac),\n", "(0xbae15be86455c1ab, 0xbe432e5a4ddeea30),\n", "(0xba5ad966c12f1e3c, 0x3dcf0ce34d2066a6),\n", "(0x39e9717155dc7521, 0xbd52a4e1aea45c18),\n", "(0x394f447fe5de1290, 0x3cd1474ade9154ac),\n", "(0xb8e1699d9009a7fc, 0xbc4978ba84f218c0),\n", "(0xb8505502096ead17, 0x3bbe9598c016378b),\n", "(0x37942b6c36b2c5f1, 0xbb2e7e5fcfc4b7b1),\n", "(0x37210853b78bd08a, 0x3a99a6c1266c116d),\n", "(0xb686c9639c9d976e, 0xba02738998fe7337),\n", "(0xb603b739ee04b9fe, 0x3966f58cd41b6d08),\n" ] } ], "source": [ "from sage.all import *\n", "\n", "R = LaurentSeriesRing(RealField(300), 'x', default_prec=300)\n", "x = R.gen()\n", "N = 16 # Number of terms (adjust as needed)\n", "gamma = RealField(300)(euler_gamma)\n", "d2 = RealField(300)(2)\n", "pi = RealField(300).pi()\n", "log2 = RealField(300)(2).log()\n", "\n", "def j_series(n, x):\n", " return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)])\n", "\n", "J1_series = j_series(1, x)\n", "\n", "def harmony(m):\n", " return sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1))\n", "\n", "def z_series(x):\n", " return sum([(-1)**m * (x)**(ZZ(2)*ZZ(m)) / (ZZ(2)**(2*m) * ZZ(m).factorial() * (ZZ(m) - ZZ(1)).factorial()) * (harmony(m) + harmony(m - 1)) for m in range(1, N)])\n", "\n", "W1 = d2/pi * J1_series\n", "Z1 = -(d2/(x*pi) * z_series(x) + d2/pi * gamma * J1_series(x) - d2/pi * log2 * J1_series(x))\n", "\n", "def y1_full(x):\n", " return d2/pi * (J1_series(x) * x.log() - 1/x * ( 1 - z_series(x)) + (gamma - log2) * J1_series(x))\n", "\n", "def y1_full_expanded(x):\n", " return d2/pi * J1_series(x) * x.log() - d2/(x*pi) + d2/(x*pi) * z_series(x) + d2/pi * gamma * J1_series(x) - d2/pi * log2 * J1_series(x)\n", "\n", "# print(\"W0(x) =\", W0)\n", "# print(\"Z0(x) =\", Z0)\n", "\n", "terms = 30\n", "\n", "from mpmath import mp, bessely, taylor\n", "\n", "def Y1_approx(val):\n", " # Substitute numeric value and convert to high precision real\n", " w = W1.truncate(terms)(val)\n", " z = Z1.truncate(terms)(val)\n", " return RealField(107)(w) * RealField(107)(val).log() - RealField(107)(z) - RealField(107)(2)/(pi * val)\n", "\n", "mp.prec = 120\n", "\n", "print(\"W = \", RealField(64)(W1.truncate(terms)(0.89357696627916749)))\n", "print(\"Z = \", RealField(64)(Z1.truncate(terms)(0.89357696627916749)))\n", "print(\"LOG = \", RealField(110)(0.89357696627916749).log())\n", "print_double_double(\"\", RealField(110)(2).log())\n", "print(\"Y1 approx = \", Y1_approx(RealField(100)(0.89357696627916749)))\n", "print(\"Y1 full = \", y1_full(RealField(100)(0.89357696627916749)))\n", "print(\"Y1 full expanded = \", y1_full_expanded(RealField(100)(0.89357696627916749)))\n", "print(\"Y1 = \", bessely(1, 0.89357696627916749))\n", "\n", "print(W1.truncate(10))\n", "\n", "def print_series(z, N):\n", " for i in range(N):\n", " coeff = z[i]\n", " if coeff != 0:\n", " # print(double_to_hex(RealField(300)(coeff)) + \",\")\n", " print_double_double(\"\", RealField(300)(coeff))\n", "\n", "print_series(Z1, 30)\n", "\n", "# print_double_double(\"2/PI\", -d2/pi)" ] }, { "cell_type": "code", "execution_count": 3, "id": "d045ceba-09f4-4bef-8a14-ec78358f5648", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Zero 1: x ≈ 2.1971413260310170351490335626989662730530183315\n", "Zero 2: x ≈ 5.429681040794135132772005190852584196583757476\n", "Zero 3: x ≈ 8.596005868331168926429606180163967851102921567\n", "Zero 4: x ≈ 11.749154830839881243399421939922350714301165983\n", "Zero 5: x ≈ 14.897442128336725378844819156429870879807150631\n", "Zero 6: x ≈ 18.043402276727855564304555507889508902163088325\n", "Zero 7: x ≈ 21.188068934142213016142481528685423196935024605\n", "Zero 8: x ≈ 24.33194257135691203599294405185012965141433334\n", "Zero 9: x ≈ 27.475294980449223512212285525410668235700897307\n", "Zero 10: x ≈ 30.618286491641114715761625696447448310277939571\n", "Zero 11: x ≈ 33.761017796109325692471759911249650993879821496\n", "Zero 12: x ≈ 36.903555316142950053588159309844303659060544565\n", "Zero 13: x ≈ 40.045944640266876089064214537312936172020628336\n", "Zero 14: x ≈ 43.18821809739321126847753320012759720745635785\n", "Zero 15: x ≈ 46.330399250701686587724463565243621670014635651\n", "Zero 16: x ≈ 49.472505679924095824128003887609267273294894412\n", "Extrema (peaks/valleys) of Y1(x):\n", "nExtrema: 3.6830228565851776998989672428339960814554645007\n", "nExtrema: 6.9414999536541756557519437170770430269117513846\n", "nExtrema: 10.123404655436613079787752723081255467685818178\n", "nExtrema: 13.285758156782854437262071956503251636724978539\n", "nExtrema: 16.440058007293281606967213074369456583397533058\n", "nExtrema: 19.590241756629494709149314724221899261015530877\n", "nExtrema: 22.738034717396327495094571334536887209572307957\n", "nExtrema: 25.88431461878886739812166951504948259990602185\n", "nExtrema: 29.029575819372535446204461736683550674552942795\n", "nExtrema: 32.174118233366201264764645453604774990445259304\n", "nExtrema: 35.318134458192094224611119506813139521194128385\n", "nExtrema: 38.46175387099754904698883606468604352323243467\n", "nExtrema: 41.605066618873107563462560180667045930524308478\n", "nExtrema: 44.748137449080790184972524852342872814656989109\n", "nExtrema: 47.891014070791065265177381690996464185566793068\n", "nExtrema: 51.033732416116105032686173503315800718030899016\n", "Peak or zero 1: x ≈ 2.1971413260310170351490335626989662730530183315\n", "Peak or zero 2: x ≈ 3.6830228565851776998989672428339960814554645007\n", "Peak or zero 3: x ≈ 5.429681040794135132772005190852584196583757476\n", "Peak or zero 4: x ≈ 6.9414999536541756557519437170770430269117513846\n", "Peak or zero 5: x ≈ 8.596005868331168926429606180163967851102921567\n", "Peak or zero 6: x ≈ 10.123404655436613079787752723081255467685818178\n", "Peak or zero 7: x ≈ 11.749154830839881243399421939922350714301165983\n", "Peak or zero 8: x ≈ 13.285758156782854437262071956503251636724978539\n", "Peak or zero 9: x ≈ 14.897442128336725378844819156429870879807150631\n", "Peak or zero 10: x ≈ 16.440058007293281606967213074369456583397533058\n", "Peak or zero 11: x ≈ 18.043402276727855564304555507889508902163088325\n", "Peak or zero 12: x ≈ 19.590241756629494709149314724221899261015530877\n", "Peak or zero 13: x ≈ 21.188068934142213016142481528685423196935024605\n", "Peak or zero 14: x ≈ 22.738034717396327495094571334536887209572307957\n", "Peak or zero 15: x ≈ 24.33194257135691203599294405185012965141433334\n", "Peak or zero 16: x ≈ 25.88431461878886739812166951504948259990602185\n", "Peak or zero 17: x ≈ 27.475294980449223512212285525410668235700897307\n", "Peak or zero 18: x ≈ 29.029575819372535446204461736683550674552942795\n", "Peak or zero 19: x ≈ 30.618286491641114715761625696447448310277939571\n", "Peak or zero 20: x ≈ 32.174118233366201264764645453604774990445259304\n", "Peak or zero 21: x ≈ 33.761017796109325692471759911249650993879821496\n", "Peak or zero 22: x ≈ 35.318134458192094224611119506813139521194128385\n", "Peak or zero 23: x ≈ 36.903555316142950053588159309844303659060544565\n", "Peak or zero 24: x ≈ 38.46175387099754904698883606468604352323243467\n", "Peak or zero 25: x ≈ 40.045944640266876089064214537312936172020628336\n", "Peak or zero 26: x ≈ 41.605066618873107563462560180667045930524308478\n", "Peak or zero 27: x ≈ 43.18821809739321126847753320012759720745635785\n", "Peak or zero 28: x ≈ 44.748137449080790184972524852342872814656989109\n", "Peak or zero 29: x ≈ 46.330399250701686587724463565243621670014635651\n", "Peak or zero 30: x ≈ 47.891014070791065265177381690996464185566793068\n", "Peak or zero 31: x ≈ 49.472505679924095824128003887609267273294894412\n", "Peak or zero 32: x ≈ 51.033732416116105032686173503315800718030899016\n", "\n", "pub(crate) static Y1_ZEROS_RATIONAL128: [DyadicFloat128; 32] = [\n", "DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0u128, },\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0x8c9df6a6_ff921721_70d796f3_2017e155_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -126,\n", " mantissa: 0xebb6a57f_dd0ba813_bac0714e_41288d0a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -125,\n", " mantissa: 0xadbff274_3d8173bf_cf758451_d17ddc12_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -125,\n", " mantissa: 0xde20c482_c42a9979_60b6b1c4_6ac0d861_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0x89893d73_0b4da147_9cc068d9_0466df5b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xa1f97728_f463f31e_974bad1c_87ff760c_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xbbfc89c6_a1903021_f8f0d9c0_c1004d6b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xd4927725_1f295f04_8842e547_536abdb0_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -124,\n", " mantissa: 0xee5bec46_f4245543_edcb5e0e_3f61c303_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x83853d21_ed573107_320221cd_5e56e5bd_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x9058e34a_f8f1d4bc_236756f0_2443a2d1_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0x9cb8d0ab_8ba87dad_f9db6021_03963101_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xa9812a49_0c466a72_3628820a_51d726a6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xb5e77ebe_f43d16ea_13f68de4_8ba361d6_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xc2a7d181_c10650a9_7baf812d_902b3e46_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xcf13138a_f89548b7_abfbb4b7_a49ab892_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xdbcd6774_67dbe718_767820ae_26dd1f44_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xe83c923f_47a8d7dd_bd7a9deb_4735604f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -123,\n", " mantissa: 0xf4f24030_2941dfc3_0b11f705_3d347846_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x80b24c0c_d7c7d045_14bac1f3_64dc3c4b_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x870b483f_c7daacd2_82a82102_617f3d05_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x8d45c50a_16a9b38c_10df6bba_66a06121_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x939d3d9a_d3d7f924_81e87adf_e5728360_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0x99d8d601_baf1897d_f5b6f701_c7a2c72e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xa02f0c1c_9d7da9a8_ffacaac8_460e01b5_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xa66b9695_6fd85d49_4a6a01ea_f3270784_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xacc0bc3e_b346d87f_918feb38_b06e7e1f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xb2fe17be_52dc0406_8b22b3c4_1ca42b60_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xb952542e_618bedb3_8de1b41f_c6aa4a1f_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xbf9065fe_194b3791_6e4d6441_9244033e_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xc5e3d887_69cafe33_9981aa85_e88e1e1a_u128,\n", "},\n", "DyadicFloat128 {\n", " sign: DyadicSign::Pos,\n", " exponent: -122,\n", " mantissa: 0xcc228ac0_20228b48_e7a9e413_f5d7ef48_u128,\n", "},\n", "];\n" ] } ], "source": [ "R120 = RealField(120)\n", "\n", "zeros = []\n", "\n", "mp.prec = 160\n", "\n", "step = mpf(\"0.1\")\n", "epsilon = mpf(\"1e-35\")\n", "x = mpf(\"1.25\")\n", "\n", "previous_zero = R120(0)\n", "y1_zeros = []\n", "\n", "while x < mpf(\"52.0\"):\n", " f1 = bessely(1, x)\n", " f2 = bessely(1, x + step)\n", " if f1 * f2 < 0:\n", " zero = findroot(lambda t: bessely(1, t), (x, x + step), solver='secant', tol=mp.mpf(\"1e-41\"))\n", " previous_zero = zero\n", " y1_zeros.append(zero)\n", " if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon:\n", " zeros.append(previous_zero)\n", " x += step\n", "\n", "y1_extrema = []\n", "\n", "x = mpf(\"1.25\")\n", "while x < mpf(\"52.0\"):\n", " d1 = mp.diff(lambda t: bessely(1, t), x)\n", " d2 = mp.diff(lambda t: bessely(1, t), x + step)\n", " if d1 * d2 < 0:\n", " extremum = findroot(lambda t: mp.diff(lambda u: bessely(1, u), t), (x, x + step), solver='secant', tol=mp.mpf(\"1e-41\"))\n", " y1_extrema.append(extremum)\n", " x += step\n", "\n", "# Print results\n", "for i, z in enumerate(y1_zeros):\n", " print(f\"Zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"Extrema (peaks/valleys) of Y1(x):\")\n", "for e in y1_extrema:\n", " print(f\"nExtrema: {e}\")\n", "\n", "y1_zeros.extend(y1_extrema)\n", "\n", "y1_zeros = sorted(y1_zeros)\n", "\n", "# Print results\n", "for i, z in enumerate(y1_zeros):\n", " print(f\"Peak or zero {i+1}: x ≈ {z}\")\n", "\n", "print(\"\")\n", "\n", "# print(f\"pub(crate) static Y1_ZEROS: [(u64, u64); {len(y1_zeros)}] = [\")\n", "# print(f\"(0x0, 0x0),\")\n", "# for z in y1_zeros:\n", "# k = split_double_double(z)\n", "# hi = double_to_hex(k[1])\n", "# lo = double_to_hex(k[0])\n", "# print(f\"({lo}, {hi}),\")\n", " \n", "# print(\"];\")\n", "\n", "print(f\"pub(crate) static Y1_ZEROS_RATIONAL128: [DyadicFloat128; {len(y1_zeros)}] = [\")\n", "print(f\"DyadicFloat128 {{ sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0u128, }},\")\n", "for z in y1_zeros:\n", " print_dyadic(z)\n", " \n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 8, "id": "f246ed8f-8a98-4ccb-a485-6b8eece735cc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y1F_COEFFS: [[u64;19]; 32] = [\n", "[\n", "0x3bdca2ee18606a4b,\n", "0x3fe0aa48442f014b,\n", "0xbfbe56f82217b8f4,\n", "0xbfa0d2af4e932400,\n", "0xbf73a6dec3726cd5,\n", "0x3f7e671c7d12ea48,\n", "0xbf65429dc5c0e9d4,\n", "0x3f517ab4af4655e4,\n", "0xbf40b2d8647a250d,\n", "0x3f2eea7b1b675766,\n", "0xbf1c3fb728e7d2ff,\n", "0x3f09d1da72e12f44,\n", "0xbef7964bf8511e22,\n", "0x3ee57c2a83e1f972,\n", "0xbed33f4211a00375,\n", "0x3ec02bcdac2103fd,\n", "0xbea6fefcf033ab9d,\n", "0x3e874128ed97d3bb,\n", "0xbe57d5b1eac16658,\n", "],\n", "[\n", "0x3fdaabb4011ed330,\n", "0x3c54da7c52fcf446,\n", "0xbfc8b45babe797b6,\n", "0x3f8e147099a6f00d,\n", "0x3f88c5af1eeb2143,\n", "0xbf4133fa47d8ea48,\n", "0xbf3bf8af93e7a2f0,\n", "0x3f021d64bd4e2cd8,\n", "0x3eb44d2c32fdaf23,\n", "0x3eb14c3b9e7960c1,\n", "0xbe9b8ee25c629be6,\n", "0x3e7a85b5b497dc6c,\n", "0xbe5bfa422fb8d949,\n", "0x3e3f0ad81d293f5a,\n", "0xbe20e6844c6faba7,\n", "0x3e0214b2d826d072,\n", "0xbde4ff658967d425,\n", "0x3dcb549cdc774a83,\n", "0xbda6b5df4d9c1682,\n", "],\n", "[\n", "0x3b7ff35240713789,\n", "0xbfd5c7c556f0c19a,\n", "0x3fa00b9f8571ca1f,\n", "0x3faa15d92dfe3e27,\n", "0xbf710a329e2c23f5,\n", "0xbf61be6db9923ac9,\n", "0x3f2337c7e138eb84,\n", "0x3f085b940eb5f37f,\n", "0xbec80619146a1e65,\n", "0xbea255e6cf4b3254,\n", "0x3e5b62ccdc392c5a,\n", "0x3e380b1a5a61e6b5,\n", "0xbdfa7ec7fd0d2925,\n", "0x3d840d04ff01d1b2,\n", "0xbd938dc1b2e33eca,\n", "0x3d74839c586126ca,\n", "0xbd4b045bc7ad769b,\n", "0x3d261d10a8575c45,\n", "0xbd052a6cc14bcc54,\n", "],\n", "[\n", "0xbfd36732d4b96094,\n", "0x3b3886a5ed6fd628,\n", "0x3fc3001c8002caf8,\n", "0xbf7bf5a03bab4999,\n", "0xbf8751ea028c1953,\n", "0x3f423874cd8d0402,\n", "0x3f364f6610d6493b,\n", "0xbef02978de38394f,\n", "0xbed72f0766d0d9c7,\n", "0x3e8f2081874e556c,\n", "0x3e6defd5dce91973,\n", "0xbe2205c70046a2c7,\n", "0xbdfb6432eb3ab7ea,\n", "0x3db028a1c0572973,\n", "0x3d807791dcab03a0,\n", "0xbd29778204deee13,\n", "0xbd08342db2e7148e,\n", "0x3cc898efb37f9dad,\n", "0xbc84e2adc305e2ab,\n", "],\n", "[\n", "0xbac1435819592d4c,\n", "0x3fd15f993fceab5c,\n", "0xbf902b3933cf21b1,\n", "0xbfa6395dfe49fcd4,\n", "0x3f63ced2a2e69180,\n", "0x3f607a678d6000bb,\n", "0xbf1b50d7e1d3201e,\n", "0xbf06f7bab104f34b,\n", "0x3ec176e72bf94a3a,\n", "0x3ea2becb2b6bacd1,\n", "0xbe5a384eebfb23c2,\n", "0xbe341e7a921f7f66,\n", "0x3de9e3284b918a26,\n", "0x3dbec40b21f2c78f,\n", "0xbd726865da6190a9,\n", "0xbd416f4fe7eed351,\n", "0x3cf3160bd2bd6c64,\n", "0x3cbf6d61c945b95c,\n", "0xbc706809636e0aec,\n", "],\n", "[\n", "0x3fd00ef3745e0e3c,\n", "0x3aff192f298c81c3,\n", "0xbfbfcdacdda138f2,\n", "0x3f706cc34cd829fa,\n", "0x3f84641bb10c16cb,\n", "0xbf37fac943e2a16d,\n", "0xbf34769ed32e14a2,\n", "0x3ee80608ecda1508,\n", "0x3ed5cc8242d77e23,\n", "0xbe888c8f2538feb8,\n", "0xbe6ce5908c1e5174,\n", "0x3e1ed16257e17417,\n", "0x3dfa30d623eda066,\n", "0xbdaa5076123e3ecf,\n", "0xbd814cd297d2be7e,\n", "0x3d306166947e23e9,\n", "0x3d01635f73179569,\n", "0xbcaeafcf4c2f127b,\n", "0xbc7b0828175d92fa,\n", "],\n", "[\n", "0x3aba1488e1b7782d,\n", "0xbfcdc14ea14e89f9,\n", "0x3f84429fef5b5fbd,\n", "0x3fa367d7d608e4ba,\n", "0xbf59d6eb2bc49e35,\n", "0xbf5dc4f991b3db86,\n", "0x3f1315ec04d6e6bb,\n", "0x3f0571814a1aa2f5,\n", "0xbeba2977fa42f00f,\n", "0xbea1e864230850b8,\n", "0x3e54a7b82d3fa1e5,\n", "0x3e33906609f9fe4c,\n", "0xbde549e8b0e16969,\n", "0xbdbe32cf2ce99d6f,\n", "0x3d6eff542dd345c3,\n", "0x3d415e2a9c2f4933,\n", "0xbcf0d48dde3c3ffe,\n", "0xbcbeac3c36b4bce2,\n", "0x3c6af1612c5ddab0,\n", "],\n", "[\n", "0xbfcc075da85beb4f,\n", "0xbafcfa84f4024782,\n", "0x3fbbdeb6ff9f55e1,\n", "0xbf661eefb74da882,\n", "0xbf8229ea914b846e,\n", "0x3f30cbcc6778fd37,\n", "0x3f32aa59f5091f7b,\n", "0xbee1c15d5251ae54,\n", "0xbed4583f15abd654,\n", "0x3e831d151a12624a,\n", "0x3e6b74e57c21e022,\n", "0xbe19044f1339b061,\n", "0xbdf93b1ec70c7bbc,\n", "0x3da61a4e437e8105,\n", "0x3d80d4305f038451,\n", "0xbd2c3aad6f3b35c7,\n", "0xbd010dec3a02c58c,\n", "0x3cab15901b6d0925,\n", "0x3c7ab2531f00c501,\n", "],\n", "[\n", "0xbab392a85abdc950,\n", "0x3fca7022be084d99,\n", "0xbf7c650b6b83109a,\n", "0xbfa163191c30aa62,\n", "0x3f526b045287ddca,\n", "0x3f5b17602840abf5,\n", "0xbf0c0a9cee3c8429,\n", "0xbf03e398cbc472de,\n", "0x3eb3f35db1ff19f5,\n", "0x3ea0e9b612dbc0ea,\n", "0xbe5056babcd79a11,\n", "0xbe32c1a8c8d768b1,\n", "0x3de161b6a84838d0,\n", "0x3dbd4ca9d2d67d78,\n", "0xbd69fdd67a999eab,\n", "0xbd4101919ce84a07,\n", "0x3cecd91fa7851496,\n", "0x3cbe3f8588ebbfdf,\n", "0xbc67a4499c96e38d,\n", "],\n", "[\n", "0x3fc931a5a0ae5aa0,\n", "0x3afa23fd08be9891,\n", "0xbfb919c8a3f203fa,\n", "0x3f602a38da6262a9,\n", "0x3f807ced48910819,\n", "0xbf2900f33a00690a,\n", "0xbf31278d46fd153c,\n", "0x3edb2595529cf19f,\n", "0x3ed2f7c2d608e0bb,\n", "0xbe7e212d23787793,\n", "0xbe69f3fcf3631e9c,\n", "0x3e144fbf033f1974,\n", "0x3df82268e7ab0cdb,\n", "0xbda26cc2714815d4,\n", "0xbd80418b35c32375,\n", "0x3d28122e50410f0a,\n", "0x3d009aba27e11464,\n", "0xbca78943175d4e84,\n", "0xbc7a379f959c0224,\n", "],\n", "[\n", "0x3aaf25ce7e30cbc6,\n", "0xbfc80781c32422e7,\n", "0x3f754eda697a0098,\n", "0x3f9fbe6df840847f,\n", "0xbf4be318d61276e1,\n", "0xbf58efee4094379c,\n", "0x3f059145b4f0e4dd,\n", "0x3f0282d26a74c382,\n", "0xbeaf56c29d9ad6c8,\n", "0xbe9fdd03174f6b47,\n", "0x3e4a44a7907d0ec6,\n", "0x3e31df6533090779,\n", "0xbddc96e9cb6ee22b,\n", "0xbdbc3439a99213c4,\n", "0x3d65d387fc8083e0,\n", "0x3d40830db4ec8a6e,\n", "0xbce8ad426f9ce3f5,\n", "0xbcbd93c0cf35d116,\n", "0x3c649b19a5449ffa,\n", "],\n", "[\n", "0xbfc713fc51664c74,\n", "0xbaf73aab14face16,\n", "0x3fb7049760cde490,\n", "0xbf58ef5f1cbe4874,\n", "0xbf7e5f53caf3bead,\n", "0x3f237b0b62ddadd1,\n", "0x3f2fd3bac08286da,\n", "0xbed5789803de3adb,\n", "0xbed1c0faa8999393,\n", "0x3e7845b49b063dc7,\n", "0x3e6886872800e226,\n", "0xbe10b03677687883,\n", "0xbdf7049d17bd230b,\n", "0x3d9edd9ca057f252,\n", "0x3d7f445f42a168e6,\n", "0xbd24866878075342,\n", "0xbd0015a37275b46d,\n", "0x3ca463bd3d4059be,\n", "0x3c79974848138496,\n", "],\n", "[\n", "0xbaa9a62f9227c851,\n", "0x3fc62d94d97e859c,\n", "0xbf70bf614807033c,\n", "0xbf9d5f857a2a6107,\n", "0x3f46081b0b7fe572,\n", "0x3f57307b03e248f8,\n", "0xbf0132c0aa83d0db,\n", "0xbf0154ed4598d2e4,\n", "0x3ea94f64f476e3f5,\n", "0x3e9e1272585385c0,\n", "0xbe4588c758dd66db,\n", "0xbe31021cdd7a4f3a,\n", "0x3dd7cfa7a39f5d48,\n", "0x3dbb0e00d41ec645,\n", "0xbd6276c9a451cdb1,\n", "0xbd3fe8cf17671ae1,\n", "0x3ce52f1a6f7ae06f,\n", "0x3cbcc2eb893d62ce,\n", "0xbc61f4c0af8bd0fb,\n", "],\n", "[\n", "0x3fc56b97f8091ac5,\n", "0x3af48a947d2475cd,\n", "0xbfb560fcc8c08469,\n", "0x3f53fafa39618883,\n", "0x3f7c49141623372f,\n", "0xbf1f69980694fd17,\n", "0xbf2dc5f848aa9d33,\n", "0x3ed178fc979b779d,\n", "0x3ed0b494a4bafca8,\n", "0xbe73fc3884c243a5,\n", "0xbe673afb9fb48ff7,\n", "0x3e0bd903464b077a,\n", "0x3df5f3bafabcdabe,\n", "0xbd9a1c27612b5f03,\n", "0xbd7e04553366c10e,\n", "0x3d219970f1564c7c,\n", "0x3cff128fbd867c78,\n", "0xbca1b4d2be53f3ad,\n", "0xbc78e13fb654b036,\n", "],\n", "[\n", "0x3aa5951bb8e2b477,\n", "0xbfc4b2a38f1ab9b4,\n", "0x3f6b3878aadeb34d,\n", "0x3f9b750d89a9b35f,\n", "0xbf41f6911725a956,\n", "0xbf55beee6fd51c8a,\n", "0x3efc3625d7a65087,\n", "0x3f005375a588a71f,\n", "0xbea4ee5e4e7cafc0,\n", "0xbe9c7b3d81b5dc31,\n", "0x3e41fce14f464e1e,\n", "0x3e30346643a98dcb,\n", "0xbdd41c86191a49ce,\n", "0xbdb9eed9da04017a,\n", "0x3d5f8cee5e5b42b4,\n", "0x3d3ec41075d33352,\n", "0xbce24e44459e28b0,\n", "0xbcbbe16f7d769c15,\n", "0x3c5f670ad9138f1f,\n", "],\n", "[\n", "0xbfc413644356a52b,\n", "0xbaf22d9ab9060f8f,\n", "0x3fb40bb88c6f2b85,\n", "0xbf5078d13cfc400e,\n", "0xbf7a9191262ab9d5,\n", "0x3f1a005297618f35,\n", "0x3f2c0cbad847a60e,\n", "0xbecd1a72e7c35fa0,\n", "0xbecf9a2654099c0b,\n", "0x3e70c6b06e20d1c0,\n", "0x3e66136d6425acf0,\n", "0xbe0797767778226d,\n", "0xbdf4f77b30ed58c3,\n", "0x3d96572059bf2445,\n", "0x3d7cd12649b82d6f,\n", "0xbd1e6ce514a88f2d,\n", "0xbcfdfabaf5c37514,\n", "0x3c9eea8202989176,\n", "0x3c782260f7596e02,\n", "],\n", "[\n", "0xbaa27e57c2b07d4b,\n", "0x3fc37aaceac987b9,\n", "0xbf66afe4fe0bc0f7,\n", "0xbf99de7a33bc3a97,\n", "0x3f3e024f567ac487,\n", "0x3f548843c426abe0,\n", "0xbef7a8e14711c0f4,\n", "0xbefeeceb341ad81c,\n", "0x3ea1a743e05b383f,\n", "0x3e9b143d39c8eb5f,\n", "0xbe3e8e00011fabc3,\n", "0xbe2ef28e31ff924c,\n", "0x3dd137a1bd136742,\n", "0x3db8e0878264a773,\n", "0xbd5b3dc655a5a5f4,\n", "0xbd3da652e8239897,\n", "0x3cdfe34eace42448,\n", "0x3cbafd0cc7251807,\n", "0xbc5b9b0102453020,\n", "],\n", "[\n", "0x3fc2f4e70d6c7e01,\n", "0x3af022defda0ec45,\n", "0xbfb2ef24d6f7526a,\n", "0x3f4bc33c9dc6ec82,\n", "0x3f7920414ee2acbe,\n", "0xbf15f9173916a219,\n", "0xbf2a94fdbdcec471,\n", "0x3ec8b309990f94db,\n", "0x3ece087ff4517bd5,\n", "0xbe6ca22ab12c685c,\n", "0xbe650d1f28632753,\n", "0x3e044415529c950b,\n", "0x3df411b8a7d9d1bc,\n", "0xbd9354e8c7a8bfd7,\n", "0xbd7bb16e8ee8c711,\n", "0x3d1a881fddcb8d86,\n", "0x3cfcecee70233b69,\n", "0xbc9b2b6cccd3802a,\n", "0xbc77637662fa6ba8,\n", "],\n", "[\n", "0x3aa00f5dbb23e90b,\n", "0xbfc2740819f1caaa,\n", "0x3f6349369dc780bb,\n", "0x3f98868d7401bf2e,\n", "0xbf398cd1bebe1445,\n", "0xbf537eef9aadeee2,\n", "0x3ef43394c95b2d29,\n", "0x3efd6dfcdb026013,\n", "0xbe9e448fbc8a1c95,\n", "0xbe99d764ee07a6b7,\n", "0x3e3a53958c8a71d8,\n", "0x3e2da0e1c86368ce,\n", "0xbdcdd7f914e496e5,\n", "0xbdb7e67ff45daf48,\n", "0x3d57c2e32861f41c,\n", "0x3d3c96e18ab6db69,\n", "0xbcdc0099b11f0478,\n", "0xbcba1dfeafeb6e19,\n", "0x3c586b4c940f74bc,\n", "],\n", "[\n", "0xbfc20198200b699d,\n", "0xbaecc875d54af9d0,\n", "0x3fb1fd242a74e630,\n", "0xbf47cf261dfbf19a,\n", "0xbf77e4820ec1dde4,\n", "0x3f12e1bd281dfcba,\n", "0x3f2950bb06c6fdf9,\n", "0xbec54a38ab6af51a,\n", "0xbecca94f38024fb4,\n", "0x3e68c7e75971843f,\n", "0x3e6423fc7e24ed40,\n", "0xbe019fe1d8a6e0d8,\n", "0xbdf34198c7517f5a,\n", "0x3d90e78c95f157aa,\n", "0x3d7aa74c4042e051,\n", "0xbd1756942b9afcaf,\n", "0xbcfbedc3e7dae4e4,\n", "0x3c980b9567289463,\n", "0x3c76a9e024cc6a52,\n", "],\n", "[\n", "0xba9c33661811b8ff,\n", "0x3fc192f2627a74e3,\n", "0xbf60a846a83fecf2,\n", "0xbf975eceaabf7f86,\n", "0x3f3617c581be35b1,\n", "0x3f529934b7a84483,\n", "0xbef18123e8751889,\n", "0xbefc1f05a2d85150,\n", "0x3e9a4e0bc09262e9,\n", "0x3e98be81ad44b8a4,\n", "0xbe36f73795dfb5c7,\n", "0xbe2c70ab155167d1,\n", "0x3dca26218cc79400,\n", "0x3db7011269271056,\n", "0xbd54ec138a5f86cd,\n", "0xbd3b98bf6fa2fe47,\n", "0x3cd8c95d73f0c84c,\n", "0x3cb948b2dd021429,\n", "0xbc55bd7c63fa9765,\n", "],\n", "[\n", "0x3fc12f9870d68e18,\n", "0x3ae9cd1ac1fa64f9,\n", "0xbfb12c11811945f9,\n", "0x3f44b638f21f0f76,\n", "0x3f76d2a897d58353,\n", "0xbf10732e5458ba20,\n", "0xbf2835929300df3e,\n", "0x3ec297283816a814,\n", "0x3ecb73adedf11a1f,\n", "0xbe65b455b903b389,\n", "0xbe6353f0797a3bf1,\n", "0x3dfefc9ac10b87d9,\n", "0x3df2853545ffa79d,\n", "0xbd8dd8945079a88f,\n", "0xbd79b28860cd63f8,\n", "0x3d14b29ba2797832,\n", "0x3cfaff02f362ca7e,\n", "0xbc956d8436ee55ed,\n", "0xbc75f881bb0137f5,\n", "],\n", "[\n", "0x3a9900b85a085cfa,\n", "0xbfc0cf3ee98f769b,\n", "0x3f5d26e7af251f79,\n", "0x3f965d05948a946a,\n", "0xbf335959b8482e40,\n", "0xbf51cff175d05c2a,\n", "0x3eeeb59416879104,\n", "0x3efaf7544eeac751,\n", "0xbe9720522bb1fa69,\n", "0xbe97c41261703475,\n", "0x3e343fa0ea5ba663,\n", "0x3e2b5e23abb21a5f,\n", "0xbdc722397b59adb6,\n", "0xbdb62f213532a0b8,\n", "0x3d5294a89e377c98,\n", "0x3d3aac95aead6ada,\n", "0xbcd61abb584f3fc2,\n", "0xbcb87f3345758fd5,\n", "0x3c537a3b70fc94b7,\n", "],\n", "[\n", "0xbfc077eede4a0d89,\n", "0xbae73fb2e67b1968,\n", "0x3fb0751548b2924d,\n", "0xbf423b5d46a73864,\n", "0xbf75e2467c8fb832,\n", "0x3f0cfe5c189d6e4d,\n", "0x3f273bbd8c7aef2c,\n", "0xbec06974d3d04263,\n", "0xbeca6081d36e6a0b,\n", "0x3e6334a83cf5d21d,\n", "0x3e6299571cb4bb1e,\n", "0xbdfb7f5bc046450f,\n", "0xbdf1da63b49ed896,\n", "0x3d8a92885fb339ae,\n", "0x3d78d1d6e93bb23d,\n", "0xbd127ea4434f9fb5,\n", "0xbcfa20dab6b920e9,\n", "0x3c93389d892643a0,\n", "0x3c7550b88147fd02,\n", "],\n", "[\n", "0xba96582ab366c758,\n", "0x3fc0230ba90f2871,\n", "0xbf59ca16f0c9734e,\n", "0xbf9579c1bdbcfc99,\n", "0x3f3120ecfac5c017,\n", "0x3f511dd26bbe2946,\n", "0xbeeb37e7c9a57147,\n", "0xbef9f01e7c19098c,\n", "0x3e94887fe7a88a4d,\n", "0x3e96e3723883fe87,\n", "0xbe3204b644d485a1,\n", "0xbe2a659b13b69c6b,\n", "0x3dc4a40c8498625a,\n", "0x3db56f0212f628e4,\n", "0xbd50a0fef4ac5a44,\n", "0xbd39d1d92cf50973,\n", "0x3cd3d93917ae0666,\n", "0x3cb7c222c421cbf8,\n", "0xbc518e27cddeecfd,\n", "],\n", "[\n", "0x3fbfab0b166d23d8,\n", "0x3ae50cd9856106aa,\n", "0xbfafa65c1ce7ebd6,\n", "0x3f4035bf503ffc1f,\n", "0x3f750d1b04713c41,\n", "0xbf09cd14a92842a1,\n", "0xbf265d504af5d8fe,\n", "0x3ebd3feeb33d9cae,\n", "0x3ec96a257062f750,\n", "0xbe61254f302b04d0,\n", "0xbe61f11585e02bfc,\n", "0x3df89a7674827723,\n", "0x3df13f0ba458182e,\n", "0xbd87d67ae3559fb7,\n", "0xbd78038124810666,\n", "0x3d10a3cffab7b16e,\n", "0x3cf952a4679b4020,\n", "0xbc9158ffabf6b26f,\n", "0xbc74b2e8c7ca451f,\n", "],\n", "[\n", "0x3a9422b204fbf27f,\n", "0xbfbf13fb0c0e6fcd,\n", "0x3f5706ed3d935d00,\n", "0x3f94af74cbd77bef,\n", "0xbf2e9a9e66e5a792,\n", "0xbf507ec9ed824fcb,\n", "0x3ee856d4518ab29c,\n", "0x3ef9040de830648a,\n", "0xbe9262f69c56c4a2,\n", "0xbe9618c94a54555e,\n", "0x3e3029d2c8bd8b0e,\n", "0x3e2983bca06d479e,\n", "0xbdc28e29fd7e309a,\n", "0xbdb4beea8ebaabe8,\n", "0x3d4df87d00b82fa1,\n", "0x3d39076f370434b4,\n", "0xbcd1ef67bd03c16c,\n", "0xbcb7115a994eb5d5,\n", "0x3c4fd28ad1effa7c,\n", "],\n", "[\n", "0xbfbe891b327da16d,\n", "0xbae325aba995f36e,\n", "0x3fae8533ce07bdb8,\n", "0xbf3d1253218e31b0,\n", "0xbf744e6826476498,\n", "0x3f07271a9b5e3cb4,\n", "0x3f2595b697c8ec04,\n", "0xbeba46b03ecb3892,\n", "0xbec88c173e076203,\n", "0x3e5ed9b1754f626a,\n", "0x3e615891ef312cd4,\n", "0xbdf62ca3527c988f,\n", "0xbdf0b14767922479,\n", "0x3d85879b58ff9d05,\n", "0x3d7745bb7346aea9,\n", "0xbd0e20fb122a7c2a,\n", "0xbcf89354d05f7b8c,\n", "0x3c8f7da941b1f5c8,\n", "0x3c741ef462ba56a3,\n", "],\n", "[\n", "0xba923c4506ec812e,\n", "0x3fbe018dac1c17e3,\n", "0xbf54b994dd05c1fb,\n", "0xbf93f9e0db07e7ef,\n", "0x3f2b8e55b75b13ab,\n", "0x3f4fdf68a78bb3d2,\n", "0xbee5ee9d17106a07,\n", "0xbef82ee6dfdfedd8,\n", "0x3e90962d7f6d601e,\n", "0x3e9560edce7d4b08,\n", "0xbe2d34381cff4d39,\n", "0xbe28b5a0e715b17d,\n", "0x3dc0cab951aa6b0b,\n", "0x3db41d218be1cc79,\n", "0xbd4b2d2a51de7089,\n", "0xbd384c06737cf8d9,\n", "0x3cd04c96e113bd0a,\n", "0x3cb66c4b3dc74284,\n", "0xbc4cfe4908cedcb8,\n", "],\n", "[\n", "0x3fbd84391bb2748d,\n", "0x3ae17f232c3596e7,\n", "0xbfad80edb3c4ea05,\n", "0x3f3a431f5421f7ef,\n", "0x3f73a282fe7b63a8,\n", "0xbf04ed653e607bdc,\n", "0xbf24e15832bda3c4,\n", "0x3eb7c5832dd13719,\n", "0x3ec7c2b80da8df7e,\n", "0xbe5bf160ccd30135,\n", "0xbe60cda2141b0afb,\n", "0x3df41d31d25837e8,\n", "0x3df02f6ca822716e,\n", "0xbd83901f0d351db4,\n", "0xbd7696cdd91c27b7,\n", "0x3d0b6e1487e46414,\n", "0x3cf7e1bb61dba0fc,\n", "0xbc8cbb194749390a,\n", "0xbc7394699d841c82,\n", "],\n", "[\n", "0x3a909e71c2163ed3,\n", "0xbfbd09b21e36c0bd,\n", "0x3f52c84acfb586b4,\n", "0x3f9355b904fbf7ee,\n", "0xbf28fb570465af0d,\n", "0xbf4edc3292ba6cfd,\n", "0x3ee3e552ee8c2575,\n", "0x3ef76d44f6a83510,\n", "0xbe8e1ee2dc4a3910,\n", "0xbe94b944bbd4ab57,\n", "0x3e2a8c3a4ce04c1b,\n", "0x3e27f8c9ef133245,\n", "0xbdbe92957079603b,\n", "0xbdb388138abed52f,\n", "0x3d48c7ca6d80cb32,\n", "0x3d379e45475751e8,\n", "0xbccdc773f7abde68,\n", "0xbcb5d2331c76adb9,\n", "0x3c4a8aa5ca753696,\n", "],\n", "[\n", "0xbfbc97d79918527d,\n", "0xbae4d780a21f2057,\n", "0x3fac95081ab2b511,\n", "0xbf37e0b14f7d7c3f,\n", "0xbf730688f6836a76,\n", "0x3f030941f6e78e36,\n", "0x3f243d5898657a6f,\n", "0xbeb5a39a94f2ad1c,\n", "0xbec70b18406146b4,\n", "0x3e597607f952cd69,\n", "0x3e604e788f4f18d9,\n", "0xbdf2598918fbb9ee,\n", "0xbdef701541acccd2,\n", "0x3d81df5bcb47b899,\n", "0x3d75f524c73bc009,\n", "0xbd0919aede2dcbf2,\n", "0xbcf73c65c9ce91ed,\n", "0x3c8a553df0f1b569,\n", "0x3c72fe9f3f0dcae2,\n", "],\n", "];\n" ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = 2 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(y1_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 250;\n", "bessel_y1 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_y1(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RR(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "degree = 18\n", "\n", "print(f\"pub(crate) static Y1F_COEFFS: [[u64; {degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print(\"[\")\n", " for c in coeffs:\n", " print(double_to_hex(c) + \",\")\n", " print(\"],\")\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 60, "id": "cec2c64b-9ef9-4242-bf7b-0abc24a8adbe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y1F_COEFFS: [[u64; 29]; 32] = [\n", "[\n", "0x0000000000000000,\n", "0x3fe0aa48442f014b,\n", "0xbfbe56f82217b8f1,\n", "0xbfa0d2af4e932386,\n", "0xbf73a6dec37290aa,\n", "0x3f7e671c7d1196fd,\n", "0xbf65429dc5a45612,\n", "0x3f517ab4afac0735,\n", "0xbf40b2d877d5a29c,\n", "0x3f2eea7bbb907646,\n", "0xbf1c3fae3b0ad706,\n", "0x3f09d174c9ccecd9,\n", "0xbef7956ad3fe9783,\n", "0x3ee5865d11ebb14d,\n", "0xbed3a27f1fd4ac6e,\n", "0x3ec1e742c1cf6acb,\n", "0xbeb051d134cb0a72,\n", "0x3e9dbea846629267,\n", "0xbe8b1a1682f5eb1f,\n", "0x3e78b0b08d8ccddf,\n", "0xbe667d8a7cc18981,\n", "0x3e547c0e174bc402,\n", "0xbe42a7fb50d94c09,\n", "0x3e30fd661ade45f0,\n", "0xbe1ef1655b283bca,\n", "0x3e0c2d21fe733c5f,\n", "0xbdf9a7efb711afac,\n", "0x3de75c3fc5194fe2,\n", "0xbdd544fd359e8d1a,\n", "],\n", "[\n", "0x3fdaabb4011ed330,\n", "0x0000000000000000,\n", "0xbfc8b45babe797ba,\n", "0x3f8e147099a6f0ea,\n", "0x3f88c5af1eeb2d6b,\n", "0xbf4133fa47da52e2,\n", "0xbf3bf8af93ff0b8c,\n", "0x3f021d64be62ccf9,\n", "0x3eb44d2ce67b2d18,\n", "0x3eb14c3ab2ad79cc,\n", "0xbe9b8eee52e1ce01,\n", "0x3e7a85f1a878746a,\n", "0xbe5bf86b3c89849b,\n", "0x3e3f01920a1ecb6b,\n", "0xbe20fac544c5a674,\n", "0x3e02818841d3a289,\n", "0xbde42b5ceddd3872,\n", "0x3dc5f9472a38633d,\n", "0xbda7ed484e6442ee,\n", "0x3d8a0b10351f65a6,\n", "0xbd6c567ba5000a2c,\n", "0x3d4ed39e06bafa8a,\n", "0xbd30c36f7f68d190,\n", "0x3d123a81488a8c60,\n", "0xbcf3d198a043957c,\n", "0x3cd58b80d1da3cb2,\n", "0xbcb76b414bca83a9,\n", "0x3c99742311b12a8a,\n", "0xbc7ba9b697b16de5,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfd5c7c556f0c19a,\n", "0x3fa00b9f8571ca1f,\n", "0x3faa15d92dfe3e27,\n", "0xbf710a329e2c23fa,\n", "0xbf61be6db9923acf,\n", "0x3f2337c7e138f484,\n", "0x3f085b940eb607f9,\n", "0xbec80619147b78f2,\n", "0xbea255e6cf70cf33,\n", "0x3e5b62cd02014989,\n", "0x3e380b1aac007d1d,\n", "0xbdfa7ee05a568fe6,\n", "0x3d84065ca5f23bb5,\n", "0xbd93847684c7da93,\n", "0x3d74980895b5067a,\n", "0xbd4c00f7d6be89d7,\n", "0x3d2402fd58efd6fd,\n", "0xbcfded82b76f72f2,\n", "0x3cd6380d6ba31980,\n", "0xbcb06b38ec70e0a6,\n", "0x3c88443f14394c1d,\n", "0xbc61ee2105252260,\n", "0x3c3a7c72c37961bf,\n", "0xbc138e5e595f9137,\n", "0x3becdf0d22c4f792,\n", "0xbbc54e9dcbced4f1,\n", "0x3b9f718438e6ba2f,\n", "0xbb773276f637119d,\n", "],\n", "[\n", "0xbfd36732d4b96094,\n", "0x0000000000000000,\n", "0x3fc3001c8002caf8,\n", "0xbf7bf5a03bab4999,\n", "0xbf8751ea028c1953,\n", "0x3f423874cd8d0401,\n", "0x3f364f6610d64939,\n", "0xbef02978de3838b9,\n", "0xbed72f0766d0d591,\n", "0x3e8f2081874c7e33,\n", "0x3e6defd5dce00666,\n", "0xbe2205c6fe8f26fd,\n", "0xbdfb6432e005a435,\n", "0x3db0289fce476883,\n", "0x3d80778a2d37fe43,\n", "0xbd29723fe5684800,\n", "0xbd082f3f70663f33,\n", "0x3cc7a09f40ec7306,\n", "0xbc85319ec342127c,\n", "0x3c62d63483483be2,\n", "0xbc38c3ecf9381019,\n", "0x3c0ba15f09ca6382,\n", "0xbbdf92174ea83693,\n", "0x3bb25604c3a40365,\n", "0xbb853b55eb1a54fe,\n", "0x3b5889d72e8200c6,\n", "0xbb2c5b6e1cc194ec,\n", "0x3b0061d24b95ed7a,\n", "0xbad2ec48f5a0d298,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fd15f993fceab5c,\n", "0xbf902b3933cf21b1,\n", "0xbfa6395dfe49fcd4,\n", "0x3f63ced2a2e69180,\n", "0x3f607a678d6000bb,\n", "0xbf1b50d7e1d32020,\n", "0xbf06f7bab104f355,\n", "0x3ec176e72bf94b8f,\n", "0x3ea2becb2b6bbc6d,\n", "0xbe5a384eebfe1367,\n", "0xbe341e7a923c3a90,\n", "0x3de9e3284f5dd101,\n", "0x3dbec40b623ea350,\n", "0xbd726868b83f8d7d,\n", "0xbd416f7ae80cad77,\n", "0x3cf318658ecb9bd5,\n", "0x3cbfacabdbabe483,\n", "0xbc713cc1f6930364,\n", "0xbc33cb94044d8aee,\n", "0x3bda22029099f534,\n", "0x3bb47d9b88989e97,\n", "0xbb745299177606ed,\n", "0x3b3503d9701ead82,\n", "0xbb08176b7514ca80,\n", "0x3ad863cb123482cb,\n", "0xbaa6552586051784,\n", "0x3a74afbafce97c21,\n", "0xba435b67b2348d11,\n", "],\n", "[\n", "0x3fd00ef3745e0e3c,\n", "0x0000000000000000,\n", "0xbfbfcdacdda138f2,\n", "0x3f706cc34cd829fa,\n", "0x3f84641bb10c16cb,\n", "0xbf37fac943e2a16d,\n", "0xbf34769ed32e14a2,\n", "0x3ee80608ecda1520,\n", "0x3ed5cc8242d77e79,\n", "0xbe888c8f253923cc,\n", "0xbe6ce5908c1f1376,\n", "0x3e1ed1625825eeeb,\n", "0x3dfa30d624f10edf,\n", "0xbdaa50765ef82dbe,\n", "0xbd814cd364ef8287,\n", "0x3d306199db2399a2,\n", "0x3d0164150f087360,\n", "0xbcaefb1085d3b5a6,\n", "0xbc7ba1419f5a6f40,\n", "0x3c27638ccf29c1b0,\n", "0x3bf18a62dccdca9d,\n", "0xbb9b54a4a2d7343a,\n", "0xbb635931e0eacdee,\n", "0x3b1036817e50e3af,\n", "0x3aca87e3e3debd9e,\n", "0xba44ec6558f8bb31,\n", "0xba4d684c0820785d,\n", "0x3a0f0d58bca1c41b,\n", "0xb9d3324adb1198fb,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfcdc14ea14e89f9,\n", "0x3f84429fef5b5fbd,\n", "0x3fa367d7d608e4ba,\n", "0xbf59d6eb2bc49e35,\n", "0xbf5dc4f991b3db86,\n", "0x3f1315ec04d6e6bc,\n", "0x3f0571814a1aa301,\n", "0xbeba2977fa42f227,\n", "0xbea1e86423086328,\n", "0x3e54a7b82d41f690,\n", "0x3e3390660a1bb74c,\n", "0xbde549e8b3ed12f4,\n", "0xbdbe32cf77b347a3,\n", "0x3d6eff58d55a39fb,\n", "0x3d415e5c0af749d4,\n", "0xbcf0d67f939f4917,\n", "0xbcbef3f2afde9972,\n", "0x3c6c60ed345061d2,\n", "0x3c360519c76d6d8a,\n", "0xbbe324831e767061,\n", "0xbba99201cd6f64ed,\n", "0x3b55120660d9db07,\n", "0x3b18d03fd947900e,\n", "0xbac397b2f45393ab,\n", "0xba840af84bf4566b,\n", "0x3a2d23b6405995b9,\n", "0x39ee07cb3c4c18f5,\n", "0xb998bdd233710fab,\n", "],\n", "[\n", "0xbfcc075da85beb4f,\n", "0x0000000000000000,\n", "0x3fbbdeb6ff9f55e1,\n", "0xbf661eefb74da882,\n", "0xbf8229ea914b846e,\n", "0x3f30cbcc6778fd37,\n", "0x3f32aa59f5091f7b,\n", "0xbee1c15d5251ae6a,\n", "0xbed4583f15abd692,\n", "0x3e831d151a1284aa,\n", "0x3e6b74e57c226d3c,\n", "0xbe19044f1378d3e4,\n", "0xbdf93b1ec7cafe33,\n", "0x3da61a4e89bf8438,\n", "0x3d80d430f7e78fff,\n", "0xbd2c3b0a8f7a7b0e,\n", "0xbd010e773677ab43,\n", "0x3cab59410f7e6f10,\n", "0x3c7b2e693f06a801,\n", "0xbc24d1b6b5dbdd8a,\n", "0xbbf17c6418e80b27,\n", "0x3b999a3de4a881f9,\n", "0x3b628ca7ea60d3ed,\n", "0xbb09f8cd292fbd53,\n", "0xbad0840446d9db33,\n", "0x3a7627f31e8af8f1,\n", "0x3a38fffe9d4c8a9c,\n", "0xb9e006ef0777e888,\n", "0xb9a065411b7d93bb,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fca7022be084d99,\n", "0xbf7c650b6b83109a,\n", "0xbfa163191c30aa62,\n", "0x3f526b045287ddca,\n", "0x3f5b17602840abf5,\n", "0xbf0c0a9cee3c842a,\n", "0xbf03e398cbc472ea,\n", "0x3eb3f35db1ff1b8e,\n", "0x3ea0e9b612dbd385,\n", "0xbe5056babcd9632b,\n", "0xbe32c1a8c8f963a5,\n", "0x3de161b6aa9fde63,\n", "0x3dbd4caa1e0162bc,\n", "0xbd69fdda132e53b1,\n", "0xbd4101c31e1df223,\n", "0x3cecdc25a81e55f3,\n", "0x3cbe87025cca1380,\n", "0xbc68c602211c7544,\n", "0xbc35d4a3a29a7da9,\n", "0x3be0f3be0d4b8ee0,\n", "0x3ba97a197d3cf12a,\n", "0xbb52f220fc5e4bf1,\n", "0xbb18bb200c3f6737,\n", "0x3ac1a0fc9e585d08,\n", "0x3a8449eb5d1ccd0b,\n", "0xba2bc209d14d289f,\n", "0xb9ec816d53cd34ad,\n", "0x3992bab6d9003fb7,\n", "],\n", "[\n", "0x3fc931a5a0ae5aa0,\n", "0x0000000000000000,\n", "0xbfb919c8a3f203fa,\n", "0x3f602a38da6262a9,\n", "0x3f807ced48910819,\n", "0xbf2900f33a00690a,\n", "0xbf31278d46fd153c,\n", "0x3edb2595529cf1c7,\n", "0x3ed2f7c2d608e0eb,\n", "0xbe7e212d2378b576,\n", "0xbe69f3fcf3638b5a,\n", "0x3e144fbf0377cdfa,\n", "0x3df82268e83f4ed0,\n", "0xbda26cc2b02dc737,\n", "0xbd80418bae8bbc48,\n", "0x3d2812815e643e0a,\n", "0x3d009b2ac849ff66,\n", "0xbca7c55d0a6d0728,\n", "0xbc7aa167b939df6b,\n", "0x3c22645687164ddf,\n", "0x3bf137648ca710a0,\n", "0xbb96ed64da2728ee,\n", "0xbb62564f89aafafd,\n", "0x3b0789c5abd21586,\n", "0x3ad05f7f4ebd3555,\n", "0xba7442d6813292c4,\n", "0xba38df199441f62a,\n", "0x39ddaedad9d103ec,\n", "0x39a0449ffb72e4c0,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc80781c32422e7,\n", "0x3f754eda697a0098,\n", "0x3f9fbe6df840847f,\n", "0xbf4be318d61276e1,\n", "0xbf58efee4094379c,\n", "0x3f059145b4f0e4de,\n", "0x3f0282d26a74c38e,\n", "0xbeaf56c29d9ad959,\n", "0xbe9fdd03174f902a,\n", "0x3e4a44a7907fee59,\n", "0x3e31df65332ab3e4,\n", "0xbddc96e9cf361a43,\n", "0xbdbc3439f3fac67e,\n", "0x3d65d38ae50afdda,\n", "0x3d40833ea1f83461,\n", "0xbce8afb70fb3c9e8,\n", "0xbcbdda411e59ed8f,\n", "0x3c65889665db09a8,\n", "0x3c35792846a5c5e9,\n", "0xbbdde1c2aac4bc04,\n", "0xbba92deda741b574,\n", "0x3b50e62611579a41,\n", "0x3b18898163cacd25,\n", "0xbabfc6f37553b483,\n", "0xba843147e449ee48,\n", "0x3a293dd77e784298,\n", "0x39ec7209a4872362,\n", "0xb9912bb6b7e0baa6,\n", "],\n", "[\n", "0xbfc713fc51664c74,\n", "0x0000000000000000,\n", "0x3fb7049760cde490,\n", "0xbf58ef5f1cbe4874,\n", "0xbf7e5f53caf3bead,\n", "0x3f237b0b62ddadd1,\n", "0x3f2fd3bac08286da,\n", "0xbed5789803de3afe,\n", "0xbed1c0faa89993b9,\n", "0x3e7845b49b0674ba,\n", "0x3e6886872801396c,\n", "0xbe10b036779ac071,\n", "0xbdf7049d18354c88,\n", "0x3d9edd9d0fb2ebd2,\n", "0x3d7f44600957fa58,\n", "0xbd2486b1d6a91df8,\n", "0xbd0016025abd20b4,\n", "0x3ca498b3d1754fd7,\n", "0x3c79f47baf518ec1,\n", "0xbc2029b685b728de,\n", "0xbbf0ddbdab448097,\n", "0x3b94667d2d37a045,\n", "0x3b620a8a21b80dcb,\n", "0xbb052c2caec48eea,\n", "0xbad02a81f53376b9,\n", "0x3a7266275dfcd434,\n", "0x3a38a1141391318a,\n", "0xb9db2e3c29487cd8,\n", "0xb9a026227f1d2f6d,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc62d94d97e859c,\n", "0xbf70bf614807033c,\n", "0xbf9d5f857a2a6107,\n", "0x3f46081b0b7fe572,\n", "0x3f57307b03e248f8,\n", "0xbf0132c0aa83d0dc,\n", "0xbf0154ed4598d2f0,\n", "0x3ea94f64f476e615,\n", "0x3e9e12725853a9fb,\n", "0xbe4588c758dfc8ab,\n", "0xbe31021cdd9b5f7f,\n", "0x3dd7cfa7a6c26b53,\n", "0x3dbb0e011d23f5e3,\n", "0xbd6276cc0fa65a6a,\n", "0xbd3fe92f0882b440,\n", "0x3ce53126d86bf487,\n", "0x3cbd07f6c1993c8c,\n", "0xbc62bc249a86f7c9,\n", "0xbc34ffb4f0789e1c,\n", "0x3bda504d6417aae1,\n", "0x3ba8bd8d3bf76896,\n", "0xbb4e157fb142efc6,\n", "0xbb1834ef259f93cb,\n", "0x3abc8e7b497b27c6,\n", "0x3a83fd162f3a5584,\n", "0xba26e0585c2f983a,\n", "0xb9ec3d3ba73f49c5,\n", "0x398f5bc57aacdc58,\n", "],\n", "[\n", "0x3fc56b97f8091ac5,\n", "0x0000000000000000,\n", "0xbfb560fcc8c08469,\n", "0x3f53fafa39618883,\n", "0x3f7c49141623372f,\n", "0xbf1f69980694fd17,\n", "0xbf2dc5f848aa9d34,\n", "0x3ed178fc979b77bd,\n", "0x3ed0b494a4bafcc7,\n", "0xbe73fc3884c2743a,\n", "0xbe673afb9fb4d844,\n", "0x3e0bd90346a3e0ed,\n", "0x3df5f3bafb215b44,\n", "0xbd9a1c27c37569c8,\n", "0xbd7e0455dbf9cc4f,\n", "0x3d2199b19fcacda0,\n", "0x3cff1334609dc3bd,\n", "0xbca1e37265d5ce04,\n", "0xbc79353f1aee0a50,\n", "0x3c1c68e4abc12011,\n", "0x3bf075c553243bdb,\n", "0xbb921f6f50442923,\n", "0xbb61ae48340c53aa,\n", "0x3b02fdf33e2b9584,\n", "0x3acfcd13a6548328,\n", "0xba70a5f4affbe604,\n", "0xba384ccca4432680,\n", "0x39d8c95636d09811,\n", "0x399ff36c30c5594c,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc4b2a38f1ab9b4,\n", "0x3f6b3878aadeb34d,\n", "0x3f9b750d89a9b35f,\n", "0xbf41f6911725a956,\n", "0xbf55beee6fd51c8a,\n", "0x3efc3625d7a65089,\n", "0x3f005375a588a72b,\n", "0xbea4ee5e4e7cb18b,\n", "0xbe9c7b3d81b5ff94,\n", "0x3e41fce14f48518c,\n", "0x3e30346643c9d86e,\n", "0xbdd41c861bc1c34b,\n", "0xbdb9eeda214eabbe,\n", "0x3d5f8cf277ce6338,\n", "0x3d3ec46e14cd5d9e,\n", "0xbce2500181b463c7,\n", "0xbcbc24c2b350e45a,\n", "0x3c605d9c149f1b8a,\n", "0x3c34752e1249314b,\n", "0xbbd73842b12b31ea,\n", "0xbba83594fd823055,\n", "0x3b4acb92f062a2fd,\n", "0x3b17c779242729e1,\n", "0xbab9a6de3d6e1877,\n", "0xba83b3c68747091c,\n", "0x3a24b55c31763430,\n", "0x39ebeab3c6cb6a58,\n", "0xb98c95e05b27e740,\n", "],\n", "[\n", "0xbfc413644356a52b,\n", "0x0000000000000000,\n", "0x3fb40bb88c6f2b85,\n", "0xbf5078d13cfc400e,\n", "0xbf7a9191262ab9d5,\n", "0x3f1a005297618f35,\n", "0x3f2c0cbad847a60e,\n", "0xbecd1a72e7c35fd8,\n", "0xbecf9a2654099c40,\n", "0x3e70c6b06e20fcbe,\n", "0x3e66136d6425ea74,\n", "0xbe07977677c6badc,\n", "0xbdf4f77b3143a31f,\n", "0x3d965720b0a36de3,\n", "0x3d7cd126dc5db8d4,\n", "0xbd1e6d575a54f608,\n", "0xbcfdfb4d0beacd2f,\n", "0x3c9f3cccbe3a6b08,\n", "0x3c786f5c7a82aa3d,\n", "0xbc190b8ec99be279,\n", "0xbbf0061c1563865c,\n", "0x3b901f2cce387f59,\n", "0x3b61476b2aa5f9cd,\n", "0xbb010995cf568203,\n", "0xbacf2f8eadcda35c,\n", "0x3a6e19ecc98ab1c0,\n", "0x3a37e713fd44413e,\n", "0xb9d6910a2ab8996f,\n", "0xb99f834c970b77da,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc37aaceac987b9,\n", "0xbf66afe4fe0bc0f7,\n", "0xbf99de7a33bc3a97,\n", "0x3f3e024f567ac487,\n", "0x3f548843c426abe0,\n", "0xbef7a8e14711c0f5,\n", "0xbefeeceb341ad833,\n", "0x3ea1a743e05b39ca,\n", "0x3e9b143d39c90dd5,\n", "0xbe3e8e00012321d3,\n", "0xbe2ef28e323e7496,\n", "0x3dd137a1bf5bde2c,\n", "0x3db8e087c7cb7f1d,\n", "0xbd5b3dc9dd36d846,\n", "0xbd3da6ae03deea14,\n", "0x3cdfe64e83599736,\n", "0x3cbb3e899a8275b8,\n", "0xbc5cc15471c3a791,\n", "0xbc33e34956740ffd,\n", "0x3bd491cabcac2ce3,\n", "0x3ba7a07e1fc0dd64,\n", "0xbb47ecb9d1547f7f,\n", "0xbb174a2cfb1be55e,\n", "0x3ab712c909b7eb19,\n", "0x3a835bca00a6162a,\n", "0xba22c13871e75a28,\n", "0xb9eb82223e5c0790,\n", "0x398a0d72ea78cfb2,\n", "],\n", "[\n", "0x3fc2f4e70d6c7e01,\n", "0x0000000000000000,\n", "0xbfb2ef24d6f7526a,\n", "0x3f4bc33c9dc6ec82,\n", "0x3f7920414ee2acbe,\n", "0xbf15f9173916a219,\n", "0xbf2a94fdbdcec471,\n", "0x3ec8b309990f950c,\n", "0x3ece087ff4517c02,\n", "0xbe6ca22ab12cb4b7,\n", "0xbe650d1f28635cda,\n", "0x3e04441552e259a7,\n", "0x3df411b8a8258957,\n", "0xbd9354e914c31b45,\n", "0xbd7bb16f111ebae7,\n", "0x3d1a888536e27439,\n", "0x3cfced726c1026c9,\n", "0xbc9b745d75ff6377,\n", "0xbc77aaea63220bec,\n", "0x3c162ef6548b0ef1,\n", "0x3bef27eac447efa0,\n", "0xbb8cc635a651ed03,\n", "0xbb60db1d9fbb3868,\n", "0x3afea050ba5a6c00,\n", "0x3ace84aeda9b4b7b,\n", "0xba6b3ca6e927e7ca,\n", "0xba37754b584db1b4,\n", "0x39d48c23ea283d56,\n", "0x399f01c71ecf182b,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc2740819f1caaa,\n", "0x3f6349369dc780bb,\n", "0x3f98868d7401bf2e,\n", "0xbf398cd1bebe1445,\n", "0xbf537eef9aadeee2,\n", "0x3ef43394c95b2d2b,\n", "0x3efd6dfcdb026028,\n", "0xbe9e448fbc8a1f43,\n", "0xbe99d764ee07c839,\n", "0x3e3a53958c8d74ff,\n", "0x3e2da0e1c8a08d37,\n", "0xbdcdd7f918de776f,\n", "0xbdb7e68037d5c861,\n", "0x3d57c2e63bbe27ca,\n", "0x3d3c973a175ffbb6,\n", "0xbcdc033788921736,\n", "0xbcba5d9f2bdd8af3,\n", "0x3c596cb946e78db0,\n", "0x3c335090afbe104f,\n", "0xbbd24f9089431e12,\n", "0xbba7060105333e1d,\n", "0x3b457032c08fa72b,\n", "0x3b16c43d570a329d,\n", "0xbab4ce5eeb2252e9,\n", "0xba82fa99d3f60727,\n", "0x3a21035a54fa4f71,\n", "0x39eb0a7a1202f74d,\n", "0xb987c4181cb159cb,\n", "],\n", "[\n", "0xbfc20198200b699d,\n", "0x0000000000000000,\n", "0x3fb1fd242a74e630,\n", "0xbf47cf261dfbf19a,\n", "0xbf77e4820ec1dde4,\n", "0x3f12e1bd281dfcbb,\n", "0x3f2950bb06c6fdf9,\n", "0xbec54a38ab6af546,\n", "0xbecca94f38024fdc,\n", "0x3e68c7e75971c85c,\n", "0x3e6423fc7e251ca9,\n", "0xbe019fe1d8e51b96,\n", "0xbdf34198c795142c,\n", "0x3d90e78cdab26dd9,\n", "0x3d7aa74cb5ba4b0e,\n", "0xbd1756ee8369797d,\n", "0xbcfbee3ccbac62a4,\n", "0x3c984c93627c1364,\n", "0x3c76ecd2977e750f,\n", "0xbc13c1ad2197e738,\n", "0xbbee45c9096ecdab,\n", "0x3b89c8e8d1127213,\n", "0x3b606d492670f0ba,\n", "0xbafb9c058bf87bc8,\n", "0xbacdd33a39371327,\n", "0x3a68b21edf0d733b,\n", "0x3a36fc3cd1a4c613,\n", "0xb9d2bb8db2dfce26,\n", "0xb99e748406456732,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc192f2627a74e3,\n", "0xbf60a846a83fecf2,\n", "0xbf975eceaabf7f86,\n", "0x3f3617c581be35b1,\n", "0x3f529934b7a84483,\n", "0xbef18123e875188a,\n", "0xbefc1f05a2d85165,\n", "0x3e9a4e0bc0926544,\n", "0x3e98be81ad44d933,\n", "0xbe36f73795e25c01,\n", "0xbe2c70ab158cd19a,\n", "0x3dca262190472d9a,\n", "0x3db70112aab52bc2,\n", "0xbd54ec163f88c02f,\n", "0xbd3b991575a9daff,\n", "0x3cd8cbabadfd45c5,\n", "0x3cb9867f1ea8526f,\n", "0xbc56a0c58ce9652e,\n", "0xbc32c10fa17839d7,\n", "0x3bd06304545a75ab,\n", "0x3ba66b5f3f801768,\n", "0xbb434a75e18850f7,\n", "0xbb163af2240f11d6,\n", "0x3ab2d27f5aad2f87,\n", "0x3a82947c379d043b,\n", "0xba1ef0cd1e11d5d6,\n", "0xb9ea897622f547ac,\n", "0x3985b7a56e26e118,\n", "],\n", "[\n", "0x3fc12f9870d68e18,\n", "0x0000000000000000,\n", "0xbfb12c11811945fa,\n", "0x3f44b638f21f0f76,\n", "0x3f76d2a897d58353,\n", "0xbf10732e5458ba20,\n", "0xbf2835929300df3e,\n", "0x3ec297283816a83b,\n", "0x3ecb73adedf11a43,\n", "0xbe65b455b903f09c,\n", "0xbe6353f0797a6699,\n", "0x3dfefc9ac17b1eeb,\n", "0x3df28535463ce067,\n", "0xbd8dd894cbbee3f9,\n", "0xbd79b288cc392b5b,\n", "0x3d14b2ec9ace070c,\n", "0x3cfaff72f6057832,\n", "0xbc95a7bfada02748,\n", "0xbc7637b7b45ad224,\n", "0x3c11b216f1fba65d,\n", "0x3bed6a4aa25cbcad,\n", "0xbb873661259c7b49,\n", "0xbb6000a243c0a825,\n", "0x3af8faeb08a0872d,\n", "0x3acd2042259aeb3b,\n", "0xba66742de4a4a980,\n", "0xba367fbd4af52810,\n", "0x39d11cea7748dd35,\n", "0x399de0520986210d,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfc0cf3ee98f769b,\n", "0x3f5d26e7af251f79,\n", "0x3f965d05948a946a,\n", "0xbf335959b8482e40,\n", "0xbf51cff175d05c2a,\n", "0x3eeeb59416879106,\n", "0x3efaf7544eeac766,\n", "0xbe9720522bb1fc81,\n", "0xbe97c41261705419,\n", "0x3e343fa0ea5e007d,\n", "0x3e2b5e23abebd7a4,\n", "0xbdc722397e750312,\n", "0xbdb62f2174e6be49,\n", "0x3d5294ab060a163a,\n", "0x3d3aace944141c61,\n", "0xbcd61cc8146cdfa2,\n", "0xbcb8bb3c270a284c,\n", "0x3c54449d96647c28,\n", "0x3c323712fdd32979,\n", "0xbbcd7cedd05f23ee,\n", "0xbba5d3f2f4d18257,\n", "0x3b416f9a8cd62e2d,\n", "0x3b15b1f1d821a3b4,\n", "0xbab116d887db5467,\n", "0xba822c96cd78a74c,\n", "0x3a1c3754078e6137,\n", "0x39ea0388f41538a5,\n", "0xb983e3d577169c43,\n", "],\n", "[\n", "0xbfc077eede4a0d89,\n", "0x0000000000000000,\n", "0x3fb0751548b2924d,\n", "0xbf423b5d46a73864,\n", "0xbf75e2467c8fb832,\n", "0x3f0cfe5c189d6e4d,\n", "0x3f273bbd8c7aef2d,\n", "0xbec06974d3d04287,\n", "0xbeca6081d36e6a2b,\n", "0x3e6334a83cf6092b,\n", "0x3e6299571cb4e1fb,\n", "0xbdfb7f5bc0aada50,\n", "0xbdf1da63b4d6f878,\n", "0x3d8a9288ceccd9f2,\n", "0x3d78d1d74c88ee4c,\n", "0xbd127eed3a482d7f,\n", "0xbcfa2143706ccb79,\n", "0x3c936d1464c4bf11,\n", "0x3c758cc3ad07daa3,\n", "0xbc0fe0c8ce969c5e,\n", "0xbbec97f785528e08,\n", "0x3b84fee6252fe140,\n", "0x3b5f2dcbce169f1a,\n", "0xbaf6b095bc2831d4,\n", "0xbacc6f522af04f90,\n", "0x3a647af3c1c3a557,\n", "0x3a3602a9d860d2a3,\n", "0xb9cf58721d5d6786,\n", "0xb99d48fda4a9df67,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fc0230ba90f2871,\n", "0xbf59ca16f0c9734e,\n", "0xbf9579c1bdbcfc99,\n", "0x3f3120ecfac5c017,\n", "0x3f511dd26bbe2946,\n", "0xbeeb37e7c9a57149,\n", "0xbef9f01e7c1909a0,\n", "0x3e94887fe7a88c2c,\n", "0x3e96e37238841d4b,\n", "0xbe3204b644d6a04b,\n", "0xbe2a659b13eebf8a,\n", "0x3dc4a40c87601c97,\n", "0x3db56f0250e4fcac,\n", "0xbd50a1011bf4a7dd,\n", "0xbd39d22a6dc5a57c,\n", "0x3cd3db0f19da31da,\n", "0x3cb7fc7d4070961b,\n", "0xbc5243aa7bbc81ca,\n", "0xbc31b3c3dd0d783d,\n", "0x3bcaabdcaba1878d,\n", "0x3ba541bb402b78f0,\n", "0xbb3fa915cdaddb2d,\n", "0xbb152ba16ad63ba9,\n", "0x3aaf26322e6939a3,\n", "0x3a81c51fa64eb3db,\n", "0xba19d00760b94df4,\n", "0xb9e97bff11d536c1,\n", "0x3982436a57398b65,\n", "],\n", "[\n", "0x3fbfab0b166d23d8,\n", "0x0000000000000000,\n", "0xbfafa65c1ce7ebd6,\n", "0x3f4035bf503ffc1f,\n", "0x3f750d1b04713c41,\n", "0xbf09cd14a92842a2,\n", "0xbf265d504af5d8fe,\n", "0x3ebd3feeb33d9cee,\n", "0x3ec96a257062f76e,\n", "0xbe61254f302b36b2,\n", "0xbe61f11585e04fca,\n", "0x3df89a7674dd98cd,\n", "0x3df13f0ba48c1692,\n", "0xbd87d67b47fd268e,\n", "0xbd780381812ad9b0,\n", "0x3d10a41213b1209a,\n", "0x3cf9530714f8af8a,\n", "0xbc918884a9ff4796,\n", "0xbc74ec3ce9f29027,\n", "0x3c0cde4ce08c6119,\n", "0x3bebd00bdae20153,\n", "0xbb831454d0bd6f49,\n", "0xbb5e623854cff634,\n", "0x3af4b117674c743f,\n", "0x3acbc2c0ede2286c,\n", "0xba62be3ca56b47a4,\n", "0xba35870a752de79f,\n", "0x39ccc9aaaa2d7785,\n", "0x399cb160d1404bde,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfbf13fb0c0e6fcd,\n", "0x3f5706ed3d935d00,\n", "0x3f94af74cbd77bef,\n", "0xbf2e9a9e66e5a792,\n", "0xbf507ec9ed824fcb,\n", "0x3ee856d4518ab29e,\n", "0x3ef9040de830649e,\n", "0xbe9262f69c56c652,\n", "0xbe9618c94a54734d,\n", "0x3e3029d2c8bf70d6,\n", "0x3e2983bca0a3e67c,\n", "0xbdc28e2a00002a82,\n", "0xbdb4beeacafc4fad,\n", "0x3d4df880e37a5060,\n", "0x3d3907be43054aec,\n", "0xbcd1f10ff685083d,\n", "0xbcb74a1dc71abca4,\n", "0x3c508d41117c93a5,\n", "0x3c313795880a7796,\n", "0xbbc83ea1cebb3c84,\n", "0xbba4b5cc8ded02e2,\n", "0x3b3cdf002471ce45,\n", "0x3b14a97cafad6c19,\n", "0xbaac7f1793e7126e,\n", "0xba815f93ab822e98,\n", "0x3a17b0d93bc7bbc8,\n", "0x39e8f533a6e89c51,\n", "0xb980d0e69df431e0,\n", "],\n", "[\n", "0xbfbe891b327da16d,\n", "0x0000000000000000,\n", "0x3fae8533ce07bdb8,\n", "0xbf3d1253218e31b0,\n", "0xbf744e6826476498,\n", "0x3f07271a9b5e3cb4,\n", "0x3f2595b697c8ec04,\n", "0xbeba46b03ecb38cc,\n", "0xbec88c173e07621e,\n", "0x3e5ed9b1754fbd3c,\n", "0x3e615891ef314e18,\n", "0xbdf62ca352cf904e,\n", "0xbdf0b14767c2b010,\n", "0x3d85879bb4a2a8ac,\n", "0x3d7745bbca5b0e82,\n", "0xbd0e21736ab8469f,\n", "0xbcf893b256068d4e,\n", "0x3c8fd42c80d0363c,\n", "0x3c7455e80611a38d,\n", "0xbc0a4682da825109,\n", "0xbbeb12f0bb38aa78,\n", "0x3b816a7f586e7ed5,\n", "0x3b5d9fa09d2f4600,\n", "0xbaf2f1ad1590d095,\n", "0xbacb1c0038406c42,\n", "0x3a61363c85b6c4db,\n", "0x3a350e3e866a311e,\n", "0xb9ca841b08aca0a3,\n", "0xb99c1b88defd89e5,\n", "],\n", "[\n", "0x0000000000000000,\n", "0x3fbe018dac1c17e3,\n", "0xbf54b994dd05c1fb,\n", "0xbf93f9e0db07e7ef,\n", "0x3f2b8e55b75b13ab,\n", "0x3f4fdf68a78bb3d2,\n", "0xbee5ee9d17106a08,\n", "0xbef82ee6dfdfedeb,\n", "0x3e90962d7f6d61a6,\n", "0x3e9560edce7d682d,\n", "0xbe2d34381d02bdbe,\n", "0xbe28b5a0e74ae0d3,\n", "0x3dc0cab953f05720,\n", "0x3db41d21c68d7ed3,\n", "0xbd4b2d2dd7cb3c52,\n", "0xbd384c5369d2e33d,\n", "0x3cd04e17ab25ece9,\n", "0x3cb6a38e0aef9402,\n", "0xbc4e28099fc927bb,\n", "0xbc30c28e6023fb13,\n", "0x3bc62487323559ca,\n", "0x3ba430a24f21f4b6,\n", "0xbb3a70372a5a35f5,\n", "0xbb142c5d07f39eeb,\n", "0x3aaa2aaf684b8a30,\n", "0x3a80fce718ed7a5e,\n", "0xba15d07c57e5f8fc,\n", "0xb9e870c605b22513,\n", "0x397f0df397c6ab28,\n", "],\n", "[\n", "0x3fbd84391bb2748d,\n", "0x0000000000000000,\n", "0xbfad80edb3c4ea05,\n", "0x3f3a431f5421f7ef,\n", "0x3f73a282fe7b63a8,\n", "0xbf04ed653e607bdd,\n", "0xbf24e15832bda3c4,\n", "0x3eb7c5832dd1374f,\n", "0x3ec7c2b80da8df98,\n", "0xbe5bf160ccd35445,\n", "0xbe60cda2141b2a1e,\n", "0x3df41d31d2a419e4,\n", "0x3df02f6ca850168a,\n", "0xbd83901f61054085,\n", "0xbd7696ce2b748d02,\n", "0x3d0b6e82997a390e,\n", "0x3cf7e214796bec19,\n", "0xbc8d0a3822eede44,\n", "0xbc73c944a2b7aa9b,\n", "0x3c080748c2fd3ed7,\n", "0x3bea608ebfb61101,\n", "0xbb7fee483d06f76f,\n", "0xbb5ce67588df7595,\n", "0x3af168f59e870bd0,\n", "0x3aca7bdf85923387,\n", "0xba5fb7c898747d3e,\n", "0xba349926b4cfc177,\n", "0x39c87ee43e8319a5,\n", "0x399b88e0b427fc4f,\n", "],\n", "[\n", "0x0000000000000000,\n", "0xbfbd09b21e36c0bd,\n", "0x3f52c84acfb586b4,\n", "0x3f9355b904fbf7ee,\n", "0xbf28fb570465af0d,\n", "0xbf4edc3292ba6cfd,\n", "0x3ee3e552ee8c2577,\n", "0x3ef76d44f6a83523,\n", "0xbe8e1ee2dc4a3bda,\n", "0xbe94b944bbd4c7bf,\n", "0x3e2a8c3a4ce36f16,\n", "0x3e27f8c9ef47068e,\n", "0xbdbe9295749ee471,\n", "0xbdb38813c3eb77e4,\n", "0x3d48c7cda44b7754,\n", "0x3d379e90468589ab,\n", "0xbccdca323fb2ed13,\n", "0xbcb6080be2ba756c,\n", "0x3c4b9a8e33ba54fc,\n", "0x3c3054766d105243,\n", "0xbbc44fda8d0857c1,\n", "0xbba3b2575150baf6,\n", "0x3b384ea306ad146b,\n", "0x3b13b4adf072996e,\n", "0xbaa81d1af5c14291,\n", "0xba809dac6fd771cd,\n", "0x3a14269f3ec695f6,\n", "0x39e7efc8823b70ff,\n", "0xb97cc17289b2fc79,\n", "],\n", "[\n", "0xbfbc97d79918527d,\n", "0x0000000000000000,\n", "0x3fac95081ab2b511,\n", "0xbf37e0b14f7d7c3f,\n", "0xbf730688f6836a76,\n", "0x3f030941f6e78e36,\n", "0x3f243d5898657a6f,\n", "0xbeb5a39a94f2ad54,\n", "0xbec70b18406146f7,\n", "0x3e597607f9532274,\n", "0x3e604e788f4f63b9,\n", "0xbdf2598919473e7e,\n", "0xbdef70154273be01,\n", "0x3d81df5c1ca3869c,\n", "0x3d75f5256665e918,\n", "0xbd091a176f7295bc,\n", "0xbcf73cf989310b2d,\n", "0x3c8a9f0a04e769ab,\n", "0x3c7345b205781db7,\n", "0xbc0611e4c0bb0b33,\n", "0xbbe9b88423fdad3a,\n", "0x3b7d637382cff4b7,\n", "0x3b5c36bddd0beae2,\n", "0xbaf00eec29705267,\n", "0xbac9e2beddaac35c,\n", "0x3a5d51fa8552737e,\n", "0x3a342847a5dc8d0a,\n", "0xb9c6b1f64bc800a0,\n", "0xb99afa5762782cbb,\n", "],\n", "];\n" ] } ], "source": [ "mp.prec = 60\n", "terms = 29\n", "print(f\"pub(crate) static Y1F_COEFFS: [[u64; {terms}]; {len(y1_zeros)}] = [\")\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffsf(poly, n):\n", " print(\"[\")\n", " for i in range(0, n):\n", " coeff = poly[i]\n", " print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(y1_zeros)):\n", " k_range = y1_zeros[i]\n", " range_diff = k_range - prev_zero\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, bessely, taylor\n", " poly = taylor(lambda val: bessely(1, val), x0, terms)\n", " # print(poly)\n", " print_taylor_coeffsf(poly, terms)\n", " prev_zero = y1_zeros[i]\n", "\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "5f9d9869-d248-44ed-b7a3-1ad663f37709", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "];\n" ] } ], "source": [ "def compute_intervals(zeros):\n", " intervals = []\n", " for i in range(0, len(zeros)):\n", " if i == 0:\n", " a = 1.95 - zeros[i]\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " elif i + 1 > len(zeros) - 1:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - 0.03 - zeros[i]\n", " b = (zeros[i]) + 0.83 + 0.03 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " else:\n", " a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.03\n", " b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i]\n", " intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i])))\n", " return intervals\n", "\n", "intervals = compute_intervals(y1_zeros)\n", "# print(intervals)\n", "\n", "def build_sollya_script(a, b, zero, deg):\n", " return f\"\"\"\n", "prec = 200;\n", "bessel_y1 = library(\"/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib\");\n", "f = bessel_y1(x + {zero});\n", "d = [{a}, {b}];\n", "pf = remez(f, {deg}, d);\n", "for i from 0 to degree(pf) do {{\n", " write(coeff(pf, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(a, b, zero, degree=12):\n", " sollya_script = build_sollya_script(a, b, zero, degree)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "# def print_remez_coeffs(poly):\n", "# print(\"[\")\n", "# for i in range(len(poly)):\n", "# coeff = poly[i]\n", "# print_double_double(\"\", coeff)\n", "# print(\"],\")\n", "\n", "def print_remez_coeffsd(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " print_dyadic(coeff)\n", " # print_double_double(\"\", coeff)\n", " print(\"],\")\n", "\n", "\n", "# degree = 27\n", "\n", "# print(f\"pub(crate) static Y1_COEFFS: [[(u64, u64); {degree + 1}]; {len(intervals)}] = [\")\n", "# for i in range(0, len(intervals)):\n", "# interval = intervals[i]\n", "# call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", "# coeffs = load_coefficients(f\"coefficients.txt\")\n", "# print_remez_coeffs(coeffs)\n", "# print(\"];\")\n", "\n", "degree = 29\n", "\n", "print(f\"pub(crate) static Y1_COEFFS_RATIONAL128: [[DyadicFloat128; {degree + 1}]; {len(intervals)}] = [\")\n", "for i in range(0, len(intervals)):\n", " interval = intervals[i]\n", " call_sollya_on_interval(interval[0], interval[1], interval[2], degree)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_remez_coeffsd(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "70c43f69-cb27-4b99-b748-3aa58b8d2dd3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static Y1_COEFFS: [[(u64, u64); 28]; 32] = [\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc749367c4c05aaa, 0x3fe0aa48442f014b),\n", "(0xbc58e5288bbf5fe3, 0xbfbe56f82217b8f1),\n", "(0x3c45adcf3e0230ee, 0xbfa0d2af4e932386),\n", "(0xbc1aef581a20d1b6, 0xbf73a6dec37290aa),\n", "(0x3bea0fd3a3179817, 0x3f7e671c7d1196fd),\n", "(0x3bdbfdc1a54825cd, 0xbf65429dc5a45612),\n", "(0x3bf2b56b5db9ac40, 0x3f517ab4afac0735),\n", "(0x3bebebd87be68c3c, 0xbf40b2d877d5a29c),\n", "(0xbbcf3ef5ec675b9a, 0x3f2eea7bbb907646),\n", "(0xbbbc5481911cf1b3, 0xbf1c3fae3b0ad706),\n", "(0xbb97d87196deccbb, 0x3f09d174c9ccecd9),\n", "(0x3b9ce9bed2434862, 0xbef7956ad3fe9783),\n", "(0xbb81a3285733db7f, 0x3ee5865d11ebb14d),\n", "(0x3b7c0f8e48b356f0, 0xbed3a27f1fd4ac6e),\n", "(0xbb601bb903ea5d53, 0x3ec1e742c1cf6acb),\n", "(0xbb208185a8aebef4, 0xbeb051d134cb0a72),\n", "(0x3b2d22383a2945e9, 0x3e9dbea846629267),\n", "(0xbb2d0bd2365f955b, 0xbe8b1a1682f5eb1f),\n", "(0xbb17f54155dbfd8e, 0x3e78b0b08d8ccddf),\n", "(0x3b0c6ae86d8ad6fe, 0xbe667d8a7cc18981),\n", "(0xbaea87f82b9f7fa9, 0x3e547c0e174bc402),\n", "(0x3ae6655ff087a6b2, 0xbe42a7fb50d94c09),\n", "(0xba74f97124d12cda, 0x3e30fd661ade45f0),\n", "(0x3aad4c923a16d045, 0xbe1ef1655b283bca),\n", "(0x3aa6328133433e29, 0x3e0c2d21fe733c5f),\n", "(0xba292d7e82d617f2, 0xbdf9a7efb711afac),\n", "(0xba60d9e2266f470a, 0x3de75c3fc5194fe2),\n", "],\n", "[\n", "(0x3c3c696f3eb0ae77, 0x3fdaabb4011ed330),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc682b7fe4dd90ef, 0xbfc8b45babe797ba),\n", "(0x3bf255e280edf040, 0x3f8e147099a6f0ea),\n", "(0xbbfea368c6887e7f, 0x3f88c5af1eeb2d6b),\n", "(0xbbca04ffe9904e56, 0xbf4133fa47da52e2),\n", "(0xbbd3086cde21e2cb, 0xbf3bf8af93ff0b8c),\n", "(0xbbafa9018f253e3c, 0x3f021d64be62ccf9),\n", "(0x3b3a4d52bc5a61e1, 0x3eb44d2ce67b2d18),\n", "(0xbb48016de8c47acb, 0x3eb14c3ab2ad79cc),\n", "(0x3b28724eeca6e146, 0xbe9b8eee52e1ce01),\n", "(0xbb184699c450d4ac, 0x3e7a85f1a878746a),\n", "(0xbaf5fb00f2f338b7, 0xbe5bf86b3c89849b),\n", "(0x3adf14ae65986334, 0x3e3f01920a1ecb6b),\n", "(0xbac5a8492238e17f, 0xbe20fac544c5a674),\n", "(0x3a972f86dd69da9b, 0x3e02818841d3a289),\n", "(0xba686f565d0da109, 0xbde42b5ceddd3872),\n", "(0x3a540c6129af60a6, 0x3dc5f9472a38633d),\n", "(0xba4276328d0b688c, 0xbda7ed484e6442ee),\n", "(0xba23ab0f9748db4a, 0x3d8a0b10351f65a6),\n", "(0x39d5b91f2ce320af, 0xbd6c567ba5000a2c),\n", "(0x39e0b587d390388d, 0x3d4ed39e06bafa8a),\n", "(0xb9ca4dd40bbdfa57, 0xbd30c36f7f68d190),\n", "(0xb9ae9f2d1d6c950e, 0x3d123a81488a8c60),\n", "(0x39796d1b53f4c705, 0xbcf3d198a043957c),\n", "(0xb97e66e460933260, 0x3cd58b80d1da3cb2),\n", "(0xb95de7856c390662, 0xbcb76b414bca83a9),\n", "(0x3923face03bca6a1, 0x3c99742311b12a8a),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c7b8d2a1c496808, 0xbfd5c7c556f0c19a),\n", "(0xbc370c18fffb661e, 0x3fa00b9f8571ca1f),\n", "(0xbc4e4289c3acba27, 0x3faa15d92dfe3e27),\n", "(0xbbf5a3591cb63f33, 0xbf710a329e2c23fa),\n", "(0xbc0511883ce39919, 0xbf61be6db9923acf),\n", "(0x3bcb8759d4a0e5cd, 0x3f2337c7e138f484),\n", "(0x3ba7299907aec5c4, 0x3f085b940eb607f9),\n", "(0xbb2063eb830ecaea, 0xbec80619147b78f2),\n", "(0xbb4468879e6c349e, 0xbea255e6cf70cf33),\n", "(0xbafc601de5ef1462, 0x3e5b62cd02014989),\n", "(0xbad6adc77b77235d, 0x3e380b1aac007d1d),\n", "(0x3a624f45defeeef1, 0xbdfa7ee05a568fe6),\n", "(0xba283df15edc8775, 0x3d84065ca5f23bb5),\n", "(0xba2c1a2ebca15779, 0xbd93847684c7da93),\n", "(0x3a08225b40e694f7, 0x3d74980895b5067a),\n", "(0xb9eed81f16f01fb8, 0xbd4c00f7d6be89d7),\n", "(0xb9a4e2f268d1912d, 0x3d2402fd58efd6fd),\n", "(0x399973b6338a6d0f, 0xbcfded82b76f72f2),\n", "(0x3978023c06cffc92, 0x3cd6380d6ba31980),\n", "(0xb94735a17d43c8d2, 0xbcb06b38ec70e0a6),\n", "(0x3907f71a9df6b85b, 0x3c88443f14394c1d),\n", "(0xb8f01075b123018b, 0xbc61ee2105252260),\n", "(0xb8b57669955b81a8, 0x3c3a7c72c37961bf),\n", "(0xb8954dc89e6e0348, 0xbc138e5e595f9137),\n", "(0xb87ee16a4e8bff5b, 0x3becdf0d22c4f792),\n", "(0xb86abb1732ed43be, 0xbbc54e9dcbced4f1),\n", "(0xb82e4e62e1a676d6, 0x3b9f718438e6ba2f),\n", "],\n", "[\n", "(0xbc583acf6511df31, 0xbfd36732d4b96094),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc5b435291c33433, 0x3fc3001c8002caf8),\n", "(0x3c085153ba2c907f, 0xbf7bf5a03bab4999),\n", "(0x3c28d66c540219c4, 0xbf8751ea028c1953),\n", "(0x3be6d2f429037cfc, 0x3f423874cd8d0401),\n", "(0xbbb4d7b925522373, 0x3f364f6610d64939),\n", "(0xbb9920eb782e7608, 0xbef02978de3838b9),\n", "(0x3b66c8e5402ae5c0, 0xbed72f0766d0d591),\n", "(0x3b20b724f28fabb4, 0x3e8f2081874c7e33),\n", "(0xbafe89c3eab7b761, 0x3e6defd5dce00666),\n", "(0x3ab712e9adc751d5, 0xbe2205c6fe8f26fd),\n", "(0xba90a1fcff20092c, 0xbdfb6432e005a435),\n", "(0xba40d93a2f6bee54, 0x3db0289fce476883),\n", "(0xba2c7d1344d3ff23, 0x3d80778a2d37fe43),\n", "(0x39a7b4208bcbde0d, 0xbd29723fe5684800),\n", "(0xb9a84df62153f4f5, 0xbd082f3f70663f33),\n", "(0xb91998f4a32b0e4b, 0x3cc7a09f40ec7306),\n", "(0x39256931314bf68c, 0xbc85319ec342127c),\n", "(0x38fd4eda573e2499, 0x3c62d63483483be2),\n", "(0xb8a4a42a37750699, 0xbc38c3ecf9381019),\n", "(0x3893811d88a13751, 0x3c0ba15f09ca6382),\n", "(0xb8653a606cd73ccb, 0xbbdf92174ea83693),\n", "(0x385bcb6c1b8ec617, 0x3bb25604c3a40365),\n", "(0xb82168dd0f69d5f1, 0xbb853b55eb1a54fe),\n", "(0xb7e96fc33c8ede98, 0x3b5889d72e8200c6),\n", "(0xb7b3762a6112ab36, 0xbb2c5b6e1cc194ec),\n", "(0xb78614198a535866, 0x3b0061d24b95ed7a),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c61dc672a53c590, 0x3fd15f993fceab5c),\n", "(0xbc1455aa7db14f38, 0xbf902b3933cf21b1),\n", "(0x3c443ede64b782d9, 0xbfa6395dfe49fcd4),\n", "(0x3be10ad2b71b9820, 0x3f63ced2a2e69180),\n", "(0x3c0f30cad7e0ebe8, 0x3f607a678d6000bb),\n", "(0x3baf8fd02659f1ef, 0xbf1b50d7e1d32020),\n", "(0x3b91fb17827843f5, 0xbf06f7bab104f355),\n", "(0xbb60ab92724984c7, 0x3ec176e72bf94b8f),\n", "(0x3b31557f6e92a4a7, 0x3ea2becb2b6bbc6d),\n", "(0x3aea30e9dd0c4fab, 0xbe5a384eebfe1367),\n", "(0xbad27d53b702d9ee, 0xbe341e7a923c3a90),\n", "(0x3a8be8710ba9cded, 0x3de9e3284f5dd101),\n", "(0xba5a7ff332888842, 0x3dbec40b623ea350),\n", "(0x3a1bb0f2b7e06e32, 0xbd726868b83f8d7d),\n", "(0xb9d127448ae5dbb8, 0xbd416f7ae80cad77),\n", "(0xb98b4267f56d6b60, 0x3cf318658ecb9bd5),\n", "(0x394a28f7ccb2ac45, 0x3cbfacabdbabe483),\n", "(0xb8fdeb4ca08fc098, 0xbc713cc1f6930364),\n", "(0x38c8e1a7a7c446ff, 0xbc33cb94044d8aee),\n", "(0x3846a7a1323190de, 0x3bda22029099f534),\n", "(0x385ab5c5889916dc, 0x3bb47d9b88989e97),\n", "(0x381dfc385d309d52, 0xbb745299177606ed),\n", "(0x37def84f6911654b, 0x3b3503d9701ead82),\n", "(0x3757dbc183f5d86f, 0xbb08176b7514ca80),\n", "(0x3726e80a82be2e11, 0x3ad863cb123482cb),\n", "(0xb7400c9d5c314e72, 0xbaa6552586051784),\n", "(0xb6ed950d76fdf6bc, 0x3a74afbafce97c21),\n", "],\n", "[\n", "(0xbc64f19a2762f5ae, 0x3fd00ef3745e0e3c),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc2a5ca3437ac1c3, 0xbfbfcdacdda138f2),\n", "(0x3c19a8e604f93931, 0x3f706cc34cd829fa),\n", "(0x3c01d3813b5701a3, 0x3f84641bb10c16cb),\n", "(0x3bbd08ac252b4932, 0xbf37fac943e2a16d),\n", "(0xbbd98c55ed55e5ec, 0xbf34769ed32e14a2),\n", "(0xbb8b665d8b88b73b, 0x3ee80608ecda1520),\n", "(0xbb7d207258864fea, 0x3ed5cc8242d77e79),\n", "(0x3b2f5c5f133a954a, 0xbe888c8f253923cc),\n", "(0xbb0d50fa8d8c7a72, 0xbe6ce5908c1f1376),\n", "(0x3abc19806933366e, 0x3e1ed1625825eeeb),\n", "(0x3a969b1553c1a884, 0x3dfa30d624f10edf),\n", "(0x3a41711a2b894301, 0xbdaa50765ef82dbe),\n", "(0x39ef8b9861fc6da9, 0xbd814cd364ef8287),\n", "(0xb9bec99ce5124af1, 0x3d306199db2399a2),\n", "(0x39a24cb0ca5a627f, 0x3d0164150f087360),\n", "(0xb90883d74ed9e2a1, 0xbcaefb1085d3b5a6),\n", "(0x390110bd90901ca7, 0xbc7ba1419f5a6f40),\n", "(0x389f7ac7f08169b1, 0x3c27638ccf29c1b0),\n", "(0xb89f51222b4b42bb, 0x3bf18a62dccdca9d),\n", "(0xb83b3be96059d0b4, 0xbb9b54a4a2d7343a),\n", "(0x38017f10a44ce3ed, 0xbb635931e0eacdee),\n", "(0x37be3118e01854ca, 0x3b1036817e50e3af),\n", "(0xb7657afa36f3f4a9, 0x3aca87e3e3debd9e),\n", "(0x36c384606510e7f7, 0xba44ec6558f8bb31),\n", "(0x36c308ed950cf583, 0xba4d684c0820785d),\n", "(0xb6acfa02e081161c, 0x3a0f0d58bca1c41b),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c54d14c77bc1691, 0xbfcdc14ea14e89f9),\n", "(0x3c2340bd04e7df4a, 0x3f84429fef5b5fbd),\n", "(0x3c4f19a8f5b1379e, 0x3fa367d7d608e4ba),\n", "(0xbbf4eb6bddef363a, 0xbf59d6eb2bc49e35),\n", "(0xbba2f121221c388c, 0xbf5dc4f991b3db86),\n", "(0x3bbf047b90425584, 0x3f1315ec04d6e6bc),\n", "(0x3b9087e84c57d2ad, 0x3f0571814a1aa301),\n", "(0x3b2795eb85278f1d, 0xbeba2977fa42f227),\n", "(0x3b3f92ddd9da4ad7, 0xbea1e86423086328),\n", "(0x3aff19e1c5d9e237, 0x3e54a7b82d41f690),\n", "(0xbad0197985af09ca, 0x3e3390660a1bb74c),\n", "(0x3a8a68e5322dab0d, 0xbde549e8b3ed12f4),\n", "(0x3a500e54fb5a85ec, 0xbdbe32cf77b347a3),\n", "(0xb9d3ea446c95f85a, 0x3d6eff58d55a39fb),\n", "(0x39d1c41d97727556, 0x3d415e5c0af749d4),\n", "(0x3994a6959d259d8b, 0xbcf0d67f939f4917),\n", "(0x3951f0d6f37c7a4e, 0xbcbef3f2afde9972),\n", "(0xb8ce371e6c4a5fb7, 0x3c6c60ed345061d2),\n", "(0xb8ce6598cd4716cf, 0x3c360519c76d6d8a),\n", "(0xb868ddc08c092699, 0xbbe324831e767061),\n", "(0x3820a7a0186edebf, 0xbba99201cd6f64ed),\n", "(0xb7d50b99e3cbd8ed, 0x3b55120660d9db07),\n", "(0x37bd05b3e6de1af6, 0x3b18d03fd947900e),\n", "(0x373b419f47dccb93, 0xbac397b2f45393ab),\n", "(0x371a75815e071b8c, 0xba840af84bf4566b),\n", "(0x36c253d300be5f73, 0x3a2d23b6405995b9),\n", "(0x365d14598eec4332, 0x39ee07cb3c4c18f5),\n", "],\n", "[\n", "(0xbc5a8046704071bd, 0xbfcc075da85beb4f),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc53b0c30f3f6eaa, 0x3fbbdeb6ff9f55e1),\n", "(0x3bef54869c1812be, 0xbf661eefb74da882),\n", "(0xbc20492140a086db, 0xbf8229ea914b846e),\n", "(0xbbc9a664ae9a2c1e, 0x3f30cbcc6778fd37),\n", "(0xbbd8078d46437190, 0x3f32aa59f5091f7b),\n", "(0xbb7b81f3aff07289, 0xbee1c15d5251ae6a),\n", "(0x3b707e9f1d7b7e6a, 0xbed4583f15abd692),\n", "(0xbb2cc9b93ff3f6ce, 0x3e831d151a1284aa),\n", "(0x3b0aa58bdebda7d1, 0x3e6b74e57c226d3c),\n", "(0x3abe0f534111cac9, 0xbe19044f1378d3e4),\n", "(0xba92c7e898648f68, 0xbdf93b1ec7cafe33),\n", "(0x3a314e62ad0639ef, 0x3da61a4e89bf8438),\n", "(0x3a298cd71751f9aa, 0x3d80d430f7e78fff),\n", "(0xb9c643be1c5347dd, 0xbd2c3b0a8f7a7b0e),\n", "(0xb9608e40ab9aafb9, 0xbd010e773677ab43),\n", "(0x3946ed856edf6b25, 0x3cab59410f7e6f10),\n", "(0xb8e86e49965ef8df, 0x3c7b2e693f06a801),\n", "(0xb8bd6df9232d394a, 0xbc24d1b6b5dbdd8a),\n", "(0x389d45bfc9e28c95, 0xbbf17c6418e80b27),\n", "(0x38330cb81415d134, 0x3b999a3de4a881f9),\n", "(0x38014861b029a2c1, 0x3b628ca7ea60d3ed),\n", "(0x3763e7968eedb33e, 0xbb09f8cd292fbd53),\n", "(0xb772e1ee82abca63, 0xbad0840446d9db33),\n", "(0x36eac14fda382bcb, 0x3a7627f31e8af8f1),\n", "(0x36d03dd271f85894, 0x3a38fffe9d4c8a9c),\n", "(0x368992b4a1b37e32, 0xb9e006ef0777e888),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c57ba12cd0fc91f, 0x3fca7022be084d99),\n", "(0xbc17334559c5138c, 0xbf7c650b6b83109a),\n", "(0xbc4d0f8f36713120, 0xbfa163191c30aa62),\n", "(0x3bbcf7c95031f425, 0x3f526b045287ddca),\n", "(0xbbf7b71420f279ea, 0x3f5b17602840abf5),\n", "(0xbb99a95b35521d32, 0xbf0c0a9cee3c842a),\n", "(0xbb91505ce3b29a78, 0xbf03e398cbc472ea),\n", "(0x3b5125ae0677178c, 0x3eb3f35db1ff1b8e),\n", "(0xbb4e582cdfc5009b, 0x3ea0e9b612dbd385),\n", "(0x3ae57a34bc6cd52d, 0xbe5056babcd9632b),\n", "(0x3ad18fdd63164b8f, 0xbe32c1a8c8f963a5),\n", "(0xb9e37fef15ca364c, 0x3de161b6aa9fde63),\n", "(0xba4ed1a8c48bfaf3, 0x3dbd4caa1e0162bc),\n", "(0xba0907496979f354, 0xbd69fdda132e53b1),\n", "(0x39dc92d876d25063, 0xbd4101c31e1df223),\n", "(0xb980f5f389d54392, 0x3cecdc25a81e55f3),\n", "(0xb9476a7e07116985, 0x3cbe87025cca1380),\n", "(0x38f93a72b93872b3, 0xbc68c602211c7544),\n", "(0xb8dd598494fb4eb0, 0xbc35d4a3a29a7da9),\n", "(0x387e1025298516ea, 0x3be0f3be0d4b8ee0),\n", "(0x3829d1ee76262ed4, 0x3ba97a197d3cf12a),\n", "(0xb7f42ff2642fd193, 0xbb52f220fc5e4bf1),\n", "(0xb79a001d511e0971, 0xbb18bb200c3f6737),\n", "(0xb75720aadc56d8cc, 0x3ac1a0fc9e585d08),\n", "(0xb6f810019c65facf, 0x3a8449eb5d1ccd0b),\n", "(0x36c0524fdb6e5bf4, 0xba2bc209d14d289f),\n", "(0xb663781b8b017ac7, 0xb9ec816d53cd34ad),\n", "],\n", "[\n", "(0x3c518b0303bbe2f5, 0x3fc931a5a0ae5aa0),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c348c3f5f957887, 0xbfb919c8a3f203fa),\n", "(0xbc0ef6b166c80aea, 0x3f602a38da6262a9),\n", "(0xbc207165718dd6e6, 0x3f807ced48910819),\n", "(0x3bc68f5ae1c2651e, 0xbf2900f33a00690a),\n", "(0xbbc8c05ccff0a4b4, 0xbf31278d46fd153c),\n", "(0xbb6f62aece58de7b, 0x3edb2595529cf1c7),\n", "(0xbb731bd5840756d7, 0x3ed2f7c2d608e0eb),\n", "(0xbb1f324b35355b3a, 0xbe7e212d2378b576),\n", "(0xbb005c49ab958b73, 0xbe69f3fcf3638b5a),\n", "(0xbab2a5d22fb87422, 0x3e144fbf0377cdfa),\n", "(0xba636fc80c961f59, 0x3df82268e83f4ed0),\n", "(0x3a40f5458ba7db6a, 0xbda26cc2b02dc737),\n", "(0x3a2ce24e6964787f, 0xbd80418bae8bbc48),\n", "(0x39b27ec279e7b798, 0x3d2812815e643e0a),\n", "(0x39a36cf3023b50ff, 0x3d009b2ac849ff66),\n", "(0x39133d4af08ad917, 0xbca7c55d0a6d0728),\n", "(0x38de47b036357356, 0xbc7aa167b939df6b),\n", "(0x3886507c635a91ef, 0x3c22645687164ddf),\n", "(0xb88b93b25f237a68, 0x3bf137648ca710a0),\n", "(0xb8159c0acc3fb928, 0xbb96ed64da2728ee),\n", "(0x37e7e2b02a3ea356, 0xbb62564f89aafafd),\n", "(0xb7a8f4b2647af4ab, 0x3b0789c5abd21586),\n", "(0xb7722d480745c160, 0x3ad05f7f4ebd3555),\n", "(0x37185f3d16f70670, 0xba7442d6813292c4),\n", "(0xb6d2d55a451fd98e, 0xba38df199441f62a),\n", "(0xb65428bef2d53556, 0x39ddaedad9d103ec),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc63db68c567283b, 0xbfc80781c32422e7),\n", "(0xbc1bf83906fd50c1, 0x3f754eda697a0098),\n", "(0x3c232419a9d405db, 0x3f9fbe6df840847f),\n", "(0x3bd5a76a98bd9674, 0xbf4be318d61276e1),\n", "(0xbbe633162d1131fe, 0xbf58efee4094379c),\n", "(0xbb4139e1a56d06b2, 0x3f059145b4f0e4de),\n", "(0x3b2db153b13f2cee, 0x3f0282d26a74c38e),\n", "(0x3b48c60f3e751263, 0xbeaf56c29d9ad959),\n", "(0xbb2ffef5e5f8ef91, 0xbe9fdd03174f902a),\n", "(0x3acf87aa0c95189d, 0x3e4a44a7907fee59),\n", "(0xbaded732eaed6428, 0x3e31df65332ab3e4),\n", "(0xba6ed0d6f75e03b2, 0xbddc96e9cf361a43),\n", "(0x3a2be09d928f0cb2, 0xbdbc3439f3fac67e),\n", "(0x3a0894702a4e04ba, 0x3d65d38ae50afdda),\n", "(0x39c847e4ec1195d0, 0x3d40833ea1f83461),\n", "(0xb9816bc0dd8ea673, 0xbce8afb70fb3c9e8),\n", "(0x395196a0917179fd, 0xbcbdda411e59ed8f),\n", "(0xb8c4610e8c50f3dd, 0x3c65889665db09a8),\n", "(0xb8d125a6e60383eb, 0x3c35792846a5c5e9),\n", "(0x38475c9e6c26184f, 0xbbdde1c2aac4bc04),\n", "(0xb834983a005c0922, 0xbba92deda741b574),\n", "(0xb7fd331deb45d073, 0x3b50e62611579a41),\n", "(0xb7b4d43c6fbeedae, 0x3b18898163cacd25),\n", "(0x37345581502d5210, 0xbabfc6f37553b483),\n", "(0xb72eac4aa67583bb, 0xba843147e449ee48),\n", "(0x36a768c097b2d633, 0x3a293dd77e784298),\n", "(0xb667f8f81d88a65c, 0x39ec7209a4872362),\n", "],\n", "[\n", "(0x3c559364e26d93ec, 0xbfc713fc51664c74),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc488077fd102b67, 0x3fb7049760cde490),\n", "(0xbbff945ad3318fed, 0xbf58ef5f1cbe4874),\n", "(0x3c0b034f6fcde568, 0xbf7e5f53caf3bead),\n", "(0x3bcb16596420523c, 0x3f237b0b62ddadd1),\n", "(0xbb7411414067003c, 0x3f2fd3bac08286da),\n", "(0xbb66bf25df78108f, 0xbed5789803de3afe),\n", "(0xbb30f115b8c73e8d, 0xbed1c0faa89993b9),\n", "(0xbb1173613a4d69f6, 0x3e7845b49b0674ba),\n", "(0x3ada42fc2e50738e, 0x3e6886872801396c),\n", "(0x3a9cf261fcd9b5e3, 0xbe10b036779ac071),\n", "(0xba8ed0f2c9abc118, 0xbdf7049d18354c88),\n", "(0x3a3b53ce13beae6c, 0x3d9edd9d0fb2ebd2),\n", "(0x3a01c67e454c422c, 0x3d7f44600957fa58),\n", "(0xb9c8cf2dd5194971, 0xbd2486b1d6a91df8),\n", "(0x39a50688f914608c, 0xbd0016025abd20b4),\n", "(0x392da82dcfc4875f, 0x3ca498b3d1754fd7),\n", "(0xb9082f62c6ce39c5, 0x3c79f47baf518ec1),\n", "(0x38a6105821b4975c, 0xbc2029b685b728de),\n", "(0x389216a765538354, 0xbbf0ddbdab448097),\n", "(0x3830ae5354e24a65, 0x3b94667d2d37a045),\n", "(0x38016f3b498e4738, 0x3b620a8a21b80dcb),\n", "(0xb78daf501176b370, 0xbb052c2caec48eea),\n", "(0x377fe5ca7bc39984, 0xbad02a81f53376b9),\n", "(0xb714e540400d2a70, 0x3a7266275dfcd434),\n", "(0xb6a1501fbef1dde4, 0x3a38a1141391318a),\n", "(0x3672180bf6683e02, 0xb9db2e3c29487cd8),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc6d2f0105f3ce7c, 0x3fc62d94d97e859c),\n", "(0x3bd10ece6e29b084, 0xbf70bf614807033c),\n", "(0xbc37013075a066f9, 0xbf9d5f857a2a6107),\n", "(0x3be49380eb03f78d, 0x3f46081b0b7fe572),\n", "(0x3bfce3676d17b40c, 0x3f57307b03e248f8),\n", "(0xbbabc5fb92b99e67, 0xbf0132c0aa83d0dc),\n", "(0x3b962d899f08a704, 0xbf0154ed4598d2f0),\n", "(0x3b436681f34b2420, 0x3ea94f64f476e615),\n", "(0xbb2a69d5b51b6d77, 0x3e9e12725853a9fb),\n", "(0x3aec161d9909f167, 0xbe4588c758dfc8ab),\n", "(0xbade3ba8f2d73fb0, 0xbe31021cdd9b5f7f),\n", "(0x3a7b80d7aefb24c5, 0x3dd7cfa7a6c26b53),\n", "(0xba5b73dd1f1185ae, 0x3dbb0e011d23f5e3),\n", "(0x3a0a3aee2b581931, 0xbd6276cc0fa65a6a),\n", "(0xb9d2974c386cdc2a, 0xbd3fe92f0882b440),\n", "(0xb982bfc89a29ddc4, 0x3ce53126d86bf487),\n", "(0xb94dd068a7b1e2e7, 0x3cbd07f6c1993c8c),\n", "(0xb8fb38430712c4a6, 0xbc62bc249a86f7c9),\n", "(0xb8d065bd6a2ed972, 0xbc34ffb4f0789e1c),\n", "(0xb854136ccbc577a4, 0x3bda504d6417aae1),\n", "(0xb84be408189a39ee, 0x3ba8bd8d3bf76896),\n", "(0x37eab1c3ced9a78a, 0xbb4e157fb142efc6),\n", "(0x37a40d8e8cc67990, 0xbb1834ef259f93cb),\n", "(0xb75167300d24b2f1, 0x3abc8e7b497b27c6),\n", "(0x36d98f27f9bf4556, 0x3a83fd162f3a5584),\n", "(0x36c5a4266d838510, 0xba26e0585c2f983a),\n", "(0x366678ba75bc0bf4, 0xb9ec3d3ba73f49c5),\n", "],\n", "[\n", "(0xbc5b858aeca267e1, 0x3fc56b97f8091ac5),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc21d2a41bfc4c1d, 0xbfb560fcc8c08469),\n", "(0xbbe6529450b1ff0b, 0x3f53fafa39618883),\n", "(0xbc1ad54776e42e6f, 0x3f7c49141623372f),\n", "(0x3bb39ecd4785a672, 0xbf1f69980694fd17),\n", "(0x3bcc2a33b89df073, 0xbf2dc5f848aa9d34),\n", "(0xbb7ed412867be695, 0x3ed178fc979b77bd),\n", "(0x3b73a93300f0b087, 0x3ed0b494a4bafcc7),\n", "(0xbb1a1471efd3f084, 0xbe73fc3884c2743a),\n", "(0x3b0b5eabaa159e81, 0xbe673afb9fb4d844),\n", "(0xbaa47c72ef2556f3, 0x3e0bd90346a3e0ed),\n", "(0xba99f08140c074ed, 0x3df5f3bafb215b44),\n", "(0x3a2ab2b535dc2fdf, 0xbd9a1c27c37569c8),\n", "(0xba09f88e2bb9d462, 0xbd7e0455dbf9cc4f),\n", "(0xb9cdb0302c98b2dd, 0x3d2199b19fcacda0),\n", "(0x39851865cfbaca3e, 0x3cff1334609dc3bd),\n", "(0xb8c2cd00a5fcb440, 0xbca1e37265d5ce04),\n", "(0x38c8d0340828b4e4, 0xbc79353f1aee0a50),\n", "(0xb897b28613de5d51, 0x3c1c68e4abc12011),\n", "(0x388b3ab1625e378c, 0x3bf075c553243bdb),\n", "(0xb82923cf876dbeab, 0xbb921f6f50442923),\n", "(0xb80ef47dee3f5afd, 0xbb61ae48340c53aa),\n", "(0x37a8614c654ed794, 0x3b02fdf33e2b9584),\n", "(0x376126c601c703f9, 0x3acfcd13a6548328),\n", "(0x371d5986e5068b9e, 0xba70a5f4affbe604),\n", "(0x36c041d0dc32e320, 0xba384ccca4432680),\n", "(0xb652e0a78e43b84d, 0x39d8c95636d09811),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc5e9088e9ff2518, 0xbfc4b2a38f1ab9b4),\n", "(0x3bf658189763e4b9, 0x3f6b3878aadeb34d),\n", "(0xbc3525fe797e2126, 0x3f9b750d89a9b35f),\n", "(0x3bb2c48be700f9e6, 0xbf41f6911725a956),\n", "(0xbbed0a355d52c196, 0xbf55beee6fd51c8a),\n", "(0xbb8079c92f6ce1f4, 0x3efc3625d7a65089),\n", "(0xbba1cffb5ca00bc2, 0x3f005375a588a72b),\n", "(0xbb398a011960416e, 0xbea4ee5e4e7cb18b),\n", "(0xbb2804ad812748e6, 0xbe9c7b3d81b5ff94),\n", "(0x3aea91d5277c5345, 0x3e41fce14f48518c),\n", "(0xbadb70b3ae1d3fb1, 0x3e30346643c9d86e),\n", "(0xba7397dad107b33b, 0xbdd41c861bc1c34b),\n", "(0xba5410a8098eafad, 0xbdb9eeda214eabbe),\n", "(0x39f8372842605aa2, 0x3d5f8cf277ce6338),\n", "(0xb9de510926654c46, 0x3d3ec46e14cd5d9e),\n", "(0xb962703fb3cb397d, 0xbce2500181b463c7),\n", "(0xb95b2c04b73484a3, 0xbcbc24c2b350e45a),\n", "(0x3888f6781f273b56, 0x3c605d9c149f1b8a),\n", "(0x38d31e5cc968c925, 0x3c34752e1249314b),\n", "(0x387b7657eab8f7e8, 0xbbd73842b12b31ea),\n", "(0xb846e57a01049463, 0xbba83594fd823055),\n", "(0xb7e962546fd68b46, 0x3b4acb92f062a2fd),\n", "(0x37beb28a448a691b, 0x3b17c779242729e1),\n", "(0xb7536df5c047d7ba, 0xbab9a6de3d6e1877),\n", "(0x36e0ce403e109088, 0xba83b3c68747091c),\n", "(0x36bd2b9ab8c7eb26, 0x3a24b55c31763430),\n", "(0x36831011a1450327, 0x39ebeab3c6cb6a58),\n", "],\n", "[\n", "(0xbc4d00ae4313eed0, 0xbfc413644356a52b),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c2e7840863e7c03, 0x3fb40bb88c6f2b85),\n", "(0x3bd5631193c7aba5, 0xbf5078d13cfc400e),\n", "(0x3c1a406bffcdbe35, 0xbf7a9191262ab9d5),\n", "(0x3bbe2809cb431b0a, 0x3f1a005297618f35),\n", "(0x3bc92fd90e2b1396, 0x3f2c0cbad847a60e),\n", "(0x3b6faeaea4946f0f, 0xbecd1a72e7c35fd8),\n", "(0x3b6a2e571e6832b0, 0xbecf9a2654099c40),\n", "(0x3b14a1a09cd63457, 0x3e70c6b06e20fcbe),\n", "(0xbb08c15da7295060, 0x3e66136d6425ea74),\n", "(0xbaa9c15db46970d1, 0xbe07977677c6badc),\n", "(0x3a91f266c960af6f, 0xbdf4f77b3143a31f),\n", "(0xba2ade992d25ffbb, 0x3d965720b0a36de3),\n", "(0x3a0635bc57fc436d, 0x3d7cd126dc5db8d4),\n", "(0x39b0b42ceb8837b9, 0xbd1e6d575a54f608),\n", "(0x399c1abf000da8a7, 0xbcfdfb4d0beacd2f),\n", "(0x3926e0efc20cf902, 0x3c9f3cccbe3a6b08),\n", "(0xb90208f2daceba75, 0x3c786f5c7a82aa3d),\n", "(0xb890e01b243ac14b, 0xbc190b8ec99be279),\n", "(0x386588585f7010ee, 0xbbf0061c1563865c),\n", "(0x3839090c97be6541, 0x3b901f2cce387f59),\n", "(0xb808c405323747f4, 0x3b61476b2aa5f9cd),\n", "(0x37aa73fdd9180681, 0xbb010995cf568203),\n", "(0x376999ab5e964dc7, 0xbacf2f8eadcda35c),\n", "(0xb6eef0a26c086d84, 0x3a6e19ecc98ab1c0),\n", "(0x36cbb3d7e3e4912f, 0x3a37e713fd44413e),\n", "(0x367917d21157a7a9, 0xb9d6910a2ab8996f),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4997782859a00d, 0x3fc37aaceac987b9),\n", "(0xbc09de167b0f4e45, 0xbf66afe4fe0bc0f7),\n", "(0xbc3d91e80a0529b8, 0xbf99de7a33bc3a97),\n", "(0x3bdacaad4f266959, 0x3f3e024f567ac487),\n", "(0xbbf5aee36a6b58af, 0x3f548843c426abe0),\n", "(0xbb8ed7ac2e5eef51, 0xbef7a8e14711c0f5),\n", "(0x3b9b3675770103a2, 0xbefeeceb341ad833),\n", "(0xbb4d96e3726387e9, 0x3ea1a743e05b39ca),\n", "(0xbb36e8969001b255, 0x3e9b143d39c90dd5),\n", "(0xbad319f8c4237007, 0xbe3e8e00012321d3),\n", "(0x3aae89c8a788cf46, 0xbe2ef28e323e7496),\n", "(0x3a7f30cb64f4f0d2, 0x3dd137a1bf5bde2c),\n", "(0x3a5bf7dee3b649de, 0x3db8e087c7cb7f1d),\n", "(0x39fb7806a5d33650, 0xbd5b3dc9dd36d846),\n", "(0xb9c8eb799dd68c33, 0xbd3da6ae03deea14),\n", "(0x394156b16e9a68f1, 0x3cdfe64e83599736),\n", "(0xb93c20b358422ecc, 0x3cbb3e899a8275b8),\n", "(0x38e23edcbf53670c, 0xbc5cc15471c3a791),\n", "(0x38d6153c40fa8364, 0xbc33e34956740ffd),\n", "(0x387da1d09b7c1150, 0x3bd491cabcac2ce3),\n", "(0xb84c9d6b2a07c067, 0x3ba7a07e1fc0dd64),\n", "(0x37bbd51dd0af2201, 0xbb47ecb9d1547f7f),\n", "(0x37bc94c2359a7968, 0xbb174a2cfb1be55e),\n", "(0x375ec790d520dd3c, 0x3ab712c909b7eb19),\n", "(0x3721fa30708a2d3f, 0x3a835bca00a6162a),\n", "(0xb6b4073920a6f8c9, 0xba22c13871e75a28),\n", "(0x368fbab0e8ced2dd, 0xb9eb82223e5c0791),\n", "],\n", "[\n", "(0x3c4f123683cf20a8, 0x3fc2f4e70d6c7e01),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc5702b97938a87e, 0xbfb2ef24d6f7526a),\n", "(0x3be17c9efd9928a1, 0x3f4bc33c9dc6ec82),\n", "(0xbc153a673a682d1a, 0x3f7920414ee2acbe),\n", "(0xbba8c8602e5501dd, 0xbf15f9173916a219),\n", "(0xbbbd01332ea23750, 0xbf2a94fdbdcec471),\n", "(0xbb6340ead67ee8d4, 0x3ec8b309990f950c),\n", "(0x3b62bfaf2a2bd5b2, 0x3ece087ff4517c02),\n", "(0x3b05bdd16bb39ef5, 0xbe6ca22ab12cb4b7),\n", "(0x3ad4981496e99ee8, 0xbe650d1f28635cda),\n", "(0x3aac3cc89e59b451, 0x3e04441552e259a7),\n", "(0xba95d08c5f0c93c3, 0x3df411b8a8258957),\n", "(0xb9eff3ddb842e46e, 0xbd9354e914c31b45),\n", "(0x3a11319e6211da5e, 0xbd7bb16f111ebae7),\n", "(0x39af5cff5d440351, 0x3d1a888536e27439),\n", "(0xb9967f728b3f0a85, 0x3cfced726c1026c9),\n", "(0x39328206ff6f6ec6, 0xbc9b745d75ff6377),\n", "(0xb91cb1d8bb8b1e84, 0xbc77aaea63220bec),\n", "(0xb8b1d26bdb3cb23f, 0x3c162ef6548b0ef1),\n", "(0xb85086d51f21de1e, 0x3bef27eac447efa0),\n", "(0xb81b0359e4922880, 0xbb8cc635a651ed03),\n", "(0xb7c265c1a580ae14, 0xbb60db1d9fbb3868),\n", "(0x379bfffc557e0311, 0x3afea050ba5a6c00),\n", "(0xb7616b89acbe6940, 0x3ace84aeda9b4b7b),\n", "(0xb690317b7234e3f2, 0xba6b3ca6e927e7ca),\n", "(0xb6d96744c0e38388, 0xba37754b584db1b4),\n", "(0xb67873c14331a4ce, 0x39d48c23ea283d56),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c6b7326e3fbaa70, 0xbfc2740819f1caaa),\n", "(0xbbad91d196951b1e, 0x3f6349369dc780bb),\n", "(0x3c211249d3675d98, 0x3f98868d7401bf2e),\n", "(0x3bab901426ad555e, 0xbf398cd1bebe1445),\n", "(0x3b8e845cf46e9c36, 0xbf537eef9aadeee2),\n", "(0xbb978bd7232789d5, 0x3ef43394c95b2d2b),\n", "(0x3b98d34686b724d9, 0x3efd6dfcdb026028),\n", "(0xbb39039620a1668b, 0xbe9e448fbc8a1f43),\n", "(0x3b1ab8335f5b2e44, 0xbe99d764ee07c839),\n", "(0xbad24a385ba857b8, 0x3e3a53958c8d74ff),\n", "(0x3aae692fcd7541f7, 0x3e2da0e1c8a08d37),\n", "(0xba682664a5ef0aa2, 0xbdcdd7f918de776f),\n", "(0xba55452efda66af5, 0xbdb7e68037d5c861),\n", "(0x39e92d13e5b8bdbb, 0x3d57c2e63bbe27ca),\n", "(0xb9b76fb98c811c8b, 0x3d3c973a175ffbb6),\n", "(0x3961655ae92c79f4, 0xbcdc033788921736),\n", "(0xb93459b0496214b2, 0xbcba5d9f2bdd8af3),\n", "(0xb8c9fbdcd265117f, 0x3c596cb946e78db0),\n", "(0x38ca3b3e172d732c, 0x3c335090afbe104f),\n", "(0xb87ce7df25d16bb8, 0xbbd24f9089431e12),\n", "(0x38470e95a1733e58, 0xbba7060105333e1d),\n", "(0x37e148c26a9d2e03, 0x3b457032c08fa72b),\n", "(0xb7bcc5adf699f555, 0x3b16c43d570a329d),\n", "(0xb7472f3277e653fc, 0xbab4ce5eeb2252e9),\n", "(0xb72e4e66be44e7f5, 0xba82fa99d3f60727),\n", "(0xb6c49cda263bbcc6, 0x3a21035a54fa4f71),\n", "(0xb682adf1bab34466, 0x39eb0a7a1202f74d),\n", "],\n", "[\n", "(0x3c34f78a7cfd8a8a, 0xbfc20198200b699d),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c1ede75d6e0c0b0, 0x3fb1fd242a74e630),\n", "(0x3be31a446a0673c4, 0xbf47cf261dfbf19a),\n", "(0xbc0b11e38b0823f1, 0xbf77e4820ec1dde4),\n", "(0xbbbbba7e6db23817, 0x3f12e1bd281dfcbb),\n", "(0x3bc48aed48d0a248, 0x3f2950bb06c6fdf9),\n", "(0x3b5f50566d2c2881, 0xbec54a38ab6af546),\n", "(0xbb69fdc0d6c27c0b, 0xbecca94f38024fdc),\n", "(0xbaf76dde5144d48d, 0x3e68c7e75971c85c),\n", "(0xbb0678751b2ddc2c, 0x3e6423fc7e251ca9),\n", "(0x3aab4294ffe166f7, 0xbe019fe1d8e51b96),\n", "(0xba976b836ebd0291, 0xbdf34198c795142c),\n", "(0x3a1b6fa7e1df9192, 0x3d90e78cdab26dd9),\n", "(0xba1a2a34bc1f8645, 0x3d7aa74cb5ba4b0e),\n", "(0xb9a65f2dd9b4219b, 0xbd1756ee8369797d),\n", "(0xb98cae4f94465269, 0xbcfbee3ccbac62a4),\n", "(0xb93edac05af99c66, 0x3c984c93627c1364),\n", "(0x39192f873368f6f8, 0x3c76ecd2977e750f),\n", "(0x3893a3df310cde1b, 0xbc13c1ad2197e738),\n", "(0xb83e79b62fc45f90, 0xbbee45c9096ecdab),\n", "(0x3808f4906192c428, 0x3b89c8e8d1127213),\n", "(0xb7d635517d589b2c, 0x3b606d492670f0ba),\n", "(0xb772bd51822a155e, 0xbafb9c058bf87bc8),\n", "(0xb755af5326fb8ade, 0xbacdd33a39371327),\n", "(0xb6fa0c8a817bd238, 0x3a68b21edf0d733b),\n", "(0x36ce1e27351bb092, 0x3a36fc3cd1a4c613),\n", "(0xb678b7b2ca8c7003, 0xb9d2bb8db2dfce26),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc4081c2a50ad27b, 0x3fc192f2627a74e3),\n", "(0x3c06268e5916da13, 0xbf60a846a83fecf2),\n", "(0xbc1be434e30d7a64, 0xbf975eceaabf7f86),\n", "(0x3bbc2d7f1eb14a8d, 0x3f3617c581be35b1),\n", "(0xbbb0beeca29a2b7c, 0x3f529934b7a84483),\n", "(0xbb91b58b66aaaf71, 0xbef18123e875188a),\n", "(0x3b94740ce7aaa9f5, 0xbefc1f05a2d85165),\n", "(0xbb3fd873b639f93b, 0x3e9a4e0bc0926545),\n", "(0xbb233d21389cb3a0, 0x3e98be81ad44d933),\n", "(0xbabb1f9cab4acd40, 0xbe36f73795e25c01),\n", "(0x3ababafdeab2d269, 0xbe2c70ab158cd19a),\n", "(0x3a5796ce7385bd76, 0x3dca262190472d9a),\n", "(0x3a444e202e2ab843, 0x3db70112aab52bc2),\n", "(0xb9f5bd722355d797, 0xbd54ec163f88c02f),\n", "(0x39d5477d64dc86b2, 0xbd3b991575a9daff),\n", "(0x39314b432a7313b8, 0x3cd8cbabadfd45c5),\n", "(0xb953683d210d31e2, 0x3cb9867f1ea8526f),\n", "(0x38f1cbbb05b76a2a, 0xbc56a0c58ce9652e),\n", "(0x38dd3e4ed9b9011d, 0xbc32c10fa17839d7),\n", "(0x387159e93c92ec73, 0x3bd06304545a75ab),\n", "(0x3831184208b9509c, 0x3ba66b5f3f801768),\n", "(0xb7bf7ef3af29f9f4, 0xbb434a75e18850f7),\n", "(0xb7b72f867bfa08f9, 0xbb163af2240f11d6),\n", "(0x374e71e41ce0bd04, 0x3ab2d27f5aad2f87),\n", "(0xb70e338eb53b4d25, 0x3a82947c379d043b),\n", "(0xb6a879620ef8dcbc, 0xba1ef0cd1e11d5d6),\n", "(0xb68cfba8dcf4726a, 0xb9ea897622f547ac),\n", "],\n", "[\n", "(0x3c68f71f103b6bf8, 0x3fc12f9870d68e18),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc5fd0d25668ad6b, 0xbfb12c11811945f9),\n", "(0x3bebc70ffc015b97, 0x3f44b638f21f0f76),\n", "(0x3c1bc10a4e0506fd, 0x3f76d2a897d58353),\n", "(0x3ba5de76c7b42be1, 0xbf10732e5458ba20),\n", "(0x3bcfca03362738f1, 0xbf2835929300df3f),\n", "(0x3b4992f62f113a88, 0x3ec297283816a83b),\n", "(0xbb50d6dea529ee4f, 0x3ecb73adedf11a43),\n", "(0xbb0dce80931068a0, 0xbe65b455b903f09c),\n", "(0x3b029572874fb52c, 0xbe6353f0797a6699),\n", "(0xba8bf23ef2ca5a38, 0x3dfefc9ac17b1eeb),\n", "(0xba878bfeeecafab3, 0x3df28535463ce067),\n", "(0xba096b62f6b59354, 0xbd8dd894cbbee3f9),\n", "(0xba0f655d10343892, 0xbd79b288cc392b5b),\n", "(0x3986335c7e33b227, 0x3d14b2ec9ace070c),\n", "(0xb998edce804ba0e3, 0x3cfaff72f6057832),\n", "(0xb936e4ec62dfa238, 0xbc95a7bfada02748),\n", "(0x39060aebd6f74bda, 0xbc7637b7b45ad224),\n", "(0x38b5e34b545164b0, 0x3c11b216f1fba65d),\n", "(0x387400818419c16a, 0x3bed6a4aa25cbcad),\n", "(0x38222d3819e4ad1c, 0xbb873661259c7b49),\n", "(0xb7c47385cbfe72a2, 0xbb6000a243c0a825),\n", "(0x3790aa941ed924d2, 0x3af8faeb08a0872d),\n", "(0x374285ea5fb533a8, 0x3acd2042259aeb3b),\n", "(0xb70ef65d241a95c5, 0xba66742de4a4a980),\n", "(0xb6dbeb8e3fb1ee6a, 0xba367fbd4af52810),\n", "(0xb666550a2bc73761, 0x39d11cea7748dd35),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c60c06e2860e868, 0xbfc0cf3ee98f769b),\n", "(0xbbfc2c390327e0f7, 0x3f5d26e7af251f79),\n", "(0xbc394225ed089995, 0x3f965d05948a946a),\n", "(0xbbcb3460aae30c17, 0xbf335959b8482e40),\n", "(0xbbf744279fabe84a, 0xbf51cff175d05c2a),\n", "(0xbb83714c1d2b4ff3, 0x3eeeb59416879106),\n", "(0xbb89158b4542d2c4, 0x3efaf7544eeac766),\n", "(0x3b284917e9900e02, 0xbe9720522bb1fc81),\n", "(0xbb31671693e842ab, 0xbe97c41261705419),\n", "(0x3a886ab60cf89699, 0x3e343fa0ea5e007d),\n", "(0xbab8f90fa25a8f71, 0x3e2b5e23abebd7a4),\n", "(0x3a64e5cdf3a099a5, 0xbdc722397e750312),\n", "(0xba51768b235cacdf, 0xbdb62f2174e6be49),\n", "(0xb9fb8faac380f50e, 0x3d5294ab060a163a),\n", "(0xb9de9b0cd3f3a20f, 0x3d3aace944141c61),\n", "(0xb96472a1bdce3160, 0xbcd61cc8146cdfa2),\n", "(0xb9583fcfac500424, 0xbcb8bb3c270a284c),\n", "(0xb8f56040266e6114, 0x3c54449d96647c28),\n", "(0xb8c4997de83d7967, 0x3c323712fdd32979),\n", "(0xb84d0513eb7ddb33, 0xbbcd7cedd05f23ee),\n", "(0xb8138c0b1312b9f5, 0xbba5d3f2f4d18257),\n", "(0xb7d6343b2af8488e, 0x3b416f9a8cd62e2d),\n", "(0xb7b741512b4836ab, 0x3b15b1f1d821a3b4),\n", "(0x375de94b9017c7ec, 0xbab116d887db5467),\n", "(0xb720b9ee354d1861, 0xba822c96cd78a74c),\n", "(0xb6b7416d012e04a4, 0x3a1c3754078e6137),\n", "(0x3688b4af62f8f0ae, 0x39ea0388f41538a5),\n", "],\n", "[\n", "(0xbc6742aa46ea9b31, 0xbfc077eede4a0d89),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c3cabc5883fc763, 0x3fb0751548b2924d),\n", "(0x3bd8c3b817f5bd1a, 0xbf423b5d46a73864),\n", "(0x3c1e7b0b0210cbce, 0xbf75e2467c8fb832),\n", "(0xbb9abdc3996174ac, 0x3f0cfe5c189d6e4d),\n", "(0xbbcf4c0c63a8394c, 0x3f273bbd8c7aef2d),\n", "(0x3b6d9272577eb6ff, 0xbec06974d3d04287),\n", "(0xbb56fb637949537f, 0xbeca6081d36e6a2b),\n", "(0xbaee9b9b25b5c745, 0x3e6334a83cf6092b),\n", "(0xbb0e3539c19e4313, 0x3e6299571cb4e1fb),\n", "(0xba80b2cd2f45d38c, 0xbdfb7f5bc0aada50),\n", "(0xba81831c37e0afc0, 0xbdf1da63b4d6f878),\n", "(0xba03f6e20cbba970, 0x3d8a9288ceccd9f2),\n", "(0x3a17055344e86eaa, 0x3d78d1d74c88ee4c),\n", "(0x39a439e54f23f947, 0xbd127eed3a482d7f),\n", "(0xb9766b420f9bcda0, 0xbcfa2143706ccb79),\n", "(0x3933ce1edc9f0854, 0x3c936d1464c4bf11),\n", "(0x3907d2e3e5d4bfa8, 0x3c758cc3ad07daa3),\n", "(0xb89bcc0a4f099447, 0xbc0fe0c8ce969c5e),\n", "(0x38838ca595ab732b, 0xbbec97f785528e08),\n", "(0x3821507942984ee9, 0x3b84fee6252fe140),\n", "(0xb7df46f0f7734483, 0x3b5f2dcbce169f1a),\n", "(0x379086aaae683dab, 0xbaf6b095bc2831d4),\n", "(0xb76de10fe678bda7, 0xbacc6f522af04f90),\n", "(0xb703ee192a62f4f4, 0x3a647af3c1c3a557),\n", "(0x36d76dc7bb35ad50, 0x3a3602a9d860d2a3),\n", "(0xb66b7ac21c3ed2e5, 0xb9cf58721d5d6786),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c61166b7995967a, 0x3fc0230ba90f2871),\n", "(0x3bfb746b17280b83, 0xbf59ca16f0c9734e),\n", "(0xbc375b99fcae0fa4, 0xbf9579c1bdbcfc99),\n", "(0x3bc1259c7efa1ad5, 0x3f3120ecfac5c017),\n", "(0xbbd35a76e06cda58, 0x3f511dd26bbe2946),\n", "(0x3b72ed405d5bc473, 0xbeeb37e7c9a57149),\n", "(0xbb86e93d7c515f0c, 0xbef9f01e7c1909a0),\n", "(0xbb2f562d62e60e11, 0x3e94887fe7a88c2c),\n", "(0xbad010f87629f8e9, 0x3e96e37238841d4b),\n", "(0xba99b7f19b7b3b20, 0xbe3204b644d6a04b),\n", "(0xbacc8fcda8a1a29b, 0xbe2a659b13eebf8a),\n", "(0x3a42b743f24d4d7e, 0x3dc4a40c87601c97),\n", "(0xba577207717e09cd, 0x3db56f0250e4fcac),\n", "(0xb9f8225d38237f55, 0xbd50a1011bf4a7dd),\n", "(0x39d5262f16494ab9, 0xbd39d22a6dc5a57c),\n", "(0x397bb4017d6e9239, 0x3cd3db0f19da31da),\n", "(0x392600d1fe84f91f, 0x3cb7fc7d4070961b),\n", "(0xb8c183aaceabe7cd, 0xbc5243aa7bbc81ca),\n", "(0x38c5abd4abae47a9, 0xbc31b3c3dd0d783d),\n", "(0xb86b0ca32f2b28ba, 0x3bcaabdcaba1878d),\n", "(0xb83fe00611a5322d, 0x3ba541bb402b78f0),\n", "(0xb7d85111e57bb4b2, 0xbb3fa915cdaddb2d),\n", "(0xb798d2801af024f8, 0xbb152ba16ad63ba9),\n", "(0xb7344e83ea6e82fc, 0x3aaf26322e6939a3),\n", "(0x36eecf18659e6ff5, 0x3a81c51fa64eb3db),\n", "(0x36ba22c423e879e5, 0xba19d00760b94df4),\n", "(0xb6523572ecb98917, 0xb9e97bff11d536c1),\n", "],\n", "[\n", "(0xbc446154ab44acb3, 0x3fbfab0b166d23d8),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4290cc8b89531c, 0xbfafa65c1ce7ebd6),\n", "(0x3be9bdd7d19e67a3, 0x3f4035bf503ffc1f),\n", "(0x3be801473cc85f32, 0x3f750d1b04713c41),\n", "(0x3babe22a416a82d0, 0xbf09cd14a92842a2),\n", "(0x3bca868e6f4e4828, 0xbf265d504af5d8fe),\n", "(0x3b5814b5b963313b, 0x3ebd3feeb33d9cee),\n", "(0xbb4c05f6b4f39a25, 0x3ec96a257062f76e),\n", "(0x3b0b04fde272af41, 0xbe61254f302b36b2),\n", "(0x3ad771b26251f405, 0xbe61f11585e04fca),\n", "(0x3a8b3d53767b22ba, 0x3df89a7674dd98cd),\n", "(0x3a7b6db02fadeed1, 0x3df13f0ba48c1692),\n", "(0x3a248f4db1fc6761, 0xbd87d67b47fd268e),\n", "(0x3a0a84c861831984, 0xbd780381812ad9b0),\n", "(0xb98981455f0897cf, 0x3d10a41213b1209a),\n", "(0xb98573618414b59a, 0x3cf9530714f8af8a),\n", "(0x393f79d60d660532, 0xbc918884a9ff4796),\n", "(0x3912da336a20734e, 0xbc74ec3ce9f29027),\n", "(0x3896c9321058ffc6, 0x3c0cde4ce08c6119),\n", "(0x38894686518435ab, 0x3bebd00bdae20153),\n", "(0x37ff64113a65f339, 0xbb831454d0bd6f49),\n", "(0x37e88cc5762134d4, 0xbb5e623854cff634),\n", "(0x3793b39a55f6f728, 0x3af4b117674c743f),\n", "(0xb76c32187c451ad3, 0x3acbc2c0ede2286c),\n", "(0xb7077e3bc9fbf218, 0xba62be3ca56b47a4),\n", "(0x36dcde9bceca3e29, 0xba35870a752de79f),\n", "(0x361b91f4f1f1a50f, 0x39ccc9aaaa2d7785),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c50db2c50623ec0, 0xbfbf13fb0c0e6fcd),\n", "(0x3bf63fd50ee5b7c3, 0x3f5706ed3d935d00),\n", "(0x3c3a7c91ef9a7da1, 0x3f94af74cbd77bef),\n", "(0xbbac31e3b8ee4b9e, 0xbf2e9a9e66e5a792),\n", "(0x3bf35ae9733a6eb6, 0xbf507ec9ed824fcb),\n", "(0xbb4a1610320898f4, 0x3ee856d4518ab29e),\n", "(0xbb9af9c37c81d002, 0x3ef9040de830649e),\n", "(0x3af6ec0adcce1274, 0xbe9262f69c56c652),\n", "(0xbb34da0db90f5974, 0xbe9618c94a54734d),\n", "(0x3acfc6bc581d66ff, 0x3e3029d2c8bf70d6),\n", "(0x3ab60f30da5c2b13, 0x3e2983bca0a3e67c),\n", "(0x3a60395605657e5e, 0xbdc28e2a00002a82),\n", "(0xba51c639ac25ee1a, 0xbdb4beeacafc4fad),\n", "(0x39ed7df744a0b21a, 0x3d4df880e37a5060),\n", "(0x39d1f98cd4e6ac14, 0x3d3907be43054aec),\n", "(0xb95bcb238e3393c6, 0xbcd1f10ff685083d),\n", "(0xb948ad06b5e0f6af, 0xbcb74a1dc71abca4),\n", "(0xb8f9b8f70559bd9a, 0x3c508d41117c93a5),\n", "(0xb8b35b059841e08e, 0x3c313795880a7796),\n", "(0x3865f51a8e31e18f, 0xbbc83ea1cebb3c84),\n", "(0x3838606560ae8152, 0xbba4b5cc8ded02e2),\n", "(0xb7df776dd1580636, 0x3b3cdf002471ce45),\n", "(0x37b71f6e27bbe64e, 0x3b14a97cafad6c19),\n", "(0x374d40fd5c1285de, 0xbaac7f1793e7126e),\n", "(0xb6f7da220c547e42, 0xba815f93ab822e98),\n", "(0xb6a0911cfb822772, 0x3a17b0d93bc7bbc8),\n", "(0xb6846b70143e3a42, 0x39e8f533a6e89c51),\n", "],\n", "[\n", "(0xbc5bf01bf61d8ed3, 0xbfbe891b327da16d),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc3636379e4f582e, 0x3fae8533ce07bdb8),\n", "(0x3bc53b9dd0e187fa, 0xbf3d1253218e31b0),\n", "(0xbc1eae521e3467c6, 0xbf744e6826476498),\n", "(0xbb6864ec60e7a724, 0x3f07271a9b5e3cb4),\n", "(0x3bace83941ef46ea, 0x3f2595b697c8ec04),\n", "(0xbb5f57ab96615e4a, 0xbeba46b03ecb38cc),\n", "(0xbb4dc38fda916c56, 0xbec88c173e07621e),\n", "(0x3add237c79a7a74d, 0x3e5ed9b1754fbd3c),\n", "(0xbb0d6748ba8d2dd7, 0x3e615891ef314e18),\n", "(0x3a8caeca005426a6, 0xbdf62ca352cf904e),\n", "(0x3a7916c3c0550fc0, 0xbdf0b14767c2b010),\n", "(0x3a25951d764f773e, 0x3d85879bb4a2a8ac),\n", "(0xb9f96759cfddd4b5, 0x3d7745bbca5b0e82),\n", "(0xb99c649f85048056, 0xbd0e21736ab8469f),\n", "(0x399387632a0c4eab, 0xbcf893b256068d4e),\n", "(0x39225636fb1c995b, 0x3c8fd42c80d0363c),\n", "(0xb919336e177a135c, 0x3c7455e80611a38d),\n", "(0xb894f0ece16e6c03, 0xbc0a4682da825109),\n", "(0x388f20cb0640e817, 0xbbeb12f0bb38aa78),\n", "(0xb7ff5df786b91715, 0x3b816a7f586e7ed5),\n", "(0xb7ff8ddcae160d2a, 0x3b5d9fa09d2f4601),\n", "(0xb7808a35f4fc1e15, 0xbaf2f1ad1590d095),\n", "(0x373f1307c6b6dcfd, 0xbacb1c0038406c42),\n", "(0x36f40bb96d08f57f, 0x3a61363c85b6c4db),\n", "(0x36cb8e8704706c26, 0x3a350e3e866a311e),\n", "(0xb666cdfdf4125dc0, 0xb9ca841b08aca0a3),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc3b9f1d130797af, 0x3fbe018dac1c17e3),\n", "(0x3be072789a66cf0c, 0xbf54b994dd05c1fb),\n", "(0xbc338b4f0d3a4111, 0xbf93f9e0db07e7ef),\n", "(0xbb9a899561323713, 0x3f2b8e55b75b13ab),\n", "(0xbbd251fa83bbf98d, 0x3f4fdf68a78bb3d2),\n", "(0xbb783beff5b1db62, 0xbee5ee9d17106a08),\n", "(0x3b70935ad53575b8, 0xbef82ee6dfdfedeb),\n", "(0xbb36eeb8b4341708, 0x3e90962d7f6d61a6),\n", "(0x3b3ddb699c127f13, 0x3e9560edce7d682d),\n", "(0xbaadbe6f075c9b8e, 0xbe2d34381d02bdbe),\n", "(0xbab5faefe806c858, 0xbe28b5a0e74ae0d3),\n", "(0xba651c26d41110d4, 0x3dc0cab953f05720),\n", "(0xba4cdfa2ed9741f0, 0x3db41d21c68d7ed3),\n", "(0x39efbfd30004913c, 0xbd4b2d2dd7cb3c52),\n", "(0xb9d97fd3cf0000fa, 0xbd384c5369d2e33d),\n", "(0x3968bd8125247874, 0x3cd04e17ab25ece9),\n", "(0xb928ec3a9bb7352b, 0x3cb6a38e0aef9402),\n", "(0x38ed2d1073a2c3f0, 0xbc4e28099fc927bb),\n", "(0x38d2c69d895d6715, 0xbc30c28e6023fb13),\n", "(0xb8509810eebec087, 0x3bc62487323559ca),\n", "(0xb84607b5c3508235, 0x3ba430a24f21f4b6),\n", "(0x37dcd1d9a6fb187a, 0xbb3a70372a5a35f5),\n", "(0xb7ba9055f83c1a46, 0xbb142c5d07f39eeb),\n", "(0x3747d181d0f16b66, 0x3aaa2aaf684b8a30),\n", "(0x371c65863116b54e, 0x3a80fce718ed7a5e),\n", "(0xb6b4123df1746b77, 0xba15d07c57e5f8fc),\n", "(0xb6898be9e1a577c3, 0xb9e870c605b22513),\n", "],\n", "[\n", "(0xbc4d7a7b8d722118, 0x3fbd84391bb2748d),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c4b439a88ed803c, 0xbfad80edb3c4ea05),\n", "(0xbbd902d343595b94, 0x3f3a431f5421f7ef),\n", "(0xbc13a66c5c4dc37b, 0x3f73a282fe7b63a8),\n", "(0x3bacf6f60b03558d, 0xbf04ed653e607bdd),\n", "(0xbbb378680e9561c9, 0xbf24e15832bda3c4),\n", "(0xbb5464c53ca44363, 0x3eb7c5832dd1374f),\n", "(0x3b40f0848ee7f0af, 0x3ec7c2b80da8df98),\n", "(0xbadb963cfc74e722, 0xbe5bf160ccd35445),\n", "(0xbac9dbc6baadaa9d, 0xbe60cda2141b2a1e),\n", "(0x3a876692ed94eb99, 0x3df41d31d2a419e4),\n", "(0xba8205fd4d4f295d, 0x3df02f6ca850168a),\n", "(0xba12525d1774cdfa, 0xbd83901f61054085),\n", "(0xba17ee02df9f104d, 0xbd7696ce2b748d02),\n", "(0x39ad0bfbcbf0de66, 0x3d0b6e82997a390e),\n", "(0x39911978fd395acf, 0x3cf7e214796bec19),\n", "(0x38f14ad6e06bfc76, 0xbc8d0a3822eede44),\n", "(0x38ea8d322da40464, 0xbc73c944a2b7aa9b),\n", "(0x38a984e57b8c632b, 0x3c080748c2fd3ed7),\n", "(0xb88ca608783691d5, 0x3bea608ebfb61101),\n", "(0xb7fd3b588ddf9629, 0xbb7fee483d06f76f),\n", "(0x37f5b0b20d62c293, 0xbb5ce67588df7595),\n", "(0x37950cdd33b84f9d, 0x3af168f59e870bd0),\n", "(0x376249d762f468f2, 0x3aca7bdf85923387),\n", "(0xb6fefd0fec5de258, 0xba5fb7c898747d3e),\n", "(0x36de35ad136a6653, 0xba349926b4cfc177),\n", "(0xb6321892fca8dd05, 0x39c87ee43e8319a5),\n", "],\n", "[\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0xbc56edd809f4ec43, 0xbfbd09b21e36c0bd),\n", "(0xbbfd63853cd1251f, 0x3f52c84acfb586b4),\n", "(0x3c340975d5184af6, 0x3f9355b904fbf7ee),\n", "(0xbbc2e53f276aee1d, 0xbf28fb570465af0d),\n", "(0x3bdedf2b372334ad, 0xbf4edc3292ba6cfd),\n", "(0xbb81b7d6d1c233d4, 0x3ee3e552ee8c2577),\n", "(0xbb9b6ea46d6db74f, 0x3ef76d44f6a83523),\n", "(0x3b2fdb93f3ce1be4, 0xbe8e1ee2dc4a3bda),\n", "(0x3b3cccd4251153ff, 0xbe94b944bbd4c7bf),\n", "(0xbac468738fc1e577, 0x3e2a8c3a4ce36f16),\n", "(0x3ac2a4a12f818a06, 0x3e27f8c9ef47068e),\n", "(0xba40acae788b04d5, 0xbdbe9295749ee471),\n", "(0x3a1164a101ab66dc, 0xbdb38813c3eb77e4),\n", "(0x39e5c1a4e6a441fe, 0x3d48c7cda44b7754),\n", "(0xb9a073f8f8b180ec, 0x3d379e90468589ab),\n", "(0xb96fed4f7bb5b2dd, 0xbccdca323fb2ed13),\n", "(0xb95878df442a1f61, 0xbcb6080be2ba756c),\n", "(0x387f1fa3709d7eff, 0x3c4b9a8e33ba54fc),\n", "(0xb8dc56a14b4f3362, 0x3c3054766d105243),\n", "(0xb857137346804b31, 0xbbc44fda8d0857c1),\n", "(0x384bb0403ea0d8f3, 0xbba3b2575150baf6),\n", "(0xb7a85fe85251016c, 0x3b384ea306ad146b),\n", "(0x37b304a7ebd0a72a, 0x3b13b4adf072996e),\n", "(0x3748b8e00542081f, 0xbaa81d1af5c14291),\n", "(0x372aac7dc3b524ef, 0xba809dac6fd771cd),\n", "(0x36baf45596c923ee, 0x3a14269f3ec695f6),\n", "(0x36759ddc6feb07d0, 0x39e7efc8823b70ff),\n", "],\n", "[\n", "(0xbc579e384ae35818, 0xbfbc97d79918527d),\n", "(0x0000000000000000, 0x0000000000000000),\n", "(0x3c415f3ee939a0c0, 0x3fac95081ab2b511),\n", "(0x3bd3c58af0675f79, 0xbf37e0b14f7d7c3f),\n", "(0x3c167e93b7727b21, 0xbf730688f6836a76),\n", "(0xbb9eaad919470a89, 0x3f030941f6e78e36),\n", "(0x3bb70db1e3b31015, 0x3f243d5898657a6f),\n", "(0xbb39f8046976f799, 0xbeb5a39a94f2ad54),\n", "(0xbb5db47207819abe, 0xbec70b18406146f7),\n", "(0x3af60534adb9126c, 0x3e597607f9532274),\n", "(0xbad703287fac9a7c, 0x3e604e788f4f63b9),\n", "(0xba876fad0fcbbb39, 0xbdf2598919473e7e),\n", "(0xba640135e9b4a88f, 0xbdef70154273be01),\n", "(0xba130237cf72ed16, 0x3d81df5c1ca3869c),\n", "(0x3a1164e3491c1c38, 0x3d75f5256665e918),\n", "(0x3995f76e145eb882, 0xbd091a176f7295bc),\n", "(0xb9928726702a883a, 0xbcf73cf989310b2d),\n", "(0x39202ef4e750363b, 0x3c8a9f0a04e769ab),\n", "(0x38f077c349f5886f, 0x3c7345b205781db7),\n", "(0xb8add8bb23d58463, 0xbc0611e4c0bb0b33),\n", "(0xb87f88c08a95c014, 0xbbe9b88423fdad3a),\n", "(0xb8109abefbf8e094, 0x3b7d637382cff4b7),\n", "(0x37f703e341c86f9e, 0x3b5c36bddd0beae2),\n", "(0xb7802c952716a8be, 0xbaf00eec29705267),\n", "(0xb755facd187ba820, 0xbac9e2beddaac35c),\n", "(0xb6e129db12cb1ab9, 0x3a5d51fa8552737e),\n", "(0xb6cd627e8469503b, 0x3a342847a5dc8d0a),\n", "(0xb66dc34aae9113ef, 0xb9c6b1f64bc800a0),\n", "],\n", "];\n" ] } ], "source": [ "# Taylor series for f64\n", "mp.prec = 115\n", "terms = 28\n", "print(f\"pub(crate) static Y1_COEFFS: [[(u64, u64); {terms}]; {len(y1_zeros)}] = [\")\n", "\n", "def get_constant_term(poly, y):\n", " for term in poly.operands():\n", " if term.is_constant():\n", " return term\n", "\n", "def print_taylor_coeffs(poly, n):\n", " print(\"[\")\n", " for i in range(0, n):\n", " coeff = poly[i]\n", " print_double_double(\"\", RealField(115)(coeff))\n", " # print(f\"{double_to_hex(coeff)},\")\n", " print(\"],\")\n", "\n", "prev_zero = 0\n", "\n", "for i in range(0, len(y1_zeros)):\n", " k_range = y1_zeros[i]\n", " range_diff = k_range - prev_zero\n", "\n", " x0 = mp.mpf(k_range)\n", " from mpmath import mp, bessely, taylor\n", " poly = taylor(lambda val: bessely(1, val), x0, terms)\n", " # print(poly)\n", " print_taylor_coeffs(poly, terms)\n", " prev_zero = y1_zeros[i]\n", "\n", "print(\"];\")\n", "\n", "# mp.prec = 140\n", "# terms = 28\n", "# print(f\"pub(crate) static Y1_COEFFS_RATIONAL128: [[DyadicFloat128; {terms}]; {len(y1_zeros)}] = [\")\n", "\n", "# def get_constant_term(poly, y):\n", "# for term in poly.operands():\n", "# if term.is_constant():\n", "# return term\n", "\n", "# def print_taylor_dyadic_cef(poly, n):\n", "# print(\"[\")\n", "# for i in range(0, n):\n", "# coeff = poly[i]\n", "# print_dyadic(coeff)\n", "# print(\"],\")\n", "\n", "# prev_zero = 0\n", "\n", "# for i in range(0, len(y1_zeros)):\n", "# k_range = y1_zeros[i]\n", "# range_diff = k_range - prev_zero\n", "\n", "# x0 = mp.mpf(k_range)\n", "# from mpmath import mp, bessely, taylor, chebyfit\n", "# poly = taylor(lambda val: bessely(1, val), x0, terms)\n", "# print_taylor_dyadic_cef(poly, terms)\n", "# prev_zero = y1_zeros[i]\n", "\n", "# print(\"];\")" ] }, { "cell_type": "code", "execution_count": null, "id": "624075d7-07cd-4364-9f4b-46497a9f4067", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/cbrt.sollya000064400000000000000000000006331046102023000141720ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [1.0, 2.0]; f_cbrt = x^(1/3); Q = fpminimax(f_cbrt, 3, [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cbrt, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 1 do print(coeff(Q, i));pxfm-0.1.23/notes/compound_exp.sollya000064400000000000000000000007571046102023000157470ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = exp(x); w = 1; p = remez(f, 6, d, w); pf = fpminimax(f, [|0,1,2,3,4,5,6|], [|1, 107...|], d, absolute, floating, 0, p); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; for i from 0 to degree(pf) do print(coeff(pf, i)); print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/exp(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); pxfm-0.1.23/notes/compound_expm1.sollya000064400000000000000000000007311046102023000161750ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = expm1(x); w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7|], [|1, 1, 107...|], d, absolute, floating); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; for i from 1 to degree(pf) do print(coeff(pf, i)); print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/expm1(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); pxfm-0.1.23/notes/compound_expm1_tiny.sollya000064400000000000000000000007231046102023000172410ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-7,2^-7]; f = expm1(x); w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9|], [|1, 1, 107...|], d, absolute, floating); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; for i from 1 to degree(pf) do print(coeff(pf, i)); print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/expm1(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); pxfm-0.1.23/notes/compound_m1_expm1.sollya000064400000000000000000000006641046102023000165770ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; // display = hexadecimal; n = 9; P = 128; N = 1; n = 7; d = [-0.00016923,0.00016923]; f = 1; w = 1/expm1(x); p = remez(f, n, d, w); Q = horner(fpminimax(expm1(x), [|1,2,3,4,5,6,7,8|], [|0,P...|], d, relative, floating)); e = -log2(dirtyinfnorm(Q * w - f, d)); print ("exp(x) :\n Q(x) =", Q); for i from 1 to degree(Q) do print(coeff(Q, i)); print (" precision:", pretty(e)); pxfm-0.1.23/notes/compound_m1_expm1_fast.sollya000064400000000000000000000007331046102023000176110ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = expm1(x); w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7|], [|1, 1, D...|], d, absolute, floating); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; for i from 1 to degree(pf) do printdouble(coeff(pf, i)); print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/expm1(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); pxfm-0.1.23/notes/compound_m1_expm1_tiny.sollya000064400000000000000000000007001046102023000176310ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; // display = hexadecimal; n = 9; P = 128; N = 1; d = [-0.125,0.125]; f = 1; w = 1/expm1(x); p = remez(f, n, d, w); Q = horner(fpminimax(expm1(x), [|1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18|], [|0,P...|], d, relative, floating)); e = -log2(dirtyinfnorm(Q * w - f, d)); print ("exp(x) :\n Q(x) =", Q); for i from 1 to degree(Q) do print(coeff(Q, i)); print (" precision:", pretty(e)); pxfm-0.1.23/notes/compoundf_expf.sollya000064400000000000000000000004561046102023000162570ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d=[-1/2^6,1/2^6]; n=4; f = 2^x; w = 1; p = remez(f, n, d, w); pf = fpminimax(2^x, n, [|1,53...|], d, absolute, floating, 0, p); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = hexadecimal; print (pf); display = decimal; print (pretty(err_p)); pxfm-0.1.23/notes/compoundf_expm1.sollya000064400000000000000000000005151046102023000163430ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d=[-1/2^6,1/2^6]; n=4; f = 2^x - 1; w = 1; pf = fpminimax(f, [|1,2,3,4,5|], [|53...|], d, absolute, floating); for i from 1 to degree(pf) do print(coeff(pf, i)); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; print (pf); display = decimal; print (pretty(err_p)); pxfm-0.1.23/notes/compoundf_expm1_accurate.sollya000064400000000000000000000005371046102023000202160ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d=[-1/2^6,1/2^6]; n=8; f = 2^x - 1; w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7,8|], [|107,107,107,53...|], d, absolute, floating); err_p = -log2(dirtyinfnorm(pf*w-f, d)); for i from 1 to degree(pf) do print(coeff(pf, i)); display = decimal; print (pf); display = decimal; print (pretty(err_p)); pxfm-0.1.23/notes/cosf.sollya000064400000000000000000000005351046102023000141730ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; f_cos_16 = cos(x); Q = fpminimax(f_cos_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); err_p = -log2(dirtyinfnorm(Q-f_cos_16, [0, pi/16])); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/cosm1.sollya000064400000000000000000000005321046102023000142600ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [2^-27, 2^-7]; f_cosm1 = (cos(x) - 1); Q = fpminimax(f_cosm1, [|2,4,6,8|], [|0, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_cosm1, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 2 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/cosm1_hard.sollya000064400000000000000000000005241046102023000152570ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [2^-27, 2^-7]; f_cosm1 = cos(x) - 1; Q = fpminimax(f_cosm1, [|2,4,6,8|], [|0, 107...|], d); err_p = -log2(dirtyinfnorm(Q-f_cosm1, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 2 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/cosm1f.sollya000064400000000000000000000005451046102023000144320ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0.0000000000001, pi/16]; f_cosm1 = (cos(x) - 1); Q = fpminimax(f_cosm1, [|2,4,6,8|], [|0, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_cosm1, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 2 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/cospi.sollya000064400000000000000000000006601046102023000143550ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6|], [|107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cos, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/cospi_dd.sollya000064400000000000000000000006601046102023000150240ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|107...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cos, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/cospi_fast_dd.sollya000064400000000000000000000006661046102023000160470ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|1, 107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cos, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/cospi_zero_dd.sollya000064400000000000000000000006711046102023000160650ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.000244140625]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8, 10|], [|107...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cos, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/cospif.sollya000064400000000000000000000005431046102023000145230ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 1/16]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cos, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/cospif_0p25.sollya000064400000000000000000000005561046102023000152750ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.25]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8, 10, 12|], [|1, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_cos, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/cotf.ipynb000064400000000000000000000027501046102023000140130ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 21, "id": "882a5dd6-ad4c-4018-9340-f89a20888f2e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0xbfd5555555555555\n", "0xbf96c16c16c16c17\n", "0xbf61566abc011567\n", "0xbf2bbd779334ef0b\n", "0xbef66a8f2bf70ebe\n" ] } ], "source": [ "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "print(double_to_hex(DD(-1)/DD(3)))\n", "print(double_to_hex(DD(-1)/DD(45)))\n", "print(double_to_hex(DD(-2)/DD(945)))\n", "print(double_to_hex(DD(-1)/DD(4725)))\n", "print(double_to_hex(DD(-2)/DD(93555)))" ] }, { "cell_type": "code", "execution_count": null, "id": "68400e43-6a6a-43c2-93d3-72c4d833c1ac", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/cotf.sollya000064400000000000000000000005311046102023000141700ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; f_cotf = x/tan(x); Q = fpminimax(f_cotf, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); err_p = -log2(dirtyinfnorm(Q-f_cotf, [0, pi/32])); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/csc.ipynb000064400000000000000000000035201046102023000136240ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 11, "id": "b45fc0c2-86a5-44f3-8efb-f4233018327f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x3fc5555555555555\n", "0x3f93e93e93e93e94\n", "0x3f60b2463814bc5f\n", "0x3f2b85fca40e852d\n", "0x3ef65f59e4611336\n", "0x3ec225c0d5895dfa\n" ] } ], "source": [ "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "DD = RealField(190)\n", "\n", "def float_to_hex(f):\n", " packed = struct.pack('>f', float(f))\n", " return '0x' + packed.hex()\n", "\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "print(double_to_hex((DD(1)/DD(6)).exact_rational()))\n", "print(double_to_hex((DD(7)/DD(360)).exact_rational()))\n", "print(double_to_hex((DD(31)/DD(15210)).exact_rational()))\n", "print(double_to_hex((DD(127)/DD('604800')).exact_rational()))\n", "print(double_to_hex((DD(73)/DD('3421440')).exact_rational()))\n", "print(double_to_hex((DD('1414477')/DD('653837184000')).exact_rational()))\n" ] }, { "cell_type": "code", "execution_count": null, "id": "f206a0e4-c159-4ffa-8bb7-27a437b2f494", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/cscf.sollya000064400000000000000000000005721046102023000141600ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; f = 1 / sin(x) - 1/x; d = [0.000443633; pi/16]; pf = fpminimax(f, [|1, 3, 5, 7, 9|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(pf-f, d)); print("Csc [2^-23, pi/16]"); print(pf); display = decimal; print ("absolute error:", pretty(err_p)); for i from 1 to degree(pf) by 2 do printdouble(coeff(pf, i)); pxfm-0.1.23/notes/dd_log.sollya000064400000000000000000000011731046102023000144700ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log(1+x); p0 = x-x^2/2; w = 1; pf = p0+fpminimax(f-p0, [|3,4,5,6,7,8,9,10,11|], [|107...|], d, absolute, floating); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, absolute, 2^(-10))); display = hexadecimal; print (pf); display = decimal; print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, relative, 2^(-10))); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/dd_log10.sollya000064400000000000000000000005351046102023000146320ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log10(1+x)/x; pf = fpminimax(f, 9, [|107...|], d, absolute, floating); print(pf); f = 1; w = x/log10(1+x); err_p = -log2(dirtyinfnorm(pf*x-log10(1+x), d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/dd_log1p_fast.sollya000064400000000000000000000011641046102023000157460ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log(1+x); p0 = x-x^2/2; w = 1; pf = p0+fpminimax(f-p0, [|3,4,5,6,7,8,9|], [|107, D...|], d, absolute, floating); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, absolute, 2^(-10))); display = decimal; print (pf); display = decimal; print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, relative, 2^(-10))); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/dd_log1p_tiny_fast.sollya000064400000000000000000000011341046102023000170060ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12,2^-12]; f = log(1+x); p0 = x-x^2/2; w = 1; pf = p0+fpminimax(f-p0, [|3,4,5,6,7|], [|107, D...|], d, absolute, floating); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, absolute, 2^(-10))); display = decimal; print (pf); display = decimal; print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, relative, 2^(-10))); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/dd_log2.sollya000064400000000000000000000005701046102023000145520ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log2(1+x)/x; w = 1; p = remez(f, 8, d, w); pf = fpminimax(f, 9, [|107...|], d, absolute, floating); print(pf); f = 1; w = x/log2(1+x); err_p = -log2(dirtyinfnorm(pf*x-log2(1+x), d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/dd_log_fast.sollya000064400000000000000000000011721046102023000155040ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log(1+x); p0 = x-x^2/2; w = 1; p = remez(f-p0, 8, d, w); pf = p0+fpminimax(f-p0, [|3,4,5,6,7,8,9,10,11,12|], [|107, 107, 107, D...|], d, absolute, floating); err_p = -log2(supnorm(pf, log(1+x), d, absolute, 2^(-10))); display = hexadecimal; print (pf); display = decimal; print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, relative, 2^(-10))); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/exp10f_small.sollya000064400000000000000000000005471046102023000155370ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-1/32, 1/32]; f_exp10f = (10^y - 1)/y; Q = fpminimax(f_exp10f, 6, [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm((Q*y + 1)-10^y, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/exp2f.sollya000064400000000000000000000005371046102023000142670ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-1/64, 1/64]; f_exp2f = (2^y - 1)/y; Q = fpminimax(f_exp2f, 4, [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_exp2f, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/exp2f_small.sollya000064400000000000000000000005371046102023000154570ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-1/32, 1/32]; f_exp2f = (2^y - 1)/y; Q = fpminimax(f_exp2f, 5, [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_exp2f, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/exp_rational128.ipynb000064400000000000000000000056041046102023000160010ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 7, "id": "fc1de6a9-2b51-46ad-adf8-0aed0494718d", "metadata": {}, "outputs": [], "source": [ "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(190)\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x = RealField(190)(x).exact_rational()\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def split_triple_double(x, prec):\n", " x_hi = RealField(prec)(x) \n", " x_mid = RealField(prec)(x - DD(x_hi))\n", " x_lo = (x - DD(x_hi) - DD(x_mid))\n", " return (x_lo, x_mid, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def print_triple_double(mark, x, prec):\n", " splat = split_triple_double(x, prec)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}, {double_to_hex(splat[2])}),\")\n", "\n", "def format_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_hex(m)},\")\n", " print(\"},\")" ] }, { "cell_type": "code", "execution_count": 8, "id": "401fec27-c3e0-4007-ac0d-c2fa5d7af03b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0x3b0b0e2633fe0685, 0x3d0718432a000000, 0xbf262e42ff000000),\n" ] } ], "source": [ "k = -RealField(190)(2)**(-12) * RealField(190)(2).log()\n", "print_triple_double(\"\", k, 30)" ] }, { "cell_type": "code", "execution_count": null, "id": "2a27e2ab-a645-4844-b9bf-d3e8b2a7c28d", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/expf.sollya000064400000000000000000000005211046102023000141760ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-8, 2^-8]; f_exp = expm1(x)/x; Q = fpminimax(f_exp, 3, [|D...|], [-2^-8, 2^-8]); err_p = -log2(dirtyinfnorm(Q-f_exp, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/gammaf.sollya000064400000000000000000000006601046102023000144700ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; //prec = 1500; pxfm_gamma = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = pxfm_gamma(x + 1); d = [0, 1]; w = 1; pf = remez(f, 16, d); w = 1; or_f = pxfm_gamma(x + 1); pf1 = pf; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 1 do { print("'", coeff(pf, i), "',"); };pxfm-0.1.23/notes/inv_cbrt.sollya000064400000000000000000000006501046102023000150450ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [1.0, 2.0]; f_inv_cbrt = x^(-1/3); Q = fpminimax(f_inv_cbrt, 5, [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_inv_cbrt, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 1 do print(coeff(Q, i));pxfm-0.1.23/notes/inverff.sollya000064400000000000000000000033021046102023000146730ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 150; d = [0.25, 0.5]; f = 3.9355463812787410974469983046555801290619594e9*x^24 - 4.5246026244384908642814791377304835136843534e10*x^23 + 2.4362407388812130000845083659128499989273569e11*x^22 - 8.1633977267388496546936799134874805863015282e11*x^21 + 1.9078443946677331339825830636134700094629649e12*x^20 - 3.3033111807763282009824639245166067471347171e12*x^19 + 4.3934226329517058595055324528036257712949034e12*x^18 - 4.5928963474503051271004596702158172065455963e12*x^17 + 3.8302508386470367060541755052713632511631753e12*x^16 - 2.5716198617368772263217891819596008598843229e12*x^15 + 1.3969067607281243266212587664398367627952630e12*x^14 - 6.1480916442304850256040331920303517989841794e11*x^13 + 2.1887903737100660029154408592265686573459860e11*x^12 - 6.2736502400284099096956577098164151107956917e10*x^11 + 1.4363509955189548208339153785014028912437216e10*x^10 - 2.5966912775509086024146690818437206009395648e9*x^9 + 3.6482518059419479152510854160286795432428263e8*x^8 - 3.8983566572592302427620438812930734432638947e7*x^7 + 3.0767002957981533588597192807806373861779260e6*x^6 - 172228.41234292446751491027445911121020256755*x^5 + 6453.0276580455544567596723159833941822013785*x^4 - 148.22011835660733528550887339593435011575072*x^3 + 1.8135865148007225586654047902884036425972788*x^2 - 0.0087036568883852303301078415962842225110281525*x + 0.88623389393525708634218134616533616863715583; Q = fpminimax(f, 9, [|D...|], d); err_p = -log2(dirtyinfnorm(Q-f, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i)); for i from 0 to degree(Q) by 1 do print(coeff(Q, i));pxfm-0.1.23/notes/log1p.sollya000064400000000000000000000012571046102023000142650ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; prec = 1024; d = [-0.00202941894531250,0.00212097167968735]; f = log(1+x); p0 = x-x^2/2; w = 1; p = remez(f-p0, 9, d, w); pf = p0+fpminimax(f-p0, [|3,4,5,6,7,8,9,10,11,12,13,14|], [|DD...|], d, absolute, floating); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, absolute, 2^(-10))); display = decimal; print (pf); display = decimal; print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, relative, 2^(-10))); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/log1p_tiny.sollya000064400000000000000000000007051046102023000153250ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; p1 = 1; p2 = -1/2; p3 = 1/3; p4 = -1/4; p5 = 1/5; p6 = -1/6; p7 = 1/7; p8 = -1/8; p = p1*x+p2*x^2+p3*x^3+p4*x^4+p5*x^5+p6*x^6+p7*x^7+p8*x^8; d = [-0.00202941894531250,0.00212097167968735]; f = log(1+x); w = 1; err_p = -log2(dirtyinfnorm(p*w-f, d)); print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); err_p = -log2(dirtyinfnorm(p*w-f, d)); print ("relative error:", pretty(err_p)); pxfm-0.1.23/notes/log1pf.sollya000064400000000000000000000005211046102023000144240ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-6; 2^-6]; f_log1pf = log(1+x)/x; Q = fpminimax(f_log1pf, 7, [|0, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_log1pf, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/log1pf_core.sollya000064400000000000000000000005071046102023000154400ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-8, 2^-7]; f_log = log(1 + x)/x; Q = fpminimax(f_log, 6, [|D...|], d); err_p = -log2(dirtyinfnorm(Q-f_log, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/log1pmx.sollya000064400000000000000000000006331046102023000146270ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-6; 2^-6]; f_log1pf = (log(1+x) - x)/x^2; Q = fpminimax(f_log1pf, 10, [|0, 107, 107, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_log1pf, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i)); for i from 0 to degree(Q) by 1 do print(coeff(Q, i));pxfm-0.1.23/notes/log1pmx_at_zero.sollya000064400000000000000000000006341046102023000163530ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-10; 2^-10]; f_log1pf = (log(1+x) - x)/x^2; Q = fpminimax(f_log1pf, 7, [|0, 107, 107, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_log1pf, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i)); for i from 0 to degree(Q) by 1 do print(coeff(Q, i));pxfm-0.1.23/notes/log1pmx_at_zero_hard.sollya000064400000000000000000000006241046102023000173500ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-10; 2^-10]; f_log1pf = (log(1+x) - x)/x^2; Q = fpminimax(f_log1pf, 7, [|0, 107...|], d); err_p = -log2(dirtyinfnorm(Q-f_log1pf, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i)); for i from 0 to degree(Q) by 1 do print(coeff(Q, i));pxfm-0.1.23/notes/log1pmxf.sollya000064400000000000000000000005311046102023000147720ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-6; 2^-6]; f_log1pf = (log(1+x) - x)/x^2; Q = fpminimax(f_log1pf, 6, [|0, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_log1pf, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/log2.sollya000064400000000000000000000004731046102023000141050ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-8, 2^-7]; f = (log2(1 + x))/x; w = 1; pf = fpminimax(f, 5, [|D...|], [-2^-8, 2^-7]); print(pf); f = 1; err_p = -log2(dirtyinfnorm(pf*x-log2(1+x), d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do printdouble(coeff(pf, i)); pxfm-0.1.23/notes/log2p1.sollya000064400000000000000000000003011046102023000143340ustar 00000000000000f = log(x + 1)/x; I = [1; sqrt(2)]; P = fpminimax(f, 12, [|1, -0.5, 128...|], I, relative, floating); print("Log(x+1) [1; sqrt(2)]"); print(P); for i from 0 to degree(P) do print(coeff(P, i));pxfm-0.1.23/notes/log_dyadic.sollya000064400000000000000000000004001046102023000153260ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; P = fpminimax((log(1 + x) - x)/x^2, 2, [|1, 128...|], [-0x1.0002143p-29 , 0x1p-29]); err = -log2(dirtyinfnorm(log(1 + x)/x - x*P, [-0x1.0002143p-29 , 0x1p-29])); print ("relative error:", pretty(err));pxfm-0.1.23/notes/one_twenty_eight_over_pi.sollya000064400000000000000000000006271046102023000203410ustar 00000000000000for i from 0 to 63 do { if i < 3 then { pi_inv = 0.25 + 2^(16*(i - 3)) / pi; } else { pi_inv = 2^(16*(i-3)) / pi; }; pn = nearestint(pi_inv); pi_frac = pi_inv - pn; a = round(pi_frac, 51, RN); b = round(pi_frac - a, 51, RN); c = round(pi_frac - a - b, 51, RN); d = round(pi_frac - a - b - c, D, RN); print("{", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "},"); };pxfm-0.1.23/notes/pow_exp_1.sollya000064400000000000000000000006651046102023000151460ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = exp(x); w = 1; p = remez(f, 4, d, w); pf = fpminimax(f, [|0,1,2,3,4|], [|53...|], d, absolute, floating, 0, p); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = hexadecimal; print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/exp(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); pxfm-0.1.23/notes/pow_expm1_1.sollya000064400000000000000000000007471046102023000154050ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = expm1(x); w = 1; p = remez(f, 4, d, w); pf = fpminimax(f, [|1,2,3,4,5|], [|0, 53...|], d, absolute, floating); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; for i from 0 to degree(pf) do print(coeff(pf, i)); print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/expm1(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); pxfm-0.1.23/notes/powm1f_exp2m1.sollya000064400000000000000000000005311046102023000156420ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-6, 2^-6]; f_exp = (2^x - 1)/x; Q = fpminimax(f_exp, 5, [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_exp, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 1 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/r_erf_tiny.sollya000064400000000000000000000010331046102023000153730ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 1/16]; f = x/erf(x); Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|107, 107, 107, D...|], d); err_p = -log2(dirtyinfnorm(Q-f, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do { write(coeff(Q, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }; for i from 0 to degree(Q) by 2 do print(coeff(Q, i)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); pxfm-0.1.23/notes/r_erf_tiny_hard.sollya000064400000000000000000000005221046102023000163730ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 1/16]; f = x/erf(x); Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|107...|], d); err_p = -log2(dirtyinfnorm(Q-f, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/r_erff.sollya000064400000000000000000000010031046102023000144730ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 1/16]; f = x/erf(x); Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|D...|], d); err_p = -log2(dirtyinfnorm(Q-f, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do { write(coeff(Q, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }; for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/rerf.ipynb000064400000000000000000000165401046102023000140200ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 3, "id": "5c31a739-c406-4706-8161-19f1890fc512", "metadata": {}, "outputs": [], "source": [ "from scipy.special import j1\n", "from scipy.optimize import brentq\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(157)\n", "\n", "def double_to_hex(f):\n", " # Converts Python float (f64) to hex string\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo, x_hi)\n", "\n", "def print_double_double(mark, x):\n", " splat = split_double_double(x)\n", " print(f\"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),\")\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")\n" ] }, { "cell_type": "code", "execution_count": 28, "id": "6eff360d-b2de-471a-a6d2-98410ce6e72a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static RERF_FAST: [[u64; 18]; 95] = [\n", "];\n" ] } ], "source": [ "def build_sollya_script(idx):\n", " return f\"\"\"\n", "d = [{idx}/16, {idx + 1}/16];\n", "\n", "f = 1/erf(x);\n", "Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24|], [|107, 107, 107, 107, 107, 107, D...|], d);\n", "\n", "for i from 0 to degree(Q) by 2 do {{\n", " write(coeff(Q, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(idx):\n", " sollya_script = build_sollya_script(idx)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "def print_coeffs(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " v_str = \"\"\n", " if i == 0:\n", " (lo, hi) = split_double_double(coeff)\n", " v_str += double_to_hex(lo) + \",\" + double_to_hex(hi) + \",\"\n", " elif i == 1:\n", " (lo, hi) = split_double_double(coeff)\n", " v_str += double_to_hex(lo) + \",\" + double_to_hex(hi) + \",\"\n", " elif i == 2:\n", " (lo, hi) = split_double_double(coeff)\n", " v_str += double_to_hex(lo) + \",\" + double_to_hex(hi) + \",\"\n", " elif i == 3:\n", " (lo, hi) = split_double_double(coeff)\n", " v_str += double_to_hex(lo) + \",\" + double_to_hex(hi) + \",\"\n", " elif i == 4:\n", " (lo, hi) = split_double_double(coeff)\n", " v_str += double_to_hex(lo) + \",\" + double_to_hex(hi) + \",\"\n", " elif i == 5:\n", " (lo, hi) = split_double_double(coeff)\n", " v_str += double_to_hex(lo) + \",\" + double_to_hex(hi) + \",\"\n", " else:\n", " v_str += double_to_hex(coeff) + \",\"\n", " print(v_str)\n", " print(\"],\")\n", "\n", "print(f\"pub(crate) static RERF_FAST: [[u64; 18]; 95] = [\")\n", "for i in range(1, 96):\n", " call_sollya_on_interval(i)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_coeffs(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": 29, "id": "fbc20044-1f58-4776-8c0a-8ee406770911", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pub(crate) static RERF_HARD: [[(u64, u64); 11]; 96] = [\n", "];\n" ] } ], "source": [ "def build_sollya_script(idx):\n", " return f\"\"\"\n", "d = [{idx}/16, {idx + 1}/16];\n", "\n", "f = x/erf(x);\n", "Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20|], [|107...|], d);\n", "\n", "for i from 0 to degree(Q) by 2 do {{\n", " write(coeff(Q, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(idx):\n", " sollya_script = build_sollya_script(idx)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "def print_coeffs(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " print_double_double(\"\", coeff)\n", " print(\"],\")\n", "\n", "print(f\"pub(crate) static RERF_HARD: [[(u64, u64); 11]; 96] = [\")\n", "for i in range(0, 96):\n", " call_sollya_on_interval(i)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_coeffs(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": null, "id": "07c7c419-fe62-4672-b80a-9fae74d5800d", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/rerff.ipynb000064400000000000000000000314301046102023000141610ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 2, "id": "7d8ff047-2c60-4751-b874-3b2971c582fe", "metadata": {}, "outputs": [], "source": [ "from scipy.special import j1\n", "from scipy.optimize import brentq\n", "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "\n", "DD = RealField(157)\n", "\n", "def double_to_hex(f):\n", " # Converts Python float (f64) to hex string\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "def split_double_double(x):\n", " # Split RR value x into hi + lo (double-double)\n", " x_hi = DR(x) # convert to f64\n", " x_lo = x - DD(x_hi)\n", " return (x_lo,x_hi)\n", "\n", "def format_dyadic_hex(value):\n", " l = hex(value)[2:]\n", " n = 8\n", " x = [l[i:i + n] for i in range(0, len(l), n)]\n", " return \"0x\" + \"_\".join(x) + \"_u128\"\n", "\n", "def print_dyadic(value):\n", " (s, m, e) = RealField(128)(value).sign_mantissa_exponent();\n", " print(\"DyadicFloat128 {\")\n", " print(f\" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},\")\n", " print(f\" exponent: {e},\")\n", " print(f\" mantissa: {format_dyadic_hex(m)},\")\n", " print(\"},\")\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "14684051-e84d-4b7b-b943-b542ca5259df", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "static COEFFS: [[u64; 8]; 32] = [\n", "[\n", "0x3fec5bf891b4ef6b ,\n", "0x3fd2e7fb0bcdee7f ,\n", "0x3f842aa5641a200a ,\n", "0xbf752081ae81d16e ,\n", "0x3f2e1a191fb85592 ,\n", "0xbf203a20ad500043 ,\n", "0x3f861a864f719e76 ,\n", "0xbfc79f68bad20bd1 ,\n", "],\n", "[\n", "0x3fec5bf891b4ef6b ,\n", "0x3fd2e7fb0bcdf45b ,\n", "0x3f842aa561f35512 ,\n", "0xbf75207c8167ac1d ,\n", "0x3f2db4b119b4ce20 ,\n", "0x3f20fa28737c4219 ,\n", "0xbef38e74cca2219a ,\n", "0xbec5d70713fc621e ,\n", "],\n", "[\n", "0x3fec5bf891b4ef30 ,\n", "0x3fd2e7fb0bce1c0f ,\n", "0x3f842aa56138541f ,\n", "0xbf75207c6197eb7c ,\n", "0x3f2db4799120e074 ,\n", "0x3f20fc28d915a6e9 ,\n", "0xbef3ea5b479dc053 ,\n", "0xbebbffe6df8ec372 ,\n", "],\n", "[\n", "0x3fec5bf891b4bf18 ,\n", "0x3fd2e7fb0bde166f ,\n", "0x3f842aa53c721766 ,\n", "0xbf7520796733bbec ,\n", "0x3f2db21eebf4144f ,\n", "0x3f210545cc78d0f0 ,\n", "0xbef48ad7e4aa2d10 ,\n", "0xbeb24a043ad31907 ,\n", "],\n", "[\n", "0x3fec5bf891ab16e9 ,\n", "0x3fd2e7fb0dc7b919 ,\n", "0x3f842aa29d8381e7 ,\n", "0xbf7520592585d601 ,\n", "0x3f2da30df1566e43 ,\n", "0x3f212780ff325aa6 ,\n", "0xbef5e98ea9819e42 ,\n", "0xbe9849d52099dcb9 ,\n", "],\n", "[\n", "0x3fec5bf890ddfa8d ,\n", "0x3fd2e7fb28aab312 ,\n", "0x3f842a8a461f0eb7 ,\n", "0xbf751f93b2d27114 ,\n", "0x3f2d66789eed5f95 ,\n", "0x3f21818ff1832f50 ,\n", "0xbef84264724049ef ,\n", "0x3e9df12b02e82a5a ,\n", "],\n", "[\n", "0x3fec5bf887f64fa4 ,\n", "0x3fd2e7fbfcc05f75 ,\n", "0x3f842a02323e2099 ,\n", "0xbf751c86d291ced6 ,\n", "0x3f2cbd5653cde433 ,\n", "0x3f223299b32b8583 ,\n", "0xbefb7fc6e286cd94 ,\n", "0x3eb49676cb3da393 ,\n", "],\n", "[\n", "0x3fec5bf84f8e2488 ,\n", "0x3fd2e7ffe83d2974 ,\n", "0x3f842821c5cc659c ,\n", "0xbf7514805a6196e3 ,\n", "0x3f2b723680f64bb5 ,\n", "0x3f233416dcfcd366 ,\n", "0xbefefe55300afaa7 ,\n", "0x3ebf0c475fb71e7a ,\n", "],\n", "[\n", "0x3fec5bf7999e6afe ,\n", "0x3fd2e809c6d4caa7 ,\n", "0x3f84247256be4a56 ,\n", "0xbf750838db0c0cf5 ,\n", "0x3f29e7e867267388 ,\n", "0x3f24226adee5ce74 ,\n", "0xbf00c0830af2bf01 ,\n", "0x3ec26fb6b18e628b ,\n", "],\n", "[\n", "0x3fec5bf801fc5ad5 ,\n", "0x3fd2e80618e8941e ,\n", "0x3f84254c04b0b234 ,\n", "0xbf7509d7cf351201 ,\n", "0x3f2a01829944820c ,\n", "0x3f241d7bb0c7e2de ,\n", "0xbf00c2d844916d26 ,\n", "0x3ec2817d39abc26b ,\n", "],\n", "[\n", "0x3fec5c0938a12f13 ,\n", "0x3fd2e7706c510d79 ,\n", "0x3f8448392db86aae ,\n", "0xbf75526e9c6046f0 ,\n", "0x3f2facd0bc0e7862 ,\n", "0x3f21fc4093e1e6b7 ,\n", "0xbefdf54af68ba968 ,\n", "0x3ebfe348fc246c15 ,\n", "],\n", "[\n", "0x3fec5c6dcdadc5d8 ,\n", "0x3fd2e495072afff3 ,\n", "0x3f84d6f390564d4d ,\n", "0xbf764a7e85749c85 ,\n", "0x3f37effb62caee80 ,\n", "0x3f19cb39bc236ae6 ,\n", "0xbef6d7035785e8f3 ,\n", "0x3eb755aa2e58fc52 ,\n", "],\n", "[\n", "0x3fec5dd74381acff ,\n", "0x3fd2dbe68140f116 ,\n", "0x3f86459e1acfda0f ,\n", "0xbf7865203923a03d ,\n", "0x3f43665053a48049 ,\n", "0x3f0409e353b761ea ,\n", "0xbeeb0b00f567c9f8 ,\n", "0x3eabc33000611b25 ,\n", "],\n", "[\n", "0x3fec6175431226d1 ,\n", "0x3fd2c8dcbb0babcc ,\n", "0x3f88f5bfd61e5d2e ,\n", "0xbf7bc60de8dff620 ,\n", "0x3f4d9b7076c7767c ,\n", "0xbf0106584fac3547 ,\n", "0xbed0a56cd1030deb ,\n", "0x3e970ee11e7beb48 ,\n", "],\n", "[\n", "0x3fec68445d99a8e9 ,\n", "0x3fd2a9d608dbfea2 ,\n", "0x3f8cc072ddf22cb6 ,\n", "0xbf7fe5f2efdc5f5c ,\n", "0x3f5431d1deff38bc ,\n", "0xbf197220e4a1dda8 ,\n", "0x3ec9e2469e6c1c67 ,\n", "0x3e4be72535d53d7b ,\n", "],\n", "[\n", "0x3fec713c415bf088 ,\n", "0x3fd28610e83aa38c ,\n", "0x3f9049ee1942f46b ,\n", "0xbf81c513d165d6fd ,\n", "0x3f585bc13e0fcaba ,\n", "0xbf22715362e30768 ,\n", "0x3ede6bfa3c69e8e3 ,\n", "0xbe852cd85f8dea5b ,\n", "],\n", "[\n", "0x3fec770e08b47107 ,\n", "0x3fd2716324b22047 ,\n", "0x3f91460d403e6b9c ,\n", "0xbf829ab46375f10d ,\n", "0x3f5a0e7f00c76fb5 ,\n", "0xbf2484890f2d7eeb ,\n", "0x3ee207b21bbd8496 ,\n", "0xbe8bbee036671b6a ,\n", "],\n", "[\n", "0x3fec6f4a2d01088d ,\n", "0x3fd288e494bc89b7 ,\n", "0x3f905203788a2821 ,\n", "0xbf81eab2727ce365 ,\n", "0x3f58ddba75a3c100 ,\n", "0xbf2347c9a317a175 ,\n", "0x3ee099c93ce5f44f ,\n", "0xbe88e9f9c064f833 ,\n", "],\n", "[\n", "0x3fec4c9bbce50c7d ,\n", "0x3fd2e8175b0e1837 ,\n", "0x3f89a2d1518c7a4c ,\n", "0xbf7f3fa91859127e ,\n", "0x3f55431c495b1077 ,\n", "0xbf1fc1af665bb1f8 ,\n", "0x3eda0f1d735195cb ,\n", "0xbe827b8d6fa224ed ,\n", "],\n", "[\n", "0x3fec03cce39d7213 ,\n", "0x3fd39c2316e290bf ,\n", "0x3f7b674438899313 ,\n", "0xbf783644c88c71fb ,\n", "0x3f5047a3da485180 ,\n", "0xbf1748b54f823d57 ,\n", "0x3ed20c86d3302f22 ,\n", "0xbe77f94cafe045a8 ,\n", "],\n", "[\n", "0x3feb913f0adf6c4b ,\n", "0x3fd49c4cedae09fc ,\n", "0xbf4a6dea9778f474 ,\n", "0xbf7006dc4e6c8125 ,\n", "0x3f461483c254fa5f ,\n", "0xbf0e75052760bf18 ,\n", "0x3ec65425869bc096 ,\n", "0xbe6bc2df9fbc0f82 ,\n", "],\n", "[\n", "0x3feafbeda3b7d400 ,\n", "0x3fd5cb900ee1fb5e ,\n", "0xbf8228d16e87de3d ,\n", "0xbf6011d44e155bf5 ,\n", "0x3f3993b736442257 ,\n", "0xbf017c7ee5efa6ad ,\n", "0x3eb886e337d2e3c2 ,\n", "0xbe5cba4b79e90043 ,\n", "],\n", "[\n", "0x3fea54849d309eba ,\n", "0x3fd701afa55e3d21 ,\n", "0xbf90c72bb2e2799f ,\n", "0xbf33c92573294e34 ,\n", "0x3f265284f7a6d53a ,\n", "0xbef09f09298ed1e8 ,\n", "0x3ea7153a46cb2e27 ,\n", "0xbe49ef6ec79265fd ,\n", "],\n", "[\n", "0x3fe9b128df667870 ,\n", "0x3fd816d295a867cb ,\n", "0xbf9713f11ea84a26 ,\n", "0x3f4edcbdd63903bb ,\n", "0x3ef44f54fc7a6024 ,\n", "0xbed45da547d2fcb8 ,\n", "0x3e9049754d57a9a7 ,\n", "0xbe32aba05ca26a69 ,\n", "],\n", "[\n", "0x3fe927f49edf4ace ,\n", "0x3fd8ecd207c6a7d1 ,\n", "0xbf9b8cd215124008 ,\n", "0x3f5cbab209dd389d ,\n", "0xbf12a8920ea6230f ,\n", "0x3eb442dfce60b0e2 ,\n", "0x3e52494e415c7728 ,\n", "0xbe09a1b1bbb9cee4 ,\n", "],\n", "[\n", "0x3fe8ca3d7437d06f ,\n", "0x3fd973c08b6d33fb ,\n", "0xbf9e272ca1fccc06 ,\n", "0x3f61efd00e2016b6 ,\n", "0xbf1e6dab18e9d45a ,\n", "0x3ed0b446e3469be1 ,\n", "0xbe7503c584488bed ,\n", "0x3e069968660290a4 ,\n", "],\n", "[\n", "0x3fe8a1f4b154f663 ,\n", "0x3fd9a9a8b81692d4 ,\n", "0xbf9f1e9312dd4501 ,\n", "0x3f632b4d20599404 ,\n", "0xbf2119c1b5e43b24 ,\n", "0x3ed42b9874284d56 ,\n", "0xbe7c17cc1eef4b9d ,\n", "0x3e117f0a9057a689 ,\n", "],\n", "[\n", "0x3fe8b15bfcf78f33 ,\n", "0x3fd99720c884ab33 ,\n", "0xbf9ed2265979f5a6 ,\n", "0x3f62d3c30432692b ,\n", "0xbf20a17346c37362 ,\n", "0x3ed36538f2d21c31 ,\n", "0xbe7aac6bb10f8b90 ,\n", "0x3e1061d3a1737044 ,\n", "],\n", "[\n", "0x3fe8f479e98cb825 ,\n", "0x3fd94ab3f8d0c80c ,\n", "0xbf9da7afe85abf94 ,\n", "0x3f618fe28f71a3d4 ,\n", "0xbf1df723b2a63e38 ,\n", "0x3ed0d190252a7f7c ,\n", "0xbe7631fdd49272b0 ,\n", "0x3e0a17567cab4a94 ,\n", "],\n", "[\n", "0x3fe9636d647b61c0 ,\n", "0x3fd8d4aaba0e0212 ,\n", "0xbf9bf904574e56ea ,\n", "0x3f5fb68684d8555d ,\n", "0xbf19d06f9cf17bbf ,\n", "0x3ecb92b9f0b8acf3 ,\n", "0xbe7145bde0c499ae ,\n", "0x3e033cf1cb08ce4c ,\n", "],\n", "[\n", "0x3fe9f4c3301b6d33 ,\n", "0x3fd844100b4598b3 ,\n", "0xbf9a0b94e19be990 ,\n", "0x3f5c0ed55c70532f ,\n", "0xbf15a786c9e62b23 ,\n", "0x3ec5e3f05a04f5c6 ,\n", "0xbe69ea9db2e37883 ,\n", "0x3dfb3e5ad2cd0fb2 ,\n", "],\n", "[\n", "0x3fea9f469c75536c ,\n", "0x3fd7a51b3d9eda10 ,\n", "0xbf980f63a2cb486c ,\n", "0x3f5887f72a9f07e0 ,\n", "0xbf11e4d454f2f994 ,\n", "0x3ec113d0aed8bdef ,\n", "0xbe6311f84083acf4 ,\n", "0x3df2e4dc2e50e3fa ,\n", "],\n", "];\n" ] } ], "source": [ "def build_sollya_script(idx):\n", " return f\"\"\"\n", "d = [{idx}/8, {idx + 1}/8];\n", "\n", "f = x/erf(x);\n", "Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|D...|], d);\n", "\n", "for i from 0 to degree(Q) by 2 do {{\n", " write(coeff(Q, i)) >> \"coefficients.txt\";\n", " write(\"\\\\n\") >> \"coefficients.txt\";\n", "}};\n", "\"\"\"\n", "\n", "def load_coefficients(filename):\n", " with open(filename, \"r\") as f:\n", " return [RealField(500)(line.strip()) for line in f if line.strip()]\n", "\n", "def call_sollya_on_interval(idx):\n", " sollya_script = build_sollya_script(idx)\n", " with open(\"tmp_interval.sollya\", \"w\") as f:\n", " f.write(sollya_script)\n", " import subprocess\n", " if os.path.exists(\"coefficients.txt\"):\n", " os.remove(\"coefficients.txt\")\n", " try:\n", " result = subprocess.run(\n", " [\"sollya\", \"tmp_interval.sollya\"],\n", " check=True,\n", " capture_output=True,\n", " text=True\n", " )\n", " except subprocess.CalledProcessError as e:\n", " return\n", "\n", "def print_coeffs(poly):\n", " print(\"[\")\n", " for i in range(len(poly)):\n", " coeff = poly[i]\n", " print(double_to_hex(coeff), \",\")\n", " print(\"],\")\n", "\n", "print(f\"static COEFFS: [[u64; 8]; 32] = [\")\n", "for i in range(0, 32):\n", " call_sollya_on_interval(i)\n", " coeffs = load_coefficients(f\"coefficients.txt\")\n", " print_coeffs(coeffs)\n", "print(\"];\")" ] }, { "cell_type": "code", "execution_count": null, "id": "1e58d58c-65c7-49e0-81bc-2d114c9e6ace", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/sec.ipynb000064400000000000000000000167141046102023000136370ustar 00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "d1c368c9-c0f8-4873-b4d3-9d90f741dddd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x3fe0000000000000\n", "0x3fcaaaaaaaaaaaab\n", "0x3fb5b05b05b05b06\n", "0x3fa1965965965966\n", "0x3f8c834283cd3723\n", "0x3f771c9634451939\n", "0x3f62bbcea738201f\n" ] } ], "source": [ "from sage.all import *\n", "import struct\n", "\n", "DR = RealField(53)\n", "DD = RealField(190)\n", "\n", "def float_to_hex(f):\n", " packed = struct.pack('>f', float(f))\n", " return '0x' + packed.hex()\n", "\n", "\n", "def double_to_hex(f):\n", " packed = struct.pack('>d', float(f))\n", " return '0x' + packed.hex()\n", "\n", "print(double_to_hex(DD(1)/DD(2)))\n", "print(double_to_hex(DD(5)/DD(24)))\n", "print(double_to_hex(DD(61)/DD(720)))\n", "print(double_to_hex(DD(277)/DD(8064)))\n", "print(double_to_hex(DD(50521)/DD(3628800)))\n", "print(double_to_hex(DD('540553')/DD('95800320')))\n", "print(double_to_hex(DD('199360981')/DD('87178291200')))" ] }, { "cell_type": "code", "execution_count": 2, "id": "70be4e15-defd-4c5e-b915-4c0cd90a952f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Order 6: 0.004\n", "Order 8: 0.013000000000000005\n", "Order 10: 0.03000000000000002\n", "Order 12: 0.05300000000000004\n", "Order 14: 0.08100000000000006\n" ] } ], "source": [ "# test max cutoff for direct evaluation\n", "from mpmath import mp, sec, taylor, mpf\n", "\n", "mp.dps = 50 \n", "true_sec = lambda x: sec(x)\n", "approx_sec = lambda x, n: sum(c * mpf(x)**i for i, c in enumerate(taylor(sec, 0, n+1)))\n", "\n", "def max_x_for_order(n, max_rel_error=2**-68):\n", " x = 0.0\n", " step = 0.001\n", " while True:\n", " x += step\n", " exact = true_sec(x)\n", " approx = approx_sec(x, n)\n", " rel_error = abs((approx - exact) / exact)\n", " if rel_error > max_rel_error:\n", " return x - step\n", "\n", "print(\"Order 6:\", max_x_for_order(6))\n", "print(\"Order 8:\", max_x_for_order(8))\n", "print(\"Order 10:\", max_x_for_order(10))\n", "print(\"Order 12:\", max_x_for_order(12))\n", "print(\"Order 14:\", max_x_for_order(14))" ] }, { "cell_type": "code", "execution_count": 16, "id": "c92dbf4e-a129-4e1e-b276-9df0a40588d9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0x3bf0000000000000\n", "0x3bd0000000000000\n" ] } ], "source": [ "print(double_to_hex(2**-64))\n", "print(double_to_hex(2**-66))" ] }, { "cell_type": "code", "execution_count": 26, "id": "3284ecf5-455b-4ea0-8f27-800a007a4834", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "50521/3628800*x^10 + 277/8064*x^8 + 61/720*x^6 + 5/24*x^4 + 1/2*x^2 + 1\n", "0.08472222222222223*hi^6 + 0.5083333333333333*hi*lo^5 + 0.08472222222222223*lo^6 + (1.2708333333333335*hi^2 + 0.20833333333333334)*lo^4 + 0.20833333333333334*hi^4 + (1.6944444444444446*hi^3 + 0.8333333333333334*hi)*lo^3 + (1.2708333333333335*hi^4 + 1.25*hi^2 + 0.5)*lo^2 + 0.5*hi^2 + (0.5083333333333333*hi^5 + 0.8333333333333334*hi^3 + 1.0*hi)*lo + 1\n" ] } ], "source": [ "x = var('x')\n", "f = 1 / cos(x)\n", "\n", "# Generate Taylor (Maclaurin) series for sec(x) around x=0 up to order 10\n", "taylor_series = f.taylor(x, 0, 10)\n", "show(taylor_series)\n", "\n", "hi = var('hi')\n", "lo = var('lo')\n", "\n", "x = hi + lo\n", "\n", "series = 61/720*x**6 + 5/24*x**4 + 1/2*x**2 + 1\n", "expanded_series = series.simplify_full()\n", "print(expanded_series)\n" ] }, { "cell_type": "code", "execution_count": 25, "id": "5de9f676-b3e7-4ecf-8522-1350b7a81600", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-1/5040*u_hi^7 + 1/120*u_hi^5 - 1/6*u_hi^3 + u_hi\n", "-1/5040*(7*u_hi^6 + 21*u_hi^5*u_lo + 35*u_hi^4*u_lo^2 + 35*u_hi^3*u_lo^3 + 21*u_hi^2*u_lo^4 + 7*u_hi*u_lo^5 + u_lo^6 - 210*u_hi^4 - 420*u_hi^3*u_lo - 420*u_hi^2*u_lo^2 - 210*u_hi*u_lo^3 - 42*u_lo^4 + 2520*u_hi^2 + 2520*u_hi*u_lo + 840*u_lo^2 - 5040)*u_lo\n", "sin(y) ≈ \n", " u_hi\n", " + u_hi^3 * (-1/6 + u_hi^2 * (1/120 - u_hi^2 * 1/5040))\n", " + u_lo * (1 + u_hi^2 * (-1/2 + u_hi^2 / 24))\n", "Difference from true Taylor series:\n", "-(3.96508223080413e-19)*u_hi^7 - 0.0013888888888888885*u_hi^6*u_lo - 0.001388888888888889*u_hi*u_lo^6 - 0.000198412698412698*u_lo^7 + (-0.004166666666666667*u_hi^2 + 0.008333333333333333)*u_lo^5 + (-0.006944444444444444*u_hi^3 + 0.041666666666666664*u_hi)*u_lo^4 + (-0.006944444444444444*u_hi^4 + 0.08333333333333333*u_hi^2 - 0.16666666666666666)*u_lo^3 + (-0.0041666666666666675*u_hi^5 + 0.08333333333333333*u_hi^3 - 0.5*u_hi)*u_lo^2\n" ] } ], "source": [ "# Declare variables\n", "y = var('y')\n", "\n", "# Taylor expand sin(y) around y=0 up to y^7\n", "sin_series = sin(y).taylor(y, 0, 7)\n", "\n", "u_hi, u_lo = var('u_hi u_lo')\n", "y = u_hi + u_lo\n", "\n", "# Substitute y = u_hi + u_lo\n", "sin_series_hi_lo = sin_series.substitute(y = u_hi + u_lo)\n", "\n", "# Expand all terms\n", "expanded = sin_series_hi_lo.expand()\n", "\n", "# Now collect terms similar to the target form manually:\n", "# Split into hi-only and lo-containing parts\n", "\n", "# Extract terms involving only u_hi\n", "hi_only = expanded.coefficient(u_lo, 0)\n", "print(hi_only)\n", "\n", "# Extract terms involving u_lo (linear in u_lo only here)\n", "lo_term = (expanded - hi_only).factor()\n", "\n", "print(lo_term)\n", "\n", "# Now print the terms manually in Horner form\n", "print(\"sin(y) ≈ \")\n", "print(\" u_hi\")\n", "print(\" + u_hi^3 * (-1/6 + u_hi^2 * (1/120 - u_hi^2 * 1/5040))\")\n", "print(\" + u_lo * (1 + u_hi^2 * (-1/2 + u_hi^2 / 24))\")\n", "\n", "# Optional: verify that your manual form equals original\n", "manual = (\n", " u_hi\n", " + u_hi**3 * (-1/6 + u_hi**2 * (1/120 - u_hi**2 * (1/5040)))\n", " + u_lo * (1 + u_hi**2 * (-1/2 + u_hi**2 / 24))\n", ")\n", "\n", "print(\"Difference from true Taylor series:\")\n", "print((expanded - manual).simplify_full())\n" ] }, { "cell_type": "code", "execution_count": null, "id": "01559748-6d65-489f-9080-16a71dcec734", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "81042114-e07e-4a64-9763-70bacda7d420", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.5" } }, "nbformat": 4, "nbformat_minor": 5 } pxfm-0.1.23/notes/secf.sollya000064400000000000000000000005731046102023000141630ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; f = 1 / cos(x); d = [0.000244141; pi/16]; pf = fpminimax(f, [|0, 2, 4, 6, 8, 10|], [|1, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(pf-f, d)); print("Sec [2^-23, pi/16]"); print(pf); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do printdouble(coeff(pf, i)); pxfm-0.1.23/notes/sin.sollya000064400000000000000000000006521046102023000140320ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, pi/256]; f_sin = sin(y)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6|], [|1, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinc.sollya000064400000000000000000000063441046102023000142010ustar 00000000000000f = sin(x)/x; I = [0.0; 0.25]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10|], [|1, D...|], I, absolute, floating); print("Sinc [0, 0.25]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [0.0; 0.25]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|1, 128...|], I, absolute, floating); print("Sinc [0.0, 0.25]"); for i from 0 to degree(P) by 2 do print(coeff(P, i)); I = [0.25; 0.35]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10|], [|1, D...|], I, absolute, floating); print("Sinc [0.25, 0.35]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [0.25; 0.35]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|1, 128...|], I, absolute, floating); print("Sinc [0.25, 0.36]"); for i from 0 to degree(P) by 2 do print(coeff(P, i)); I = [0.35; 0.5]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|1, D...|], I, absolute, floating); print("Sinc [0.35, 0.5]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [0.35; 0.55]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|1, 128...|], I, absolute, floating); print("Sinc [0.35, 0.55]"); for i from 0 to degree(P) by 2 do print(coeff(P, i)); I = [0.5; 0.7]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|1, D...|], I, absolute, floating); print("Sinc [0.5, 0.7]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [0.5; 0.7]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|1, 128...|], I, relative, floating); print("Sinc [0.5, 0.7]"); for i from 0 to degree(P) by 2 do print(coeff(P, i)); I = [0.7; 0.85]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|1, D...|], I, relative, floating); print("Sinc [0.7, 0.9]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [0.7; 0.85]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|1, 128...|], I, relative, floating); print("Sinc [0.7, 0.9]"); for i from 0 to degree(P) by 2 do print(coeff(P, i)); I = [0.85; 1.0]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|1, D...|], I, relative, floating); print("Sinc [0.85, 1.0]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [0.85; 1.0]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22|], [|1, 128...|], I, relative, floating); print("Sinc [0.85, 1.0]"); for i from 0 to degree(P) by 2 do print(coeff(P, i)); I = [1.0; 1.12]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|1, D...|], I, relative, floating); print("Sinc [1.0, 1.12]"); print(P); for i from 0 to degree(P) by 2 do printdouble(coeff(P, i)); err = dirtyinfnorm(P - f, I); print("Err:"); print(err); printdouble(err); I = [1.0; 1.12]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22|], [|1, 128...|], I, relative, floating); print("Sinc [1.0, 1.12]"); for i from 0 to degree(P) by 2 do print(coeff(P, i));pxfm-0.1.23/notes/sincf.sollya000064400000000000000000000005561046102023000143460ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; f = sin(x) / x; d = [0.0; 0.000443633]; pf = fpminimax(f, [|0, 2|], [|1, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(pf-f, d)); print("Sinc [0, 0.000443633]"); print(pf); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(pf) by 2 do printdouble(coeff(pf, i)); pxfm-0.1.23/notes/sincos.sollya000064400000000000000000000016371046102023000145430ustar 00000000000000f = sin(x); I = [-pi/256; pi/256]; P = fpminimax(f, [|1, 3, 5, 7, 9, 11, 13|], [|1, 128...|], I, relative, floating); print("Sin [-pi/256; pi/256]"); print(P); for i from 1 to degree(P) by 2 do print(coeff(P, i)); f = cos(x); I = [-pi/256; pi/256]; P = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12|], [|1, 128...|], I, relative, floating); print("Cos [-pi/256; pi/256]"); print(P); for i from 0 to degree(P) by 2 do print(coeff(P, i)); procedure ulp(x, n) { return 2^(floor(log2(abs(x))) - n); }; display=hexadecimal!; for i from 0 to 127 do { if i < 3 then { pi_inv = 0.25 + 2^(16*(i - 3)) / pi; } else { pi_inv = 2^(16*(i-3)) / pi; }; pn = nearestint(pi_inv); pi_frac = pi_inv - pn; a = round(pi_frac, 51, RN); b = round(pi_frac - a, 51, RN); c = round(pi_frac - a - b, 51, RN); d = round(pi_frac - a - b - c, D, RN); print("(", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "),"); };pxfm-0.1.23/notes/sincosf.sollya000064400000000000000000000015751046102023000147120ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.5]; f_sin = sin(y*pi/32)/y; Q = fpminimax(sin(y*pi/32)/y, [|0, 2, 4, 6|], [|D...|], d); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do print(coeff(Q, i)); f_cos = cos(y*pi/32); P = fpminimax(f_cos, [|0, 2, 4, 6|], [|1, D...|], d); err_p = -log2(dirtyinfnorm(P-f_cos, d)); display = decimal; print (P); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(P) by 2 do print(coeff(P, i)); f_sinpi_16 = sin(x)/x; Q = fpminimax(f_sinpi_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); err_p = -log2(dirtyinfnorm(Q-f_sinpi_16, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinmx.sollya000064400000000000000000000006711046102023000144000ustar 00000000000000 pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [2^-26, pi/16]; f_sinmx = (sin(x) - x)/x; Q = fpminimax(f_sinmx, [|0, 2, 4, 6, 8, 10, 12|], [|127, 127, D...|], d); err_p = -log2(dirtyinfnorm(Q-f_sinmx, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinmx_hard.sollya000064400000000000000000000006731046102023000154000ustar 00000000000000 pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [2^-26, pi/16]; f_sinmx = (sin(x) - x)/x; Q = fpminimax(f_sinmx, [|0, 2, 4, 6, 8, 10, 12, 14|], [|127, 127...|], d); err_p = -log2(dirtyinfnorm(Q-f_sinmx, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinmxf.sollya000064400000000000000000000006461046102023000145500ustar 00000000000000 pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [2^-10, pi/16]; f_sinmx = (sin(x) - x)/x; Q = fpminimax(f_sinmx, [|0, 2, 4, 6, 8|], [|D...|], d); err_p = -log2(dirtyinfnorm(Q-f_sinmx, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpi.sollya000064400000000000000000000006621046102023000143640ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6|], [|107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpi_dd.sollya000064400000000000000000000005461046102023000150340ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8|], [|107...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpi_fast_dd.sollya000064400000000000000000000006721046102023000160510ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8|], [|107, 107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpi_zero.sollya000064400000000000000000000006731046102023000154250ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpi_zero_dd.sollya000064400000000000000000000006701046102023000160710ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|107...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpi_zero_fast_dd.sollya000064400000000000000000000007111046102023000171020ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10, 12|], [|107, 107, 107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinpif.sollya000064400000000000000000000005541046102023000145320ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 1/16]; f_sin = sin(y*pi)/y; Q = fpminimax(sin(y*pi)/y, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/sinpif_0p125.sollya000064400000000000000000000005521046102023000153570ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.125]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/sinpif_0p25.sollya000064400000000000000000000005511046102023000152750ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.25]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/sinpif_0p25_2.sollya000064400000000000000000000005551046102023000155220ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.25]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10, 12|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sin, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/sinсpi_at_zero.sollya000064400000000000000000000006021046102023000166230ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.03515625]; f_sincpi = sin(y*pi)/(y*pi); Q = fpminimax(f_sincpi, [|0, 2, 4, 6, 8, 10|], [|107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sincpi, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/sinсpi_at_zero_dd.sollya000064400000000000000000000005751046102023000173030ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.03515625]; f_sincpi = sin(y*pi)/(y*pi); Q = fpminimax(f_sincpi, [|0, 2, 4, 6, 8, 10, 12|], [|107...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sincpi, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/sinсpif.sollya000064400000000000000000000005661046102023000152570ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 1/16]; f_sincpif = sin(y*pi)/(y*pi); Q = fpminimax(f_sincpif, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_sincpif, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/tanf.sollya000064400000000000000000000005211046102023000141640ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.5]; f_tan = tan(x*pi/32)/x; Q = fpminimax(f_tan, [|0, 2, 4, 6|], [|D...|], d); err_p = -log2(dirtyinfnorm(Q-f_tan, d)); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/tanf_at_zero.sollya000064400000000000000000000005261046102023000157140ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; f_tan = tan(x)/x; Q = fpminimax(f_tan, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); err_p = -log2(dirtyinfnorm(Q-f_tan, [0, pi/32])); display = decimal; print (Q); display = decimal; print ("absolute error:", pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/tanpi.sollya000064400000000000000000000006731046102023000143570ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_tan = tan(y*pi)/y; Q = fpminimax(f_tan, [|0, 2, 4, 6, 8|], [|107, D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q*y-tan(y*pi), d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/tanpi_dd.sollya000064400000000000000000000006741046102023000150270ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.0078128]; f_tan = tan(y*pi)/y; Q = fpminimax(f_tan, [|0, 2, 4, 6, 8, 10|], [|107...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q*y-tan(y*pi), d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i)); print("---"); for i from 0 to degree(Q) by 2 do print(coeff(Q, i));pxfm-0.1.23/notes/tanpif.sollya000064400000000000000000000005441046102023000145220ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [0, 0.5]; f_tan = tan(y*pi/32)/y; Q = fpminimax(f_tan, [|0, 2, 4, 6|], [|D...|], d, relative, floating); err_p = -log2(dirtyinfnorm(Q-f_tan, d)); display = decimal; print (Q); display = decimal; print ("absolute error:",pretty(err_p)); for i from 0 to degree(Q) by 2 do printdouble(coeff(Q, i));pxfm-0.1.23/notes/td_log.sollya000064400000000000000000000012301046102023000145020ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log(1+x); p0 = x-x^2/2; w = 1; p = remez(f-p0, 8, d, w); pf = p0+fpminimax(f-p0, [|3,4,5,6,7,8,9,10,11,12|], [|157...|], d, absolute, floating); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, absolute, 2^(-10))); display = hexadecimal; print (pf); display = decimal; print ("absolute error:", pretty(err_p)); f = 1; w = 1/log(1+x); // err_p = -log2(dirtyinfnorm(pf*w-f, d)); err_p = -log2(supnorm(pf, log(1+x), d, relative, 2^(-10))); print ("relative error:", pretty(err_p)); for i from 1 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/td_log10.sollya000064400000000000000000000005361046102023000146530ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log10(1+x)/x; pf = fpminimax(f, 10, [|157...|], d, absolute, floating); print(pf); f = 1; w = x/log10(1+x); err_p = -log2(dirtyinfnorm(pf*x-log10(1+x), d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/notes/td_log2.sollya000064400000000000000000000005711046102023000145730ustar 00000000000000pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-0.0040283203125,0.0040283203125]; f = log2(1+x)/x; w = 1; p = remez(f, 8, d, w); pf = fpminimax(f, 10, [|157...|], d, absolute, floating); print(pf); f = 1; w = x/log2(1+x); err_p = -log2(dirtyinfnorm(pf*x-log2(1+x), d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) do print(coeff(pf, i)); pxfm-0.1.23/src/acos.rs000064400000000000000000000263331046102023000127520ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::acospi::PI_OVER_TWO_F128; use crate::asin::asin_eval; use crate::asin_eval_dyadic::asin_eval_dyadic; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; /// Computes acos(x) /// /// Max found ULP 0.5 pub fn f_acos(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; const PI_OVER_TWO: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c91a62633145c07), f64::from_bits(0x3ff921fb54442d18), ); let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); // |x| < 0.5. if x_e < E_BIAS - 1 { // |x| < 2^-55. if x_e < E_BIAS - 55 { // When |x| < 2^-55, acos(x) = pi/2 return (x_abs + f64::from_bits(0x35f0000000000000)) + PI_OVER_TWO.hi; } let x_sq = DoubleDouble::from_exact_mult(x, x); let err = x_abs * f64::from_bits(0x3cc0000000000000); // Polynomial approximation: // p ~ asin(x)/x let (p, err) = asin_eval(x_sq, err); // asin(x) ~ x * p let r0 = DoubleDouble::from_exact_mult(x, p.hi); // acos(x) = pi/2 - asin(x) // ~ pi/2 - x * p // = pi/2 - x * (p.hi + p.lo) let r_hi = f_fmla(-x, p.hi, PI_OVER_TWO.hi); // Use Dekker's 2SUM algorithm to compute the lower part. let mut r_lo = ((PI_OVER_TWO.hi - r_hi) - r0.hi) - r0.lo; r_lo = f_fmla(-x, p.lo, r_lo + PI_OVER_TWO.lo); let r_upper = r_hi + (r_lo + err); let r_lower = r_hi + (r_lo - err); if r_upper == r_lower { return r_upper; } return acos_less_0p5_hard(x, x_sq); } // |x| >= 0.5 let x_sign = if x.is_sign_negative() { -1.0 } else { 1.0 }; const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); // |x| >= 1 if x_e >= E_BIAS { // x = +-1, asin(x) = +- pi/2 if x_abs == 1.0 { // x = 1, acos(x) = 0, // x = -1, acos(x) = pi return if x == 1.0 { 0.0 } else { f_fmla(-x_sign, PI.hi, PI.lo) }; } // |x| > 1, return NaN. return f64::NAN; } // When |x| >= 0.5, we perform range reduction as follow: // // When 0.5 <= x < 1, let: // y = acos(x) // We will use the double angle formula: // cos(2y) = 1 - 2 sin^2(y) // and the complement angle identity: // x = cos(y) = 1 - 2 sin^2 (y/2) // So: // sin(y/2) = sqrt( (1 - x)/2 ) // And hence: // y/2 = asin( sqrt( (1 - x)/2 ) ) // Equivalently: // acos(x) = y = 2 * asin( sqrt( (1 - x)/2 ) ) // Let u = (1 - x)/2, then: // acos(x) = 2 * asin( sqrt(u) ) // Moreover, since 0.5 <= x < 1: // 0 < u <= 1/4, and 0 < sqrt(u) <= 0.5, // And hence we can reuse the same polynomial approximation of asin(x) when // |x| <= 0.5: // acos(x) ~ 2 * sqrt(u) * P(u). // // When -1 < x <= -0.5, we reduce to the previous case using the formula: // acos(x) = pi - acos(-x) // = pi - 2 * asin ( sqrt( (1 + x)/2 ) ) // ~ pi - 2 * sqrt(u) * P(u), // where u = (1 - |x|)/2. // u = (1 - |x|)/2 let u = f_fmla(x_abs, -0.5, 0.5); // v_hi + v_lo ~ sqrt(u). // Let: // h = u - v_hi^2 = (sqrt(u) - v_hi) * (sqrt(u) + v_hi) // Then: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // ~ v_hi + h / (2 * v_hi) // So we can use: // v_lo = h / (2 * v_hi). let v_hi = u.sqrt(); let h; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { h = f_fmla(v_hi, -v_hi, u); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let v_hi_sq = DoubleDouble::from_exact_mult(v_hi, v_hi); h = (u - v_hi_sq.hi) - v_hi_sq.lo; } // Scale v_lo and v_hi by 2 from the formula: // vh = v_hi * 2 // vl = 2*v_lo = h / v_hi. let vh = v_hi * 2.0; let vl = h / v_hi; // Polynomial approximation: // p ~ asin(sqrt(u))/sqrt(u) let err = vh * f64::from_bits(0x3cc0000000000000); let (p, err) = asin_eval(DoubleDouble::new(0.0, u), err); // Perform computations in double-double arithmetic: // asin(x) = pi/2 - (v_hi + v_lo) * (ASIN_COEFFS[idx][0] + p) let r0 = DoubleDouble::quick_mult(DoubleDouble::new(vl, vh), p); let r_hi; let r_lo; if x.is_sign_positive() { r_hi = r0.hi; r_lo = r0.lo; } else { let r = DoubleDouble::from_exact_add(PI.hi, -r0.hi); r_hi = r.hi; r_lo = (PI.lo - r0.lo) + r.lo; } let r_upper = r_hi + (r_lo + err); let r_lower = r_hi + (r_lo - err); if r_upper == r_lower { return r_upper; } acos_hard(x, u, v_hi, h, vh, vl) } #[cold] #[inline(never)] fn acos_hard(x: f64, u: f64, v_hi: f64, h: f64, vh: f64, vl: f64) -> f64 { // Ziv's accuracy test failed, we redo the computations in Float128. // Recalculate mod 1/64. let idx = (u * f64::from_bits(0x4050000000000000)).round() as usize; // After the first step of Newton-Raphson approximating v = sqrt(u), we have // that: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // v_lo = h / (2 * v_hi) // With error: // sqrt(u) - (v_hi + v_lo) = h * ( 1/(sqrt(u) + v_hi) - 1/(2*v_hi) ) // = -h^2 / (2*v * (sqrt(u) + v)^2). // Since: // (sqrt(u) + v_hi)^2 ~ (2sqrt(u))^2 = 4u, // we can add another correction term to (v_hi + v_lo) that is: // v_ll = -h^2 / (2*v_hi * 4u) // = -v_lo * (h / 4u) // = -vl * (h / 8u), // making the errors: // sqrt(u) - (v_hi + v_lo + v_ll) = O(h^3) // well beyond 128-bit precision needed. // Get the rounding error of vl = 2 * v_lo ~ h / vh // Get full product of vh * vl let vl_lo; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { vl_lo = f_fmla(-v_hi, vl, h) / v_hi; } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let vh_vl = DoubleDouble::from_exact_mult(v_hi, vl); vl_lo = ((h - vh_vl.hi) - vh_vl.lo) / v_hi; } let t = h * (-0.25) / u; let vll = f_fmla(vl, t, vl_lo); let m_v_p = DyadicFloat128::new_from_f64(vl) + DyadicFloat128::new_from_f64(vll); let mut m_v = DyadicFloat128::new_from_f64(vh) + m_v_p; m_v.sign = if x.is_sign_negative() { DyadicSign::Neg } else { DyadicSign::Pos }; // Perform computations in Float128: // acos(x) = (v_hi + v_lo + vll) * P(u) , when 0.5 <= x < 1, // = pi - (v_hi + v_lo + vll) * P(u) , when -1 < x <= -0.5. let y_f128 = DyadicFloat128::new_from_f64(f_fmla(idx as f64, f64::from_bits(0xbf90000000000000), u)); let p_f128 = asin_eval_dyadic(y_f128, idx); let mut r_f128 = m_v * p_f128; if x.is_sign_negative() { const PI_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; r_f128 = PI_F128 + r_f128; } r_f128.fast_as_f64() } #[cold] #[inline(never)] fn acos_less_0p5_hard(x: f64, x_sq: DoubleDouble) -> f64 { // Ziv's accuracy test failed, perform 128-bit calculation. // Recalculate mod 1/64. let idx = (x_sq.hi * f64::from_bits(0x4050000000000000)).round() as usize; // Get x^2 - idx/64 exactly. When FMA is available, double-double // multiplication will be correct for all rounding modes. Otherwise, we use // Float128 directly. let mut x_f128 = DyadicFloat128::new_from_f64(x); let u: DyadicFloat128; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { // u = x^2 - idx/64 let u_hi = DyadicFloat128::new_from_f64(f_fmla( idx as f64, f64::from_bits(0xbf90000000000000), x_sq.hi, )); u = u_hi.quick_add(&DyadicFloat128::new_from_f64(x_sq.lo)); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let x_sq_f128 = x_f128.quick_mul(&x_f128); u = x_sq_f128.quick_add(&DyadicFloat128::new_from_f64( idx as f64 * f64::from_bits(0xbf90000000000000), )); } let p_f128 = asin_eval_dyadic(u, idx); // Flip the sign of x_f128 to perform subtraction. x_f128.sign = x_f128.sign.negate(); let r = PI_OVER_TWO_F128.quick_add(&x_f128.quick_mul(&p_f128)); r.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn f_acos_test() { assert_eq!(f_acos(0.7), 0.7953988301841436); assert_eq!(f_acos(-0.1), 1.6709637479564565); assert_eq!(f_acos(-0.4), 1.9823131728623846); } } pxfm-0.1.23/src/acosf.rs000064400000000000000000000152201046102023000131110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use std::hint::black_box; #[inline] pub(crate) fn poly12(z: f64, c: [u64; 12]) -> f64 { let z2 = z * z; let z4 = z2 * z2; let mut c0 = f_fmla(z, f64::from_bits(c[1]), f64::from_bits(c[0])); let c2 = f_fmla(z, f64::from_bits(c[3]), f64::from_bits(c[2])); let mut c4 = f_fmla(z, f64::from_bits(c[5]), f64::from_bits(c[4])); let c6 = f_fmla(z, f64::from_bits(c[7]), f64::from_bits(c[6])); let mut c8 = f_fmla(z, f64::from_bits(c[9]), f64::from_bits(c[8])); let c10 = f_fmla(z, f64::from_bits(c[11]), f64::from_bits(c[10])); c0 = f_fmla(c2, z2, c0); c4 = f_fmla(c6, z2, c4); c8 = f_fmla(z2, c10, c8); f_fmla(z4, f_fmla(z4, c8, c4), c0) } #[cold] fn as_special(x: f32) -> f32 { const PIH: f32 = f64::from_bits(0x400921fb60000000) as f32; const PIL: f32 = -f64::from_bits(0x3e70000000000000) as f32; let t = x.to_bits(); if t == (0x7fu32 << 23) { return 0.0; } // x=1 if t == (0x17fu32 << 23) { return PIH + PIL; } // x=-1 let ax = t.wrapping_shl(1); if ax > (0xffu32 << 24) { return x + x; } // nan f32::NAN } /// Compute acos /// /// Max found ULP 0.49999982 #[inline] pub fn f_acosf(x: f32) -> f32 { const PI2: f64 = f64::from_bits(0x3ff921fb54442d18); const O: [f64; 2] = [0., f64::from_bits(0x400921fb54442d18)]; let xs = x as f64; let mut r: f64; let t = x.to_bits(); let ax = t.wrapping_shl(1); if ax >= 0x7f << 24 { return as_special(x); } if ax < 0x7ec2a1dcu32 { // |x| < 0.880141 const B: [u64; 16] = [ 0x3fefffffffd9ccb8, 0x3fc5555c94838007, 0x3fb32ded4b7c20fa, 0x3fa8566df703309e, 0xbf9980c959bec9a3, 0x3fe56fbb04998344, 0xc01403d8e4c49f52, 0x403b06c3e9f311ea, 0xc059ea97c4e2c21f, 0x407200b8261cc61b, 0xc082274c2799a5c7, 0x408a558a59cc19d3, 0xc08aca4b6a529ff0, 0x408228744703f813, 0xc06d7dbb0b322228, 0x4045c2018c0c0105, ]; /* avoid spurious underflow */ if ax < 0x40000000u32 { // |x| < 2^-63 return PI2 as f32; } let z = xs; let z2 = z * z; let w0 = f_fmla(z2, f64::from_bits(B[1]), f64::from_bits(B[0])); let w1 = f_fmla(z2, f64::from_bits(B[3]), f64::from_bits(B[2])); let w2 = f_fmla(z2, f64::from_bits(B[5]), f64::from_bits(B[4])); let w3 = f_fmla(z2, f64::from_bits(B[7]), f64::from_bits(B[6])); let w4 = f_fmla(z2, f64::from_bits(B[9]), f64::from_bits(B[8])); let w5 = f_fmla(z2, f64::from_bits(B[11]), f64::from_bits(B[10])); let w6 = f_fmla(z2, f64::from_bits(B[13]), f64::from_bits(B[12])); let w7 = f_fmla(z2, f64::from_bits(B[15]), f64::from_bits(B[14])); let z4 = z2 * z2; let z8 = z4 * z4; let z16 = z8 * z8; r = z * ((f_fmla(z4, w1, w0) + z8 * f_fmla(z4, w3, w2)) + z16 * (f_fmla(z4, w5, w4) + z8 * f_fmla(z4, w7, w6))); let ub = f64::from_bits(0x3ff921fb54574191) - r; let lb = f64::from_bits(0x3ff921fb543118a0) - r; // Ziv's accuracy test if ub == lb { return ub as f32; } } // accurate path if ax < (0x7eu32 << 24) { const C: [u64; 12] = [ 0x3fc555555555529c, 0x3fb333333337e0dd, 0x3fa6db6db3b4465e, 0x3f9f1c72e13ac306, 0x3f96e89cebe06bc4, 0x3f91c6dcf5289094, 0x3f8c6dbbcc7c6315, 0x3f88f8dc2615e996, 0x3f7a5833b7bf15e8, 0x3f943f44ace1665c, 0xbf90fb17df881c73, 0x3fa07520c026b2d6, ]; if t == 0x328885a3u32 { return black_box(f64::from_bits(0x3ff921fb60000000) as f32) + black_box(f64::from_bits(0x3e60000000000000) as f32); } if t == 0x39826222u32 { return black_box(f64::from_bits(0x3ff920f6a0000000) as f32) + black_box(f64::from_bits(0x3e60000000000000) as f32); } let x2 = xs * xs; r = f_fmla(-(xs * x2), poly12(x2, C), PI2 - xs); } else { const C: [u64; 12] = [ 0x3ff6a09e667f3bcb, 0x3fbe2b7dddff2db9, 0x3f9b27247ab42dbc, 0x3f802995cc4e0744, 0x3f65ffb0276ec8ea, 0x3f5033885a928dec, 0x3f3911f2be23f8c7, 0x3f24c3c55d2437fd, 0x3f0af477e1d7b461, 0x3f0abd6bdff67dcb, 0xbef1717e86d0fa28, 0x3ef6ff526de46023, ]; let bx = xs.abs(); let z = 1.0 - bx; let s = f64::copysign(z.sqrt(), xs); r = f_fmla(s, poly12(z, C), O[t.wrapping_shr(31) as usize]); } r as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_acosf() { assert_eq!(f_acosf(-0.5), 2.0943952); assert_eq!(f_acosf(0.5), std::f32::consts::FRAC_PI_3); assert!(f_acosf(7.).is_nan()); } } pxfm-0.1.23/src/acospi.rs000064400000000000000000000300301046102023000132700ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::asin::asin_eval; use crate::asin_eval_dyadic::asin_eval_dyadic; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; pub(crate) const INV_PI_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc76b01ec5417056), f64::from_bits(0x3fd45f306dc9c883), ); // 1/PI with 128-bit precision generated by SageMath with: // def format_hex(value): // l = hex(value)[2:] // n = 8 // x = [l[i:i + n] for i in range(0, len(l), n)] // return "0x" + "'".join(x) + "_u128" // r = 1/pi // (s, m, e) = RealField(128)(r).sign_mantissa_exponent(); // print(format_hex(m)); pub(crate) const INV_PI_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa2f9836e_4e441529_fc2757d1_f534ddc1_u128, }; pub(crate) const PI_OVER_TWO_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; /// Computes acos(x)/PI /// /// Max ULP 0.5 pub fn f_acospi(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; const PI_OVER_TWO: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c91a62633145c07), f64::from_bits(0x3ff921fb54442d18), ); let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); // |x| < 0.5. if x_e < E_BIAS - 1 { // |x| < 2^-55. if x_e < E_BIAS - 55 { // When |x| < 2^-55, acos(x) = pi/2 return f_fmla(f64::from_bits(0xbc80000000000000), x, 0.5); } let x_sq = DoubleDouble::from_exact_mult(x, x); let err = x_abs * f64::from_bits(0x3cc0000000000000); // Polynomial approximation: // p ~ asin(x)/x let (p, err) = asin_eval(x_sq, err); // asin(x) ~ x * p let r0 = DoubleDouble::from_exact_mult(x, p.hi); // acos(x) = pi/2 - asin(x) // ~ pi/2 - x * p // = pi/2 - x * (p.hi + p.lo) let mut r_hi = f_fmla(-x, p.hi, PI_OVER_TWO.hi); // Use Dekker's 2SUM algorithm to compute the lower part. let mut r_lo = ((PI_OVER_TWO.hi - r_hi) - r0.hi) - r0.lo; r_lo = f_fmla(-x, p.lo, r_lo + PI_OVER_TWO.lo); let p = DoubleDouble::mult(DoubleDouble::new(r_lo, r_hi), INV_PI_DD); r_hi = p.hi; r_lo = p.lo; let r_upper = r_hi + (r_lo + err); let r_lower = r_hi + (r_lo - err); if r_upper == r_lower { return r_upper; } // Ziv's accuracy test failed, perform 128-bit calculation. // Recalculate mod 1/64. let idx = (x_sq.hi * f64::from_bits(0x4050000000000000)).round() as usize; // Get x^2 - idx/64 exactly. When FMA is available, double-double // multiplication will be correct for all rounding modes. Otherwise, we use // Float128 directly. let mut x_f128 = DyadicFloat128::new_from_f64(x); let u: DyadicFloat128; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { // u = x^2 - idx/64 let u_hi = DyadicFloat128::new_from_f64(f_fmla( idx as f64, f64::from_bits(0xbf90000000000000), x_sq.hi, )); u = u_hi.quick_add(&DyadicFloat128::new_from_f64(x_sq.lo)); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let x_sq_f128 = x_f128.quick_mul(&x_f128); u = x_sq_f128.quick_add(&DyadicFloat128::new_from_f64( idx as f64 * f64::from_bits(0xbf90000000000000), )); } let p_f128 = asin_eval_dyadic(u, idx); // Flip the sign of x_f128 to perform subtraction. x_f128.sign = x_f128.sign.negate(); let mut r = PI_OVER_TWO_F128.quick_add(&x_f128.quick_mul(&p_f128)); r = r.quick_mul(&INV_PI_F128); return r.fast_as_f64(); } // |x| >= 0.5 const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); // |x| >= 1 if x_e >= E_BIAS { // x = +-1, asin(x) = +- pi/2 if x_abs == 1.0 { // x = 1, acos(x) = 0, // x = -1, acos(x) = pi return if x == 1.0 { 0.0 } else { 1.0 }; } // |x| > 1, return NaN. return f64::NAN; } // When |x| >= 0.5, we perform range reduction as follow: // // When 0.5 <= x < 1, let: // y = acos(x) // We will use the double angle formula: // cos(2y) = 1 - 2 sin^2(y) // and the complement angle identity: // x = cos(y) = 1 - 2 sin^2 (y/2) // So: // sin(y/2) = sqrt( (1 - x)/2 ) // And hence: // y/2 = asin( sqrt( (1 - x)/2 ) ) // Equivalently: // acos(x) = y = 2 * asin( sqrt( (1 - x)/2 ) ) // Let u = (1 - x)/2, then: // acos(x) = 2 * asin( sqrt(u) ) // Moreover, since 0.5 <= x < 1: // 0 < u <= 1/4, and 0 < sqrt(u) <= 0.5, // And hence we can reuse the same polynomial approximation of asin(x) when // |x| <= 0.5: // acos(x) ~ 2 * sqrt(u) * P(u). // // When -1 < x <= -0.5, we reduce to the previous case using the formula: // acos(x) = pi - acos(-x) // = pi - 2 * asin ( sqrt( (1 + x)/2 ) ) // ~ pi - 2 * sqrt(u) * P(u), // where u = (1 - |x|)/2. // u = (1 - |x|)/2 let u = f_fmla(x_abs, -0.5, 0.5); // v_hi + v_lo ~ sqrt(u). // Let: // h = u - v_hi^2 = (sqrt(u) - v_hi) * (sqrt(u) + v_hi) // Then: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // ~ v_hi + h / (2 * v_hi) // So we can use: // v_lo = h / (2 * v_hi). let v_hi = u.sqrt(); let h; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { h = f_fmla(v_hi, -v_hi, u); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let v_hi_sq = DoubleDouble::from_exact_mult(v_hi, v_hi); h = (u - v_hi_sq.hi) - v_hi_sq.lo; } // Scale v_lo and v_hi by 2 from the formula: // vh = v_hi * 2 // vl = 2*v_lo = h / v_hi. let vh = v_hi * 2.0; let vl = h / v_hi; // Polynomial approximation: // p ~ asin(sqrt(u))/sqrt(u) let err = vh * f64::from_bits(0x3cc0000000000000); let (p, err) = asin_eval(DoubleDouble::new(0.0, u), err); // Perform computations in double-double arithmetic: // asin(x) = pi/2 - (v_hi + v_lo) * (ASIN_COEFFS[idx][0] + p) let r0 = DoubleDouble::quick_mult(DoubleDouble::new(vl, vh), p); let mut r_hi; let mut r_lo; if x.is_sign_positive() { r_hi = r0.hi; r_lo = r0.lo; } else { let r = DoubleDouble::from_exact_add(PI.hi, -r0.hi); r_hi = r.hi; r_lo = (PI.lo - r0.lo) + r.lo; } let p = DoubleDouble::mult(DoubleDouble::new(r_lo, r_hi), INV_PI_DD); r_hi = p.hi; r_lo = p.lo; let r_upper = r_hi + (r_lo + err); let r_lower = r_hi + (r_lo - err); if r_upper == r_lower { return r_upper; } // Ziv's accuracy test failed, we redo the computations in Float128. // Recalculate mod 1/64. let idx = (u * f64::from_bits(0x4050000000000000)).round() as usize; // After the first step of Newton-Raphson approximating v = sqrt(u), we have // that: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // v_lo = h / (2 * v_hi) // With error: // sqrt(u) - (v_hi + v_lo) = h * ( 1/(sqrt(u) + v_hi) - 1/(2*v_hi) ) // = -h^2 / (2*v * (sqrt(u) + v)^2). // Since: // (sqrt(u) + v_hi)^2 ~ (2sqrt(u))^2 = 4u, // we can add another correction term to (v_hi + v_lo) that is: // v_ll = -h^2 / (2*v_hi * 4u) // = -v_lo * (h / 4u) // = -vl * (h / 8u), // making the errors: // sqrt(u) - (v_hi + v_lo + v_ll) = O(h^3) // well beyond 128-bit precision needed. // Get the rounding error of vl = 2 * v_lo ~ h / vh // Get full product of vh * vl let vl_lo; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { vl_lo = f_fmla(-v_hi, vl, h) / v_hi; } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let vh_vl = DoubleDouble::from_exact_mult(v_hi, vl); vl_lo = ((h - vh_vl.hi) - vh_vl.lo) / v_hi; } let t = h * (-0.25) / u; let vll = f_fmla(vl, t, vl_lo); // m_v = -(v_hi + v_lo + v_ll). let m_v_p = DyadicFloat128::new_from_f64(vl) + DyadicFloat128::new_from_f64(vll); let mut m_v = DyadicFloat128::new_from_f64(vh) + m_v_p; m_v.sign = if x.is_sign_negative() { DyadicSign::Neg } else { DyadicSign::Pos }; // Perform computations in Float128: // acos(x) = (v_hi + v_lo + vll) * P(u) , when 0.5 <= x < 1, // = pi - (v_hi + v_lo + vll) * P(u) , when -1 < x <= -0.5. let y_f128 = DyadicFloat128::new_from_f64(f_fmla(idx as f64, f64::from_bits(0xbf90000000000000), u)); let p_f128 = asin_eval_dyadic(y_f128, idx); let mut r_f128 = m_v * p_f128; if x.is_sign_negative() { const PI_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; r_f128 = PI_F128 + r_f128; } r_f128 = r_f128.quick_mul(&INV_PI_F128); r_f128.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn acospi_test() { assert_eq!(f_acospi(0.5), 0.3333333333333333); assert!(f_acospi(1.5).is_nan()); } } pxfm-0.1.23/src/acospif.rs000064400000000000000000000073741046102023000134550ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::asinpif::ASINCOSF_PI_TABLE; use crate::common::{dd_fmla, f_fmla}; /// Computes acos(x)/PI /// /// Max ULP 0.5 #[inline] pub fn f_acospif(x: f32) -> f32 { let ax = x.abs(); let az = ax as f64; let z = x as f64; let t: u32 = x.to_bits(); let e: i32 = ((t >> 23) & 0xff) as i32; if e >= 127 { if x == 1.0 { return 0.0; } if x == -1.0 { return 1.0; } if e == 0xff && (t.wrapping_shl(9)) != 0 { return x + x; } // nan return f32::NAN; } let s: i32 = 146i32.wrapping_sub(e); let mut i = 0i32; if s < 32 { i = (((t & 0x007fffff) | 1 << 23) >> s) as i32; } let c = ASINCOSF_PI_TABLE[i as usize & 15]; let z2 = z * z; let z4 = z2 * z2; if i == 0 { let mut c0 = f_fmla(z2, f64::from_bits(c[1]), f64::from_bits(c[0])); let c2 = f_fmla(z2, f64::from_bits(c[3]), f64::from_bits(c[2])); let mut c4 = f_fmla(z2, f64::from_bits(c[5]), f64::from_bits(c[4])); let c6 = f_fmla(z2, f64::from_bits(c[7]), f64::from_bits(c[6])); c0 += c2 * z4; c4 += c6 * z4; /* For |x| <= 0x1.0fd288p-127, c0 += c4*(z4*z4) would raise a spurious underflow exception, we use an FMA instead, where c4 * z4 does not underflow. */ c0 = dd_fmla(c4 * z4, z4, c0); f_fmla(-z, c0, 0.5) as f32 } else { let f = (1. - az).sqrt(); let mut c0 = f_fmla(az, f64::from_bits(c[1]), f64::from_bits(c[0])); let c2 = f_fmla(az, f64::from_bits(c[3]), f64::from_bits(c[2])); let mut c4 = f_fmla(az, f64::from_bits(c[5]), f64::from_bits(c[4])); let c6 = f_fmla(az, f64::from_bits(c[7]), f64::from_bits(c[6])); c0 += c2 * z2; c4 += c6 * z2; c0 += c4 * z4; static SIGN: [f64; 2] = [0., 1.]; let r = SIGN[(t >> 31) as usize] + c0 * f64::copysign(f, x as f64); r as f32 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_acospif() { assert_eq!(f_acospif(0.0), 0.5); assert_eq!(f_acospif(0.5), 0.33333334); assert_eq!(f_acospif(1.0), 0.0); } } pxfm-0.1.23/src/asin.rs000064400000000000000000000363071046102023000127610ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::asin_eval_dyadic::asin_eval_dyadic; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; static ASIN_COEFFS: [[u64; 12]; 9] = [ [ 0x3ff0000000000000, 0x0000000000000000, 0x3fc5555555555555, 0x3c65555555555555, 0x3fb3333333333333, 0x3fa6db6db6db6db7, 0x3f9f1c71c71c71c7, 0x3f96e8ba2e8ba2e9, 0x3f91c4ec4ec4ec4f, 0x3f8c99999999999a, 0x3f87a87878787878, 0x3f83fde50d79435e, ], [ 0x3ff015a397cf0f1c, 0xbc8eebd6ccfe3ee3, 0x3fc5f3581be7b08b, 0xbc65df80d0e7237d, 0x3fb4519ddf1ae530, 0x3fa8eb4b6eeb1696, 0x3fa17bc85420fec8, 0x3f9a8e39b5dcad81, 0x3f953f8df127539b, 0x3f91a485a0b0130a, 0x3f8e20e6e4930020, 0x3f8a466a7030f4c9, ], [ 0x3ff02be9ce0b87cd, 0x3c7e5d09da2e0f04, 0x3fc69ab5325bc359, 0xbc692f480cfede2d, 0x3fb58a4c3097aab1, 0x3fab3db36068dd80, 0x3fa3b94821846250, 0x3f9eedc823765d21, 0x3f998e35d756be6b, 0x3f95ea4f1b32731a, 0x3f9355115764148e, 0x3f916a5853847c91, ], [ 0x3ff042dc6a65ffbf, 0xbc8c7ea28dce95d1, 0x3fc74c4bd7412f9d, 0x3c5447024c0a3c87, 0x3fb6e09c6d2b72b9, 0x3faddd9dcdae5315, 0x3fa656f1f64058b8, 0x3fa21a42e4437101, 0x3f9eed0350b7edb2, 0x3f9b6bc877e58c52, 0x3f9903a0872eb2a4, 0x3f974da839ddd6d8, ], [ 0x3ff05a8621feb16b, 0xbc7e5b33b1407c5f, 0x3fc809186c2e57dd, 0xbc33dcb4d6069407, 0x3fb8587d99442dc5, 0x3fb06c23d1e75be3, 0x3fa969024051c67d, 0x3fa54e4f934aacfd, 0x3fa2d60a732dbc9c, 0x3fa149f0c046eac7, 0x3fa053a56dba1fba, 0x3f9f7face3343992, ], [ 0x3ff072f2b6f1e601, 0xbc92dcbb05419970, 0x3fc8d2397127aeba, 0x3c6ead0c497955fb, 0x3fb9f68df88da518, 0x3fb21ee26a5900d7, 0x3fad08e7081b53a9, 0x3fa938dd661713f7, 0x3fa71b9f299b72e6, 0x3fa5fbc7d2450527, 0x3fa58573247ec325, 0x3fa585a174a6a4ce, ], [ 0x3ff08c2f1d638e4c, 0x3c7b47c159534a3d, 0x3fc9a8f592078624, 0xbc6ea339145b65cd, 0x3fbbc04165b57aab, 0x3fb410df5f58441d, 0x3fb0ab6bdf5f8f70, 0x3fae0b92eea1fce1, 0x3fac9094e443a971, 0x3fac34651d64bc74, 0x3facaa008d1af080, 0x3fadc165bc0c4fc5, ], [ 0x3ff0a649a73e61f2, 0x3c874ac0d817e9c7, 0x3fca8ec30dc93890, 0xbc48ab1c0eef300c, 0x3fbdbc11ea95061b, 0x3fb64e371d661328, 0x3fb33e0023b3d895, 0x3fb2042269c243ce, 0x3fb1cce74bda2230, 0x3fb244d425572ce9, 0x3fb34d475c7f1e3e, 0x3fb4d4e653082ad3, ], [ 0x3ff0c152382d7366, 0xbc9ee6913347c2a6, 0x3fcb8550d62bfb6d, 0xbc6d10aec3f116d5, 0x3fbff1bde0fa3ca0, 0x3fb8e5f3ab69f6a4, 0x3fb656be8b6527ce, 0x3fb5c39755dc041a, 0x3fb661e6ebd40599, 0x3fb7ea3dddee2a4f, 0x3fba4f439abb4869, 0x3fbd9181c0fda658, ], ]; #[inline] pub(crate) fn asin_eval(u: DoubleDouble, err: f64) -> (DoubleDouble, f64) { // k = round(u * 32). let k = (u.hi * f64::from_bits(0x4040000000000000)).round(); let idx = k as u64; // y = u - k/32. let y_hi = f_fmla(k, f64::from_bits(0xbfa0000000000000), u.hi); // Exact let y = DoubleDouble::from_exact_add(y_hi, u.lo); let y2 = y.hi * y.hi; // Add double-double errors in addition to the relative errors from y2. let err = f_fmla(err, y2, f64::from_bits(0x3990000000000000)); let coeffs = ASIN_COEFFS[idx as usize]; let c0 = DoubleDouble::quick_mult( y, DoubleDouble::new(f64::from_bits(coeffs[3]), f64::from_bits(coeffs[2])), ); let c1 = f_fmla(y.hi, f64::from_bits(coeffs[5]), f64::from_bits(coeffs[4])); let c2 = f_fmla(y.hi, f64::from_bits(coeffs[7]), f64::from_bits(coeffs[6])); let c3 = f_fmla(y.hi, f64::from_bits(coeffs[9]), f64::from_bits(coeffs[8])); let c4 = f_fmla(y.hi, f64::from_bits(coeffs[11]), f64::from_bits(coeffs[10])); let y4 = y2 * y2; let d0 = f_fmla(y2, c2, c1); let d1 = f_fmla(y2, c4, c3); let mut r = DoubleDouble::from_exact_add(f64::from_bits(coeffs[0]), c0.hi); let e1 = f_fmla(y4, d1, d0); r.lo = f_fmla(y2, e1, f64::from_bits(coeffs[1]) + c0.lo + r.lo); (r, err) } /// Computes asin(x) /// /// Max found ULP 0.5 pub fn f_asin(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); // |x| < 0.5. if x_e < E_BIAS - 1 { // |x| < 2^-26. if x_e < E_BIAS - 26 { // When |x| < 2^-26, the relative error of the approximation asin(x) ~ x // is: // |asin(x) - x| / |asin(x)| < |x^3| / (6|x|) // = x^2 / 6 // < 2^-54 // < epsilon(1)/2. // = x otherwise. , if x.abs() == 0. { return x; } // Get sign(x) * min_normal. let eps = f64::copysign(f64::MIN_POSITIVE, x); let normalize_const = if x_e == 0 { eps } else { 0.0 }; let scaled_normal = f_fmla(x + normalize_const, f64::from_bits(0x4350000000000000), eps); return f_fmla( scaled_normal, f64::from_bits(0x3c90000000000000), -normalize_const, ); } let x_sq = DoubleDouble::from_exact_mult(x, x); let err = x_abs * f64::from_bits(0x3cc0000000000000); // Polynomial approximation: // p ~ asin(x)/x let (p, err) = asin_eval(x_sq, err); // asin(x) ~ x * (ASIN_COEFFS[idx][0] + p) let r0 = DoubleDouble::from_exact_mult(x, p.hi); let r_lo = f_fmla(x, p.lo, r0.lo); let r_upper = r0.hi + (r_lo + err); let r_lower = r0.hi + (r_lo - err); if r_upper == r_lower { return r_upper; } // Ziv's accuracy test failed, perform 128-bit calculation. // Recalculate mod 1/64. let idx = (x_sq.hi * f64::from_bits(0x4050000000000000)).round() as usize; // Get x^2 - idx/64 exactly. When FMA is available, double-double // multiplication will be correct for all rounding modes. Otherwise, we use // Float128 directly. let x_f128 = DyadicFloat128::new_from_f64(x); let u: DyadicFloat128; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { // u = x^2 - idx/64 let u_hi = DyadicFloat128::new_from_f64(f_fmla( idx as f64, f64::from_bits(0xbf90000000000000), x_sq.hi, )); u = u_hi.quick_add(&DyadicFloat128::new_from_f64(x_sq.lo)); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let x_sq_f128 = x_f128.quick_mul(&x_f128); u = x_sq_f128.quick_add(&DyadicFloat128::new_from_f64( idx as f64 * (f64::from_bits(0xbf90000000000000)), )); } let p_f128 = asin_eval_dyadic(u, idx); let r = x_f128.quick_mul(&p_f128); return r.fast_as_f64(); } const PI_OVER_TWO: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c91a62633145c07), f64::from_bits(0x3ff921fb54442d18), ); let x_sign = if x.is_sign_negative() { -1.0 } else { 1.0 }; // |x| >= 1 if x_e >= E_BIAS { // x = +-1, asin(x) = +- pi/2 if x_abs == 1.0 { // return +- pi/2 return f_fmla(x_sign, PI_OVER_TWO.hi, x_sign * PI_OVER_TWO.lo); } // |x| > 1, return NaN. if x.is_nan() { return x; } return f64::NAN; } // u = (1 - |x|)/2 let u = f_fmla(x_abs, -0.5, 0.5); // v_hi + v_lo ~ sqrt(u). // Let: // h = u - v_hi^2 = (sqrt(u) - v_hi) * (sqrt(u) + v_hi) // Then: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // ~ v_hi + h / (2 * v_hi) // So we can use: // v_lo = h / (2 * v_hi). // Then, // asin(x) ~ pi/2 - 2*(v_hi + v_lo) * P(u) let v_hi = u.sqrt(); let h; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { h = f_fmla(v_hi, -v_hi, u); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let v_hi_sq = DoubleDouble::from_exact_mult(v_hi, v_hi); h = (u - v_hi_sq.hi) - v_hi_sq.lo; } // Scale v_lo and v_hi by 2 from the formula: // vh = v_hi * 2 // vl = 2*v_lo = h / v_hi. let vh = v_hi * 2.0; let vl = h / v_hi; // Polynomial approximation: // p ~ asin(sqrt(u))/sqrt(u) let err = vh * f64::from_bits(0x3cc0000000000000); let (p, err) = asin_eval(DoubleDouble::new(0.0, u), err); // Perform computations in double-double arithmetic: // asin(x) = pi/2 - (v_hi + v_lo) * (ASIN_COEFFS[idx][0] + p) let r0 = DoubleDouble::quick_mult(DoubleDouble::new(vl, vh), p); let r = DoubleDouble::from_exact_add(PI_OVER_TWO.hi, -r0.hi); let r_lo = PI_OVER_TWO.lo - r0.lo + r.lo; let (r_upper, r_lower); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { r_upper = f_fmla(r.hi, x_sign, f_fmla(r_lo, x_sign, err)); r_lower = f_fmla(r.hi, x_sign, f_fmla(r_lo, x_sign, -err)); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let r_lo = r_lo * x_sign; let r_hi = r.hi * x_sign; r_upper = r_hi + (r_lo + err); r_lower = r.hi + (r_lo - err); } if r_upper == r_lower { return r_upper; } // Ziv's accuracy test failed, we redo the computations in Float128. // Recalculate mod 1/64. let idx = (u * f64::from_bits(0x4050000000000000)).round() as usize; // After the first step of Newton-Raphson approximating v = sqrt(u), we have // that: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // v_lo = h / (2 * v_hi) // With error: // sqrt(u) - (v_hi + v_lo) = h * ( 1/(sqrt(u) + v_hi) - 1/(2*v_hi) ) // = -h^2 / (2*v * (sqrt(u) + v)^2). // Since: // (sqrt(u) + v_hi)^2 ~ (2sqrt(u))^2 = 4u, // we can add another correction term to (v_hi + v_lo) that is: // v_ll = -h^2 / (2*v_hi * 4u) // = -v_lo * (h / 4u) // = -vl * (h / 8u), // making the errors: // sqrt(u) - (v_hi + v_lo + v_ll) = O(h^3) // well beyond 128-bit precision needed. // Get the rounding error of vl = 2 * v_lo ~ h / vh // Get full product of vh * vl let vl_lo; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { vl_lo = f_fmla(-v_hi, vl, h) / v_hi; } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let vh_vl = DoubleDouble::from_exact_mult(v_hi, vl); vl_lo = ((h - vh_vl.hi) - vh_vl.lo) / v_hi; } // vll = 2*v_ll = -vl * (h / (4u)). let t = h * (-0.25) / u; let vll = f_fmla(vl, t, vl_lo); // m_v = -(v_hi + v_lo + v_ll). let mv0 = DyadicFloat128::new_from_f64(vl) + DyadicFloat128::new_from_f64(vll); let mut m_v = DyadicFloat128::new_from_f64(vh) + mv0; m_v.sign = DyadicSign::Neg; // Perform computations in Float128: // asin(x) = pi/2 - (v_hi + v_lo + vll) * P(u). let y_f128 = DyadicFloat128::new_from_f64(f_fmla(idx as f64, f64::from_bits(0xbf90000000000000), u)); const PI_OVER_TWO_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let p_f128 = asin_eval_dyadic(y_f128, idx); let r0_f128 = m_v.quick_mul(&p_f128); let mut r_f128 = PI_OVER_TWO_F128.quick_add(&r0_f128); if x.is_sign_negative() { r_f128.sign = DyadicSign::Neg; } r_f128.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn f_asin_test() { assert_eq!(f_asin(-0.4), -0.41151684606748806); assert_eq!(f_asin(-0.8), -0.9272952180016123); assert_eq!(f_asin(0.3), 0.3046926540153975); assert_eq!(f_asin(0.6), 0.6435011087932844); } } pxfm-0.1.23/src/asin_eval_dyadic.rs000064400000000000000000001375071046102023000153110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval16; // > procedure PRINTF128(a) { // write("{"); // if (a < 0) // then write("Sign::NEG, ") else write("Sign::Pos, "); // a_exp = floor(log2(a)) + 1; // write((a + 2 ^ a_exp) * 2 ^ -128); // print("},"); // }; // > verbosity = 0; // > procedure ASIN_APPROX(N, Deg) { // abs_error = 0; // rel_error = 0; // for i from 1 to N / 4 do { // Q = fpminimax(asin(sqrt(i / N + x)) / sqrt(i / N + x), Deg, // [| 128... | ], [ -1 / (2 * N), 1 / (2 * N) ]); // abs_err = dirtyinfnorm(asin(sqrt(i / N + x)) - sqrt(i / N + x) * Q, // [ -1 / (2 * N), 1 / (2 * N) ]); // rel_err = dirtyinfnorm(asin(sqrt(i / N + x)) / sqrt(i / N + x) - Q, // [ -1 / (2 * N), 1 / (2 * N) ]); // if (abs_err > abs_error) then abs_error = abs_err; // if (rel_err > rel_error) then rel_error = rel_err; // write("{"); // for j from 0 to Deg do PRINTF128(coeff(Q, j)); // print("},"); // }; // print("Absolute Errors:", abs_error); // print("Relative Errors:", rel_error); // }; // > ASIN_APPROX(64, 15); // ... // Absolute Errors: 0x1.0b3...p-129 // Relative Errors: 0x1.1db...p-128 // // For k = 0, we use Taylor polynomial of asin(x)/x around x = 0. // asin(x)/x ~ 1 + x^2/6 + (3 x^4)/40 + (5 x^6)/112 + (35 x^8)/1152 + // + (63 x^10)/2816 + (231 x^12)/13312 + (143 x^14)/10240 + // + (6435 x^16)/557056 + (12155 x^18)/1245184 + // + (46189 x^20)/5505024 + (88179 x^22)/12058624 + // + (676039 x^24)/104857600 + (1300075 x^26)/226492416 + // + (5014575 x^28)/973078528 + (9694845 x^30)/2080374784. static ASIN_COEFFS_F128: [[DyadicFloat128; 16]; 17] = [ [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x99999999_99999999_99999999_9999999a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xb6db6db6_db6db6db_6db6db6d_b6db6db7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf8e38e38_e38e38e3_8e38e38e_38e38e39_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xb745d174_5d1745d1_745d1745_d1745d17_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8e276276_27627627_62762762_76276276_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xe4cccccc_cccccccc_cccccccc_cccccccd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xbd43c3c3_c3c3c3c3_c3c3c3c3_c3c3c3c4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x9fef286b_ca1af286_bca1af28_6bca1af3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x89779e79_e79e79e7_9e79e79e_79e79e7a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xef9de9bd_37a6f4de_9bd37a6f_4de9bd38_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd3431eb8_51eb851e_b851eb85_1eb851ec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbc16ed09_7b425ed0_97b425ed_097b425f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa8dd1846_9ee58469_ee58469e_e58469ee_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x98b41def_7bdef7bd_ef7bdef7_bdef7bdf_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8055f060_94f0f05f_3ac3b927_50a701d9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xad19c2ea_e3dd2429_8d04f71d_b965ee1b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9dfa882b_7b31af17_f9f19d33_0c45d24b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xbedd3b58_c9e605ef_1404e1f0_4ba57940_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x83df2581_cb4fea82_b406f201_2fde6d5c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc534fe61_9b82dd16_ed5d8a43_f7710526_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x9b56fa62_88295ddf_ce8425fe_a04d733e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xfdeddb19_4a030da7_27158080_d24caf46_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xd55827db_ff416ea8_042c4d8c_07cddeeb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xb71d73a9_f2ba0688_5eaeeae9_413a0f5f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x9fde87e2_ace91274_38f82666_d619c1ba_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x8d876557_5e4626a1_1b621336_93587847_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xfd801840_c8710595_6880fe13_a9657f8f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xe54245a9_4c8c2ebb_30488494_64b0e34d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd11eb46f_4095a661_8890d123_15c96482_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xc01a4201_467fbc0b_960618d5_ec2adaa8_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80ad1cbe_7878de11_4293301c_11ce9d49_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xaf9ac0df_3d845544_0fe5e31b_9051d03e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa28ceef8_d7297e05_f94773ad_f4a695c6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc75a5b77_58b4b11d_396c68ad_6733022b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x8bde42a1_084a6674_50c5bceb_005d4b62_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xd471cdae_e2f35a96_bd4bc513_e0ccdf2c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa9fc6fd5_d204a4e3_e609940c_6b991b67_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8d242d97_ba12b492_e25c7e7c_0c3fcf60_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xf0f1ba74_b149afc3_2f0bbab5_a20c6199_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xd21b42fb_d8e9098d_19612692_9a043332_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xba5e5492_7896a3e7_193a74d5_78631587_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xa7a17ae7_fc707f45_910e7a5d_c95251f4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x98889a6a_b0370464_50c950d3_61d79ed7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x8c29330e_4318fd29_25c5b528_84e39e7c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x81e7bf48_b25bc7c0_b9204a4f_d4f5fa8b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf2801b09_11bf0768_773996dd_5224d852_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x81058e3e_f82ba622_ab81cd63_e1a91d57_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb22e7055_c80dd354_8a2f2e8e_860d3f33_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa753ce1a_7e3d1f57_247b37e6_03f93624_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xd05c5604_8eca8d18_dcdd76b7_f4b1f185_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x947cdd5e_f1d64df0_84f78df1_e2ecb854_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xe5218370_2ebbf6e8_3727a755_57843b93_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xba482553_383b92eb_186f78f1_8c35d6af_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x9d2b034a_7266c6a1_54b78a98_1a547429_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8852f723_feea6046_e125f5a9_64e168e6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xf19c9891_6c896c99_732052fe_5c54e992_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xd9cc81a5_c5ddf0f0_d651011e_a8ecd936_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xc7173169_dcb6095f_a6160847_b595aaff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xb81cd3f6_4a422ebe_07aeb734_e4dcf3a1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xabf01b1c_d15932aa_698d4382_512318a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xa1f1cf1b_d889a1ac_7120ca2f_bbbc1745_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x99a1b838_e38fbf11_429a4350_76b7d191_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x815f4e70_5c3e68f2_e84ed170_78211dfd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb4d5a992_de1ac4da_16fe6024_3a6cc371_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xac526184_bd558c65_66642dce_edc4b04a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xd9ed9b03_46ec0bab_429ea221_4774bbc1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x9dca410c_1efaeb74_87956685_dd5fe848_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf76e411b_a926fc02_7f942265_9c39a882_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xcc71b004_eeb60c0f_1d387f76_44b46bf8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xaf527a40_6f1084fb_5019904e_d12d384d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x9a9304b0_d8a9de19_e1803691_269be22c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8b3d37c0_dbde09ef_342ddf4f_e80dd3fb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xff2e9111_3a961c78_92297bab_cc257804_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xed1fb643_f2ca31c1_b0a1553a_e077285a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xdeeb0f5e_81ad5e30_78d79ae3_83be1c18_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xd3a13ba6_8ce9abfc_a66eb1fd_c0c760fd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xcaa8c381_d44bb44f_0ab25126_9a5fae10_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xc36fb2c4_244401cf_10dd8a39_78ccbf7f_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x81ba6750_6064f4dd_08015b7c_713688f0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb791524b_d975fdd1_584037b7_103b42ca_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb18c26c5_3ced9856_db5bc672_cc95a64f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe4199ce5_d25be89b_4a0ad208_da77022d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xa7d77999_0f80e3e9_7e97e9d1_0e337550_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x85c3e039_8959c95b_e6e1e87f_7e6636b1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xe0b90ecd_95f7e6eb_a675bae0_628bd214_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc3edb6b4_ed0a684c_c7a3ee4d_f1dcd3f9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xafa274d2_e66e1f61_9e8ab3c7_7221214e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa0dd903d_e110b71a_8a1fc9df_cc080308_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x95e2f38c_60441961_72b90625_e3a37573_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8d9fe38f_2c705139_029f857c_9f628b2b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8762410a_4967a974_6b609e83_7c025a39_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x82b220be_d9ec0e5a_9ce9af7c_c65c94b9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xfe866073_2312c056_4265d82a_3afea10c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xf99b667c_5f8ef6a6_11fafa4d_5c76ebb3_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8216e353_2ffdf638_15d72316_a2f327f2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xba625eba_097ce944_7024c0a3_c873729b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb704e369_5b95ce44_cde30106_90e92cc3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xeeecee6d_7298b8a3_075da5d7_456bdcde_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xb2b78fb1_fcfdc273_1d1ac11c_e29c16f1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x90d21722_148fdaf5_0d566a01_0bb8784b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf7681c54_9771ebb6_17686858_eb5e1caf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xdb5e45c0_52ec0c1c_ff28765e_d4c44bfb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc7ff0dd7_a34ee29b_7cb689af_fe887bf5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xba4e6f37_a98a3e3f_f1175427_20f45c82_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xb08f6e11_688e4174_b3d48abe_c0a6d5cd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa9af6a33_14aabe45_26da1218_05bbb52e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa4fd22fa_1b4f0d7f_1456af96_cbd0cde6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa20229b4_7e9c2e39_22c49987_66a05c5a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa0775ca8_4409c735_351d01f1_34467927_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xa010d2d9_08428a53_53603f20_66c8b8ba_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8274cd6a_f25e642d_0b1a02fb_03f53f3e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xbd49d2c8_b9005b2a_ee795b17_92181a48_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xbcc0ac23_98e00fd7_c40811f5_486aca6a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xfa756493_b381b917_6cdea268_e44dd2fd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xbe7fce1e_462b43c6_0537d6f7_138c87ac_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x9d00958b_edc83095_b4cc907c_a92c30f1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x886a2440_ed93d825_333c19c2_6de36d73_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf616ebc0_4f576462_d9312544_e8fbe0fd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xe43f4c9d_ebb5d685_00903a00_7bd6ad39_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xd8516eab_32337672_569b4e19_a44e795c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xd091fa04_954666ee_cc4da283_82e977c0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xcbf13442_c4c0f859_0449c2c4_2fc046fe_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc9c1d1b4_dea4c76c_d101e562_dc3af77f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc9924d2a_b8ec37d9_80af1780_0fb63e4e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xcb24b252_1ff37e4a_41f35260_2b9ace95_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xce2d87ac_194a6304_1658ed0e_4cdb8161_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x82d4310f_f58b570d_266275fc_1d085c87_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc048c361_72bee7b0_8d2ca7e5_afe4f335_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc2c3ecca_216e290e_b99c5c53_5d48595a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x83611e8f_3adf2217_be3c342a_dfb1c562_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xcb481202_8b0ba9aa_e586f73d_faea68e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xaa727c9a_4caba65d_c8dc13ef_8bed52e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x96b05462_efac126e_db6871d0_0be1eff9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x8a4f8752_9b3c9232_63eb1596_a2c83eb4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x828be6f4_1b14e6e6_8efc1012_2afe425a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xfbd2f055_9d699ea9_b572008e_1fb08088_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf71b3c70_dc4610e6_bc1e581c_817b88bd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf5e8ebf6_3b0aef3f_97ba4c8f_e49b6f0a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xf7986238_1eb8bd7a_73577ed0_c05e4abf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xfbc3832a_a903cd65_a46ee523_f342c621_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x811ea5f3_7409245e_1777fdd1_59b29f80_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x85619588_b83c90ef_67740d6a_d2f372a8_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x83351a49_8764656f_e1774024_a5e751a6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc36057da_23d39c2b_336474e0_3a893914_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc913714c_a46cc0bf_3bdd68ba_53a309d4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x89f2254d_f1469d60_e1324bac_95db6742_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xd92b27f6_38df6911_5842365c_c120cc63_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xb94ff079_7848d391_486efffa_a6fbc37f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xa6c03919_862e8437_70f86a73_43da3a6e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x9bcb70c9_a378e97f_a59f25f3_ba202e33_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x95b103b0_62aa9f64_ee2d6146_76020bc5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x92fa4a1c_7d7fd161_8f25aa4e_f65ca52f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x92d387a2_c5dd771d_4015ca29_e3eda1d9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x94c13c5c_997615c3_8a2f63c8_c314226f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x987b8c8f_5e9e7a5f_e8497909_d60d1194_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x9ddb0978_da99e6ad_83d5eca2_9d079ef7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xa4d9aeee_4b512ed4_5ec95cd1_37ce3f22_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xad602af3_1e14d681_8a267da2_57c030de_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x839795b7_8f3005a4_689f57cc_d201f7dc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc691cb89_3d75d3d5_a1892f2a_bf54ec45_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xcfb46fc4_6d28c32c_9ae5ad3d_a7749dc8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x90f71352_c806c830_20edb8b2_7594386b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe8473840_d511dc77_d63def5d_7f4de9c0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc9c6eb30_aaf2b63d_ec20f671_8689534a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xb8dcfa84_eb6cab93_3023ddcc_b8f68a2f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xafde4094_c1a14390_9609a3ea_847225a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xac1254e7_5852a836_b2aca5e5_0cfc484f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xac0d3ffa_d6171016_b1a12557_858663c1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xaf0877f9_0ca5c52f_fc54b5af_b5cbc350_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xb498574f_af349a2b_f391ff83_b3570919_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xbc87c7bb_34182440_280647cd_976affb0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc6c5688f_58a42593_4569de36_0855c393_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xd368b088_5bb9496a_dd7c92df_8798aaf7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe272168a_c8dbe668_381542bf_fc24c266_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x83fbb09c_fbb0ebf4_208c9037_70373f79_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc9de6f84_8e652b0b_3b2a2bb9_f7ce3de8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xd6ac93c7_6e215233_f184fdcc_e5872970_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x987a35b9_87c02522_1927dee9_70fc6b18_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xf8be450d_266409a9_2e534ffd_905f4424_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xdc0c36d7_34415e3b_c5121c4d_4e28c17d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xcd551b98_81d982a8_1399d9ba_ddf55821_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc6f91e3f_428d6be3_646f3147_20445145_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc64f100c_85e1e8f1_6f501d1e_2155f872_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc9fe25ae_295f1f24_5924cf9a_036a31f2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xd157410e_fcc10fbb_fceb318a_b4990bd7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xdc0aeb56_ca679f92_3b3c44d8_99b1add7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xea05b383_bc339550_e5c5c34b_bfa416a1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xfb5e3897_5a5c8f62_280a90dc_9ebe9107_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x88301d81_b38f225d_2226ab7e_df342d90_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x949e3465_e4a8aef7_46311182_5fc3fde8_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x846178eb_1c7260da_3e0aca9a_51e68d84_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xcd47ac90_3c311c2b_98dd7493_4656d210_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xde020b2d_abd5628c_b88634e5_73f312fc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa086fafa_c220fb73_9939cae3_2d69683f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x855b5efa_f6963d73_e4664cb1_d43f03a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xf05c9774_fe0de25c_ccf1c1df_d2ed9941_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe484a941_19639229_f06ae955_f8edc7d1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe1a32bb2_52ca122c_bf2f0904_cfc476cb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe528e091_7bb8a01a_9218ce3e_1e85af60_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xeddd556a_faa2d46f_e91c61fa_adf12aec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xfb390fa3_15e9d55f_5683c0c4_c7719f81_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x868e5fa4_15597c8f_7c42a262_8f2d6332_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x91d79767_a3d037f9_cd84ead5_c0714310_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9fa6a035_915bc052_377a8abb_faf4e3c6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb04edefd_6ac2a93e_ec33e6f6_3d53e7c2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc416980d_dc5c186b_7bdcded6_97ea5844_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x84c8fd4d_ffdf9fc6_bdd7ebca_88183d7b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd0cf0544_11dbf845_cb6eeae5_bc980e2f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe5bb9480_7ce0eaca_74300a46_8398e944_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa92a18f8_d611860b_5f2ef8c6_8e8ca002_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x8f2e1684_17eb4e6c_1ec44b9b_e4b1c3e5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x837f1764_0ee8f416_8694b4a1_c647af0c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xfed7e2a9_05a5190e_b7d70a61_a24ad801_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x803f29ff_dc6fd2bc_3c3c4b50_a9dc860c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x84c61e09_b8aa35e4_96239f9c_b1d00b3c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x8c7ed311_f77980d6_842ddf90_6a68a0bc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9746077b_d397c2d1_038a4744_a76f5fb5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa5341277_c4185ace_54f26328_322158e8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb68d78f5_0972f6de_9189aa23_d3ecefc2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xcbbcefc2_15bade4e_f1d36947_c8b6e460_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe564a459_c851390d_d45a4748_f29f182b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x820ea28b_c89662c3_2a64ccdc_efb2b259_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x85324d39_f30f9174_ac0d817e_9c744b0b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd476186e_49c47f3a_a71f8886_7f9f21c4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xede08f54_a830e87b_07881700_65e57b6c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb271b8eb_309963ee_89187c73_0b92f7d5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x99f0011d_95d3a6dd_282bd00a_db808151_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9021134e_02b479e7_3aabf9bb_b7ab6cf3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x8e673bf2_f11db54a_909c4c72_6389499f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9226a371_88dd55f7_bfe21777_4a42a7ae_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9a4d78fc_9df79d9a_44609c02_a625808a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa68335fb_41d2d91c_e7bbd2a3_31a1d17b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb6d89c39_28d0cb26_809d4df6_e55cba1a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xcba71468_9177fc2d_7f23df2f_37226488_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe5846de8_44833ae9_34416c87_0315eb9e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x82a07032_64e6226b_200d94a1_66fc7951_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9602695c_b6fa8886_68ca0cba_b59ea683_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xad7d185a_ab3d14dd_d908a7b1_c57352bb_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x859d78fa_4405d8fa_287dbc69_95d0975e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd83ea3bc_131d6baa_67c51d88_4c4dae01_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xf6790edb_df07342b_aad85870_167af128_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xbc6daa33_12be0f85_bc7fa753_52b10a83_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa5bd41bc_9c986b13_1af2542e_92aacb59_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9e4358bc_24e04364_b4539b76_e444b790_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9f7fc21b_dca1f2b5_f3f6d44b_c5a37626_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa6fd793c_0b9c44c1_30a518cc_66b5e511_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb3dccfac_cd1592b3_bcd6b7c0_9749993d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc6056c3a_4a5f329a_48f1429d_27f930fc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xddd9e529_858a4502_6e7f3d1c_1e7dcb89_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xfc1bccee_dc8d2567_1721c468_6f7f53ec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x90f2bb21_5cdbe7e2_f9ef8e12_059cc66a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa857d5df_5b4da940_15ce4e95_7201fc79_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc54119c0_10c02bf4_d87ece17_1ef85c5f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xe8c50ebc_880356de_2c1f4c42_9ee9748f_u128, }, ], [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x860a91c1_6b9b2c23_2dd99707_ab3d688b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xdc2a86b1_5fdb645d_ea2781dd_25555f49_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xff8def07_d1e514d7_b2e8ebb6_5c3afe5e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc72f9d5b_4fb559e3_20db92e3_a5ae3f73_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb2b5f45b_1d26f4dd_0b210309_fb68914f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xae1cbaae_c7b55465_4da858f5_47e62a37_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb30f3998_10202a0d_a52ec085_a7d63289_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xbf51f27f_b7aff89d_dc24e2aa_208d2054_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xd250735e_87d0b527_6f99bcc9_bd6fc717_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xec543ec2_bddb2efb_36d9ce81_a7c84336_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x871f73e3_298ef45c_eed83998_2bc731b9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9cbb5447_af8574f1_21fa4cda_93d82b7e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb7f5a6c0_430a347f_11b22cde_91de0885_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xda153cc4_14abdb96_840df7c2_3299fec0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x826c129b_3e4a2612_b2cd11f1_4d2ba60c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9d19c289_fc0e8aa4_f351418b_b760ce90_u128, }, ], ]; #[cold] pub(crate) fn asin_eval_dyadic(u: DyadicFloat128, idx: usize) -> DyadicFloat128 { let coeffs = ASIN_COEFFS_F128[idx]; f_polyeval16( u, coeffs[0], coeffs[1], coeffs[2], coeffs[3], coeffs[4], coeffs[5], coeffs[6], coeffs[7], coeffs[8], coeffs[9], coeffs[10], coeffs[11], coeffs[12], coeffs[13], coeffs[14], coeffs[15], ) } pxfm-0.1.23/src/asinf.rs000064400000000000000000000133051046102023000131200ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::acosf::poly12; use crate::common::{dd_fmlaf, f_fmla}; #[cold] fn as_special(x: f32) -> f32 { let t = x.to_bits(); let ax = t.wrapping_shl(1); if ax > (0xffu32 << 24) { return x + x; } // nan f32::NAN } /// Computes asin /// /// Max found ULP 0.49999928 #[inline] pub fn f_asinf(x: f32) -> f32 { const PI2: f64 = f64::from_bits(0x3ff921fb54442d18); let xs = x as f64; let mut r; let t = x.to_bits(); let ax = t.wrapping_shl(1); if ax > 0x7f << 24 { return as_special(x); } if ax < 0x7ec29000u32 { // |x| < 1.49029 if ax < 115 << 24 { // |x| < 0.000244141 return dd_fmlaf(x, f64::from_bits(0x3e60000000000000) as f32, x); } const B: [u64; 16] = [ 0x3ff0000000000005, 0x3fc55557aeca105d, 0x3fb3314ec3db7d12, 0x3fa775738a5a6f92, 0x3f75d5f7ce1c8538, 0x3fd605c6d58740f0, 0xc005728b732d73c6, 0x402f152170f151eb, 0xc04f962ea3ca992e, 0x40671971e17375a0, 0xc07860512b4ba230, 0x40826a3b8d4bdb14, 0xc0836f2ea5698b51, 0x407b3d722aebfa2e, 0xc066cf89703b1289, 0x4041518af6a65e2d, ]; let z = xs; let z2 = z * z; let w0 = f_fmla(z2, f64::from_bits(B[1]), f64::from_bits(B[0])); let w1 = f_fmla(z2, f64::from_bits(B[3]), f64::from_bits(B[2])); let w2 = f_fmla(z2, f64::from_bits(B[5]), f64::from_bits(B[4])); let w3 = f_fmla(z2, f64::from_bits(B[7]), f64::from_bits(B[6])); let w4 = f_fmla(z2, f64::from_bits(B[9]), f64::from_bits(B[8])); let w5 = f_fmla(z2, f64::from_bits(B[11]), f64::from_bits(B[10])); let w6 = f_fmla(z2, f64::from_bits(B[13]), f64::from_bits(B[12])); let w7 = f_fmla(z2, f64::from_bits(B[15]), f64::from_bits(B[14])); let z4 = z2 * z2; let z8 = z4 * z4; let z16 = z8 * z8; r = z * ((f_fmla(z4, w1, w0) + z8 * f_fmla(z4, w3, w2)) + z16 * (f_fmla(z4, w5, w4) + z8 * f_fmla(z4, w7, w6))); let ub = r; let lb = r - z * f64::from_bits(0x3e0efa8eb0000000); // Ziv's accuracy test if ub == lb { return ub as f32; } } if ax < (0x7eu32 << 24) { const C: [u64; 12] = [ 0x3fc555555555529c, 0x3fb333333337e0dd, 0x3fa6db6db3b4465e, 0x3f9f1c72e13ac306, 0x3f96e89cebe06bc4, 0x3f91c6dcf5289094, 0x3f8c6dbbcc7c6315, 0x3f88f8dc2615e996, 0x3f7a5833b7bf15e8, 0x3f943f44ace1665c, 0xbf90fb17df881c73, 0x3fa07520c026b2d6, ]; let z = xs; let z2 = z * z; let c0 = poly12(z2, C); r = z + (z * z2) * c0; } else { if ax == 0x7e55688au32 { return f32::copysign(f64::from_bits(0x3fe75b8a20000000) as f32, x) + f32::copysign(f64::from_bits(0x3e50000000000000) as f32, x); } if ax == 0x7e107434u32 { return f32::copysign(f64::from_bits(0x3fe1f4b640000000) as f32, x) + f32::copysign(f64::from_bits(0x3e50000000000000) as f32, x); } let bx = xs.abs(); let z = 1.0 - bx; let s = z.sqrt(); const C: [u64; 12] = [ 0x3ff6a09e667f3bcb, 0x3fbe2b7dddff2db9, 0x3f9b27247ab42dbc, 0x3f802995cc4e0744, 0x3f65ffb0276ec8ea, 0x3f5033885a928dec, 0x3f3911f2be23f8c7, 0x3f24c3c55d2437fd, 0x3f0af477e1d7b461, 0x3f0abd6bdff67dcb, 0xbef1717e86d0fa28, 0x3ef6ff526de46023, ]; r = PI2 - s * poly12(z, C); r = f64::copysign(r, xs); } r as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_asinf() { assert_eq!(f_asinf(-0.5), -std::f32::consts::FRAC_PI_6); assert_eq!(f_asinf(0.5), std::f32::consts::FRAC_PI_6); assert!(f_asinf(7.).is_nan()); } } pxfm-0.1.23/src/asinpi.rs000064400000000000000000000330261046102023000133050ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::acospi::INV_PI_DD; use crate::asin::asin_eval; use crate::asin_eval_dyadic::asin_eval_dyadic; use crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; /// Computes asin(x)/PI /// /// Max found ULP 0.5 pub fn f_asinpi(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); // |x| < 0.5. if x_e < E_BIAS - 1 { // |x| < 2^-26. if x_e < E_BIAS - 26 { // When |x| < 2^-26, the relative error of the approximation asin(x) ~ x // is: // |asin(x) - x| / |asin(x)| < |x^3| / (6|x|) // = x^2 / 6 // < 2^-54 // < epsilon(1)/2. // = x otherwise. , if x.abs() == 0. { return x; } if x_e < E_BIAS - 56 { if (x_abs.to_bits().wrapping_shl(12)) == 0x59af9a1194efe000u64 { let e = (x.to_bits() >> 52) & 0x7ff; let h = f64::from_bits(0x3c7b824198b94a89); let l = f64::from_bits(0x391fffffffffffff); let mut t = (if x > 0. { 1.0f64 } else { -1.0f64 }).to_bits(); t = t.wrapping_sub(0x3c9u64.wrapping_sub(e).wrapping_shl(52)); return f_fmla(l, f64::from_bits(t), h * f64::from_bits(t)); } let h = x * INV_PI_DD.hi; let sx = x * f64::from_bits(0x4690000000000000); /* scale x */ let mut l = dd_fmla(sx, INV_PI_DD.hi, -h * f64::from_bits(0x4690000000000000)); l = dd_fmla(sx, INV_PI_DD.lo, l); /* scale back */ let res = dyad_fmla(l, f64::from_bits(0x3950000000000000), h); return res; } /* We use the Sollya polynomial 0x1.45f306dc9c882a53f84eafa3ea4p-2 * x + 0x1.b2995e7b7b606p-5 * x^3, with relative error bounded by 2^-106.965 on [2^-53, 2^-26] */ const C1H: f64 = f64::from_bits(0x3fd45f306dc9c883); const C1L: f64 = f64::from_bits(0xbc76b01ec5417057); const C3: f64 = f64::from_bits(0x3fab2995e7b7b606); let h = C1H; let l = dd_fmla(C3, x * x, C1L); /* multiply h+l by x */ let hh = h * x; let mut ll = dd_fmla(h, x, -hh); /* hh+ll = h*x */ ll = dd_fmla(l, x, ll); return hh + ll; } let x_sq = DoubleDouble::from_exact_mult(x, x); let err = x_abs * f64::from_bits(0x3cc0000000000000); // Polynomial approximation: // p ~ asin(x)/x let (p, err) = asin_eval(x_sq, err); // asin(x) ~ x * (ASIN_COEFFS[idx][0] + p) let mut r0 = DoubleDouble::from_exact_mult(x, p.hi); let mut r_lo = f_fmla(x, p.lo, r0.lo); r0 = DoubleDouble::mult(DoubleDouble::new(r_lo, r0.hi), INV_PI_DD); r_lo = r0.lo; let r_upper = r0.hi + (r_lo + err); let r_lower = r0.hi + (r_lo - err); if r_upper == r_lower { return r_upper; } // Ziv's accuracy test failed, perform 128-bit calculation. // Recalculate mod 1/64. let idx = (x_sq.hi * f64::from_bits(0x4050000000000000)).round() as usize; // Get x^2 - idx/64 exactly. When FMA is available, double-double // multiplication will be correct for all rounding modes. Otherwise, we use // Float128 directly. let x_f128 = DyadicFloat128::new_from_f64(x); let u: DyadicFloat128; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { // u = x^2 - idx/64 let u_hi = DyadicFloat128::new_from_f64(f_fmla( idx as f64, f64::from_bits(0xbf90000000000000), x_sq.hi, )); u = u_hi.quick_add(&DyadicFloat128::new_from_f64(x_sq.lo)); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let x_sq_f128 = x_f128.quick_mul(&x_f128); u = x_sq_f128.quick_add(&DyadicFloat128::new_from_f64( idx as f64 * (f64::from_bits(0xbf90000000000000)), )); } let p_f128 = asin_eval_dyadic(u, idx); let mut r = x_f128.quick_mul(&p_f128); r = r.quick_mul(&crate::acospi::INV_PI_F128); return r.fast_as_f64(); } const PI_OVER_TWO: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c91a62633145c07), f64::from_bits(0x3ff921fb54442d18), ); let x_sign = if x.is_sign_negative() { -1.0 } else { 1.0 }; // |x| >= 1 if x_e >= E_BIAS { // x = +-1, asin(x) = +- pi/2 if x_abs == 1.0 { // return +- pi/2 return x * 0.5; // asinpi_specific } // |x| > 1, return NaN. if x.is_nan() { return x; } return f64::NAN; } // u = (1 - |x|)/2 let u = f_fmla(x_abs, -0.5, 0.5); // v_hi + v_lo ~ sqrt(u). // Let: // h = u - v_hi^2 = (sqrt(u) - v_hi) * (sqrt(u) + v_hi) // Then: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // ~ v_hi + h / (2 * v_hi) // So we can use: // v_lo = h / (2 * v_hi). // Then, // asin(x) ~ pi/2 - 2*(v_hi + v_lo) * P(u) let v_hi = u.sqrt(); let h; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { h = f_fmla(v_hi, -v_hi, u); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let v_hi_sq = DoubleDouble::from_exact_mult(v_hi, v_hi); h = (u - v_hi_sq.hi) - v_hi_sq.lo; } // Scale v_lo and v_hi by 2 from the formula: // vh = v_hi * 2 // vl = 2*v_lo = h / v_hi. let vh = v_hi * 2.0; let vl = h / v_hi; // Polynomial approximation: // p ~ asin(sqrt(u))/sqrt(u) let err = vh * f64::from_bits(0x3cc0000000000000); let (p, err) = asin_eval(DoubleDouble::new(0.0, u), err); // Perform computations in double-double arithmetic: // asin(x) = pi/2 - (v_hi + v_lo) * (ASIN_COEFFS[idx][0] + p) let r0 = DoubleDouble::quick_mult(DoubleDouble::new(vl, vh), p); let mut r = DoubleDouble::from_exact_add(PI_OVER_TWO.hi, -r0.hi); let mut r_lo = PI_OVER_TWO.lo - r0.lo + r.lo; let p = DoubleDouble::mult(DoubleDouble::new(r_lo, r.hi), INV_PI_DD); r_lo = p.lo; r.hi = p.hi; let (r_upper, r_lower); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { r_upper = f_fmla(r.hi, x_sign, f_fmla(r_lo, x_sign, err)); r_lower = f_fmla(r.hi, x_sign, f_fmla(r_lo, x_sign, -err)); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let r_lo = r_lo * x_sign; let r_hi = r.hi * x_sign; r_upper = r_hi + (r_lo + err); r_lower = r.hi + (r_lo - err); } if r_upper == r_lower { return r_upper; } // Ziv's accuracy test failed, we redo the computations in Float128. // Recalculate mod 1/64. let idx = (u * f64::from_bits(0x4050000000000000)).round() as usize; // After the first step of Newton-Raphson approximating v = sqrt(u), we have // that: // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) // v_lo = h / (2 * v_hi) // With error: // sqrt(u) - (v_hi + v_lo) = h * ( 1/(sqrt(u) + v_hi) - 1/(2*v_hi) ) // = -h^2 / (2*v * (sqrt(u) + v)^2). // Since: // (sqrt(u) + v_hi)^2 ~ (2sqrt(u))^2 = 4u, // we can add another correction term to (v_hi + v_lo) that is: // v_ll = -h^2 / (2*v_hi * 4u) // = -v_lo * (h / 4u) // = -vl * (h / 8u), // making the errors: // sqrt(u) - (v_hi + v_lo + v_ll) = O(h^3) // well beyond 128-bit precision needed. // Get the rounding error of vl = 2 * v_lo ~ h / vh // Get full product of vh * vl let vl_lo; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { vl_lo = f_fmla(-v_hi, vl, h) / v_hi; } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let vh_vl = DoubleDouble::from_exact_mult(v_hi, vl); vl_lo = ((h - vh_vl.hi) - vh_vl.lo) / v_hi; } // vll = 2*v_ll = -vl * (h / (4u)). let t = h * (-0.25) / u; let vll = f_fmla(vl, t, vl_lo); // m_v = -(v_hi + v_lo + v_ll). let mv0 = DyadicFloat128::new_from_f64(vl) + DyadicFloat128::new_from_f64(vll); let mut m_v = DyadicFloat128::new_from_f64(vh) + mv0; m_v.sign = DyadicSign::Neg; // Perform computations in Float128: // asin(x) = pi/2 - (v_hi + v_lo + vll) * P(u). let y_f128 = DyadicFloat128::new_from_f64(f_fmla(idx as f64, f64::from_bits(0xbf90000000000000), u)); const PI_OVER_TWO_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let p_f128 = asin_eval_dyadic(y_f128, idx); let r0_f128 = m_v * p_f128; let mut r_f128 = PI_OVER_TWO_F128 + r0_f128; if x.is_sign_negative() { r_f128.sign = DyadicSign::Neg; } r_f128 = r_f128.quick_mul(&crate::acospi::INV_PI_F128); r_f128.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn f_asinpi_test() { assert_eq!( f_asinpi(-0.00000000032681723993732703), -0.00000000010402915844735117 ); assert_eq!(f_asinpi(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017801371778309684), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005666352624669099); assert_eq!(f_asinpi(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026752519513526076), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008515591441480124); assert_eq!(f_asinpi(-0.4), -0.13098988043445461); assert_eq!(f_asinpi(-0.8), -0.2951672353008666); assert_eq!(f_asinpi(0.4332432142124432), 0.14263088583055605); assert_eq!(f_asinpi(0.8543543534343434), 0.326047108714517); assert_eq!(f_asinpi(0.00323146509843243), 0.0010286090778797426); } } pxfm-0.1.23/src/asinpif.rs000064400000000000000000000166521046102023000134610ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; pub(crate) static ASINCOSF_PI_TABLE: [[u64; 8]; 16] = [ [ 0x3fd45f306dc9c882, 0x3fab2995e7b7dc2f, 0x3f98723a1cf50c7e, 0x3f8d1a4591d16a29, 0x3f83ce3aa68ddaee, 0x3f7d3182ab0cc1bf, 0x3f762b379a8b88e3, 0x3f76811411fcfec2, ], [ 0x3fdffffffffd3cda, 0xbfb17cc1b3355fdd, 0x3f9d067a1e8d5a99, 0xbf908e16fb09314a, 0x3f85eed43d42dcb2, 0xbf7f58baca7acc71, 0x3f75dab64e2dcf15, 0xbf659270e30797ac, ], [ 0x3fdfffffff7c4617, 0xbfb17cc149ded3a2, 0x3f9d0654d4cb2c1a, 0xbf908c3ba713d33a, 0x3f85d2053481079c, 0xbf7e485ebc545e7e, 0x3f7303baca167ddd, 0xbf5dee8d16d06b38, ], [ 0x3fdffffffa749848, 0xbfb17cbe71559350, 0x3f9d05a312269adf, 0xbf90862b3ee617d7, 0x3f85920708db2a73, 0xbf7cb0463b3862c3, 0x3f702b82478f95d7, 0xbf552a7b8579e729, ], [ 0x3fdfffffe1f92bb5, 0xbfb17cb3e74c64e3, 0x3f9d03af67311cbf, 0xbf9079441cbfc7a0, 0x3f852b4287805a61, 0xbf7ac3286d604a98, 0x3f6b2f1210d9701b, 0xbf4e740ddc25afd6, ], [ 0x3fdfffff92beb6e2, 0xbfb17c986fe9518b, 0x3f9cff98167c9a5e, 0xbf90638b591eae52, 0x3f84a0803828959e, 0xbf78adeca229f11d, 0x3f66b9a7ba05dfce, 0xbf4640521a43b2d0, ], [ 0x3fdffffeccee5bfc, 0xbfb17c5f1753f5ea, 0x3f9cf874e4fe258f, 0xbf9043e6cf77b256, 0x3f83f7db42227d92, 0xbf7691a6fa2a2882, 0x3f62f6543162bc61, 0xbf407d5da05822b6, ], [ 0x3fdffffd2f64431d, 0xbfb17bf8208c10c1, 0x3f9ced7487cdb124, 0xbf901a0d30932905, 0x3f83388f99b254da, 0xbf74844e245c65bd, 0x3f5fa777150197c6, 0xbf38c1ecf16a05c8, ], [ 0x3fdffffa36d1712e, 0xbfb17b523971bd4e, 0x3f9cddee26de2dee, 0xbf8fccb00abaaabc, 0x3f8269afc3622342, 0xbf72933152686752, 0x3f5a76d4956cc9a3, 0xbf32ce7d6dc651ce, ], [ 0x3fdffff5402ab3a1, 0xbfb17a5ba85da77a, 0x3f9cc96894e05c02, 0xbf8f532143cb832e, 0x3f819180b660ff09, 0xbf70c57417a78b3c, 0x3f562e26cbd7bb1e, 0xbf2ce28d33fe1df3, ], [ 0x3fdfffed8d639751, 0xbfb1790349f3ae76, 0x3f9caf9a4fd1b398, 0xbf8ec986b111342e, 0x3f80b53c3ad4baa4, 0xbf6e3c2282eeace4, 0x3f52a55369f55bbe, 0xbf2667fe48c396e8, ], [ 0x3fdfffe24b714161, 0xbfb177394fbcb719, 0x3f9c90652d920ebd, 0xbf8e3239197bddf1, 0x3f7fb2188525b025, 0xbf6b3aadd451afc7, 0x3f4f74020f31fdab, 0xbf218b0cb246768d, ], [ 0x3fdfffd298bec9e2, 0xbfb174efbfd34648, 0x3f9c6bcfe48ea92b, 0xbf8d8f9f2a16157c, 0x3f7e0044f56c8864, 0xbf6883e2347fe76c, 0x3f4a9f0e3c1b7af5, 0xbf1bb5acc0e60825, ], [ 0x3fdfffbd8b784c4d, 0xbfb1721abdd3722e, 0x3f9c41fee756d4b0, 0xbf8ce40bccf8065f, 0x3f7c59b684b70ef9, 0xbf66133d027996b3, 0x3f469cad01106397, 0xbf160f8e45494156, ], [ 0x3fdfffa23749cf88, 0xbfb16eb0a8285c06, 0x3f9c132d762e1b0d, 0xbf8c31a959398f4e, 0x3f7ac1c5b46bc8a0, 0xbf63e34f1abe51dc, 0x3f4346738737c0b9, 0xbf11b227a3f5c750, ], [ 0x3fdfff7fb25bb407, 0xbfb16aaa14d75640, 0x3f9bdfa75fca5ff2, 0xbf8b7a6e260d079c, 0x3f793ab06911033c, 0xbf61ee5560967fd5, 0x3f407d31060838bf, 0xbf0c96f33a283115, ], ]; /// Computes asin(x)/PI /// /// Max ULP 0.5 #[inline] pub fn f_asinpif(x: f32) -> f32 { let ax = x.abs(); let az = ax as f64; let z = x as f64; let t = x.to_bits(); let e: i32 = ((t >> 23) & 0xff) as i32; if e >= 127 { // |x| >= 1 or nan if ax == 1.0 { return f32::copysign(0.5, x); } // |x| = 1 if e == 0xff && (t.wrapping_shl(9)) != 0 { return x + x; } // x = nan return f32::NAN; // |x| > 1 } let s: i32 = 146i32.wrapping_sub(e); let mut i = 0i32; // s<32 corresponds to |x| >= 2^-12 if s < 32 { i = (((t & 0x007fffff) | 1 << 23) >> s) as i32; } let z2 = z * z; let z4 = z2 * z2; let c = ASINCOSF_PI_TABLE[i as usize & 15]; if i == 0 { // |x| < 2^-4 let mut c0 = f_fmla(z2, f64::from_bits(c[1]), f64::from_bits(c[0])); let c2 = f_fmla(z2, f64::from_bits(c[3]), f64::from_bits(c[2])); let mut c4 = f_fmla(z2, f64::from_bits(c[5]), f64::from_bits(c[4])); let c6 = f_fmla(z2, f64::from_bits(c[7]), f64::from_bits(c[6])); c0 = f_fmla(c2, z4, c0); c4 = f_fmla(c6, z4, c4); c0 += c4 * (z4 * z4); (z * c0) as f32 } else { // |x| >= 2^-4 let f = (1. - az).sqrt(); let mut c0 = f_fmla(az, f64::from_bits(c[1]), f64::from_bits(c[0])); let c2 = f_fmla(az, f64::from_bits(c[3]), f64::from_bits(c[2])); let mut c4 = f_fmla(az, f64::from_bits(c[5]), f64::from_bits(c[4])); let c6 = f_fmla(az, f64::from_bits(c[7]), f64::from_bits(c[6])); c0 = f_fmla(c2, z2, c0); c4 = f_fmla(c6, z2, c4); c0 += c4 * z4; let r = f_fmla( -c0, f64::copysign(f, x as f64), f64::copysign(0.5, x as f64), ); r as f32 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_asinpif() { assert_eq!(f_asinpif(0.0), 0.); assert_eq!(f_asinpif(0.5), 0.16666667); assert!(f_asinpif(1.5).is_nan()); } } pxfm-0.1.23/src/bessel/alpha0.rs000064400000000000000000000240431046102023000144430ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval9; // /// See [bessel_0_asympt_alpha] for the info pub(crate) fn bessel_0_asympt_alpha_hard(reciprocal: DyadicFloat128) -> DyadicFloat128 { static C: [DyadicFloat128; 18] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x85555555_55555555_55555555_55555555_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd6999999_99999999_99999999_9999999a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0xd1ac2492_49249249_24924924_92492492_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -123, mantissa: 0xbbcd0fc7_1c71c71c_71c71c71_c71c71c7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -118, mantissa: 0x85e8fe45_8ba2e8ba_2e8ba2e8_ba2e8ba3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -113, mantissa: 0x8b5a8f33_63c4ec4e_c4ec4ec4_ec4ec4ec_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -108, mantissa: 0xc7661d79_9d59b555_55555555_55555555_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -102, mantissa: 0xbbced715_c2897a28_78787878_78787878_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -96, mantissa: 0xe14b19b4_aae3f7fe_be1af286_bca1af28_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -89, mantissa: 0xa7af7341_db2192db_975e0c30_c30c30c3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -82, mantissa: 0x97a8f676_b349f6fc_5cefd338_590b2164_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -75, mantissa: 0xa3d299fb_6f304d73_86e15f12_0fd70a3d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -68, mantissa: 0xd050b737_cbc044ef_e8807e3c_87f43da1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -60, mantissa: 0x9a02379b_daa7e492_854f42de_6d3dffe6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -52, mantissa: 0x83011a39_380e467d_de6b70ec_b92ce0cc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -45, mantissa: 0xfe16521f_c79e5d9a_a5bed653_e3844e9a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -36, mantissa: 0x8b54b13d_3fb3e1c4_15dbb880_0bb32218_u128, }, ]; let x2 = reciprocal * reciprocal; let mut p = C[17]; for i in (0..17).rev() { p = x2 * p + C[i]; } p * reciprocal } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied. Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(0, x, 50) Q = Qn_asymptotic(0, x, 50) R_series = (-Q/P) # alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)]) alpha_series = arctan_series_Z(R_series) # see the series print(alpha_series) ``` **/ #[inline] pub(crate) fn bessel_0_asympt_alpha(recip: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 12] = [ (0x0000000000000000, 0x3fc0000000000000), (0x3c55555555555555, 0xbfb0aaaaaaaaaaab), (0x3c5999999999999a, 0x3fcad33333333333), (0xbc92492492492492, 0xbffa358492492492), (0xbcbc71c71c71c71c, 0x403779a1f8e38e39), (0xbd0745d1745d1746, 0xc080bd1fc8b1745d), (0xbd7d89d89d89d89e, 0x40d16b51e66c789e), (0x3dc5555555555555, 0xc128ecc3af33ab37), (0x3e2143c3c3c3c3c4, 0x418779dae2b8512f), (0x3df41e50d79435e5, 0xc1ec296336955c7f), (0x3ef6dcbaf0618618, 0x4254f5ee683b6432), (0x3f503a3102cc7a6f, 0xc2c2f51eced6693f), ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(C[11]), DoubleDouble::from_bit_pair(C[10]), ); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[9])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[8])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[7])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[6])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[5])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[4])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[0].1)); let z = DoubleDouble::quick_mult(p, recip); DoubleDouble::from_exact_add(z.hi, z.lo) } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied. Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(0, x, 50) Q = Qn_asymptotic(0, x, 50) R_series = (-Q/P) # alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)]) alpha_series = arctan_series_Z(R_series) # see the series print(alpha_series) ``` **/ #[inline] pub(crate) fn bessel_0_asympt_alpha_fast(recip: DoubleDouble) -> DoubleDouble { const C: [u64; 12] = [ 0x3fc0000000000000, 0xbfb0aaaaaaaaaaab, 0x3fcad33333333333, 0xbffa358492492492, 0x403779a1f8e38e39, 0xc080bd1fc8b1745d, 0x40d16b51e66c789e, 0xc128ecc3af33ab37, 0x418779dae2b8512f, 0xc1ec296336955c7f, 0x4254f5ee683b6432, 0xc2c2f51eced6693f, ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let p = f_polyeval9( x2.hi, f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), f64::from_bits(C[10]), f64::from_bits(C[11]), ); let mut z = DoubleDouble::mul_f64_add_f64(x2, p, f64::from_bits(C[2])); z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[1])); z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[0])); DoubleDouble::quick_mult(z, recip) } pxfm-0.1.23/src/bessel/alpha1.rs000064400000000000000000000241611046102023000144450ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval9; /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied. Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(1, x, 50) Q = Qn_asymptotic(1, x, 50) R_series = (-Q/P) # alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)]) alpha_series = arctan_series_Z(R_series) # see the series print(alpha_series) ``` See notes/bessel_asympt.ipynb for generation **/ #[inline] pub(crate) fn bessel_1_asympt_alpha_fast(recip: DoubleDouble) -> DoubleDouble { const C: [u64; 12] = [ 0xbfd8000000000000, 0x3fc5000000000000, 0xbfd7bccccccccccd, 0x4002f486db6db6db, 0xc03e9fbf40000000, 0x4084997b55945d17, 0xc0d4a914195269d9, 0x412cd1b53816aec1, 0xc18aa4095d419351, 0x41ef809305f11b9d, 0xc2572e6809ed618b, 0x42c4c5b6057839f9, ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let p = f_polyeval9( x2.hi, f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), f64::from_bits(C[10]), f64::from_bits(C[11]), ); let mut z = DoubleDouble::mul_f64_add_f64(x2, p, f64::from_bits(C[2])); z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[1])); z = DoubleDouble::mul_add_f64(x2, z, f64::from_bits(C[0])); DoubleDouble::quick_mult(z, recip) } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied. Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(1, x, 50) Q = Qn_asymptotic(1, x, 50) R_series = (-Q/P) # alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)]) alpha_series = arctan_series_Z(R_series) # see the series print(alpha_series) ``` See notes/bessel_asympt.ipynb for generation **/ #[inline] pub(crate) fn bessel_1_asympt_alpha(recip: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 12] = [ (0x0000000000000000, 0xbfd8000000000000), (0x0000000000000000, 0x3fc5000000000000), (0x3c6999999999999a, 0xbfd7bccccccccccd), (0x3cab6db6db6db6db, 0x4002f486db6db6db), (0x0000000000000000, 0xc03e9fbf40000000), (0x3d21745d1745d174, 0x4084997b55945d17), (0x3d789d89d89d89d9, 0xc0d4a914195269d9), (0xbdb999999999999a, 0x412cd1b53816aec1), (0xbdfe5a5a5a5a5a5a, 0xc18aa4095d419351), (0x3e7e0ca50d79435e, 0x41ef809305f11b9d), (0xbedff8b720000000, 0xc2572e6809ed618b), (0xbf64e5d8ae68b7a7, 0x42c4c5b6057839f9), ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(C[11]), DoubleDouble::from_bit_pair(C[10]), ); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[9])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[8])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[7])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[6])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[5])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[4])); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[3].1)); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[1].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[0].1)); let z = DoubleDouble::quick_mult(p, recip); DoubleDouble::from_exact_add(z.hi, z.lo) } // /// See [bessel_1_asympt_alpha] for the info pub(crate) fn bessel_1_asympt_alpha_hard(reciprocal: DyadicFloat128) -> DyadicFloat128 { static C: [DyadicFloat128; 18] = [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xc0000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa8000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xbde66666_66666666_66666666_66666666_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0x97a436db_6db6db6d_b6db6db6_db6db6db_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -123, mantissa: 0xf4fdfa00_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0xa4cbdaac_a2e8ba2e_8ba2e8ba_2e8ba2e9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -113, mantissa: 0xa548a0ca_934ec4ec_4ec4ec4e_c4ec4ec5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -108, mantissa: 0xe68da9c0_b5760666_66666666_66666666_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -102, mantissa: 0xd5204aea_0c9a8879_69696969_69696969_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -96, mantissa: 0xfc04982f_88dce9e0_ca50d794_35e50d79_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0xb973404f_6b0c58ff_c5b90000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -82, mantissa: 0xa62db02b_c1cfc563_44ea32e9_0b21642d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -75, mantissa: 0xb220e7ff_443c1584_7e85f4e0_55eb851f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -68, mantissa: 0xe10a255c_ca5e68cc_00c2d6c0_acdc8000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -60, mantissa: 0xa573790c_5186f23b_5db502ea_d9fa5432_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -52, mantissa: 0x8c0ffedc_407a7015_453df84e_9c3f1d39_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -44, mantissa: 0x874226ed_c298a17a_d8c49a4e_dc9281a5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -36, mantissa: 0x93cab36c_9ab9495c_310fa9cd_4b065359_u128, }, ]; let x2 = reciprocal * reciprocal; let mut p = C[17]; for i in (0..17).rev() { p = x2 * p + C[i]; } p * reciprocal } pxfm-0.1.23/src/bessel/beta0.rs000064400000000000000000000203441046102023000142710ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval9; /** Beta series Generated by SageMath: ```python #generate b series def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(0, x, 50) Q = Qn_asymptotic(0, x, 50) def sqrt_series(s): val = S.valuation() lc = S[val] # Leading coefficient b = lc.sqrt() * x**(val // 2) for _ in range(5): b = (b + S / b) / 2 b = b return b S = (P**2 + Q**2).truncate(50) b_series = sqrt_series(S).truncate(30) #see the series print(b_series) ``` **/ #[inline] pub(crate) fn bessel_0_asympt_beta(recip: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0x0000000000000000, 0xbfb0000000000000), (0x0000000000000000, 0x3fba800000000000), (0x0000000000000000, 0xbfe15f0000000000), (0x0000000000000000, 0x4017651180000000), (0x0000000000000000, 0xc05ab8c13b800000), (0x0000000000000000, 0x40a730492f262000), (0x0000000000000000, 0xc0fc73a7acd696f0), (0xbdf3a00000000000, 0x41577458dd9fce68), (0xbe4ba6b000000000, 0xc1b903ab9b27e18f), ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(C[9]), DoubleDouble::from_bit_pair(C[8]), ); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[7].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[6].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[5].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[4].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[3].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[2].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[1].1)); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[0].1)); p } /** Beta series Generated by SageMath: ```python #generate b series def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(0, x, 50) Q = Qn_asymptotic(0, x, 50) def sqrt_series(s): val = S.valuation() lc = S[val] # Leading coefficient b = lc.sqrt() * x**(val // 2) for _ in range(5): b = (b + S / b) / 2 b = b return b S = (P**2 + Q**2).truncate(50) b_series = sqrt_series(S).truncate(30) #see the series print(b_series) ``` **/ #[inline] pub(crate) fn bessel_0_asympt_beta_fast(recip: DoubleDouble) -> DoubleDouble { const C: [u64; 10] = [ 0x3ff0000000000000, 0xbfb0000000000000, 0x3fba800000000000, 0xbfe15f0000000000, 0x4017651180000000, 0xc05ab8c13b800000, 0x40a730492f262000, 0xc0fc73a7acd696f0, 0x41577458dd9fce68, 0xc1b903ab9b27e18f, ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let p = f_polyeval9( x2.hi, f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), ); DoubleDouble::mul_f64_add_f64(x2, p, f64::from_bits(C[0])) } /// see [bessel_0_asympt_beta] for more info pub(crate) fn bessel_0_asympt_beta_hard(recip: DyadicFloat128) -> DyadicFloat128 { static C: [DyadicFloat128; 12] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xd4000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8af80000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -125, mantissa: 0xbb288c00_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -121, mantissa: 0xd5c609dc_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -116, mantissa: 0xb9824979_31000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -111, mantissa: 0xe39d3d66_b4b78000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -105, mantissa: 0xbba2c6ec_fe733d8c_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -99, mantissa: 0xc81d5cd9_3f0c79ba_6b000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -92, mantissa: 0x86118ddf_c1ffc100_0ee1b000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -86, mantissa: 0xdc7ccfa9_930b874d_52df3464_00000000_u128, }, ]; let x2 = recip * recip; let mut p = C[11]; for i in (0..11).rev() { p = x2 * p + C[i]; } p } pxfm-0.1.23/src/bessel/beta1.rs000064400000000000000000000211761046102023000142760ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval9; /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(1, x, 50) Q = Qn_asymptotic(1, x, 50) def sqrt_series(s): val = S.valuation() lc = S[val] # Leading coefficient b = lc.sqrt() * x**(val // 2) for _ in range(5): b = (b + S / b) / 2 b = b return b S = (P**2 + Q**2).truncate(50) b_series = sqrt_series(S).truncate(30) # see the beta series print(b_series) ``` See notes/bessel_asympt.ipynb for generation **/ #[inline] pub(crate) fn bessel_1_asympt_beta_fast(recip: DoubleDouble) -> DoubleDouble { const C: [u64; 10] = [ 0x3ff0000000000000, 0x3fc8000000000000, 0xbfc8c00000000000, 0x3fe9c50000000000, 0xc01ef5b680000000, 0x40609860dd400000, 0xc0abae9b7a06e000, 0x41008711d41c1428, 0xc15ab70164c8be6e, 0x41bc1055e24f297f, ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let p = f_polyeval9( x2.hi, f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), ); DoubleDouble::mul_f64_add_f64(x2, p, f64::from_bits(C[0])) } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(1, x, 50) Q = Qn_asymptotic(1, x, 50) def sqrt_series(s): val = S.valuation() lc = S[val] # Leading coefficient b = lc.sqrt() * x**(val // 2) for _ in range(5): b = (b + S / b) / 2 b = b return b S = (P**2 + Q**2).truncate(50) b_series = sqrt_series(S).truncate(30) # see the beta series print(b_series) ``` See notes/bessel_asympt.ipynb for generation **/ #[inline] pub(crate) fn bessel_1_asympt_beta(recip: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), // 1 (0x0000000000000000, 0x3fc8000000000000), // 2 (0x0000000000000000, 0xbfc8c00000000000), // 3 (0x0000000000000000, 0x3fe9c50000000000), // 4 (0x0000000000000000, 0xc01ef5b680000000), // 5 (0x0000000000000000, 0x40609860dd400000), // 6 (0x0000000000000000, 0xc0abae9b7a06e000), // 7 (0x0000000000000000, 0x41008711d41c1428), // 8 (0xbdf7a00000000000, 0xc15ab70164c8be6e), (0xbe40e1f000000000, 0x41bc1055e24f297f), ]; // Doing (1/x)*(1/x) instead (1/(x*x)) to avoid spurious overflow/underflow let x2 = DoubleDouble::quick_mult(recip, recip); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(C[9]), DoubleDouble::from_bit_pair(C[8]), ); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[7].1)); // 8 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[6].1)); // 7 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[5].1)); // 6 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[4].1)); // 5 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[3].1)); // 4 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[2].1)); // 3 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[1].1)); // 2 p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(C[0].1)); // 1 p } /// see [bessel_1_asympt_beta] for more info pub(crate) fn bessel_1_asympt_beta_hard(recip: DyadicFloat128) -> DyadicFloat128 { static C: [DyadicFloat128; 12] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc0000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xc6000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xce280000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -125, mantissa: 0xf7adb400_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -120, mantissa: 0x84c306ea_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -116, mantissa: 0xdd74dbd0_37000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -110, mantissa: 0x84388ea0_e0a14000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -105, mantissa: 0xd5b80b26_45f372f4_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -99, mantissa: 0xe082af12_794bf6f1_e1000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -92, mantissa: 0x94a06149_f30146bc_fe8ed000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -86, mantissa: 0xf212edfc_42a62526_4fac2b0c_00000000_u128, }, ]; let x2 = recip * recip; let mut p = C[11]; for i in (0..11).rev() { p = x2 * p + C[i]; } p } pxfm-0.1.23/src/bessel/i0.rs000064400000000000000000001213651046102023000136130ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1, rational128_exp}; use crate::polyeval::{f_estrin_polyeval5, f_polyeval4}; /// Modified Bessel of the first kind of order 0 /// /// Max ULP 0.5 pub fn f_i0(x: f64) -> f64 { let xb = x.to_bits() & 0x7fff_ffff_ffff_ffff; if !x.is_normal() { if x == 0. { return 1.; } if x.is_infinite() { return f64::INFINITY; } if x.is_nan() { return f64::NAN; } } if xb > 0x40864fe5304e83e4u64 { // 713.9869085439682 return f64::INFINITY; } if xb <= 0x400ccccccccccccdu64 { // x <= 3.6 if xb <= 0x3cb0000000000000u64 { // x <= f64::EPSILON // Power series of I0(x) ~ 1 + x^2/4 + O(x^4) const R: f64 = 1. / 4.; let r = f_fmla(x, x * R, 1.); return r; } return i0_0_to_3p6_exec(f64::from_bits(xb)); } else if xb <= 0x401e000000000000u64 { // x <= 7.5 return i3p6_to_7p5(f64::from_bits(xb)); } else if xb <= 0x4023000000000000u64 { // 9.5 return i0_7p5_to_9p5(f64::from_bits(xb)); } i0_asympt(f64::from_bits(xb)) } /** Computes I0 on interval [-7.5; -3.6], [3.6; 7.5] **/ #[inline] fn i3p6_to_7p5(x: f64) -> f64 { let r = i0_3p6_to_7p5_dd(x); let err = f_fmla( r.hi, f64::from_bits(0x3c56a09e667f3bcd), // 2^-57.5 f64::from_bits(0x3c00000000000000), // 2^-63 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub != lb { return eval_small_hard_3p6_to_7p5(x); } r.to_f64() } /** Computes I0 on interval [-7.5; -3.6], [3.6; 7.5] as rational approximation I0 = 1 + (x/2)^2 * Pn((x/2)^2)/Qm((x/2)^2)) Relative error on interval 2^-(105.71). Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i0_0_to_3p6_dd(x: f64) -> DoubleDouble { const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(x, x), ONE_OVER_4); const P: [(u64, u64); 8] = [ (0xba93dec1e5396e30, 0x3ff0000000000000), (0xbc5d3d919a2b891a, 0x3fcb128f49a1f59f), (0xbc3c4d80de165459, 0x3f9353508fce278f), (0x3be7e0e75c00d411, 0x3f4b760657892e15), (0xbb9bc959d02076a4, 0x3ef588ff0ba5872e), (0x3b257756675180e4, 0x3e932e320d411521), (0xbaca098436a47ec6, 0x3e2285f524a51de0), (0x3a0e48fa0331db75, 0x3d9ee6518d82a209), ]; let ps_num = f_estrin_polyeval5( eval_x.hi, f64::from_bits(0x3f4b760657892e15), f64::from_bits(0x3ef588ff0ba5872e), f64::from_bits(0x3e932e320d411521), f64::from_bits(0x3e2285f524a51de0), f64::from_bits(0x3d9ee6518d82a209), ); let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 7] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c26136ec7050a58, 0xbfa3b5c2d9782985), (0x3bdf9cd5be66297b, 0x3f478d5c030ea692), (0xbb5036196d4b865c, 0xbee1a83b6e8c6fd6), (0xbb1a9dafadc75858, 0x3e71ba443893032b), (0xba7a719ba9ed7e7f, 0xbdf6e673af3e0c66), (0xb9e17740b37a23ec, 0x3d6e2c993fef696f), ]; let ps_den = f_polyeval4( eval_x.hi, f64::from_bits(0xbee1a83b6e8c6fd6), f64::from_bits(0x3e71ba443893032b), f64::from_bits(0xbdf6e673af3e0c66), f64::from_bits(0x3d6e2c993fef696f), ); let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000)); DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.) } // Generated by Wolfram Mathematica: // I0(x) = 1+(x/2)^2 * R((x/2)^2) // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[inline] fn i0_3p6_to_7p5_dd(x: f64) -> DoubleDouble { const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(x, x), ONE_OVER_4); const P: [(u64, u64); 10] = [ (0xbae8195e94c833a1, 0x3ff0000000000000), (0xbc6f4db3a04cf778, 0x3fcbca374cf8efde), (0x3c31e334a32ed081, 0x3f9493391f88f49c), (0x3bb77456438b622e, 0x3f4f2aff2cd821b7), (0x3b312b847b83fa80, 0x3efb249e459c00fa), (0x3b1d3faf77d3ee5b, 0x3e9cd199c39f6d6c), (0xbaaf6a6a3d483df8, 0x3e331192e34cb81f), (0x3a406e234cb7aede, 0x3dbef6023ba17d1a), (0x39dee1ec666e30b5, 0x3d3c8bab78d825e9), (0x3910b9821c993936, 0x3ca73bf438398234), ]; let ps_num = f_estrin_polyeval5( eval_x.hi, f64::from_bits(0x3e9cd199c39f6d6c), f64::from_bits(0x3e331192e34cb81f), f64::from_bits(0x3dbef6023ba17d1a), f64::from_bits(0x3d3c8bab78d825e9), f64::from_bits(0x3ca73bf438398234), ); let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c16498103ae0f29, 0xbfa0d722cc1c408a), (0x3ba9b44df49b7368, 0x3f41a06d24a9b89a), (0x3b43ef4989b8a3ed, 0xbed8363c48ecd98c), (0xbaf6197838a8a2ef, 0x3e6830647038f0ac), (0x3a96c443c7d52296, 0xbdf257666a799e31), (0x3a118e8a97f0df20, 0x3d753ffeb530f0c8), (0xb99e90b659ab1bb7, 0xbcf243374f2b7d6c), (0x38f647cfef513fc5, 0x3c654740fd120da3), (0x386d691099d0e8fc, 0xbbc9c9c826756a76), ]; let ps_den = f_estrin_polyeval5( eval_x.hi, f64::from_bits(0xbdf257666a799e31), f64::from_bits(0x3d753ffeb530f0c8), f64::from_bits(0xbcf243374f2b7d6c), f64::from_bits(0x3c654740fd120da3), f64::from_bits(0xbbc9c9c826756a76), ); let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000)); DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.) } // Generated by Wolfram Mathematica: // I0(x) = 1+(x/2)^2 * R((x/2)^2) // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[cold] #[inline(never)] fn eval_small_hard_3p6_to_7p5(x: f64) -> f64 { const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(x, x), ONE_OVER_4); const P: [(u64, u64); 10] = [ (0xbae8195e94c833a1, 0x3ff0000000000000), (0xbc6f4db3a04cf778, 0x3fcbca374cf8efde), (0x3c31e334a32ed081, 0x3f9493391f88f49c), (0x3bb77456438b622e, 0x3f4f2aff2cd821b7), (0x3b312b847b83fa80, 0x3efb249e459c00fa), (0x3b1d3faf77d3ee5b, 0x3e9cd199c39f6d6c), (0xbaaf6a6a3d483df8, 0x3e331192e34cb81f), (0x3a406e234cb7aede, 0x3dbef6023ba17d1a), (0x39dee1ec666e30b5, 0x3d3c8bab78d825e9), (0x3910b9821c993936, 0x3ca73bf438398234), ]; let mut p_num = DoubleDouble::mul_add( eval_x, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[7])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c16498103ae0f29, 0xbfa0d722cc1c408a), (0x3ba9b44df49b7368, 0x3f41a06d24a9b89a), (0x3b43ef4989b8a3ed, 0xbed8363c48ecd98c), (0xbaf6197838a8a2ef, 0x3e6830647038f0ac), (0x3a96c443c7d52296, 0xbdf257666a799e31), (0x3a118e8a97f0df20, 0x3d753ffeb530f0c8), (0xb99e90b659ab1bb7, 0xbcf243374f2b7d6c), (0x38f647cfef513fc5, 0x3c654740fd120da3), (0x386d691099d0e8fc, 0xbbc9c9c826756a76), ]; let mut p_den = DoubleDouble::mul_add( eval_x, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[7])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[6])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000)); let q = DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.); q.to_f64() } #[inline] pub(crate) fn i0_0_to_3p6_exec(x: f64) -> f64 { let r = i0_0_to_3p6_dd(x); let err = f_fmla( r.hi, f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3be0000000000000), // 2^-66 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } i0_0_to_3p6_hard(x) } // Generated by Wolfram Mathematica: // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[cold] #[inline(never)] fn i0_0_to_3p6_hard(x: f64) -> f64 { const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(x, x), ONE_OVER_4); const P: [(u64, u64); 8] = [ (0xba93dec1e5396e30, 0x3ff0000000000000), (0xbc5d3d919a2b891a, 0x3fcb128f49a1f59f), (0xbc3c4d80de165459, 0x3f9353508fce278f), (0x3be7e0e75c00d411, 0x3f4b760657892e15), (0xbb9bc959d02076a4, 0x3ef588ff0ba5872e), (0x3b257756675180e4, 0x3e932e320d411521), (0xbaca098436a47ec6, 0x3e2285f524a51de0), (0x3a0e48fa0331db75, 0x3d9ee6518d82a209), ]; let mut p_num = DoubleDouble::mul_add( eval_x, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 7] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c26136ec7050a58, 0xbfa3b5c2d9782985), (0x3bdf9cd5be66297b, 0x3f478d5c030ea692), (0xbb5036196d4b865c, 0xbee1a83b6e8c6fd6), (0xbb1a9dafadc75858, 0x3e71ba443893032b), (0xba7a719ba9ed7e7f, 0xbdf6e673af3e0c66), (0xb9e17740b37a23ec, 0x3d6e2c993fef696f), ]; let mut p_den = DoubleDouble::mul_add( eval_x, DoubleDouble::from_bit_pair(Q[6]), DoubleDouble::from_bit_pair(Q[5]), ); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[0])); let q = DoubleDouble::mul_add_f64(DoubleDouble::div(p_num, p_den), eval_x, 1.); q.to_f64() } /** Mid-interval [7.5;9.5] generated by Wolfram: I0(x)=R(1/x)/sqrt(x)*Exp(x) ```text <120] num=Numerator[approx][[1]]; den=Denominator[approx][[1]]; poly=den; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i0_7p5_to_9p5(x: f64) -> f64 { let dx = x; let recip = DoubleDouble::from_quick_recip(x); const P: [(u64, u64); 12] = [ (0x3c778e3de1f76f48, 0x3fd988450531281b), (0xbcb572f6149f389e, 0xc01a786676fb4d3a), (0x3cf2f373365347ed, 0x405c0e8405fdb642), (0x3d276a94c8f1e627, 0xc0885e4718dfb761), (0x3d569f8a993434e2, 0x40b756d52d5fa90c), (0xbd6f953f7dd1a223, 0xc0c8818365c47790), (0xbd74247967fbf7b2, 0x40e8cf89daf87353), (0x3db449add7abb056, 0x41145d3c2d96d159), (0xbdc5cc822b71f891, 0xc123694c58fd039b), (0x3da2047ac1a6fba8, 0x415462e630bf3e7e), (0xbdc2f2c06eda6a95, 0xc14c6984ebdd6792), (0xbdf51fa85dafeca5, 0x4166a437c202d27b), ]; let x2 = DoubleDouble::quick_mult(recip, recip); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3cde08e4cbf324d1, 0xc030b67bd69af0ca), (0x3cec5e4ee7e77024, 0x4071b54c0f58409c), (0xbd340e1131739e2f, 0xc09f140a738b14b3), (0x3d607673189d6644, 0x40cdb44bd822add2), (0xbd7793a4f1dd74d1, 0xc0e03fe2689b802d), (0xbd8415501228a87e, 0x410009beafea72cc), (0x3dcecdac2702661f, 0x4128c2073da9a447), (0xbdd8386404f3dec5, 0xc1389ec7d7186bf4), (0xbe06eb53a3e86436, 0x4168b7a2dc85ed0b), (0x3e098e2cefaf8299, 0xc1604f8cf34af02c), (0x3e1a5e496b547001, 0x41776b1e0153d1e9), ]; let e0 = DoubleDouble::mul_add_f64( recip, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let z = DoubleDouble::div(p_num, p_den); let e = i0_exp(dx); let r_sqrt = DoubleDouble::from_rsqrt_fast(dx); let r = DoubleDouble::quick_mult(z * r_sqrt, e); let err = f_fmla( r.hi, f64::from_bits(0x3bc0000000000000), f64::from_bits(0x392bdb8cdadbe111), ); let up = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if up != lb { return i0_7p5_to_9p5_hard(x); } r.to_f64() } /** Mid-interval [7.5;9.5] generated by Wolfram Mathematica: I0(x)=R(1/x)/sqrt(x)*Exp(x) Polynomial generated by Wolfram Mathematica: ```text <120] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[cold] #[inline(never)] fn i0_7p5_to_9p5_hard(x: f64) -> f64 { static P: [DyadicFloat128; 14] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcc422a04_45cde144_75a3800b_45c38460_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -124, mantissa: 0xada66144_fcccc1a3_036f76b2_cabd6281_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -120, mantissa: 0xeabdda02_fa201d98_10e58d1f_7eb62bd7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -116, mantissa: 0xbbfd3297_6f88a7df_5924587b_d5bdcdb8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -113, mantissa: 0xfca29453_efe393bf_1651627b_7d543875_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -110, mantissa: 0xee7c7220_bbbd248e_bb6adac6_f9a5ce95_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -107, mantissa: 0xc07455dd_830ba705_414408c6_06732a5a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -105, mantissa: 0xe2247793_b50cd0f0_80e8981d_933f75da_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -103, mantissa: 0xe14a9831_82582a0b_dd27e8b6_4ed9aac2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -101, mantissa: 0xa3b2ae2f_5b64f37e_c1538435_34f02faf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -100, mantissa: 0xbab73503_5b7e38d9_bbe4a84b_9007c6e8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -99, mantissa: 0xa68911fc_5d87bbe7_0d4fe854_5c681ac5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -99, mantissa: 0x9e997222_55ef4045_fa9f311d_57d082a2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -99, mantissa: 0xbe93656a_b0a4f32d_3ebbfdeb_b1cbb839_u128, }, ]; static Q: [DyadicFloat128; 14] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -123, mantissa: 0xdaa34a7e_861dddff_a0642080_cd83dd65_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0x93f05740_f4758772_bb9992f9_91e72795_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -115, mantissa: 0xeddcb810_054c9aab_fa7e4214_d59d18b0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0xa0180fcd_831ff6c0_ac2b8f02_37f3cfd1_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -108, mantissa: 0x97d25106_3b66907e_90b4f786_26daa0bb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -106, mantissa: 0xf595ce38_aac16c11_001b874a_99603b45_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -103, mantissa: 0x912b3715_4aca68f6_5821c2ed_43d77111_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -101, mantissa: 0x90f97141_b896e2b6_38b87354_8945a43c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -100, mantissa: 0xd3e5f967_89097d6b_3a3060fe_852ff580_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -99, mantissa: 0xf0d6de35_939da009_9ced21fd_48af7281_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -98, mantissa: 0xd2a0b183_6ac613b2_6745ce1d_8ed1c323_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -98, mantissa: 0xbb9c089a_b7e939a2_732b3fb5_2e66cd77_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -98, mantissa: 0xcb2107c3_736bef81_609718c0_ba82cd8e_u128, }, ]; let recip = DyadicFloat128::accurate_reciprocal(x); let mut p_num = P[13]; for i in (0..13).rev() { p_num = recip * p_num + P[i]; } let mut p_den = Q[13]; for i in (0..13).rev() { p_den = recip * p_den + Q[i]; } let z = p_num * p_den.reciprocal(); let r_sqrt = bessel_rsqrt_hard(x, recip); let f_exp = rational128_exp(x); (z * r_sqrt * f_exp).fast_as_f64() } #[inline(always)] fn exp_poly(z: f64) -> DoubleDouble { /* The following is a degree-4 polynomial generated by Sollya for exp(x) over [-2^-12.905,2^-12.905] with absolute error < 2^-74.34 (see sollya/Q_1.sollya). */ const Q_1: [u64; 5] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555997996, 0x3fa5555555849d8d, ]; let mut q = dd_fmla(f64::from_bits(Q_1[4]), z, f64::from_bits(Q_1[3])); q = dd_fmla(q, z, f64::from_bits(Q_1[2])); let h0 = dd_fmla(q, z, f64::from_bits(Q_1[1])); let v1 = DoubleDouble::from_exact_mult(z, h0); DoubleDouble::f64_add(f64::from_bits(Q_1[0]), v1) } #[inline] pub(crate) fn i0_exp(r: f64) -> DoubleDouble { const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); let k = (r * INVLOG2).round(); const L2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3d0718432a1b0e26), f64::from_bits(0x3f262e42ff000000), ); let zh = f_fmla(L2.lo, k, f_fmla(-L2.hi, k, r)); let bk = k as i64; let mk = (bk >> 12) + 0x3ff; let i2 = (bk >> 6) & 0x3f; let i1 = bk & 0x3f; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i2 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let mut de = DoubleDouble::quick_mult(t1, t0); let q = exp_poly(zh); de = DoubleDouble::quick_mult(de, q); let mut du = (mk as u64).wrapping_shl(52); du = f64::from_bits(du).to_bits(); DoubleDouble::quick_mult_f64(de, f64::from_bits(du)) } /** I0(x)=R(1/x)*Exp(x)/sqrt(x) Generated in Wolfram: ```text <120] poly=Numerator[approx]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]] ``` **/ #[inline] fn i0_asympt(x: f64) -> f64 { let dx = x; let recip = DoubleDouble::from_quick_recip(x); const P: [(u64, u64); 12] = [ (0xbc7ca19c5d824c54, 0x3fd9884533d43651), (0x3cca32eb734e010e, 0xc03b7ca35caf42eb), (0x3d03af8238d6f25e, 0x408b92cfcaa7070f), (0xbd7a8ff7fdebed70, 0xc0d0a3be432cce93), (0xbdababdb579bb076, 0x410a77dc51f1804d), (0x3dc5e4e3c972832a, 0xc13cb0be2f74839c), (0x3e01076f9b102e38, 0x41653b064cc61661), (0xbe2157e700d445f4, 0xc184e1b076927460), (0xbdfa4577156dde56, 0x41999e9653f9dc5f), (0xbe47aa238a739ffe, 0xc1a130f6ded40c00), (0xbe331b560b6fbf4a, 0x419317f11e674cae), (0xbe0765596077d1e3, 0xc16024404db59d3f), ]; let x2 = DoubleDouble::quick_mult(recip, recip); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcf687703e843d07, 0xc051418f1c4dd0b9), (0x3d468ab92cb87a0b, 0x40a15891d823e48d), (0x3d8bfc17e5183376, 0xc0e4fce40dd82796), (0xbdccbbcc2ecf8d4c, 0x4120beef869c61ec), (0xbdf42170b4d5d150, 0xc1523ad18834a7ed), (0xbe0eaa32f405afd4, 0x417b24ec57a8f480), (0x3e3ec900705e7252, 0xc19af2a91d23d62e), (0x3e3e220e274fa46b, 0x41b0cb905cc99ff5), (0xbe46c6c61dee11f6, 0xc1b7452e50518520), (0x3e3ed0fc063187bf, 0x41ac1772d1749896), (0xbe11c578f04f4be1, 0xc180feb5b2ca47cb), ]; let e0 = DoubleDouble::mul_add_f64( recip, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let z = DoubleDouble::div(p_num, p_den); let mut e = i0_exp(dx * 0.5); e = DoubleDouble::from_exact_add(e.hi, e.lo); let r_sqrt = DoubleDouble::from_rsqrt_fast(dx); let r = DoubleDouble::quick_mult(z * r_sqrt * e, e); let err = f_fmla( r.hi, f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3be0000000000000), // 2^-65 ); let up = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if up != lb { return i0_asympt_hard(x); } lb } #[inline] pub(crate) fn bessel_rsqrt_hard(x: f64, recip: DyadicFloat128) -> DyadicFloat128 { let r = DyadicFloat128::new_from_f64(x.sqrt()) * recip; let fx = DyadicFloat128::new_from_f64(x); let rx = r * fx; let drx = r * fx - rx; const M_ONE: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let h = r * rx + M_ONE + r * drx; let mut ddr = r; ddr.exponent -= 1; // ddr * 0.5 let dr = ddr * h; r - dr } /** I0(x)=R(1/x)*Exp(x)/sqrt(x) Generated in Wolfram: ```text <120] poly=Numerator[approx]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[cold] #[inline(never)] fn i0_asympt_hard(x: f64) -> f64 { static P: [DyadicFloat128; 16] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcc42299e_a1b28468_7e5aad4a_70b749c4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -122, mantissa: 0xabb4209d_ca11bdaa_186bef7f_390e6b77_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -116, mantissa: 0x8a2725e2_4749db25_625ad1f2_12a2a16c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -111, mantissa: 0x8b4c2cd4_9e5d0c8b_c9be4d3e_781bb676_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -107, mantissa: 0xc33fad7c_40599f7d_713e3081_6b5ad791_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -103, mantissa: 0xc81da271_b623ba88_0be032b5_827d92fa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -99, mantissa: 0x99ec4975_b6aa7cae_7692a287_ed8ae47c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -96, mantissa: 0xb3aa4745_fc2dd441_2dbd3e3c_d4539687_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -93, mantissa: 0x9f14edc2_6882afca_29d2a067_dc459729_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -91, mantissa: 0xd35c4d01_78d8cec6_fc8ae0ee_834da837_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -89, mantissa: 0xcdc529c7_6e082342_faad3073_07a9b61f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -87, mantissa: 0x8ccac88f_2598c8a6_423b1f42_63591cb9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -87, mantissa: 0xfc044cfb_a20f0885_93d58660_17819ed5_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -86, mantissa: 0x813a700c_74d23f52_f81b179d_7ff0da9f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -88, mantissa: 0xe6c43da4_297216bf_bdd987cb_636906cf_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -91, mantissa: 0xa4998323_649c3cf2_64477869_3d2c6afd_u128, }, ]; static Q: [DyadicFloat128; 16] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -121, mantissa: 0xd772d5fd_a7077638_6e007274_d83b013c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xad914ef0_451ced2e_515657ef_fc7eeb53_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -110, mantissa: 0xaf41180c_dffe96e5_f192fa40_0b1bff1e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -106, mantissa: 0xf60dc728_241f71fd_5b93e653_ccbedace_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -102, mantissa: 0xfcaefef9_39cf96e7_3cb75a98_da5e9761_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -98, mantissa: 0xc2d2c837_5789587a_13ef38c6_a24c3413_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -95, mantissa: 0xe41725c3_51d14486_a650044e_e8588f7b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -92, mantissa: 0xcabeed9b_5e2e888d_81d32b11_d289a624_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0x8764876d_11ad6607_8a8d5382_3ffe82d9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -87, mantissa: 0x84c9f9e5_6a5f5034_ad2c8512_16cb1ba1_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -86, mantissa: 0xb7c1d143_a15d8aab_03a7fa3e_b7d07a36_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -85, mantissa: 0xa78f8257_4658040f_7a1ad39c_91ea9483_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -85, mantissa: 0xb231e0ca_b729a404_44c38f52_be208507_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -86, mantissa: 0xae317981_42349081_8bc68b28_f69b8e49_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0xb451abd3_5cd79c6d_7e578164_32f16da1_u128, }, ]; let recip = DyadicFloat128::accurate_reciprocal(x); let mut p_num = P[15]; for i in (0..15).rev() { p_num = recip * p_num + P[i]; } let mut p_den = Q[15]; for i in (0..15).rev() { p_den = recip * p_den + Q[i]; } let z = p_num * p_den.reciprocal(); let r_sqrt = bessel_rsqrt_hard(x, recip); let f_exp = rational128_exp(x); (z * r_sqrt * f_exp).fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_i0() { assert_eq!(f_i0(9.500000000005492,), 1753.4809905364318); assert!(f_i0(f64::NAN).is_nan()); assert_eq!(f_i0(f64::INFINITY), f64::INFINITY); assert_eq!(f_i0(f64::NEG_INFINITY), f64::INFINITY); assert_eq!(f_i0(7.500000000788034), 268.1613117118702); assert_eq!(f_i0(715.), f64::INFINITY); assert_eq!(f_i0(12.), 18948.925349296307); assert_eq!(f_i0(16.), 893446.227920105); assert_eq!(f_i0(18.432), 9463892.87209841); assert_eq!(f_i0(26.432), 23507752424.350075); assert_eq!(f_i0(0.2), 1.010025027795146); assert_eq!(f_i0(7.5), 268.16131151518937); assert_eq!(f_i0(-1.5), 1.646723189772891); } } pxfm-0.1.23/src/bessel/i0f.rs000064400000000000000000000246551046102023000137650ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j0f::j1f_rsqrt; use crate::common::f_fmla; use crate::exponents::core_expf; use crate::polyeval::{ f_estrin_polyeval5, f_estrin_polyeval7, f_estrin_polyeval8, f_estrin_polyeval9, f_polyeval6, }; /// Modified Bessel of the first kind of order 0 /// /// Max ULP 0.5 pub fn f_i0f(x: f32) -> f32 { if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return 1.; } if x.is_infinite() { return f32::INFINITY; } if x.is_nan() { return f32::NAN; } } let xb = x.to_bits() & 0x7fff_ffff; if xb >= 0x42b7cd32 { return f32::INFINITY; } if xb < 0x3f800000u32 { // 1 return i0f_small(f32::from_bits(xb)) as f32; } else if xb <= 0x40600000u32 { // 3.5 return i0f_1_to_3p5(f32::from_bits(xb)); } else if xb <= 0x40c00000u32 { // 6 return i0f_3p5_to_6(f32::from_bits(xb)); } else if xb < 0x40f00000u32 { // 7.5 return i0f_6_to_7p5(f32::from_bits(xb)); } i0f_asympt(f32::from_bits(xb)) } /** How polynomial is obtained described at [i0f_1_to_7p5]. Computes I0(x) as follows: I0(x) = 1 + (x/2)^2 * P(x) This method valid only [0;1] Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] pub(crate) fn i0f_small(x: f32) -> f64 { let dx = x as f64; const C: f64 = 1. / 4.; let eval_x = dx * dx * C; let p = f_estrin_polyeval7( eval_x, f64::from_bits(0x3ff000000000013a), f64::from_bits(0x3fcffffffffc20b6), f64::from_bits(0x3f9c71c71e6cd6a2), f64::from_bits(0x3f5c71c65b0af15f), f64::from_bits(0x3f1234796fceb081), f64::from_bits(0x3ec0280faf31678c), f64::from_bits(0x3e664fd494223545), ); f_fmla(p, eval_x, 1.) } /** Computes I0. /// Valid only on interval [1;3.5] as rational approximation I0 = 1 + (x/2)^2 * Pn((x/2)^2)/Qm((x/2)^2)) Generated by Wolram Mathematica: ```python <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i0f_1_to_3p5(x: f32) -> f32 { let dx = x as f64; const C: f64 = 1. / 4.; let eval_x = dx * dx * C; let p_num = f_polyeval6( eval_x, f64::from_bits(0x3feffffffffffb69), f64::from_bits(0x3fc9ed7bd9dc97a7), f64::from_bits(0x3f915c14693c842e), f64::from_bits(0x3f45c6dc6a719e42), f64::from_bits(0x3eeacb79eba725f7), f64::from_bits(0x3e7b51e2acfc4355), ); let p_den = f_estrin_polyeval5( eval_x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfa84a10988f28eb), f64::from_bits(0x3f50f5599197a4be), f64::from_bits(0xbeea420cf9b13b1b), f64::from_bits(0x3e735d0c1eb6ed7d), ); f_fmla(p_num / p_den, eval_x, 1.) as f32 } // Valid only on interval [6;7] // Generated by Wolfram Mathematica: // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[inline] fn i0f_6_to_7p5(x: f32) -> f32 { let dx = x as f64; const C: f64 = 1. / 4.; let eval_x = dx * dx * C; let p_num = f_estrin_polyeval8( eval_x, f64::from_bits(0x3fefffffffffff7d), f64::from_bits(0x3fcb373b00569ccf), f64::from_bits(0x3f939069c3363b81), f64::from_bits(0x3f4c2095c90c66b3), f64::from_bits(0x3ef6713f648413db), f64::from_bits(0x3e947efa2f9936b4), f64::from_bits(0x3e2486a182f49420), f64::from_bits(0x3da213034a33de33), ); let p_den = f_estrin_polyeval7( eval_x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfa32313fea59d9e), f64::from_bits(0x3f460594c2ec6706), f64::from_bits(0xbedf725fb714690f), f64::from_bits(0x3e6d9cb39b19555c), f64::from_bits(0xbdf1900e3abcb7a6), f64::from_bits(0x3d64a21a2ea78ef6), ); f_fmla(p_num / p_den, eval_x, 1.) as f32 } // Valid only on interval [3.5;6] // Generated in Wolfram Mathematica: // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[inline] fn i0f_3p5_to_6(x: f32) -> f32 { let dx = x as f64; const C: f64 = 1. / 4.; let eval_x = dx * dx * C; let p_num = f_polyeval6( eval_x, f64::from_bits(0x3feffffffffd9550), f64::from_bits(0x3fc97e18ee033fb4), f64::from_bits(0x3f90b3199079bce1), f64::from_bits(0x3f442c300a425372), f64::from_bits(0x3ee7831030ae18ca), f64::from_bits(0x3e76387d67354932), ); let p_den = f_polyeval6( eval_x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfaa079c484e406a), f64::from_bits(0x3f5452098f1556fb), f64::from_bits(0xbef33efb4a8128ac), f64::from_bits(0x3e865996e19448ca), f64::from_bits(0xbe09acbb64533c3e), ); f_fmla(p_num / p_den, eval_x, 1.) as f32 } /** Asymptotic expansion for I0. Computes: sqrt(x) * exp(-x) * I0(x) = Pn(1/x)/Qn(1/x) hence: I0(x) = Pn(1/x)/Qm(1/x)*exp(x)/sqrt(x) Generated by Mathematica: ```text <70] num=Numerator[approx][[1]]; den=Denominator[approx][[1]]; poly=num; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` See ./notes/bessel_sollya **/ #[inline] fn i0f_asympt(x: f32) -> f32 { let dx = x as f64; let recip = 1. / dx; let p_num = f_estrin_polyeval9( recip, f64::from_bits(0x3fd9884533d44829), f64::from_bits(0xc02c940f40595581), f64::from_bits(0x406d41c495c2f762), f64::from_bits(0xc0a10ab76dda4520), f64::from_bits(0x40c825b1c2a48d07), f64::from_bits(0xc0e481d606d0b748), f64::from_bits(0x40f34759deefbd40), f64::from_bits(0xc0ef4b7fb49fa116), f64::from_bits(0x40c409a6f882ba00), ); let p_den = f_estrin_polyeval9( recip, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xc041f8a9131ad229), f64::from_bits(0x408278e56af035bb), f64::from_bits(0xc0b5a34a108f3e35), f64::from_bits(0x40dee6f278ee24f5), f64::from_bits(0xc0fa95093b0c4f9f), f64::from_bits(0x4109982b87f75651), f64::from_bits(0xc10618cc3c91e2db), f64::from_bits(0x40e30895aec6fc4f), ); let z = p_num / p_den; let e = core_expf(x); let r_sqrt = j1f_rsqrt(dx); (z * r_sqrt * e) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_i0f() { assert!(f_i0f(f32::NAN).is_nan()); assert_eq!(f_i0f(f32::NEG_INFINITY), f32::INFINITY); assert_eq!(f_i0f(f32::INFINITY), f32::INFINITY); assert_eq!(f_i0f(1.), 1.2660658); assert_eq!(f_i0f(5.), 27.239872); assert_eq!(f_i0f(16.), 893446.25); assert_eq!(f_i0f(32.), 5590908000000.0); assert_eq!(f_i0f(92.0), f32::INFINITY); assert_eq!(f_i0f(0.), 1.0); assert_eq!(f_i0f(28.), 109534600000.0); assert_eq!(f_i0f(-28.), 109534600000.0); } } pxfm-0.1.23/src/bessel/i1.rs000064400000000000000000000547411046102023000136170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::i0::{bessel_rsqrt_hard, i0_exp}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::rational128_exp; use crate::polyeval::{f_estrin_polyeval5, f_polyeval6}; /// Modified Bessel of the first kind order 1 /// /// Max found ULP 0.5 pub fn f_i1(x: f64) -> f64 { if !x.is_normal() { if x == 0. { return 0.; } if x.is_infinite() { return if x.is_sign_positive() { f64::INFINITY } else { f64::NEG_INFINITY }; } if x.is_nan() { return f64::NAN; } } let xb = x.to_bits() & 0x7fff_ffff_ffff_ffff; if xb >= 0x40864fe69ff9fec8u64 { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } static SIGN: [f64; 2] = [1., -1.]; let sign_scale = SIGN[x.is_sign_negative() as usize]; if xb < 0x401f000000000000u64 { if xb <= 0x3cb0000000000000u64 { // x <= f64::EPSILON // Power series of I1(x) ~ x/2 + x^3/16 + O(x^4) const A0: f64 = 1. / 2.; const A1: f64 = 1. / 16.; let r0 = f_fmla(x, x * A1, A0); return r0 * x; } // 7.75 return i1_0_to_7p75(f64::from_bits(xb), sign_scale); } i1_asympt(f64::from_bits(xb), sign_scale) } /** Computes I1(x) = x/2 * (1 + 1 * (x/2)^2 + (x/2)^4 * P((x/2)^2)) Polynomial generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i1_0_to_7p75(x: f64, sign_scale: f64) -> f64 { const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(x, x), ONE_OVER_4); const P: [(u64, u64); 5] = [ (0x3c55555555555555, 0x3fb5555555555555), (0x3c1253e1df138479, 0x3f7304597c4fbd4c), (0x3bcec398b7059ee9, 0x3f287b5b01f6b9c0), (0xbb7354e7c92c4f77, 0x3ed21de117470d10), (0xbb1d35ac0d7923cc, 0x3e717f3714dddc04), ]; let ps_num = f_estrin_polyeval5( eval_x.hi, f64::from_bits(0x3e063684ca1944a4), f64::from_bits(0x3d92ac4a0e48a9bb), f64::from_bits(0x3d1425988b0b0aea), f64::from_bits(0x3c899839e74ddefc), f64::from_bits(0x3bed8747bcdd1e61), ); let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 4] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc3e59afb81ac7ea, 0xbf9c4848e0661d70), (0x3bd62fa3dbc1a19c, 0x3f38a9eafcd7e674), (0x3b6f4688b9eab7d0, 0xbecbfdec51454533), ]; let ps_den = f_polyeval6( eval_x.hi, f64::from_bits(0x3e56e7cde9266a32), f64::from_bits(0xbddc316dff4a672f), f64::from_bits(0x3d5a43aaee30ebb5), f64::from_bits(0xbcd1fb023f4f1fa0), f64::from_bits(0x3c4089ede324209f), f64::from_bits(0xbb9f64f47ba69604), ); let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(eval_x, p_den, f64::from_bits(0x3ff0000000000000)); let p = DoubleDouble::div(p_num, p_den); let eval_sqr = DoubleDouble::quick_mult(eval_x, eval_x); let mut z = DoubleDouble::mul_f64_add_f64(eval_x, 0.5, 1.); z = DoubleDouble::mul_add(p, eval_sqr, z); let x_over_05 = DoubleDouble::from_exact_mult(x, 0.5); let r = DoubleDouble::quick_mult(z, x_over_05); let err = f_fmla( r.hi, f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3be0000000000000), // 2^-65 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return f64::copysign(r.to_f64(), sign_scale); } i1_0_to_7p5_hard(x, sign_scale) } // Polynomial generated by Wolfram Mathematica: // I1(x) = x/2 * (1 + 1 * (x/2)^2 + (x/2)^4 * P((x/2)^2)) // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[cold] #[inline(never)] fn i1_0_to_7p5_hard(x: f64, sign_scale: f64) -> f64 { const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(x, x), ONE_OVER_4); const P: [(u64, u64); 10] = [ (0x3c55555555555555, 0x3fb5555555555555), (0x3c1253e1df138479, 0x3f7304597c4fbd4c), (0x3bcec398b7059ee9, 0x3f287b5b01f6b9c0), (0xbb7354e7c92c4f77, 0x3ed21de117470d10), (0xbb1d35ac0d7923cc, 0x3e717f3714dddc04), (0xba928dee24678e32, 0x3e063684ca1944a4), (0xba36aa59912fcbed, 0x3d92ac4a0e48a9bb), (0x39bad76f18b5ad37, 0x3d1425988b0b0aea), (0xb923a6bab6928df4, 0x3c899839e74ddefc), (0x3864356cdfa7b321, 0x3bed8747bcdd1e61), ]; let mut p_num = DoubleDouble::mul_add( eval_x, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[7])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc3e59afb81ac7ea, 0xbf9c4848e0661d70), (0x3bd62fa3dbc1a19c, 0x3f38a9eafcd7e674), (0x3b6f4688b9eab7d0, 0xbecbfdec51454533), (0x3af0fb4a17103ef8, 0x3e56e7cde9266a32), (0xba71755779c6d4bd, 0xbddc316dff4a672f), (0x39cf8ed8d449e2c6, 0x3d5a43aaee30ebb5), (0x39704e900a373874, 0xbcd1fb023f4f1fa0), (0xb8e33e87e4bffbb1, 0x3c4089ede324209f), (0x380fb09b3fd49d5c, 0xbb9f64f47ba69604), ]; let mut p_den = DoubleDouble::mul_add( eval_x, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[7])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[6])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[0])); let p = DoubleDouble::div(p_num, p_den); let eval_sqr = DoubleDouble::quick_mult(eval_x, eval_x); let mut z = DoubleDouble::mul_f64_add_f64(eval_x, 0.5, 1.); z = DoubleDouble::mul_add(p, eval_sqr, z); let x_over_05 = DoubleDouble::from_exact_mult(x, 0.5); let r = DoubleDouble::quick_mult(z, x_over_05); f64::copysign(r.to_f64(), sign_scale) } /** Asymptotic expansion for I1. Computes: sqrt(x) * exp(-x) * I1(x) = Pn(1/x)/Qn(1/x) hence: I1(x) = Pn(1/x)/Qm(1/x)*exp(x)/sqrt(x) Generated by Wolfram Mathematica: ```text <120] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i1_asympt(x: f64, sign_scale: f64) -> f64 { let dx = x; let recip = DoubleDouble::from_quick_recip(x); const P: [(u64, u64); 12] = [ (0xbc73a823f28a2f5e, 0x3fd9884533d43651), (0x3cc0d5bb78e674b3, 0xc0354325c8029263), (0x3d20e1155aaaa283, 0x4080c09b027c46a4), (0xbd5b90dcf81b99c1, 0xc0bfc1311090c839), (0xbd98f2fda9e8fa1b, 0x40f3bb81bb190ae2), (0xbdcec960752b60da, 0xc1207c0bbbc31cd9), (0x3dd3c9a299c9c41f, 0x414253e25c4584af), (0xbde82e7b9a3e1acc, 0xc159a656aece377c), (0x3e0d3d30d701a8ab, 0x416398df24c74ef2), (0xbdf57b85ab7006e2, 0xc151fd119be1702b), (0x3dd760928f4515fd, 0xc1508327e42639bc), (0x3dc09e71bc648589, 0x4143e4933afa621c), ]; let x2 = DoubleDouble::quick_mult(recip, recip); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcb334d5a476d9ad, 0xc04a75f94c1a0c1a), (0xbd324d58ed98bfae, 0x4094b00e60301c42), (0x3d7c8725666c4360, 0xc0d36b9d28d45928), (0x3d7f8457c2945822, 0x4107d6c398a174ed), (0x3dbc655ea216594b, 0xc1339393e6776e38), (0xbdebb5dffef78272, 0x415537198d23f6a1), (0xbdb577f8abad883e, 0xc16c6c399dcd6949), (0x3e14261c5362f109, 0x4173c02446576949), (0x3dc382ededad42c5, 0xc1547dff5770f4ec), (0xbe05c0f74d4c7956, 0xc165c88046952562), (0xbdbf9145927aa2c7, 0x414395e46bc45d5b), ]; let e0 = DoubleDouble::mul_add_f64( recip, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let z = DoubleDouble::div(p_num, p_den); let e = i0_exp(dx * 0.5); let r_sqrt = DoubleDouble::from_rsqrt_fast(dx); let r = DoubleDouble::quick_mult(z * r_sqrt * e, e); let err = f_fmla( r.hi, f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3ba0000000000000), // 2^-69 ); let up = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if up == lb { return f64::copysign(r.to_f64(), sign_scale); } i1_asympt_hard(x, sign_scale) } /** Asymptotic expansion for I1. Computes: sqrt(x) * exp(-x) * I1(x) = Pn(1/x)/Qn(1/x) hence: I1(x) = Pn(1/x)/Qm(1/x)*exp(x)/sqrt(x) Generated by Wolfram Mathematica: ```text <120] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[cold] #[inline(never)] fn i1_asympt_hard(x: f64, sign_scale: f64) -> f64 { static P: [DyadicFloat128; 16] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcc42299e_a1b28468_bea7da47_28f13acc_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -124, mantissa: 0xda979406_3df6e66f_cf31c3f5_f194b48c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -120, mantissa: 0xd60b7b96_c958929b_cabe1d8c_3d874767_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -113, mantissa: 0xd27aad9a_8fb38d56_46ab4510_8479306e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -108, mantissa: 0xe0167305_c451bd1f_d2f17b68_5c62e2ff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -103, mantissa: 0x8f6d238f_c80d8e4a_08c130f6_24e1c925_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -100, mantissa: 0xfe32280f_2ea99024_d9924472_92d7ac8f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -96, mantissa: 0xa48815ac_d265609f_da4ace94_811390b2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -93, mantissa: 0x9ededfe5_833b4cc1_731efd5c_f8729c6c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -91, mantissa: 0xe5b43203_2784ae6a_f7458556_0a8308ea_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0xf5df279a_3fb4ef60_8d10adee_7dd2f47b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -87, mantissa: 0xbdb59963_7a757ed1_87280e0e_7f93ca2b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -86, mantissa: 0xc87fdea5_53177ca8_c91de5fb_3f8f78d3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -85, mantissa: 0x846d16a7_4663ef5d_ad42d599_5bc726b8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -86, mantissa: 0xb3ed2055_74262d95_389f33e4_2ac3774a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -88, mantissa: 0xa511aa32_c18c34e4_3d029a90_a71b7a55_u128, }, ]; static Q: [DyadicFloat128; 16] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -122, mantissa: 0x877b771a_ad8f5fd3_5aacf5f9_f04ee9de_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -118, mantissa: 0x89475ecd_9c84361e_800c8a3a_c8af23bf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0x837d1196_cf2723f1_23b54da8_225efe05_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -106, mantissa: 0x8ae3aecb_15355751_a9ee12e5_a4dd9dde_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -102, mantissa: 0xb0886afa_bc13f996_ab45d252_75c8f587_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -98, mantissa: 0x9b37d7cd_b114b86b_7d14a389_26599aa1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -95, mantissa: 0xc716bf54_09d5dd9f_bc16679b_93aaeca4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -92, mantissa: 0xbe0cd82e_c8af8371_ab028ed9_c7902dd2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -89, mantissa: 0x875f8d91_8ef5d434_a39d00f9_2aed3d2a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -87, mantissa: 0x8e030781_5aa4ce7f_70156b82_8b216b7c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -86, mantissa: 0xd4dd2687_92646fbd_5ea2d422_da64fc0b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -85, mantissa: 0xd6d72ab3_64b4a827_0499af0f_13a51a80_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -84, mantissa: 0x828f4e8b_728747a9_2cebe54a_810e2681_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -85, mantissa: 0x91570096_36a3fcfb_6b936d44_68dda1be_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -89, mantissa: 0xf082ad00_86024ed4_dd31613b_ec41e3f8_u128, }, ]; let recip = DyadicFloat128::accurate_reciprocal(x); let mut p_num = P[15]; for i in (0..15).rev() { p_num = recip * p_num + P[i]; } let mut p_den = Q[15]; for i in (0..15).rev() { p_den = recip * p_den + Q[i]; } let z = p_num * p_den.reciprocal(); let r_sqrt = bessel_rsqrt_hard(x, recip); let f_exp = rational128_exp(x); (z * r_sqrt * f_exp).fast_as_f64() * sign_scale } #[cfg(test)] mod tests { use super::*; #[test] fn test_fi1() { assert_eq!(f_i1(7.750000000757874), 315.8524811496668); assert_eq!(f_i1(7.482812501363189), 245.58002285881892); assert_eq!(f_i1(-7.750000000757874), -315.8524811496668); assert_eq!(f_i1(-7.482812501363189), -245.58002285881892); assert!(f_i1(f64::NAN).is_nan()); assert_eq!(f_i1(f64::INFINITY), f64::INFINITY); assert_eq!(f_i1(f64::NEG_INFINITY), f64::NEG_INFINITY); assert_eq!(f_i1(0.01), 0.005000062500260418); assert_eq!(f_i1(-0.01), -0.005000062500260418); assert_eq!(f_i1(-9.01), -1040.752038018038); assert_eq!(f_i1(9.01), 1040.752038018038); } } pxfm-0.1.23/src/bessel/i1f.rs000064400000000000000000000154041046102023000137560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j0f::j1f_rsqrt; use crate::common::f_fmla; use crate::exponents::core_expf; use crate::polyeval::{f_estrin_polyeval7, f_estrin_polyeval9, f_polyeval10}; /// Modified Bessel of the first kind order 1 /// /// Max ULP 0.5 pub fn f_i1f(x: f32) -> f32 { if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return 0.; } if x.is_infinite() { return if x.is_sign_positive() { f32::INFINITY } else { f32::NEG_INFINITY }; } if x.is_nan() { return f32::NAN; } } let xb = x.to_bits() & 0x7fff_ffff; if xb > 0x42b7d001 { // 91.906261 return if x.is_sign_negative() { f32::NEG_INFINITY } else { f32::INFINITY }; } static SIGN: [f64; 2] = [1., -1.]; let sign_scale = SIGN[x.is_sign_negative() as usize]; if xb <= 0x40f80000u32 { // |x| <= 7.75 return i1f_small(f32::from_bits(xb), sign_scale) as f32; } i1f_asympt(f32::from_bits(xb), sign_scale) } /** Computes I1(x) = x/2 * (1 + 1 * (x/2)^2 + (x/2)^4 * P((x/2)^2)) Generated by Woflram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i1f_small(x: f32, sign_scale: f64) -> f64 { let dx = x as f64; let x_over_two = dx * 0.5; let x_over_two_sqr = x_over_two * x_over_two; let x_over_two_p4 = x_over_two_sqr * x_over_two_sqr; let p_num = f_estrin_polyeval7( x_over_two_sqr, f64::from_bits(0x3fb5555555555555), f64::from_bits(0x3f706cdccca396c4), f64::from_bits(0x3f23f9e12bdbba92), f64::from_bits(0x3ec8e39208e926b2), f64::from_bits(0x3e62e53b433c42ff), f64::from_bits(0x3def7cb16d10fb46), f64::from_bits(0x3d6747cd73d9d783), ); let p_den = f_estrin_polyeval7( x_over_two_sqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfa2075f77b54885), f64::from_bits(0x3f438c6d797c29f5), f64::from_bits(0xbeda57e2a258c6da), f64::from_bits(0x3e677e777c569432), f64::from_bits(0xbdea9212a96babc1), f64::from_bits(0x3d5e183186d5d782), ); let p = p_num / p_den; let p1 = f_fmla(0.5, x_over_two_sqr, 1.); let p2 = f_fmla(x_over_two_p4, p, p1); p2 * x_over_two * sign_scale } /** Asymptotic expansion for I1. Computes: sqrt(x) * exp(-x) * I1(x) = Pn(1/x)/Qn(1/x) hence: I1(x) = Pn(1/x)/Qm(1/x)*exp(x)/sqrt(x) Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i1f_asympt(x: f32, sign_scale: f64) -> f32 { let dx = x as f64; let recip = 1. / dx; let p_num = f_polyeval10( recip, f64::from_bits(0x3fd9884533d43711), f64::from_bits(0xc0309c047537243a), f64::from_bits(0x4073bdb14a29bf68), f64::from_bits(0xc0aaf9eca14d15af), f64::from_bits(0x40d6c629318a9e42), f64::from_bits(0xc0f7bee33088a4b0), f64::from_bits(0x410d018cef093ee2), f64::from_bits(0xc111f32b325d3fe4), f64::from_bits(0x4100dddad80e0b42), f64::from_bits(0xc0c96006c91a00e2), ); let p_den = f_estrin_polyeval9( recip, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xc044a11d10bae889), f64::from_bits(0x408843069497d993), f64::from_bits(0xc0c058710de4b9b9), f64::from_bits(0x40eb0d97f71420ae), f64::from_bits(0xc10b55d181ef9ea1), f64::from_bits(0x411f9413e1932a48), f64::from_bits(0xc1213bff5bc7d2d6), f64::from_bits(0x4105c53e92d9b9c0), ); let z = p_num / p_den; let e = core_expf(x); let r_sqrt = j1f_rsqrt(dx); (z * r_sqrt * e * sign_scale) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_i1f() { assert!(f_i1f(f32::NAN).is_nan()); assert!(f_i1f(f32::INFINITY).is_infinite()); assert!(f_i1f(f32::NEG_INFINITY).is_infinite()); assert_eq!(f_i1f(0.), 0.); assert_eq!(f_i1f(1.), 0.5651591); assert_eq!(f_i1f(-1.), -0.5651591); assert_eq!(f_i1f(9.), 1030.9147); assert_eq!(f_i1f(-9.), -1030.9147); } } pxfm-0.1.23/src/bessel/i2.rs000064400000000000000000000454561046102023000136230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::i0::{bessel_rsqrt_hard, i0_exp}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::rational128_exp; /// Modified bessel of the first kind of order 2 pub fn f_i2(x: f64) -> f64 { if !x.is_normal() { if x == 0. { return 0.; } if x.is_infinite() { return f64::INFINITY; } if x.is_nan() { return f64::NAN; } } let xb = x.to_bits() & 0x7fff_ffff_ffff_ffffu64; if xb < 0x401f000000000000u64 { if xb <= 0x3cb0000000000000u64 { // x <= f64::EPSILON // Power series of I2(x) ~ x^2/8 + O(x^4) const R: f64 = 1. / 8.; let x2 = x * x * R; return x2; } // x < 7.75 return i2_small(f64::from_bits(xb)); } if xb >= 0x40864feaeefb23b8 { // x >= 713.9897136326099 return f64::INFINITY; } i2_asympt(f64::from_bits(xb)) } /** Computes I2(x) = x^2 * R(x^2) Generated by Wolfram Mathematica: ```text <75] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i2_small(x: f64) -> f64 { const P: [(u64, u64); 12] = [ (0x0000000000000000, 0x3fc0000000000000), (0x3c247833fda9de9a, 0x3f8387c6e72a1b5f), (0xbbccaf0be91261a6, 0x3f30ba88efff56fa), (0x3b57c911bfebe1d7, 0x3ecc62e53d061300), (0x3af3b963f26a3d05, 0x3e5bb090327a14e1), (0x3a898bff9d40e030, 0x3de0d29c3d37e5b5), (0xb9f2f63c80d377db, 0x3d5a9e365f1bf6e0), (0xb965e6d78e1c2b65, 0x3ccbf7ef0929b813), (0xb8da83d7d40e7310, 0x3c33737520046f4d), (0xb83f811d5aa3f36e, 0x3b91506558dab318), (0xb78e601bf5c998c3, 0x3ae2013b3e858bd1), (0xb6c8185c51734ed8, 0x3a20cc277a5051ba), ]; let x_sqr = DoubleDouble::from_exact_mult(x, x); let x2 = x_sqr * x_sqr; let x4 = x2 * x2; let x8 = x4 * x4; let e0 = DoubleDouble::mul_add_f64( x_sqr, DoubleDouble::from_bit_pair(P[1]), f64::from_bits(0x3fc0000000000000), ); let e1 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc0ba42af56ed76b, 0xbf7cd8e6e2b39f60), (0x3b90697aa005e598, 0x3efa0260394e1a3d), (0xbb0c7ccde1f63c82, 0xbe6f1766ec64e492), (0x3a63f18409bc336f, 0x3ddb80b6b5abad98), (0xb9e0cd49f22132fe, 0xbd42ff9b55d553da), (0xb934bfe64905d309, 0x3ca50814fa258ebc), (0x38a1e35c2d6860f4, 0xbc02c4f2faca2195), (0xb7ff39e268277e4e, 0x3b5aa545a2c1f16d), (0xb71053f58545760c, 0xbaacde4c133d42d1), (0xb68d0c2ccab0ae5b, 0x39f5a965b92b06bc), (0xb5dc35bda16bee7b, 0xb931375b1c9cfbc7), ]; let e0 = DoubleDouble::mul_add_f64( x_sqr, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( x_sqr, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let p = DoubleDouble::div(p_num, p_den); DoubleDouble::quick_mult(p, x_sqr).to_f64() } /** Asymptotic expansion for I2. I2(x)=R(1/x)*Exp(x)/sqrt(x) Generated in Wolfram: ```text <120] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i2_asympt(x: f64) -> f64 { let dx = x; let recip = DoubleDouble::from_quick_recip(x); const P: [(u64, u64); 12] = [ (0x3c718bb28ebc5f4e, 0x3fd9884533d43650), (0x3c96e15a87b6e1d1, 0xc0350acc9e5cb0f9), (0xbd20b212a79e08f5, 0x40809251af67598a), (0xbd563b7397df3a54, 0xc0bfc09ede682c8b), (0xbd5eb872cb057d91, 0x40f44253a9e1e1ab), (0x3d7614735e566fc5, 0xc121cbcd96dc8765), (0xbddc4f8df2010026, 0x4145a592e8ec74ad), (0x3dea227617b678a7, 0xc161df96fb6a9df9), (0x3e17c9690d906194, 0x41732c71397757f8), (0x3e0638226ce0b938, 0xc178893fde0e6ed7), (0xbe09d8dc4e7930ce, 0x417066abe24b31df), (0xbde152007ee29e54, 0xc150531da3f31b16), ]; let x2 = DoubleDouble::quick_mult(recip, recip); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcd0d33e9e73b503, 0xc0496f5a09751d50), (0x3d2f9c44a069dc4b, 0x40934427187ac370), (0xbd69e2e5a3618381, 0xc0d19983f74fdf52), (0x3d88c69a62ae8b44, 0x410524fcaa71e85a), (0xbdc0345b806dd0bf, 0xc13120daf531b66b), (0xbdd35875712fff6f, 0x4152943a4f9f1c7f), (0xbdf8dd50e92553fd, 0xc169b83aeede08ea), (0x3e0800ecaa77f79e, 0x41746c61554a08ce), (0x3dd74fbc32c5f696, 0xc16ba2febd1932a3), (0x3dc23eb2c943b539, 0x413574ae68b6b378), (0xbd95d86c5c94cd65, 0xc104adac99eaa90c), ]; let e0 = DoubleDouble::mul_add_f64( recip, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let z = DoubleDouble::div(p_num, p_den); let mut e = i0_exp(dx * 0.5); e = DoubleDouble::from_exact_add(e.hi, e.lo); let r_sqrt = DoubleDouble::from_rsqrt_fast(dx); let r = DoubleDouble::quick_mult(z * r_sqrt * e, e); let err = f_fmla( r.hi, f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3ba0000000000000), // 2^-69 ); let up = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if up == lb { return r.to_f64(); } i2_asympt_hard(x) } /** Asymptotic expansion for I2. I2(x)=R(1/x)*Exp(x)/sqrt(x) Generated in Wolfram: ```text <120] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[cold] #[inline(never)] fn i2_asympt_hard(x: f64) -> f64 { static P: [DyadicFloat128; 16] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcc42299e_a1b28468_3bb16645_ba1dc793_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -123, mantissa: 0xe202abf7_de10e93f_2a2e6a0f_af69c788_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0xf70296c3_ad33bde6_866cfd01_0e846cfc_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -113, mantissa: 0xa83df971_736c4e6c_1a35479b_ad6d9172_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0x9baa2015_9c5ca461_0aff0b62_54a70fdb_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -106, mantissa: 0xc70af95d_f95d14ad_1094ea1b_e46b2d2f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -103, mantissa: 0xa838fb48_e79fb706_642da604_6a73b4f8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -101, mantissa: 0x8fe29f37_02b1e876_39e88664_1c8b3b5d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -100, mantissa: 0xc8e9a474_0a03f93a_16d2e7a9_627eba4e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -95, mantissa: 0x8807d1f6_6d646a08_8c7e8900_12d6a5ed_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -93, mantissa: 0xe5c25026_97518024_36878256_fd81c08f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -91, mantissa: 0xeaa075f0_f5151bed_95ec612f_ab9834a7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0x9b267222_82d5c666_348d7d1d_0fedfba4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -88, mantissa: 0x81b45c4c_3e828396_1d5bdede_869c3b84_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0xf4495d43_4bc8dba6_42bdb5d6_c8ba2c9c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -90, mantissa: 0xc9b29546_0c226270_bb428035_587b6d6a_u128, }, ]; static Q: [DyadicFloat128; 16] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -121, mantissa: 0x89e18bae_ca9629a1_26927ba2_fbdd66ab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -116, mantissa: 0x92a90fc2_e905f634_4946e8a0_dd8e3874_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -112, mantissa: 0xc1742696_d29e3846_3e183737_29db8b68_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -108, mantissa: 0xabf61cc0_236a0e90_2572113d_fa339591_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -105, mantissa: 0xcff0fe90_dac1b08e_9a5740ae_b2984fc1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -102, mantissa: 0x9ff36729_e407c538_cfcea3a7_63f39043_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -101, mantissa: 0xc86ff6a3_9b803a31_d385e9ea_83f9d751_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -98, mantissa: 0xb4a125b1_6cab70f3_0f314558_708843df_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -94, mantissa: 0x9670fd33_f83bcaa7_85cf2d82_c0bf8cd5_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -92, mantissa: 0xd70b4ea5_32fedb9d_78a3c047_05e650f4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -90, mantissa: 0xb9c7904c_3f97b633_c2c0ad9b_ad573ede_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -89, mantissa: 0xc2023c21_5155e9fe_6fb17bb2_c865becd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -89, mantissa: 0xd9400a5e_27c58803_22948cf3_6154ac49_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -90, mantissa: 0x87aa272d_6a9700b4_449a9db8_1a93b0ee_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -93, mantissa: 0xd1a86655_5b259611_dfc7affc_6ffb0e20_u128, }, ]; let recip = DyadicFloat128::accurate_reciprocal(x); let mut p_num = P[15]; for i in (0..15).rev() { p_num = recip * p_num + P[i]; } let mut p_den = Q[15]; for i in (0..15).rev() { p_den = recip * p_den + Q[i]; } let z = p_num * p_den.reciprocal(); let r_sqrt = bessel_rsqrt_hard(x, recip); let f_exp = rational128_exp(x); (z * r_sqrt * f_exp).fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_i2() { assert_eq!(f_i2(7.750000000757874), 257.0034362785801); assert_eq!(f_i2(7.482812501363189), 198.26765887136534); assert_eq!(f_i2(-7.750000000757874), 257.0034362785801); assert_eq!(f_i2(-7.482812501363189), 198.26765887136534); assert!(f_i2(f64::NAN).is_nan()); assert_eq!(f_i2(f64::INFINITY), f64::INFINITY); assert_eq!(f_i2(f64::NEG_INFINITY), f64::INFINITY); assert_eq!(f_i2(0.01), 1.2500104166992188e-5); assert_eq!(f_i2(-0.01), 1.2500104166992188e-5); assert_eq!(f_i2(-9.01), 872.9250699638584); assert_eq!(f_i2(9.01), 872.9250699638584); } } pxfm-0.1.23/src/bessel/i2f.rs000064400000000000000000000144531046102023000137620ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j0f::j1f_rsqrt; use crate::exponents::core_expf; use crate::polyeval::{f_estrin_polyeval8, f_estrin_polyeval9}; /// Modified Bessel of the first kind order 2 /// /// ULP 0.5 pub fn f_i2f(x: f32) -> f32 { if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return 0.; } if x.is_infinite() { return f32::INFINITY; } if x.is_nan() { return f32::NAN; } } let xb = x.to_bits() & 0x7fff_ffff; if xb >= 0x42b7d875u32 { // |x| >= 91.92277 it's infinity return f32::INFINITY; } if xb <= 0x34000000u32 { // |x| <= f32::EPSILON let dx = x as f64; const R: f64 = 1. / 8.; return (dx * dx * R) as f32; } if xb <= 0x40f80000u32 { // |x| <= 7.75 return i2f_small(f32::from_bits(xb)); } i2f_asympt(f32::from_bits(xb)) } /** Computes I2(x) = x^2 * R(x^2) Generated by Wolfram Mathematica: ```text <75] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i2f_small(x: f32) -> f32 { let dx = x as f64; let x_sqr = dx * dx; let p_num = f_estrin_polyeval9( x_sqr, f64::from_bits(0x3fc0000000000000), f64::from_bits(0x3f831469a38d72c7), f64::from_bits(0x3f2f453dd3dd98f4), f64::from_bits(0x3ec8af52ee8fce9b), f64::from_bits(0x3e5589f2cb4e0ec9), f64::from_bits(0x3dd60fa268a4206d), f64::from_bits(0x3d4ab3091ee18d6b), f64::from_bits(0x3cb1efec43b15186), f64::from_bits(0x3c050992c6e9e63f), ); let p_den = f_estrin_polyeval8( x_sqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbf82075d8e3f1476), f64::from_bits(0x3f03ef86564a284b), f64::from_bits(0xbe7c498fab4a57d8), f64::from_bits(0x3dec162ca0f68486), f64::from_bits(0xbd53bb6398461540), f64::from_bits(0x3cb265215261e64a), f64::from_bits(0xbc01cf52cc350e81), ); let p = p_num / p_den; (p * x_sqr) as f32 } /** Asymptotic expansion for I2. Computes: sqrt(x) * exp(-x) * I2(x) = Pn(1/x)/Qn(1/x) hence: I2(x) = Pn(1/x)/Qm(1/x)*exp(x)/sqrt(x) Generated by Mathematica: ```text <70] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i2f_asympt(x: f32) -> f32 { let dx = x as f64; let recip = 1. / dx; let p_num = f_estrin_polyeval9( recip, f64::from_bits(0x3fd9884533d45f46), f64::from_bits(0xc02b979526807e1e), f64::from_bits(0x406b1dd3e795bbed), f64::from_bits(0xc09e43629031ec91), f64::from_bits(0x40c48c03a39aec1d), f64::from_bits(0xc0e0f022ccb8807a), f64::from_bits(0x40f0302eeb22a776), f64::from_bits(0xc0f02b01549d38b8), f64::from_bits(0x40dad4e70f2bc264), ); let p_den = f_estrin_polyeval9( recip, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xc0405a71a88b191c), f64::from_bits(0x407e19f7d247d098), f64::from_bits(0xc0aeaac6e0ca17fe), f64::from_bits(0x40d2301702f40a98), f64::from_bits(0xc0e7e6c6c01841b3), f64::from_bits(0x40ed67317e9e46cc), f64::from_bits(0xc0d13786aa1ef416), f64::from_bits(0xc0a6c9cfe579ae22), ); let z = p_num / p_den; let e = core_expf(x); let r_sqrt = j1f_rsqrt(dx); (z * r_sqrt * e) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_i2f() { assert_eq!(f_i2f(0.), 0.); assert_eq!(f_i2f(f32::INFINITY), f32::INFINITY); assert_eq!(f_i2f(f32::NEG_INFINITY), f32::INFINITY); assert_eq!(f_i2f(1.), 0.13574767); assert_eq!(f_i2f(-1.), 0.13574767); assert_eq!(f_i2f(9.432), 1314.6553); assert_eq!(f_i2f(-9.432), 1314.6553); } } pxfm-0.1.23/src/bessel/j0.rs000064400000000000000000000462261046102023000136160ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::alpha0::{ bessel_0_asympt_alpha, bessel_0_asympt_alpha_fast, bessel_0_asympt_alpha_hard, }; use crate::bessel::beta0::{ bessel_0_asympt_beta, bessel_0_asympt_beta_fast, bessel_0_asympt_beta_hard, }; use crate::bessel::i0::bessel_rsqrt_hard; use crate::bessel::j0_coeffs_remez::J0_COEFFS_REMEZ; use crate::bessel::j0_coeffs_taylor::J0_COEFFS_TAYLOR; use crate::bessel::j0f_coeffs::{J0_ZEROS, J0_ZEROS_VALUE}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::{f_polyeval9, f_polyeval10, f_polyeval12, f_polyeval19}; use crate::sin_helper::{cos_dd_small, cos_dd_small_fast, cos_f128_small}; use crate::sincos_reduce::{AngleReduced, rem2pi_any, rem2pi_f128}; /// Bessel of the first kind J0 pub fn f_j0(x: f64) -> f64 { let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff; if !x.is_normal() { if f64::from_bits(x_abs) == 0. { // J0 value at 0 return f64::from_bits(0x3ff0000000000000); } if x.is_infinite() { return 0.; } if x.is_nan() { return x + x; } } let ax = f64::from_bits(x_abs); if x_abs <= 0x4052b33333333333u64 { // 74.8 if x_abs <= 0x3ff199999999999au64 { // 1.1 return j0_maclaurin_series_fast(ax); } return j0_small_argument_fast(ax); } j0_asympt_fast(ax) } /** Generated by SageMath: ```python mp.prec = 180 def print_expansion_at_0(): print(f"const J0_MACLAURIN_SERIES: [(u64, u64); 12] = [") from mpmath import mp, j0, taylor poly = taylor(lambda val: j0(val), 0, 24) real_i = 0 for i in range(0, 24, 2): print_double_double("", DD(poly[i])) real_i = real_i + 1 print("];") print(poly) print_expansion_at_0() ``` **/ #[inline] pub(crate) fn j0_maclaurin_series_fast(x: f64) -> f64 { const C: [u64; 12] = [ 0x3ff0000000000000, 0xbfd0000000000000, 0x3f90000000000000, 0xbf3c71c71c71c71c, 0x3edc71c71c71c71c, 0xbe723456789abcdf, 0x3e002e85c0898b71, 0xbd8522a43f65486a, 0x3d0522a43f65486a, 0xbc80b313289be0b9, 0x3bf5601885e63e5d, 0xbb669ca9cf3b7f54, ]; let dx2 = DoubleDouble::from_exact_mult(x, x); let p = f_polyeval10( dx2.hi, f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), f64::from_bits(C[10]), f64::from_bits(C[11]), ); let mut z = DoubleDouble::mul_f64_add_f64(dx2, p, f64::from_bits(C[1])); z = DoubleDouble::mul_add_f64(dx2, z, f64::from_bits(C[0])); // squaring error (2^-56) + poly error 2^-75 let err = f_fmla( dx2.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3b40000000000000), // 2^-75 ); let ub = z.hi + (z.lo + err); let lb = z.hi + (z.lo - err); if ub == lb { return z.to_f64(); } j0_maclaurin_series(x) } /** Generated by SageMath: ```python mp.prec = 180 def print_expansion_at_0(): print(f"const J0_MACLAURIN_SERIES: [(u64, u64); 12] = [") from mpmath import mp, j0, taylor poly = taylor(lambda val: j0(val), 0, 24) real_i = 0 for i in range(0, 24, 2): print_double_double("", DD(poly[i])) real_i = real_i + 1 print("];") print(poly) print_expansion_at_0() ``` **/ #[cold] pub(crate) fn j0_maclaurin_series(x: f64) -> f64 { const C: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x0000000000000000, 0xbfd0000000000000), (0x0000000000000000, 0x3f90000000000000), (0xbbdc71c71c71c71c, 0xbf3c71c71c71c71c), (0x3b7c71c71c71c71c, 0x3edc71c71c71c71c), (0xbab23456789abcdf, 0xbe723456789abcdf), (0xba8b6edec0692e65, 0x3e002e85c0898b71), (0x3a2604db055bd075, 0xbd8522a43f65486a), (0xb9a604db055bd075, 0x3d0522a43f65486a), (0x3928824198c6f6e1, 0xbc80b313289be0b9), (0xb869b0b430eb27b8, 0x3bf5601885e63e5d), (0x380ee6b4638f3a25, 0xbb669ca9cf3b7f54), ]; let dx2 = DoubleDouble::from_exact_mult(x, x); let p = f_polyeval12( dx2, DoubleDouble::from_bit_pair(C[0]), DoubleDouble::from_bit_pair(C[1]), DoubleDouble::from_bit_pair(C[2]), DoubleDouble::from_bit_pair(C[3]), DoubleDouble::from_bit_pair(C[4]), DoubleDouble::from_bit_pair(C[5]), DoubleDouble::from_bit_pair(C[6]), DoubleDouble::from_bit_pair(C[7]), DoubleDouble::from_bit_pair(C[8]), DoubleDouble::from_bit_pair(C[9]), DoubleDouble::from_bit_pair(C[10]), DoubleDouble::from_bit_pair(C[11]), ); let r = DoubleDouble::from_exact_add(p.hi, p.lo); const ERR: f64 = f64::from_bits(0x39d0000000000000); // 2^-98 let ub = r.hi + (r.lo + ERR); let lb = r.hi + (r.lo - ERR); if ub == lb { return r.to_f64(); } j0_maclaurin_series_hard(x) } /** Generated by SageMath: ```python mp.prec = 180 def print_expansion_at_0(): print(f"const P: [DyadicFloat128; 12] = [") from mpmath import mp, j0, taylor poly = taylor(lambda val: j0(val), 0, 24) # print(poly) real_i = 0 for i in range(0, 24, 2): print_dyadic(DD(poly[i])) real_i = real_i + 1 print("];") print(poly) print_expansion_at_0() ``` **/ #[cold] #[inline(never)] pub(crate) fn j0_maclaurin_series_hard(x: f64) -> f64 { static P: [DyadicFloat128; 12] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0x91a2b3c4_d5e6f809_1a2b3c4d_5e6f8092_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -158, mantissa: 0x81742e04_4c5b8724_8909fcb6_8cd4e410_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -166, mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -174, mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -182, mantissa: 0x85989944_df05c4ef_b7cce721_23e1b391_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -191, mantissa: 0xab00c42f_31f2e799_3d2f3c53_6120e5d8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -200, mantissa: 0xb4e54e79_dbfa9c23_29738e18_bb602809_u128, }, ]; let dx = DyadicFloat128::new_from_f64(x); let x2 = dx * dx; let mut p = P[11]; for i in (0..11).rev() { p = x2 * p + P[i]; } p.fast_as_f64() } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] pub(crate) fn j0_small_argument_fast(x: f64) -> f64 { // let avg_step = 74.6145 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6299043751549631; let fx = x * INV_STEP; const J0_ZEROS_COUNT: f64 = (J0_ZEROS.len() - 1) as f64; let idx0 = fx.min(J0_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(J0_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(J0_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(J0_ZEROS[idx1]); let dist0 = (found_zero0.hi - x).abs(); let dist1 = (found_zero1.hi - x).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return j0_maclaurin_series_fast(x); } let is_too_close_too_zero = dist.abs() < 1e-3; let c = if is_too_close_too_zero { &J0_COEFFS_TAYLOR[idx - 1] } else { &J0_COEFFS_REMEZ[idx - 1] }; let r = DoubleDouble::full_add_f64(-found_zero, x.abs()); // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(J0_ZEROS_VALUE[idx]); } let p = f_polyeval19( r.hi, f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), f64::from_bits(c[9].1), f64::from_bits(c[10].1), f64::from_bits(c[11].1), f64::from_bits(c[12].1), f64::from_bits(c[13].1), f64::from_bits(c[14].1), f64::from_bits(c[15].1), f64::from_bits(c[16].1), f64::from_bits(c[17].1), f64::from_bits(c[18].1), f64::from_bits(c[19].1), f64::from_bits(c[20].1), f64::from_bits(c[21].1), f64::from_bits(c[22].1), f64::from_bits(c[23].1), ); let mut z = DoubleDouble::mul_f64_add(r, p, DoubleDouble::from_bit_pair(c[4])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[3])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[2])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[1])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[0])); let err = f_fmla( z.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3bf0000000000000), // 2^-64 ); let ub = z.hi + (z.lo + err); let lb = z.hi + (z.lo - err); if ub == lb { return z.to_f64(); } j0_small_argument_dd(r, c) } #[cold] fn j0_small_argument_dd(r: DoubleDouble, c0: &[(u64, u64); 24]) -> f64 { let c = &c0[15..]; let p0 = f_polyeval9( r.to_f64(), f64::from_bits(c[0].1), f64::from_bits(c[1].1), f64::from_bits(c[2].1), f64::from_bits(c[3].1), f64::from_bits(c[4].1), f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), ); let c = c0; let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(c[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c10000000000000), // 2^-62 f64::from_bits(0x3a90000000000000), // 2^-86 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return j0_small_argument_hard(r, c); } p.to_f64() } #[cold] #[inline(never)] fn j0_small_argument_hard(r: DoubleDouble, c: &[(u64, u64); 24]) -> f64 { let mut p = DoubleDouble::from_bit_pair(c[23]); for i in (0..23).rev() { p = DoubleDouble::mul_add(r, p, DoubleDouble::from_bit_pair(c[i])); p = DoubleDouble::from_exact_add(p.hi, p.lo); } p.to_f64() } /* Evaluates: J0 = sqrt(2/(PI*x)) * beta(x) * cos(x - PI/4 - alpha(x)) */ #[inline] pub(crate) fn j0_asympt_fast(x: f64) -> f64 { let x = x.abs(); const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let recip = if x.to_bits() > 0x7fd000000000000u64 { DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_safe_div(4.0, x), 0.25) } else { DoubleDouble::from_recip(x) }; let alpha = bessel_0_asympt_alpha_fast(recip); let beta = bessel_0_asympt_beta_fast(recip); let AngleReduced { angle } = rem2pi_any(x); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_cos = cos_dd_small_fast(r0); let z0 = DoubleDouble::quick_mult(beta, m_cos); let r_sqrt = DoubleDouble::from_rsqrt_fast(x); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let p = DoubleDouble::quick_mult(scale, z0); let err = f_fmla( p.hi, f64::from_bits(0x3be0000000000000), // 2^-65 f64::from_bits(0x3a60000000000000), // 2^-89 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } j0_asympt(x, recip, r_sqrt, angle) } /* Evaluates: J0 = sqrt(2/(PI*x)) * beta(x) * cos(x - PI/4 - alpha(x)) */ pub(crate) fn j0_asympt( x: f64, recip: DoubleDouble, r_sqrt: DoubleDouble, angle: DoubleDouble, ) -> f64 { const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let alpha = bessel_0_asympt_alpha(recip); let beta = bessel_0_asympt_beta(recip); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_cos = cos_dd_small(r0); let z0 = DoubleDouble::quick_mult(beta, m_cos); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let r = DoubleDouble::quick_mult(scale, z0); let p = DoubleDouble::from_exact_add(r.hi, r.lo); let err = f_fmla( p.hi, f64::from_bits(0x3bd0000000000000), // 2^-66 f64::from_bits(0x39e0000000000000), // 2^-97 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } j0_asympt_hard(x) } /* Evaluates: J0 = sqrt(2/(PI*x)) * beta(x) * cos(x - PI/4 - alpha(x)) */ #[cold] #[inline(never)] pub(crate) fn j0_asympt_hard(x: f64) -> f64 { const SQRT_2_OVER_PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcc42299e_a1b28468_7e59e280_5d5c7180_u128, }; const MPI_OVER_4: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let x_dyadic = DyadicFloat128::new_from_f64(x); let recip = DyadicFloat128::accurate_reciprocal(x); let alpha = bessel_0_asympt_alpha_hard(recip); let beta = bessel_0_asympt_beta_hard(recip); let angle = rem2pi_f128(x_dyadic); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_sin = cos_f128_small(r0); let z0 = beta * m_sin; let r_sqrt = bessel_rsqrt_hard(x, recip); let scale = SQRT_2_OVER_PI * r_sqrt; let p = scale * z0; p.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_j0() { assert_eq!(f_j0(-2.000976555054876), 0.22332760641907712); assert_eq!(f_j0(-2.3369499004222215E+304), -3.3630754230844632e-155); assert_eq!( f_j0(f64::from_bits(0xd71a31ffe2ff7e9f)), f64::from_bits(0xb2e58532f95056ff) ); assert_eq!(f_j0(6.1795701510782757E+307), 6.075192922402001e-155); assert_eq!(f_j0(6.1795701510782757E+301), 4.118334155030934e-152); assert_eq!(f_j0(6.1795701510782757E+157), 9.5371668900364e-80); assert_eq!(f_j0(79.), -0.08501719554953485); // Without FMA 2.703816901253004e-16 #[cfg(any( all(target_arch = "x86_64", target_feature = "fma"), target_arch = "aarch64" ))] assert_eq!(f_j0(93.463718781944774171190), 2.7038169012530046e-16); assert_eq!(f_j0(99.746819858680596470279979), -8.419106281522749e-17); assert_eq!(f_j0(f64::INFINITY), 0.); assert_eq!(f_j0(f64::NEG_INFINITY), 0.); assert!(f_j0(f64::NAN).is_nan()); } } pxfm-0.1.23/src/bessel/j0_coeffs_remez.rs000064400000000000000000001706721046102023000163500ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Taylor series expansion for J0 Generated by SageMath: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = (zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i]) + 0.83 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05 b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(j0_zeros) # print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 500; bessel_j0 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_j0(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RealField(500)(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return def print_remez_coeffs(poly): print("J0TaylorExtendedSeries {") print_double_double("a0: ", poly[0]) print_double_double("a1: ", poly[1]) print_double_double("a2: ", poly[2]) print_double_double("a3: ", poly[3]) print_double_double("a4: ", poly[4]) print_double_double("a5: ", poly[5]) print_double_double("a6: ", poly[6]) print_double_double("a7: ", poly[7]) print_double_double("a8: ", poly[8]) print_double_double("a9: ", poly[9]) print_double_double("a10: ", poly[10]) print_double_double("a11: ", poly[11]) print_double_double("a12: ", poly[12]) print_double_double("a13: ", poly[13]) print("c: [") for i in range(14, len(poly)): coeff = poly[i] print(f"{double_to_hex(coeff)},") print("],") print("},") degree = 21 print(f"pub(crate) static J0_COEFFS: [J0TaylorExtendedSeries; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print_remez_coeffs(coeffs) print("];") ``` see notes/bessel_j0_taylor.ipynb **/ pub(crate) static J0_COEFFS_REMEZ: [[(u64, u64); 24]; 47] = [ [ (0x35cabb65251ee9e1, 0xb940904225a2e689), (0xbc8ac8cc3d6baf81, 0xbfe09cdb36551280), (0xbc5b50b1160eaa90, 0x3fbba1deea029494), (0x3c4bc98bcfdb9552, 0x3facfae864368d70), (0xbc1a87a5513baa19, 0xbf81bb1cbe1a4071), (0x3bcf770f17b53b67, 0xbf61f992590d12bd), (0x3ba05111ecddc158, 0x3f315382ba06cc47), (0x3ba2b3fa2a3da72a, 0x3f06ed3b9f07eb28), (0xbb46f7b4858b68c3, 0xbed232c77d228ab6), (0x3b47b12392b6b437, 0xbea1cce302821846), (0xbab50abcf1097a30, 0x3e67ff99166c20b8), (0xbad63d3a07c5005a, 0x3e32951bd4726a93), (0xba9950044640bb2e, 0xbdf5c2c38b2a2783), (0xba541f8018d200d7, 0xbdbbdc468c1a7eee), (0xba165a9b127054c4, 0x3d7cd41cf2489ea1), (0x39d72c6649bda0f9, 0x3d3f70b02016ca26), (0xb993b90d2d9ac399, 0xbcfd22d8ef92bec0), (0xb957753210682ee6, 0xbcbbaa35275a6222), (0xb8d21bc46d19becc, 0x3c77361304109810), (0xb8d349b7e68b934a, 0x3c33829044877cd2), (0xb885327d8bda1ea2, 0xbbede8805081c87c), (0x382f2276708fc7d3, 0xbba68d801b3bad5d), (0xb8067b24c3fb14b1, 0x3b601bea84e3ff3f), (0x37a9569e06a99bfe, 0x3b19ff405c2e53c4), ], [ (0x3c62de1143765a96, 0xbfd9c6cf582cbf7f), (0xb5f60db51e8c7541, 0x395df78c3799704c), (0xbc52de1143765a6f, 0x3fc9c6cf582cbf7f), (0xbc3b84c5dde44b4f, 0xbf91f06d14e11e02), (0x3c27767d96985ea8, 0xbf8b589d1da13905), (0x3beae1afe730c7c9, 0x3f50f9103cf5b152), (0x3bd3e8ae8ef24234, 0x3f386445621cc085), (0x3b8a8903a2c6108a, 0xbefa2a033ccf2705), (0xbb6859eebd6af12b, 0xbed83a06e30c4109), (0xbb3d51d443e4c446, 0x3e96a4fd997104b3), (0x3af99b61d1c76464, 0x3e6ec03c7b7d1357), (0xbac247e4733f0637, 0xbe295db03343bc40), (0xba9b3084e57a7079, 0xbdfb1e242e3fafb5), (0x3a505dc534b67fe8, 0x3db3fa9bccb27d21), (0x3a20ef6f1892b081, 0x3d8195cae4f67f76), (0xb9ddf4b73fd307e9, 0xbd3762afe2a6aee9), (0x398a6dd1d504dc6d, 0xbd017a40c9409365), (0xb90b1f08ce463e38, 0x3cb52a10c56acb7f), (0xb8f458d9f512adee, 0x3c7b78e3226aab83), (0xb88362e957f09f13, 0xbc2e864870efa32e), (0x3883c3c8d8c9548c, 0xbbf180323daae355), (0xb84ee7453edcaae1, 0x3ba1f821fbac48d2), (0x38094473de9ddfb1, 0x3b62580a3d2321cb), (0x37afb06968799ff5, 0xbb13009d6caab011), ], [ (0x35dbe52d2b337a1c, 0xb9486fd64fd4d5ac), (0xbc6af17f78e5834c, 0x3fd5c6e60a097823), (0xbc22c1940b6591bc, 0xbf9f8f72e7a848e0), (0x3c39226a69688cd8, 0xbfab2150cb41e8c1), (0xbc0ead94b778456a, 0x3f72f7ffe90256bb), (0xbbdc44bdbd19f356, 0x3f627e31fe9a9779), (0xbbc64599a5779ae3, 0xbf26f641f41956f7), (0xbb948617d08510cb, 0xbf0863f481a43036), (0x3b680f7f67daa761, 0x3ecad77d748a06db), (0x3b3cc529a50aa60d, 0x3ea32e6d99c6af7d), (0xbac1cce367cee3c7, 0xbe62da37e38435b9), (0xbada187c686c04e7, 0xbe341d72d9392e0e), (0xba9d2e19dd36e939, 0x3df1d0433d9a0e48), (0x3a31b2df296572e6, 0x3dbe2f3389aa5fae), (0x39eecfa6ba4ba8c8, 0xbd78498ffdebd97b), (0x39d03604efc229e3, 0xbd410477aeae8e02), (0xb9773b9fe3142404, 0x3cf911a8d777928f), (0xb957c6801c088821, 0x3cbde68af5af2e98), (0xb90138809c41f3e6, 0xbc744b38708ab5a6), (0x38db3cf268b04601, 0xbc350be960e7059b), (0xb88759fc2b6b9b1a, 0x3bea7a1734099f03), (0x3834f08a90df154d, 0x3ba84749424dc4da), (0xb7d2d06b0965e481, 0xbb5c42f208f4edf8), (0xb7bf8d11d7307b88, 0xbb1812bbeb085f69), ], [ (0x3c7af22d033ee0a4, 0x3fd33518b3874e8a), (0xb565f8b72bba82bc, 0xb8cc87a125947e43), (0xbc6af22d033ee078, 0xbfc33518b3874e8a), (0xbc006437c8a4159e, 0x3f7d34125d59d8ff), (0x3c276d8715dea5f6, 0x3f880c83bdeee5b0), (0x3be6843190a13b37, 0xbf4483c20f1cb1cf), (0xbbb05a9f2f74161a, 0xbf36ffa5fc8cad74), (0x3b913c314acf400c, 0x3ef2ccf7b21fff81), (0x3b3475a5e179bf64, 0x3ed796a751f89051), (0x3b28cd72cc09b73f, 0xbe91e850e4c28d2e), (0xbb0d842a5a3f172c, 0xbe6e6a49ae425df4), (0x3ac77dfa876dbcd5, 0x3e254c4387ef6820), (0xba4ce9bca6cbfb11, 0x3dfb084d1fe8eb86), (0xba46d58ee64093b4, 0xbdb177e06f295811), (0x3a2849b6d182b267, 0xbd8198853f279199), (0xb9d57dcf1658bea4, 0x3d350c2b4db30b56), (0x39abd4acfcd6f54a, 0x3d0183edbb87358c), (0xb95012e0c95b80e9, 0xbcb376d168f148ae), (0x390c67518d849338, 0xbc7b8a6525f06ee6), (0xb8cd24af389f1494, 0x3c2c8b0bedec138a), (0x3894158db0bcbb7a, 0x3bf189a730b0f950), (0xb84a2fbef2679eb4, 0xbba1058c9711525e), (0xb80049fcdfa04e9b, 0xbb62579aecb57942), (0x37bdf8b8eca85db7, 0x3b11906f2331b44b), ], [ (0xb5f59a445e01eb06, 0x3950ae6da0547fff), (0x3c70b85158068ef5, 0xbfd15f7977a772d4), (0x3c1371b46642a67b, 0x3f900f7fcf183e0d), (0xbc44d97f9cced450, 0x3fa68b984ec6493c), (0x3c042ebf64ae5867, 0xbf648e63600d8418), (0xbbeee6fe2679d992, 0xbf60e0d60385a6f0), (0x3baeef0b8f617ca9, 0x3f1d796052775aab), (0xbba7aac03828df95, 0x3f07800bc550673c), (0xbb5a87dc43504bb3, 0xbec3324842f7d51c), (0xbb4a6095f3f5ebca, 0xbea30e8cc35f2086), (0x3ae3bca6d31bd279, 0x3e5ceda479a13c54), (0xbad0ae4da6548e0c, 0x3e34582cb217a0ff), (0xba7adb1d4f626b31, 0xbdecade19f5ddb0d), (0xba5f5d3513abe02f, 0xbdbedafbed1c0060), (0x3a0b34ecc7b06112, 0x3d743c230e74eaef), (0x39da767fb508fb46, 0x3d41820d4a511a84), (0xb98edf1089e10b5b, 0xbcf56d4abf96e195), (0xb93ff26a999ae6a3, 0xbcbee1c9645e9dcf), (0xb8e367fc57f02855, 0x3c71b0595f0e1dc1), (0xb8d180382e6bf1c1, 0x3c35c9767e2c08b3), (0x387cd5296e5b56a9, 0xbbe76fd0e549a473), (0xb84bc9a6b0df08ca, 0xbba9294c38de66a6), (0xb7e02c9e93087d88, 0x3b595008e255e71b), (0x37b5a3d651bbe212, 0x3b188b36ce9fc633), ], [ (0xbc5052a3a2541c56, 0xbfcff654544ebcd1), (0xb60528028a348c29, 0x396d15232f36db8f), (0x3c4052a3a2541b46, 0x3fbff654544ebcd1), (0xbc1261ff874dd101, 0xbf70c17ff72afae7), (0x3c123a275592e8f3, 0xbf84b0c5d5da6789), (0xbbda98843b2d7643, 0x3f394154be70ed46), (0x3bd7d4055820b3e5, 0x3f34e12c3067bef4), (0x3b83b9b8d3c54cc7, 0xbee9f32fc25ad134), (0x3b7dd34ebfa238e0, 0xbed63c5475439cb2), (0xbb2e2ce103e7ab56, 0x3e8adbafdf1415b1), (0xbb04326873ff6a93, 0x3e6d601d278516f5), (0xbaaec485a6d4e24e, 0xbe20eedcab593552), (0xba8c720226ba7a69, 0xbdfa84fedb589fe6), (0xba416138f5e356cd, 0x3dacf8e343fe22e2), (0xba24b409ac564a10, 0x3d81702cfaaee181), (0x39c7d31ba4d6f537, 0xbd320271d8cdc0c2), (0x39a6d8840aab3531, 0xbd01797e5ea36c33), (0xb92966390929c005, 0x3cb10ed3b69b52d3), (0x391516ca621c4097, 0x3c7b98f43bd2851c), (0x38b9ad988a829a99, 0xbc297cc12a1feee1), (0x389015ff3d9a5854, 0xbbf19fe694606f79), (0xb83de6f88813ef23, 0x3b9edac0e4d9d135), (0x37c618b3f375f1a3, 0x3b627614b4015fcf), (0xb797a11ae6442380, 0xbb0fd9f6fd427743), ], [ (0x36182629090c00b9, 0xb981570c6a6c1920), (0xbc56d72d40e790a3, 0x3fcdc13e66ac2e77), (0xbc17a0058564d1fe, 0xbf842ff0cdc58463), (0xbc4ea7eea5885fab, 0xbfa38d1dd8992e04), (0xbbe0000f328e352e, 0x3f5a55e9b346edc1), (0xbbf1ad5da345eb7e, 0x3f5e2e16f97d0a81), (0x3bba0bf2e3bea8c6, 0xbf13dfc3782af205), (0x3baf57787ba2c01a, 0xbf05ce7f496656d0), (0x3b554db180ff9e7b, 0x3ebbb178da9c4ac0), (0x3b4faac66e76c3d4, 0x3ea2346d74940be8), (0x3afdf2da5b6281cc, 0xbe5612f2e799b732), (0x3aa72b6634c3ae5c, 0xbe33d79882e5df9f), (0x3a865e4a580e28bc, 0x3de6dbc112bdb275), (0x3a5f226492347489, 0x3dbe88c4d898d67e), (0xba18523fedb5deb4, 0xbd70ad880fc1dc07), (0x39ce811e88c6c354, 0xbd4180d64e2c6148), (0xb9932884c5f7b3a4, 0x3cf220941372b04a), (0x395486256f555b5a, 0x3cbf18a851090945), (0x3906d76d19d83863, 0xbc6e8dc104a832cd), (0x38de3ac4d7a1c28e, 0xbc360ce0fa8619a8), (0xb8723deefb433289, 0x3be494552b1ee19e), (0x38260b2fc3fa5df7, 0x3ba98e84df559883), (0x37de2732117b2742, 0xbb56861d006ce503), (0xb727a6bd23f6ede0, 0xbb18d0646a86c4e8), ], [ (0x3c6c8c66d2e42062, 0x3fcbf3337873a7d8), (0xb60f0cbcd3444aa6, 0xb964840aa1183331), (0xbc5c8c66d2e41fc8, 0xbfbbf3337873a7d8), (0x3bfaea5f363a1a4a, 0x3f66604d91f926ee), (0xbc24192692d91168, 0x3f8251858011816b), (0xbbdcdb1275879ace, 0xbf314bc11a32c246), (0x3bd505487959e0b7, 0xbf32e7decd1f73a5), (0xbb847a9b71aaa4b6, 0x3ee293b4c9a24966), (0x3b6e3a2461d917f1, 0x3ed4a6704d05ad0b), (0x3b124de00e846cdf, 0xbe843ca9b71b6996), (0x3afc563d5074b0c6, 0xbe6bddfbf35630ba), (0xbabc60e5bca9317e, 0x3e1aae76737061db), (0xba871cc918e40357, 0x3df992424643ff62), (0xba3975292cf7e7a6, 0xbda7aad4b0989b20), (0xba0b3d3cb2ccb405, 0xbd81051e84a7a409), (0x39cd31eea0333123, 0x3d2e49ae1a0f5538), (0xb9a4374f38b86f7b, 0x3d013585a9ad29c6), (0xb943f3b2e472171f, 0xbcad5c6822190eea), (0xb91a3dcc41f8b30f, 0xbc7b5bcfa3070c5e), (0xb8b8722028e41e05, 0x3c2659e1ea7b0928), (0xb89ccb60dab570a5, 0x3bf18ed1ab836080), (0xb82cd51c1659b017, 0xbb9b79f386c69ed4), (0xb80e73ef8d65d07f, 0xbb6274a94c2329fb), (0x37966592010226ae, 0x3b0c90cd312dc7b4), ], [ (0x35b57b124ca891a6, 0xb9753e82348b36e7), (0x3c32010996eec73f, 0xbfca701d0f967500), (0xbc1331fb2bff5f5f, 0x3f7c54b930fef892), (0x3c442403558772be, 0x3fa17798aa09f11f), (0xbbf91cbfe50364c6, 0xbf52a2151407dd09), (0xbbeaf2596c181ca5, 0xbf5b541f829bfb41), (0x3b96785653f397a8, 0x3f0cc0bda19ffe34), (0x3b7cc73c0281eea2, 0x3f041f3b0662f49e), (0x3b50b097e3ffae6e, 0xbeb4b230b114b149), (0xbb39f756c517f389, 0xbea1223e2bd0689f), (0xbadb05bfc44ceed1, 0x3e511963968a437f), (0xbadcfd5e302d5caa, 0x3e32ffb8dedaa0e5), (0xba7ba82c85c63aed, 0xbde24c47f1c46f85), (0x3a56063e275fb1ee, 0xbdbda527540ac8ab), (0x3a042a1749b80056, 0x3d6b75eeb2587187), (0x39cf0477925a6771, 0x3d412dcf9e14ca72), (0x3965d39c1b93d637, 0xbcee8dc94e4a47ce), (0xb94ec20106752176, 0xbcbec6e9eef76922), (0xb90db7e15209bac8, 0x3c6a411a8f127544), (0x38d4829603e3c8d8, 0x3c35f7179d3c30ad), (0x38752bac2edc6ca6, 0xbbe1f8b6ea290920), (0xb82284d049652280, 0xbba99593860b4ea4), (0xb7dada6a0b2440d5, 0x3b53ef32d1c66177), (0xb7baf92eb88ac861, 0x3b18d6a7f6c008d1), ], [ (0x3c6e9557ccd1703f, 0xbfc925c6fca08f55), (0x35fab5fb9c5380cd, 0x397dd9d8f9235378), (0xbc5e9557ccd170e3, 0x3fb925c6fca08f55), (0xbbf0bd4a46186c99, 0xbf6049377403bcb4), (0xbc1dac1b118906a5, 0xbf809463bbd0367f), (0xbbbd1ccb59bc25f7, 0x3f297b354706c53c), (0xbbdfefc73f41d900, 0x3f314dd4404e5fcc), (0xbb768a017e0a8626, 0xbedbf665d5afcb1e), (0xbb5562ef116833bd, 0xbed32cb00ee8c1f3), (0x3b1692f6b84439ce, 0x3e7f50fa815b542a), (0xbaec0ca08efbeecb, 0x3e6a4339e5f906ee), (0x3aa7971bb866b080, 0xbe1541c07333f998), (0xba57a16f0ea87b71, 0xbdf86c0bb112e482), (0xba36e61435a1cd00, 0x3da35fba37d1f734), (0x3a1f20691ce23042, 0x3d80700770cc1156), (0xb9b992380621d60f, 0xbd2963b2030905ef), (0x3994c48a74316e13, 0xbd00c5877018b95c), (0x3934c66edb676868, 0x3ca91e0b94a51ae6), (0x38d882f89d4daaf7, 0x3c7adb6f4a466e65), (0xb8ce178a661e3146, 0xbc2373e4dad053be), (0x388de38db781365d, 0xbbf155ead1bcc6e1), (0xb838caf4a70bed71, 0x3b9843ad83497bad), (0x380a61496dc04a9e, 0x3b624dcba30b4ca7), (0xb7a04207f42b18e2, 0xbb0975abfc72009f), ], [ (0x35e086b1188ee76d, 0xb9659deaf309da6c), (0x3c4a4f96a2520bb6, 0x3fc8077f56c9b782), (0xbbf97f76587fbf04, 0xbf75467eb535deaa), (0x3c28681fd3a1f1d9, 0xbf9fd7c3ad6f59e0), (0x3be0e0f0ccefc77f, 0x3f4c1b47c809c5eb), (0x3bf6295d17ac5a65, 0x3f59166c7d3eaa7c), (0xbba4cf4874f894a7, 0xbf05f0152478f5f6), (0x3ba861e7bdca105b, 0xbf02aa939fd9fc9b), (0xbb5e0f4929f81ac1, 0x3eb0129708ec2410), (0x3b439423523353b8, 0x3ea01716dc9f2e1b), (0x3ad0e7c543b4566f, 0xbe4b227eef409a9c), (0xbadfc64557b91f43, 0xbe32101c49d611c3), (0x3a7be06eedb88596, 0x3dddb1e8b7adba58), (0x3a037d51b581b88f, 0x3dbc80aab1d93238), (0x3a04fb2f6b0c475b, 0xbd66c2b17ab70f1a), (0xb9e88a8587ab97a1, 0xbd40ad5f60b5515a), (0x398a5248c0478c2e, 0x3ce9d02ffd43b4b6), (0xb92666b9cd4e8f2b, 0x3cbe1eda1d7f5a91), (0xb8f1b085dd83117e, 0xbc668e7624b57aed), (0xb8d7b1a60f9f9ddd, 0xbc35a3dd86c4185f), (0xb803b25228593cc6, 0x3bdf559780a6bb0e), (0x382586b97e4f1ff9, 0x3ba957aa7a9d5cb7), (0xb7ed5614f18b6bf3, 0xbb5198d0c1cebd10), (0xb7a8382c4740132b, 0xbb18a72411fe5ccf), ], [ (0x3c62da0057f84d3b, 0x3fc70c511227d5aa), (0x360a5b28d6094082, 0x397cbdb54d06802e), (0xbc52da0057f84c9a, 0xbfb70c511227d5aa), (0x3bfe726f7024dd2d, 0x3f5910ebe1f1cbcd), (0xbc0e61277df378de, 0x3f7e7dc08e70e99a), (0x3bb740aae8c42ea9, 0xbf23bd7d159e09a5), (0x3bc9abf1335e8790, 0xbf300357a187375c), (0x3b7cab6494ed67eb, 0x3ed5ec73302455b1), (0xbb76a67dea84dca0, 0x3ed1e5d2836c8d99), (0xbad181196d149707, 0xbe78f41b94dfba1f), (0xbafeb3021d837aa6, 0xbe68c11aada79ae8), (0xba8510c3ac160a0a, 0x3e1141423452a28d), (0xba892fee369915f4, 0x3df73ef6f4772770), (0x3a3b488b50613a1c, 0xbda007403efd2ccd), (0x39f5bf6b3205778c, 0xbd7f93ab666786fa), (0x39cec570d9db2fc3, 0x3d25638d0e0e19b5), (0x3992830e7334f62d, 0x3d003d05920debc7), (0x3928fcb1f53c1973, 0xbca5832b6cec0d11), (0x3905c27fab0794dc, 0xbc7a2e88dfea664c), (0xb888ccbe8e25c424, 0x3c20e8847ee36bf7), (0xb88b102ba2ef2315, 0x3bf0ff53969fee86), (0x380e372a38bcf693, 0xbb955dc67acbb8c1), (0xb7f237d40b294b7a, 0xbb62083f7d27b5d9), (0x377966f003d521c9, 0x3b06a16c733cdfe2), ], [ (0x36043fe2f5037bf7, 0x39714ccaaa6fb0d5), (0xbc6444d3d89ac012, 0xbfc62d93aa9d05bb), (0xbc1afb8f729bef14, 0x3f70ba9ce88929f2), (0xbc2f64ee23828443, 0x3f9d7073daebb02c), (0x3bd6ad884b6c9520, 0xbf462813c7f58733), (0xbbc1c5da6149803a, 0xbf574a948d05638e), (0x3ba7816473a6692a, 0x3f01695765f13bbf), (0x3b9157b6b65ca494, 0x3f0170ab5eeb0e4e), (0x3b2716b17d28be20, 0xbea9c8e418a20315), (0x3b394c2374daaa73, 0xbe9e4d893dce335e), (0xbaef0ae11c684392, 0x3e460f73a6ccb16f), (0x3ad9ae1edaadae80, 0x3e312782f0f2448a), (0x3a51af0d933062c5, 0xbdd881d5842ec66b), (0xba56bb5ed05dc669, 0xbdbb4c521a31613b), (0xb9fae678b88ed7b7, 0x3d63132da6b9e700), (0x39d7ed04f36de95b, 0x3d4019364d866ae6), (0xb97cfaa457ac4250, 0xbce5f4ab6157e7be), (0x394e31d3157f8b40, 0xbcbd47ca9a1247cb), (0xb90d596ff8cf14c9, 0x3c6373719443eb4a), (0x38d15089179a9756, 0x3c352a81aa5252ec), (0x387db4c0fd37289a, 0xbbdb5bf6bb6be367), (0x384ae6b921aecd05, 0xbba8eb04a93528a2), (0xb7e3e44a16c09699, 0x3b4f12507c54bef3), (0xb7b95db3cb024c97, 0x3b184f56b858ed01), ], [ (0x3c6a47ab4241a9f5, 0xbfc5664e13b70622), (0xb5f760d6e0df5525, 0xb96a27b55db95023), (0xbc5a47ab4241aa99, 0x3fb5664e13b70622), (0x3bddc134f1d56911, 0xbf540ee3940b092f), (0xbbffe75afd61d48d, 0xbf7c5e1ad9fb2f40), (0xbbab8661007349b1, 0x3f1fb8a98ef4a243), (0xbbc018bee0f9b515, 0x3f2de9be58a373e2), (0xbb75089c8e88074b, 0xbed1bec95415e630), (0x3b44800f434e8417, 0xbed0cf264341409e), (0x3ac78de205cc4cd6, 0x3e74677d9e214cd4), (0x3b022bc30f064717, 0x3e6766cc63507104), (0xbaa2f651c24f2d57, 0xbe0c905882b94f65), (0x3a9112b75a40b2a8, 0xbdf62157963573da), (0xba20399ceae10199, 0x3d9ae2e0cbb67b5c), (0x39ff975d6442b115, 0x3d7e456a1c8db625), (0xb9a84aef2f5c2b19, 0xbd222e473663eea9), (0x399ffbe46660f083, 0xbcff56a09d8cd619), (0x393107311db89703, 0x3ca28607cd9d833f), (0x391393d18c89b7c0, 0x3c796a2f1da7d934), (0x38935c8a666a0b0e, 0xbc1d78e9ab2b3109), (0x386087d39d98f4be, 0xbbf096321470c83b), (0xb831ea93ce0d9c89, 0x3b92d4333620b1e7), (0x37b11cc0e6a17b7a, 0x3b61ad4cac5f830d), (0xb7932d42d34590f1, 0xbb041e3c367ed3b2), ], [ (0x35fb617f2a7d3e44, 0x39534fd9c53767f3), (0xbc6e5d93454f99e3, 0x3fc4b2a2ebf61ece), (0x3bf37b02bd5f62b0, 0xbf6b3297fdae7902), (0x3c2eb354a631372f, 0xbf9b8105d59b114c), (0x3bb9bab613407fc9, 0x3f420a3f8c12a1ff), (0xbbf48ec1e2f4d8eb, 0x3f55d18d69de6cfb), (0x3b0ad3357483176b, 0xbefc79db4b341e8e), (0x3b70c0983bb2f771, 0xbf00679c92c303b2), (0xbb4af53c2daf664b, 0x3ea53ac4ecd4be2d), (0x3b3bd8bfa73be7aa, 0x3e9ca7507840c04b), (0xbadae384e855ecf8, 0xbe4253415f09767a), (0x3a835115b77c34b2, 0xbe305141505c9f00), (0x3a6c4c5d652bb599, 0x3dd4919940f05334), (0xba58b3871fdc4174, 0x3dba20de95780e2b), (0xba0a69548bda3e7f, 0xbd602fff3daab710), (0x39d417d75702d45d, 0xbd3f01d18581c5a9), (0xb9753674cf72aa69, 0x3ce2d78e0d8458c3), (0xb9203e6bf52424e4, 0x3cbc5cc76fd7614d), (0xb8f39cb8f8a8d557, 0xbc60e0077908e478), (0xb8cd5838286ea7a4, 0xbc349c9cfabd7bb7), (0x381968d8765f42f8, 0x3bd7fb4989ff942e), (0x3844cfbad0863c18, 0x3ba861a8f70eebaa), (0x37deeff465dec1db, 0xbb4b7ea330f8d706), (0x37bb0df82dbf52ea, 0xbb17dc3e59fbd2b3), ], [ (0x3c6316f8ffd294bc, 0x3fc40f90793605bb), (0xb5bc63171f8ad7f8, 0xb95cae2e73fe7fb0), (0xbc5316f8ffd29417, 0xbfb40f90793605bb), (0x3bf7017919c19ee3, 0x3f5085775a5529c9), (0xbbe51eb6f0b3a2c8, 0x3f7aa0ce0421d1a8), (0x3bb34ca5a9d8eee5, 0xbf1a32a28e4bc82e), (0x3b829f8e74c703e7, 0xbf2c26ebca0e46de), (0xbb655ef820b8ed31, 0x3ecd7400876206d0), (0x3b4cb530be3f4c97, 0x3ecfc1bbf57e3ae2), (0xbb1b043cc6acf5d6, 0xbe710c7090487d3e), (0x3af031f8178d9744, 0xbe6634db39e4a305), (0xbaad7fb323c3df7f, 0x3e0810d7e4efab4a), (0xba9ee3d784feb6b0, 0x3df51b513b3c4cef), (0x3a2790b6bc250dd4, 0xbd96dd877beb37bf), (0xba19b6fbdfe4281c, 0xbd7d06057acf8fa0), (0x39a09d743019f4e9, 0x3d1f3b007c5421d0), (0xb994cbeda4661eeb, 0x3cfe3418121e09f1), (0x394f465df58cfe59, 0xbca0119136910e8f), (0xb91cf9a0016f1fe5, 0xbc789daf5f18a5af), (0xb8a09684e33e70bf, 0x3c19d09d89e3d4e7), (0x389e2b54b001cc6c, 0x3bf023a06c8fea08), (0x382b986bb50f84de, 0xbb90a4fdf6b47d26), (0xb7fdb60c46ef0002, 0xbb614563ff0bb2b8), (0x37a20bcc61b90c31, 0x3b01ebc30518711a), ], [ (0x35f3364fd9d34cb1, 0x397482cca2804d57), (0x3c5948539688f9cb, 0xbfc37aac8c1aeabb), (0x3c0e1b9871576171, 0x3f66ac0d2e2f2f87), (0xbc3e2c9f8f0de37f, 0x3f99e74e754ea71f), (0x3bc834f162077a01, 0xbf3e1c0589e32bb1), (0x3bfe8b15bd171deb, 0xbf5496158dc5f7ff), (0x3b66422ba8f591b3, 0x3ef7d55405348ca9), (0x3b913888244cb67e, 0x3eff0b30f4506228), (0xbb49c57ec3fb6664, 0xbea1d9e3629b98ec), (0x3b31cbbb1f5801f4, 0xbe9b35ef28e9de24), (0x3ac3a4c0891c58de, 0x3e3f0200e2650870), (0xbacbfc59e2173110, 0x3e2f1fb225e849cb), (0xba74d0e4dbfc0552, 0xbdd187928a64d03e), (0x3a28ff960c8419c5, 0xbdb908ba84482af5), (0xb9fd78b0c3058f80, 0x3d5bd0a97427d7c2), (0x39b4f3422c873b72, 0x3d3dd98a1888d3c4), (0x398676253f0dc67e, 0xbce05368fda435c7), (0x3954262b278fb382, 0xbcbb6e7eba338096), (0x38f1da524082e61d, 0x3c5d7e5c6064299d), (0x38dbb3c7ca9d7c4a, 0x3c34063c1ddae8bd), (0x387e4fa2050cb586, 0xbbd521e70bcccf02), (0xb83b4d316015135a, 0xbba7c8f868314c63), (0xb7a6a57c7316cadd, 0x3b486ba7bc735663), (0xb76268b35420b1c6, 0x3b1758996990291d), ], [ (0x3c689d1f48185c7e, 0xbfc2f2072e638cf4), (0xb5ed38c4f6890952, 0x394461aeca52479d), (0xbc589d1f48185d20, 0x3fb2f2072e638cf4), (0x3be64a78bbba5f88, 0xbf4bd42b64fc5bed), (0x3c082c4cf0185189, 0xbf792bb5e1e159fc), (0x3ba0f7052d2216a4, 0x3f161ace3386dfd7), (0xbbc911bb7e9afeac, 0x3f2aa8d1cf8db852), (0x3b53e6d52ff3d031, 0xbec8ef624c36fc32), (0x3b54f2165ec886a8, 0xbece26d3747fe829), (0x3b0ba49dcf5f6fd0, 0x3e6d010d2bdb6fa2), (0xbb091b80aed15c31, 0x3e65272828ae4057), (0xba8eb72fbfdc3a74, 0xbe0497b03c4482e4), (0xba9363f2627d714a, 0xbdf42e35495a0b9c), (0xba32072f1fd852bb, 0x3d93b2e62efa9f34), (0xba1e4f176dd7ecab, 0x3d7bdc7867dad736), (0xb990e20c6ed58c22, 0xbd1b1acb454d4a67), (0xb99fc3000cfbbd47, 0xbcfd1ce799670eb9), (0xb92e5f75bbb7af1c, 0x3c9c1b1fc9d584de), (0xb91578e77423719c, 0x3c77d2b95397d836), (0xb850bafe09573a49, 0xbc16c0325b1f55bb), (0xb870fccd3a2e4892, 0xbbef5c231492c633), (0xb81afdc499b9ae20, 0x3b8d8f129e22a179), (0xb80d2a72cf226d5a, 0x3b60d71423839ff2), (0x37a376b0e7e390a2, 0xbb0004820cb21317), ], [ (0xb5fe7034a738c57f, 0xb965d89919797608), (0xbc389c717cff1eb2, 0x3fc27407dfadee6d), (0x3c01b3998e256aba, 0xbf6346950bfd91f1), (0x3c3dd532243e7bdf, 0xbf988d48d1d4eb7b), (0x3bcf03d11acc3cef, 0x3f399e6923ada922), (0x3bf2c9a985d24428, 0x3f538984b76cdf4a), (0x3b96fc0cd00a1e02, 0xbef452194b75f3c7), (0xbb929abb89c807a0, 0xbefd855d7b8f0243), (0x3b33da403d28aa47, 0x3e9e8a88601ff296), (0x3aebbce16fe837d2, 0x3e99f1bd69b16e6b), (0x3ac9d47900ce737a, 0xbe3aa483fce054e3), (0x3ac5507ea35951eb, 0xbe2dc4c02391c504), (0x3a50d4172d38a515, 0x3dce48dc1b4db78b), (0xba5adebc7a9a6eae, 0x3db807112e663700), (0x39be45131e2d0e10, 0xbd582c0e5f51a78c), (0x39d352a7d1eff8f8, 0xbd3cc1592707ba1f), (0xb97498b39d0e69d4, 0x3cdc8f29e77a7dbc), (0xb95f8164e5aa870e, 0x3cba864ef2011d61), (0x38d4d82995e917f3, 0xbc59f854a17b0eb3), (0x38c2b397d698e08f, 0xbc336efc952890f2), (0xb85e61d1aea7560f, 0x3bd2bbab562fd018), (0x3844a8bee87edfd3, 0x3ba72a2cd621b87c), (0x37b0634af3b51b0d, 0xbb45ca2b0c668e28), (0xb786436234762b46, 0xbb16cc8b2df45666), ], [ (0x3c51f9b16832f362, 0x3fc1ff5eec6a01cd), (0x3608538a42387313, 0x39703f488735c3d2), (0xbc41f9b16832f226, 0xbfb1ff5eec6a01cd), (0xbbe5f2ed43d916df, 0x3f47daf64983af9d), (0xbc19a4b7b3f004ae, 0x3f77ed5fffc1c774), (0xbbafa9d6f36c74e4, 0xbf12f947962314a1), (0x3bba27856fb2a3d9, 0xbf296027ea1d6e5c), (0xbb585d62c36dd030, 0x3ec57486c67fbc78), (0x3b6dbac7c03738c9, 0x3eccc11a59e13739), (0x3b07e8342468c4ca, 0xbe690ade515567ae), (0x3aff414d51e7ab0e, 0xbe6438a7e22c9734), (0xbaac64a5bfb76d87, 0x3e01db6d29a7d049), (0xba7a7ab522e094b3, 0x3df3588cd2990098), (0xba353be57bfdf484, 0xbd912b3d3f46a156), (0xba024df787236d46, 0xbd7aca95934e0225), (0x39b4eea5a63388b9, 0x3d17c19e5c2accea), (0x399da5ae5c22cafa, 0x3cfc15e96b11e6a8), (0xb91064ad2d23f659, 0xbc98c7e06936a2ce), (0x391a3907b000a135, 0xbc770ecfa1a29de4), (0xb8a29f60e2d525d6, 0x3c142e96cdb6412a), (0xb84a16ff92e47bb9, 0x3bee735a654a68e5), (0xb8292e46bf7abeaa, 0xbb8a61d3cc01d06e), (0x37f75c146bd04a11, 0xbb6066ff09d84644), (0x3799d2dbdc6509c3, 0x3afcc034864d659f), ], [ (0xb5eb961d9912b9a7, 0xb9682c6f4767341f), (0x3c6f5f4b08a76fd4, 0xbfc192f23ce3e051), (0x3bdee957b8601e17, 0x3f60a668185c01b1), (0x3c39de5fb6906b20, 0x3f9764141d652089), (0x3bd0a73bf174fe85, 0xbf3624437a2fe76a), (0xbbe29f0dad78a87f, 0xbf52a184be0d9891), (0x3b9224756b415cd4, 0x3ef196de0eeef190), (0x3b54bbcaa68c5293, 0x3efc317f854112ad), (0xbb3c48e804e50119, 0xbe9a8019ef772196), (0x3b1fa8a6e09c6db9, 0xbe98d38497beea33), (0x3ad0d50082f534e7, 0x3e37318410813eeb), (0xbaa0ab33bf6dee66, 0x3e2c8d9d45d76323), (0xba5370b8aa12ac53, 0xbdca782c1acc5d79), (0x3a50c665c12ff6de, 0xbdb71bbb74f830ec), (0x39efa2e983abd5aa, 0x3d5539502b6b020f), (0x39c79df656360a67, 0x3d3bbc22cd6efb9f), (0xb97de689090afaa9, 0xbcd933a6400afa8f), (0xb9538df7643bec5c, 0xbcb9a8f9bcb96916), (0xb8f3ea053f8219b5, 0x3c5709ca7b2dbe67), (0x38aaa5e94cc9a9ff, 0x3c32db59b4212a49), (0x3875dd42a8ae8eb2, 0xbbd0b55ba2bce2af), (0x384f96f41944caf5, 0xbba68b427859d5fc), (0x37ed698b1a87de93, 0x3b438a193d38c988), (0x37becfa942bd3543, 0x3b163dbcc0f4e249), ], [ (0x3c6e71c482be67be, 0xbfc12dd57bf18ada), (0xb56ade05c8d02fe1, 0xb8f86dd1ee1cd4b8), (0xbc5e71c482be685a, 0x3fb12dd57bf18ada), (0x3bd11b1ac52c9e63, 0xbf44bebeff7b7f02), (0xbc1286f932bc06e0, 0xbf76d9afe88301fa), (0x3b859ae05ee9b9e1, 0x3f10842d50687949), (0xbbc5025e9c48ddf7, 0x3f2841d86b9b92f4), (0x3b45bc8a5bed0a88, 0xbec2b5caad1f2b9a), (0xbb3770fdeb5f4fdb, 0xbecb86bad42fc220), (0x3ac419e306d0b4f6, 0x3e65e5117a965bcf), (0x3b0715f2ca682ea9, 0x3e6364a25cc7309d), (0xba8789a8788b4eb8, 0xbdff53dcc9459e76), (0xba7a9cb0ee97c39b, 0xbdf297f421bb27b9), (0x3a21251ff8e8e5fd, 0x3d8e3c9c7289c6c0), (0xba04a1e2968b5e32, 0x3d79cfbae2bdb794), (0x39a8e2edbbc6a796, 0xbd1502858f3b96b9), (0xb99b52142daa6d4d, 0xbcfb20c42e50d24c), (0xb93206530eead3e5, 0x3c9604b999fb92e6), (0xb91d665f1b08d083, 0x3c7654b9ed136fab), (0x38820031c752db33, 0xbc120524ce30eaa4), (0x387abcba8637daf2, 0xbbed91d6a951e05e), (0xb811548ed562e5dd, 0x3b87ac7727dd5787), (0xb7df152483a30c1d, 0x3b5ff0620f1479de), (0x37930d38ec1cefd3, 0xbaf9eb53c9bb31d6), ], [ (0xb5b3453ff73e0bdd, 0x393fd7d1a10c14b9), (0x3c53f099a5f56db3, 0x3fc0cf3ed059c573), (0xbbff3cb9b807f03b, 0xbf5d242aa529931c), (0x3beb544962a1902a, 0xbf96613d93b0180b), (0x3bde039e228ed279, 0x3f33627f261f5116), (0x3bf7fb39963e2efc, 0x3f51d69ca0d88394), (0xbb384fc08b8a0bbe, 0xbeeed574afab70fd), (0xbb95a4431994f7ed, 0xbefb06384e48ee5b), (0xbb387c5180387ee8, 0x3e97452c65235728), (0xbaf8807a182da1e9, 0x3e97d51f133b6843), (0xbad80ae2bd8213ae, 0xbe346ac67a7e0c7c), (0x3ac7244b550b1780, 0xbe2b75d66a8d7fbb), (0x3a669cb8e5bcff01, 0x3dc75f5a5db478e9), (0xba5afd0a5423da82, 0x3db64531ca4ef465), (0xb9fa4a2410291e1f, 0xbd52ceac14a86241), (0xb9d685e38c55ad6c, 0xbd3aca497ff207d0), (0x39542d374b775a5a, 0x3cd66b96eb099cc5), (0xb9597fd736e29864, 0x3cb8d889b2e1f475), (0x38e51f4f682fb00a, 0xbc5494fef4e26442), (0xb8cc652bba3e525d, 0xbc324dc25f106529), (0x380c5c0722c461e5, 0x3bcdfc3c890260b7), (0x38473d4459e77144, 0x3ba5efe49281d368), (0x37d76e1dde8d0fdc, 0xbb419c5b516958d8), (0xb7a6d50e7f01d17c, 0xbb15aff74e510abf), ], [ (0x3c61a13e2fee5687, 0x3fc076826cc2c191), (0x35fbed7a3ebfda21, 0xb970a6aa5adc8d66), (0xbc51a13e2fee55ee, 0xbfb076826cc2c191), (0x3be79f62aa4912e7, 0x3f4241b03eaaf5d9), (0xbc15dbe9d7239a1e, 0x3f75e7f53001e4b1), (0x3ba5f4ab60853145, 0xbf0d17978e2d0336), (0xbbb79a682db866ff, 0xbf2745b0df80666a), (0x3b63b65170c03680, 0x3ec0803f7f7fe323), (0xbb5016bca9a839cb, 0x3eca7006e6ad9cfe), (0xbb09b83b761c8dad, 0xbe63590d57d48525), (0xbad1e26a947a9c23, 0xbe62a7084b42b890), (0x3a87e1ccce8475a5, 0x3dfbc0dd5a22c9a6), (0x3a7031ad9111bbe1, 0x3df1e9e4e20477ca), (0x3a2e94263a9c2435, 0xbd8ade1de2460f0e), (0x3a12379dba208e28, 0xbd78ea3bc5e5158b), (0xb9b0319572048e91, 0x3d12bb86a88d447a), (0x399493366981bd01, 0x3cfa3d6bcabdd7ff), (0xb936ae36a8b153bc, 0xbc93b47615e29aea), (0x391e0fe4bfd67f75, 0xbc75a597f7583751), (0x38b24cb1a71df570, 0x3c1030bba99bb5cc), (0x387b1b9ba6d62368, 0x3becba423ca5f9ce), (0x37e762b30a8a5a4c, 0xbb855b595b5871b2), (0x37f25ff71c04c351, 0xbb5f1916ebc1bb1a), (0xb79220ba6f90a9af, 0x3af7791a566a7a85), ], [ (0xb60c6a70e175e648, 0x39735f9916d9837d), (0x3c665439df5bb54b, 0xbfc0230b9797a7b3), (0x3bd7d914863d8b85, 0x3f59c8083b2b753a), (0xbc3c455b2fe15157, 0x3f957d3203befd90), (0xbbd3de5214d61226, 0xbf3127cba22892de), (0x3bf0c5ff9d68abde, 0xbf51234471455a6c), (0xbb8a9c283025b635, 0x3eeb4fe26ec3e489), (0xbb9cd17c61f89721, 0x3ef9fc5254f1086c), (0xbb3a464f70c3c823, 0xbe94a44c6506c43f), (0x3b3f504de9997bea, 0xbe96f17dd184ad59), (0x3a90aecf258a5953, 0x3e3225640a6a9328), (0xbab85c7b0680994b, 0x3e2a7943505d15ed), (0xba6cf77c6abfe37c, 0xbdc4d296ecea7b5b), (0xba3e0d08073ac67f, 0xbdb58177059b1ee7), (0x39fe64bae160ea42, 0x3d50cd71be541f6c), (0xb9de66ddc4c43f8f, 0x3d39eafac486df97), (0x397f8cdc2afe705d, 0xbcd417df1a7faedc), (0xb9481c4ab05db957, 0xbcb81583d8826b2f), (0x38d9d79064997308, 0x3c52822e1fc6fcbb), (0x38d8493a5a515ee9, 0x3c31c75f9746b7f8), (0xb85d87e0134de425, 0xbbcb0fab39bb8bfe), (0xb830a586be8798a7, 0xbba55a2deec91831), (0xb7d2c2b65fcec4b3, 0x3b3fe74d126342bb), (0xb796cef3b221776c, 0x3b15259d7309762d), ], [ (0x3c5d7cc4171715a0, 0xbfbfa8b41711c83a), (0xb60ba9b9f91fb8b5, 0xb966589e13c65233), (0xbc4d7cc4171716ca, 0x3fafa8b41711c83a), (0x3bca510f3e4d422a, 0xbf403a8d0f110fe1), (0x3c195ccf34ff059f, 0xbf7511c6dadaaa12), (0xbb6fad55d0eb473e, 0x3f09e040fc62c87e), (0x3bb45c7340135a79, 0x3f266582f66d8d4c), (0xbb2c8a3f0d0d8730, 0xbebd62a18e287536), (0x3b667f97c31286c8, 0xbec976fb023f0f79), (0x3b0f3da3b757dc00, 0x3e6141188eda6cd5), (0x3afa50d6da64db1a, 0x3e61fc77546c2a70), (0xba85cd99748ec679, 0xbdf8ccadf7842b28), (0x3a8f0a159918c910, 0xbdf14c0515097ba8), (0x3a267994041e70e6, 0x3d8810b7fe5b7b00), (0x3a19f29d974623dc, 0x3d781814784424c6), (0xb98d0230bc946bce, 0xbd10d30b1ed751e4), (0xb97b8f89dea8e8b4, 0xbcf96afe8202dbff), (0x39286258642b03cd, 0x3c91c038ce19ab04), (0x38e5014a0308a5f1, 0x3c750195ff9477a1), (0x3877348a77be6ba1, 0xbc0d437455c82ee5), (0xb8854f0f0926b218, 0xbbebedd520bd61e5), (0x3802b652644462a2, 0x3b835da91ec0fb79), (0xb7f3b739a177a033, 0x3b5e4a41b6b72b80), (0x376f5eb22e1b1ed0, 0xbaf55a9e0c921524), ], [ (0x361a1ce3816c12e9, 0xb970a7cb3e4926ce), (0x3c581bdf89b0a8b3, 0x3fbf13faf32c8e0a), (0xbbee91046256adc2, 0xbf570558dddb7d46), (0xbc326d6d43908d73, 0xbf94b24d7a933972), (0xbbb5423c2dd21ed6, 0x3f2ea52a21487a11), (0xbbf33353f1356cea, 0x3f50834d8f3fdd5b), (0x3b8f2ed187ec8c27, 0xbee86941a4b43bea), (0xbb93d844185ba20f, 0xbef90e32cef3e900), (0xbb24c412e1beda17, 0x3e92785f6385b273), (0xbaf58ee8d31f36a8, 0x3e962482bf9d2bb8), (0xbaaf8eeab1cf99c8, 0xbe3043125386ac84), (0x3acbaa01c1b653ac, 0xbe29943c303e31c2), (0xba66220f22c18b8e, 0x3dc2b2457a1921af), (0x3a5711c244de4ccd, 0x3db4ce82afcbf543), (0xb9d04d4e5a872347, 0xbd4e3dcde42d3546), (0xb9df1485d764cf0a, 0xbd391cdf33ca545f), (0x397020766d9e2bc7, 0x3cd220c06f47b251), (0x3941d73392b94dde, 0x3cb75f9d03c7dab4), (0xb8e752a11f1ff8cf, 0xbc50be9727e162d0), (0x38c8623cee5ad9d9, 0xbc31489750bef0f5), (0x384f066486611d86, 0x3bc88de9469da922), (0x3839422334460fd8, 0x3ba4cb353920bd3f), (0xb7d635c8739b1cc3, 0xbb3d0958e2b20819), (0x37b805c0dbe5c052, 0xbb14a01af94d0b34), ], [ (0x3c0020b4016594a1, 0x3fbe8727daa3daed), (0x35e429e6f0925013, 0x3954c091fcd570df), (0xbbf020b401657018, 0xbfae8727daa3daed), (0xbbae628434cc3c70, 0x3f3d19c52e070d9f), (0xbc1361836c55971f, 0x3f74524d4813cc25), (0xbb7cb5b9b349156d, 0xbf0735f790b535f3), (0xbbcfed1fa3bfcdb7, 0xbf259c8f9f0a3484), (0xbb45b8645b0be816, 0x3eba619ffc5a3ad0), (0x3b695223039dbc70, 0x3ec896d7dc819faf), (0xbaad000c2e45e4dd, 0xbe5f04efbdfeacf4), (0x3aff55bb37d4ad1a, 0xbe6162253f3024f4), (0x3a774121f038cc79, 0x3df653d736c3ef75), (0x3a97cad085bd78e6, 0x3df0bc406f716b3d), (0xba1b1362e426bbf6, 0xbd85b5420be0cc8e), (0xba06a1118f4cd431, 0xbd77573e801c920a), (0x399a08aaec9f5f5a, 0x3d0e6b725d3bea39), (0x399f56e3dc7cb7dc, 0x3cf8a83e6e3a037e), (0xb932a9c0fdf0215f, 0xbc901633974b8728), (0xb90da8cd34f16ed9, 0xbc74685bc5b412ab), (0xb89a26475fca50a1, 0x3c0a9719b6c2c317), (0x3884ebc520e017d9, 0x3beb2ce5154261a5), (0x381bbed6afb225d9, 0xbb81a55f76501009), (0x37e01b88fc0ca8c4, 0xbb5d84f510d0e5db), (0xb77f816f7a76ffd2, 0x3af38293e0fae553), ], [ (0x35f7b4ea1935a568, 0xb956dc89f8b0297a), (0xbc5a45a53b37a59e, 0xbfbe018d99f5da1b), (0x3be001e9c4dcec6c, 0x3f54b85897b36265), (0xbc32db4ef382192e, 0x3f93fc442153435d), (0xbbcf201dea1f5a71, 0xbf2b9694d71486e3), (0xbbef8e2381bad736, 0xbf4fe6fdc644ddde), (0x3b87d6d0d3615a87, 0x3ee5fd096e4523fb), (0xbb6b106322d36ddc, 0x3ef83770c9a84498), (0x3b3a40e2b2746cab, 0xbe90a6f6f7e05f1b), (0xbb3f771adc91215c, 0xbe956ad4a35eb0ad), (0x3ab3b86f94e0c858, 0x3e2d5bea474ca54f), (0xbac5585b134469a5, 0x3e28c39f68d21b3c), (0xba690d5e5a6b3a35, 0xbdc0e73408ce7d83), (0x3a327165e3e97d3a, 0xbdb42a6dedaa1a20), (0xb9dd142a729ed644, 0x3d4b640f953ca9d2), (0x39d7f71ecb3fc409, 0x3d385e74fde5cbdb), (0xb97b8a515f767ea6, 0xbcd07409455800ac), (0xb95ec4cbe35c9396, 0xbcb6b62242767fd2), (0xb8e317bb80a9622e, 0x3c4e76f4a5aa2684), (0x38b554cbd013807d, 0x3c30d15ee339d044), (0xb8101586ff6d60a8, 0xbbc664451d8e4e4f), (0xb849c3a261353029, 0xbba4436d1959e4e5), (0x37b47984bdada57e, 0x3b3a8bfe9a4ae941), (0x37b807503fdd6126, 0x3b1420356bcc7e9f), ], [ (0xbc5cb1f28997ca38, 0xbfbd8293aa55d18f), (0xb61515229b393b76, 0xb9729d22385eacde), (0x3c4cb1f28997c91b, 0x3fad8293aa55d18f), (0x3bb680f417a90d4b, 0xbf3a48fe4afedcc8), (0xbc16c091c5e058be, 0xbf73a5ccbc12a67b), (0xbba33c90d0f9c0c9, 0x3f04f91e41eee9bc), (0xbb9b30874f0a2926, 0x3f24e72224db2c0e), (0xbb169858252daef6, 0xbeb7dac8202ad4fb), (0x3b63726cbb3fc903, 0xbec7cbd49c315be0), (0x3aee4734322f57a4, 0x3e5c1396b62b0f84), (0x3af3c6385c4eb2c7, 0x3e60d5c64a9c427f), (0x3a70141b0643212e, 0xbdf43c4a5d5a74a1), (0xba8fd98f49242c47, 0xbdf038cb3f5e3248), (0xba158fe9d08d69ff, 0x3d83b473da8d9cc0), (0xba029334408e97a4, 0x3d76a5d59f9a7a17), (0x39ad9590d69212ea, 0xbd0ba9a1977eefff), (0xb971f0fe79a4cdf4, 0xbcf7f3d211c66187), (0x391950769136ef0f, 0x3c8d51075a5e7bbb), (0xb916720d8484ea73, 0x3c73d94e734e8879), (0xb892e80fae65fb53, 0xbc0848485fe35579), (0x38777f0c4d7b3dfa, 0xbbea774325d98b75), (0x382276ef09c2242b, 0x3b8026f3af966377), (0xb7f67847065ac7b4, 0x3b5cc9941483fe56), (0x377a99585b78b747, 0xbaf1e6750f0747ba), ], [ (0xb6025c847eb79bd4, 0xb964158ebf13126e), (0x3c5f215e77086bf5, 0x3fbd09b210b30217), (0x3bfc1f6fd559ba97, 0xbf52c74f6d120291), (0x3c0587bb3b3049ff, 0xbf9357bfc2be5860), (0xbbca26f6fb3da340, 0x3f2901e4c495acea), (0x3bdfa22468c1def8, 0x3f4ee2a36979f905), (0xbb819f063106cdcb, 0xbee3f0cb93a497a4), (0x3b845c631b76c8a1, 0xbef7748921871bcc), (0x3af9b751dac720d1, 0x3e8e39a085fc522a), (0x3b168e67fb0cb203, 0x3e94c1b7a6b2509f), (0xbaca52721df6c6b6, 0xbe2aabe92ddd7d73), (0x3ac84b97b1182cc0, 0xbe2804c5ad3234f3), (0xba54edd49d1edf2d, 0x3dbec02b4af63baf), (0xba503f24cfdd22c9, 0x3db3938387c8ea5e), (0xb9ee5637ec8cd309, 0xbd48f3df4c86043e), (0xb97c878aca76d363, 0xbd37ae3cd67c3185), (0x3953bf1f530af427, 0x3cce075e0947f84e), (0x394a5c410c455b26, 0x3cb61833a4ed09fb), (0xb8d6421dd6abfed8, 0xbc4bda71bc7ca99f), (0x38d6cb9f7285a2f3, 0xbc30616da73cfd68), (0xb860f21809293998, 0x3bc483adcba31a64), (0xb819a874856663c4, 0x3ba3c2e3aaaa861b), (0x37d51466fd699b53, 0xbb385faa94578a21), (0x379f3946f24c4995, 0xbb13a642c5cb638d), ], [ (0xbc49df1f0f8d2108, 0x3fbc96700bf039e2), (0xb5aa78cc35dda805, 0x393def6cb4dcf261), (0x3c39df1f0f8d2339, 0xbfac96700bf039e2), (0xbbb8cb9fe6e3ff6e, 0x3f37e5647d30fea8), (0x3c063977044d6f5c, 0x3f73095734a24496), (0xbb56346fb6ed118c, 0xbf0312a4db537d5b), (0x3bc2ab35d69fc6e2, 0xbf24424a96e62373), (0xbb5dc2fb5a697d64, 0x3eb5b4a6639fb7be), (0xbb533dbdb81ff3d8, 0x3ec712e4d44c4a74), (0xba8ccfbfe857180a, 0xbe59917dedf003d7), (0x3b0b894b3c8075c7, 0xbe6055757b098917), (0x3a95a6cc3450560a, 0x3df2728cdc02e18c), (0xba805244323472ea, 0x3def80393fe2fc7c), (0x3a2d37e6a4cca504, 0xbd81fcaa37a8b3b3), (0xba1bcda846633c8d, 0xbd760225681cce6f), (0x39a7e3fa90942e91, 0x3d0949ef9ee67213), (0xb995a2c090d0fa89, 0x3cf74c654a150fde), (0xb912f420e2959c3d, 0xbc8ad88e52941a98), (0x39086b9adf654b32, 0xbc7353b6bf507102), (0x38a54a053e9cfe0f, 0x3c0646e8a6aa6dbe), (0x38174c918b573c6f, 0x3be9cc769d138c5f), (0xb80b75e9f287b65e, 0xbb7db1eb4b8463d9), (0x37f46072c5cf6b31, 0xbb5c181474bdc517), (0x379310eb69ece94f, 0x3af07ca4c538ae49), ], [ (0xb6025d7555eb3333, 0xb96e6cb57bbffe78), (0xbc37a2663626dca6, 0xbfbc28612a3bc18b), (0xbbf422f2d193783c, 0x3f511f52577ff6ba), (0x3c3976e0041aa223, 0x3f92c21da135f56c), (0xbbc90eddb53bb0bc, 0xbf26ce18f8229e00), (0xbbed07e9f5028d13, 0xbf4df586d8b786e1), (0xbb8f298c930f3daa, 0x3ee230fede9c5ad4), (0xbb94e2ce32d56eeb, 0x3ef6c2a7558fc928), (0xbb04521d6df510c8, 0xbe8b97329e667f58), (0x3b301d874878e4d4, 0xbe9426ecfd66cd08), (0xbab8e3f15d7488a6, 0x3e285e012a388a8c), (0x3aca2aaf6142964c, 0x3e27557143798fcd), (0xba467e3999dd049e, 0xbdbc1f9f6fa068b6), (0x3a5bd65c11af362e, 0xbdb30842b25be60a), (0x39cac535c84bd033, 0x3d46d975726392d2), (0xb9d9799d506b6536, 0x3d370aced616e29d), (0xb960a1d7a205223b, 0xbccb8986f84a30fa), (0xb8fca075da3aafd8, 0xbcb584e49cb6db11), (0x38e10f7fdc1a5917, 0x3c4995407ad5e053), (0xb8cee1114e53e0aa, 0x3c2ff0b6f99d000a), (0x38430648734f6eb9, 0xbbc2dffde43760ea), (0x3835046e458663d2, 0xbba3496b757a3add), (0xb7dc717d402f56b2, 0x3b36778e7fdb6444), (0xb7b8d1b6dcf93aee, 0x3b13324afffd82fa), ], [ (0x3c58fff4515190b5, 0xbfbbbf246914235f), (0x35d982a917cde59c, 0x3950d75272d68d70), (0xbc48fff4515191c8, 0x3fabbf246914235f), (0x3b9cd1da148e225e, 0xbf35d923e8470178), (0xbbfbef9e89616fef, 0xbf727a96f174b6d1), (0xbb885ae82b0f986d, 0x3f01715e4bbb00e7), (0xbbcb5280334e8030, 0x3f23abacdb5106b5), (0xbb5ee327f9eba23d, 0xbeb3dc30d27849d7), (0x3b6dfe7950a9c090, 0xbec6698d6ee99eb9), (0x3aeb757878040b38, 0x3e576911a4642dff), (0xbaee8dc651ba599a, 0x3e5fbf415682210b), (0x3a81620ce1ff0741, 0xbdf0e7d3674631fb), (0xba8353972b806230, 0xbdeea1cbf2d9d28a), (0xba25d1ac6266a88d, 0x3d80805ad6510660), (0xba069055b8b763ed, 0x3d756aaba5459ef1), (0xb9a9f31ddbf5fa91, 0xbd073ab529b3b8ec), (0x398c43d0fb4ec9a1, 0xbcf6b0b8fe628d9e), (0xb8c99b2526d558a3, 0x3c88b1cfe95984a1), (0x38c9b40ec3d6b48d, 0x3c72d6d66d90227d), (0xb8a48afcea90991a, 0xbc04861250a2137e), (0xb88e608ec89832fa, 0xbbe92be16535de20), (0xb805a233b6080776, 0x3b7b6761d996b09c), (0xb7f3fb75ac66c54a, 0x3b5b702a10c5d8d6), (0x3787fbc0b82d70c7, 0xbaee7b19f87b38e8), ], [ (0x35ff73655c8feec1, 0x39576c36a9ae2d5c), (0x3c5d0edcbac85111, 0x3fbb5a6219b35e14), (0x3be54c0ba940867f, 0xbf4f645fdb1a8c89), (0x3c37a2e3fd651672, 0xbf923940d01de8e9), (0x3bb0148b185376f2, 0x3f24e86a1e6384ff), (0xbbe17bbc96492f6b, 0x3f4d1c6a18c7ed95), (0xbb8c8ebdf6811341, 0xbee0aeec61621923), (0xbb99391cbc0f757c, 0xbef61f7d30244338), (0xbaa9ea01a9b8fa8c, 0x3e8950f781c1c41c), (0x3b3c5364d9ae9a38, 0x3e93989942e07175), (0x3acc3081ebda4ff1, 0xbe265fd114ee2251), (0xbab6323d2dc56e9e, 0xbe26b3bd4dfd4b81), (0x3a5ff68cf4ae06aa, 0x3db9d8a1bbe00791), (0xba462dc328f651f0, 0x3db2875c16e4487f), (0x39a13905c77f8bc2, 0xbd4505775bc7e4de), (0x39ca895460eb8613, 0xbd3672e2d4f29271), (0x39541d93187b0343, 0x3cc95d609db7ab8a), (0xb94983f2e6b2775d, 0x3cb4fb4d36ab3e60), (0xb8c9c87d6b8b88ce, 0xbc4798ba8aedf4d9), (0xb8c9a4efd28a4426, 0xbc2f2b65d0eb351a), (0x3864f45927d43933, 0x3bc16f636e45b56a), (0xb84852ca897a91ce, 0x3ba2d6b5ad521072), (0xb7a77d76082f0cb2, 0xbb34c92434bd9c18), (0xb7baea41b7cf079e, 0xbb12c43424dc0933), ], [ (0xbc5024304247ada3, 0x3fbaf9cb49c4f935), (0xb606a30b444ceba4, 0xb9708319890a5e6d), (0x3c4024304247aeb1, 0xbfaaf9cb49c4f935), (0xbbdc12274808197b, 0x3f3413b75ce0cc1b), (0x3c06b1ae60010808, 0x3f71f7a8fec6eba8), (0xbbac4403af34826f, 0xbf0008442739ebfc), (0xbbc9d6333d2b3d56, 0xbf23215dab7537c6), (0xbb3addf7c6694661, 0x3eb242e9e6bab199), (0xbb4ca73ddba08b13, 0x3ec5cdc48f5d75eb), (0x3afbb2f24513857c, 0xbe5589cf32f43f3a), (0xbafb14e3e9852288, 0xbe5ee5f0d63c1125), (0x3a8b9bbc9f549992, 0x3def216eedb0f95e), (0x3a7b918a152ee6ef, 0x3dedd414a7d8c97b), (0xba0a1e2e293b285d, 0xbd7e69fdff8447cd), (0xba130096e56c8b4c, 0xbd74de15be68829d), (0x39845da07a4cf814, 0x3d056e1418ae157c), (0xb9994fbaa41d7396, 0x3cf61fa98590ddb6), (0x392ed1bc75d499ea, 0xbc86cf2506f44167), (0x391952212e39899e, 0xbc7261f3fbe2abde), (0x38af858de9bd8291, 0x3c02fb5ec2e4f362), (0xb884c724ba966327, 0x3be894d61148c89d), (0x3814ecb4513b97db, 0xbb7961b08a806964), (0x37f74e1e809c4297, 0xbb5ad164c25d22e1), (0x378b5dec7edc635c, 0x3aec45b6d88eaf60), ], [ (0x35fc420ae9aceac9, 0xb9652ed980617fa4), (0x3c508b7cc7933a76, 0xbfba9d1835947d70), (0xbbcfb3814e43f8ba, 0x3f4cea253049a85b), (0x3c3e993cf753c70d, 0x3f91bb71f665dcdf), (0x3bc6de474ee9719c, 0xbf23427f4797ae90), (0x3bab43046c68dd4b, 0xbf4c54a7bd6f30c1), (0xbb74fee51586a24b, 0x3edebe9e65809919), (0xbb914661f197da7a, 0x3ef58924fa089950), (0xbb1b1c449258996b, 0xbe87564501e7bcdc), (0xbb32d1ffd0fc3508, 0xbe9315306e5bb42b), (0x3ab9cf483ad9233b, 0x3e24a32382dea2a5), (0xbacfa4096d44c807, 0x3e261e0ee5367a22), (0x3a4c5e7f996c4e59, 0xbdb7db853758262e), (0x3a56a3ad86030da8, 0xbdb20facb4a9bb8a), (0xb9e5ff48c852945f, 0x3d436bd6f000149c), (0x39d6c37ca2f2d752, 0x3d35e552618cbb0c), (0x396867fd75ecd168, 0xbcc7754c8d2d22bc), (0xb9220db8a9e7d56d, 0xbcb47a92b936acfa), (0xb8edde52032032d2, 0x3c45d9205d867e02), (0x38c44f9ceec60e46, 0x3c2e71f7334b0fac), (0x3864418502fa183f, 0xbbc029e4f35c0aa8), (0xb84306e130ba75b2, 0xbba26a627f026785), (0xb79943e923428172, 0x3b334bc2432e2477), (0x37b67d0793319e79, 0x3b125bc6a2301ad4), ], [ (0xbc55d35a88f1e0a3, 0xbfba4407e04298d1), (0x35c8ff9720aff2d4, 0xb952ea1cdd28e494), (0x3c45d35a88f1df9c, 0x3faa4407e04298d1), (0xbbdfcf49ead42a08, 0xbf3288694b34ab21), (0x3c1c3cb8ccc5cfb9, 0xbf717f0266db2149), (0x3b7370def0b046b9, 0x3efd9a9a1d05433b), (0xbbc76ae4901c1264, 0x3f22a1c916a2d5a1), (0xbb55855d21f5ed77, 0xbeb0dd9e92661e07), (0xbb0d68a20388319a, 0xbec53dd972d8f232), (0x3af0f257afd1ac40, 0x3e53e6e553aac740), (0xbadedfaa1b67f332, 0x3e5e1cc65033998a), (0xba7a37ed01b9dc68, 0xbdecc8a3f36b4e82), (0xba7e73855d5a6fce, 0xbded152ceac33738), (0x3a0403bc50b56bec, 0x3d7c249e1f30a046), (0x3a07ab8d362d1a04, 0x3d745b3c1804b70e), (0x396e1c149d462be8, 0xbd03d90bb02406e2), (0xb973199796754cc5, 0xbcf598302aa37892), (0xb916ac374a93ff56, 0x3c85259cd94ec2fe), (0x3902b130fb62197d, 0x3c71f460935c9412), (0x38a7f1bf80e44c1a, 0xbc019e603f7b6fda), (0x386260160040e9ca, 0xbbe806a4e2d693da), (0xb81630b9badcde1d, 0x3b77968008016bca), (0x37d07b22ab7a0d45, 0x3b5a3b41f167ae95), (0xb76d821cbcda7119, 0xbaea4e94d614d85d), ], [ (0xb594a4d849ef503c, 0x3938d6c331cb03ad), (0x3c2748c82bad8c50, 0x3fb9ee5ee937fc89), (0x3bebaa9c093c243c, 0xbf4abf28ad5bf6da), (0x3bf098a110e15588, 0xbf9147481084ae0f), (0xbbcb58642b3fc6f6, 0x3f21d137345cfee5), (0x3bdbab7a25ea6636, 0x3f4b9c10ddf62464), (0x3b707cd24e8374d7, 0xbedc72c9d49c6d7a), (0x3b9799bc070c59b2, 0xbef4fe0b363ccc66), (0x3b2f6fb041c061d5, 0x3e859a1c336b7506), (0xbb38437a08d58d5c, 0x3e929b6632cc324d), (0xba9f406b3224c41e, 0xbe231cd6e7991df9), (0xbab2457dd0d0e718, 0xbe25930872001f69), (0x3a548f54ac84016e, 0x3db61befbaaf9fff), (0xba589a9303d7d25f, 0x3db1a038446ec46b), (0xb9db6b1cfe9b31f4, 0xbd42030319ffb5eb), (0x39bf4002924f6ae5, 0xbd356117967009ca), (0x394da21091709c76, 0x3cc5c664f861ad05), (0xb93ec733758fe60c, 0x3cb401eb6a584504), (0xb8c585bd91ee5a94, 0xbc444cf483677683), (0x38b16263dda87c68, 0xbc2dc380ac38062e), (0xb85553427dd612fd, 0x3bbe11fffb02da4f), (0xb8433d91b3bab077, 0x3ba2040b40b2538d), (0xb7df7b4517c493ac, 0xbb31f841ca6c686b), (0xb7b3136588d9a93e, 0xbb11f8bc69e97ebb), ], [ (0x3c5728ab934a269f, 0x3fb99be744018c90), (0xb60a99831efba67e, 0xb968c3fcaae6f521), (0xbc4728ab934a259d, 0xbfa99be744018c90), (0xbbc84fc914744b2d, 0x3f312d4e1c1ca4c3), (0x3c0f281d89c5c387, 0x3f710f5ca51f98b0), (0x3b9fa3d9c31f9653, 0xbefb71417476a570), (0xbb82784b5921b117, 0xbf222b9fa8dfd762), (0xbb2378a1f5ba83c5, 0x3eaf471061b7dd7e), (0x3b688d2d785bb65e, 0x3ec4b862279de756), (0x3ae3ff1d8fa9486f, 0xbe52763f34a53566), (0xbafc90858b5fda2a, 0xbe5d61e605e8e69a), (0xba8db88bf0b8b3a0, 0x3deab7331a682503), (0x3a83becc2585c0e6, 0x3dec637428f3fda0), (0xb9f91cdb1c054c59, 0xbd7a236ad0b3eba5), (0x3a130d91a2571fc8, 0xbd73e11cef6ea796), (0x39ab3e18bb4b1cc4, 0x3d0272cbaef4a6ce), (0xb992fbf6044183a9, 0x3cf519623b3e6ff3), (0x392d2f84f2aa9293, 0xbc83ac610a98a111), (0x390f58be5a588034, 0xbc718d7aab4e57b8), (0xb89f4ff0d5411205, 0x3c006837647ec51a), (0xb880cf6db8b6e7c8, 0x3be780a339ad4fe5), (0xb80c4294a291cdbe, 0xbb75fd4c1cf239b2), (0x37a40abc824fc196, 0xbb59ad37b5365c90), (0xb78678af8405295a, 0x3ae88d6e7fc415df), ], [ (0x35f8589681278026, 0x39644f6712268762), (0xbc4e31356cad466e, 0xbfb94c6f54aef04b), (0xbbe68528f64c7b1b, 0x3f48d6371f018ef0), (0xbbf705a06948b19e, 0x3f90db975fd7dc47), (0x3bc06e812fcafb21, 0xbf208bd1634353c9), (0x3beeb410edf2c87a, 0xbf4af0d3d4cd140d), (0x3b6d81ec11b0f0a1, 0x3eda6c8e7c9d023e), (0xbb94f5f0c72b68d7, 0x3ef47cddcdac15d7), (0xbaee0517040c548e, 0xbe8412394fc50e0a), (0xbb3fb62ad27acc53, 0xbe922a21cb1edfe9), (0xbac19c23bc37cb83, 0x3e21c417dedcf50f), (0xbaae59d2170adaa5, 0x3e25117f3061daaa), (0xba5e45da99f1d381, 0xbdb49009a6c8ef21), (0x3a587572c3e6ea79, 0xbdb13823dda87c56), (0xb9e347d6a1129f4a, 0x3d40c350b604f8b8), (0xb9cc2ad178b32695, 0x3d34e54a89ae35f1), (0xb96a80e6a3444766, 0xbcc447dde867e136), (0xb958d6073cf4ba2f, 0xbcb3909fa79d8804), (0xb8d64b27142de74c, 0x3c42ec7e360503ed), (0x38c6d01b41c0980d, 0x3c2d1f243bdfcc89), (0xb85a84d31e1eccc9, 0xbbbc0eb8ec6b686f), (0x383387e43fd2ce16, 0xbba1a3489d347b47), (0x37dde5e850e9f781, 0x3b30c8b4a21c4541), (0x379dea6fe0f54701, 0x3b119ac8a8b69886), ], [ (0x3c5e213a1a4b3671, 0xbfb8ffc9bd24fe08), (0xb6087102bb621f14, 0xb968aedf9eaeb722), (0xbc4e213a1a4b376e, 0x3fa8ffc9bd24fe08), (0xbbcd363274122e3f, 0xbf2ff51b38eef42c), (0xbc0f532ddb1fa0a0, 0xbf70a7a725d3fbc4), (0xbb834bf08647ec89, 0x3ef988128728122a), (0xbbb5bd6096bda7b8, 0x3f21bdc846a09e43), (0x3b30137f6ede612f, 0xbead1b60a4812ac4), (0xbb5a77139f0b51d5, 0xbec43c2d8e698c10), (0x3ad810635b7d0ab5, 0x3e512fd6ccdafecc), (0xbaf69212c4f321ef, 0x3e5cb3bb8802e835), (0x3a8f78dd26a56680, 0xbde8e1dd09a92325), (0x3a8e97521eebd870, 0xbdebbd84404b6233), (0x3a0668a211ed0544, 0x3d785bcfd7db3e06), (0xba1ac0b0871b3637, 0x3d736ed7607396ae), (0xb955951b23d30299, 0xbd01343464758a13), (0xb9870af9e1cfe573, 0xbcf4a26ef2120ad4), (0x392f6ff8929d9ec8, 0x3c825c400013c92d), (0xb91624b068d7998e, 0x3c712caecd60a253), (0xb89eef1d95657c36, 0xbbfea68103e8017a), (0xb85dbca3eb7791dd, 0xbbe7022f94b51f88), (0x381743e0f343b5ae, 0x3b748f053210dc4e), (0xb7fa879e893fa8e0, 0x3b5926bc9b441cf3), (0x378b8478cb5f337e, 0xbae6f9f3f5bcbb92), ], [ (0x3601868fee3dfc1f, 0xb967b581e11caa4e), (0x3c35e8738ef1b9cc, 0x3fb8b5ccad12d632), (0xbbd18507f867652e, 0xbf4724d0185980d2), (0x3c1f6ab95e49bea7, 0xbf907764ae2b1eeb), (0x3bbea971beb0d4c5, 0x3f1ed6acc18fdf29), (0x3bca7600bd6cd00f, 0x3f4a51693df2efbb), (0x3b5424c646ef6906, 0xbed8a0ec61e4df7b), (0xbb2fcebd0b42c3a3, 0xbef4047f31fae045), (0xbb244d840b8d48b4, 0x3e82b668af276950), (0x3b3cad3ad53887a6, 0x3e91c07467ed6403), (0xbac9698769c60aee, 0xbe2091d32eea7f0f), (0xbacf39eabd09fce6, 0xbe24987294de7d1e), (0xba4e5986bfe40615, 0x3db32fe6ab220650), (0x3a4ecd045a4261a7, 0x3db0d6b127f8ac20), (0x39d762ccc3d86511, 0xbd3f4d16b8caee52), (0xb9d08617d1af539c, 0xbd34711e3d50f4ef), (0xb96508919fc82bc0, 0x3cc2f28e5dd490f1), (0x395bb058a146ba42, 0x3cb326098ea185f3), (0xb8e94f0af2b5ad80, 0xbc41b16976a3d442), (0x38c176e23d72ae5d, 0xbc2c84134caa87ba), (0x385559d5c6add4b3, 0x3bba412149720827), (0xb840ccac5bb143cd, 0x3ba147b6307ccbc3), (0xb7b2120a01259b99, 0xbb2f70570b14782d), (0x37b4facf0ef3cce3, 0xbb11419a7914e3d3), ], [ (0x3c5b1c9821974148, 0x3fb86e51be0a9153), (0xb5f75cf6d696fc83, 0xb95827c8ffd9b363), (0xbc4b1c982197404f, 0xbfa86e51be0a9153), (0xbbcc79e50a2cd67c, 0x3f2dd3c244b53279), (0xbbe9cfc13650412e, 0x3f7046fc5a218a86), (0x3b473390e469f8a4, 0xbef7d51accbfba76), (0x3bbac27d2877fb16, 0xbf2157556c0e1b1a), (0xbb2e687ae53690de, 0x3eab2d01c12c8227), (0xbb685c4f9e1e413b, 0x3ec3c838897d0a1e), (0xbaf6af7b27e224bc, 0xbe500d37aa536a8b), (0x3afe75b9f5dba876, 0xbe5c10ecf088eac6), (0x3a7e762d28ae6967, 0x3de73f8d1af57f4c), (0xba76c817fc84ee3f, 0x3deb2227fe940228), (0x3a0d6d1da90d883a, 0xbd76c5390bcf01cc), (0x39fafe0f0f7cf1bb, 0xbd7303a6ded9e74a), (0x39a769658d5dfcab, 0x3d0017772c8c67d0), (0x39816dc9a19e88df, 0x3cf4329cf31c85bc), (0xb9187bba5059be09, 0xbc812f535bf22ca0), (0x39028bb4a0afb991, 0xbc70d1775336e3dd), (0x388f6ab178fe4eee, 0x3bfcb5a6e861125e), (0xb8764727329b2f6d, 0x3be68ab377a5b3ae), (0x380ffcd7837774b1, 0xbb7345ce122d1040), (0x37f98513cc233bda, 0xbb58a74b58fe9d86), (0x37810ff858a703fb, 0x3ae58ea451ed4ee5), ], [ (0x3609fbc30a1ed1d3, 0xb9625183186cb588), (0x3c40ee4d5b1b8051, 0xbfb829356999a097), (0x3be3831592c6b0a5, 0x3f45a280e033eb59), (0x3c215c7646576687, 0x3f9019dba8336e48), (0x3b986e85a68d172a, 0xbf1cd4559d95e619), (0xbbc0173a940c218c, 0xbf49bc857750335e), (0xbb63dae6bf1f89ae, 0x3ed70706580693f9), (0x3b8384969ed36c54, 0x3ef393fc6cf8481f), (0xbaf56ba053870856, 0xbe81800af4665cb3), (0xbb2c21dbefaffb7f, 0xbe915d91a2289a30), (0x3a9c9f08edce59cf, 0x3e1f009c83572407), (0x3ab89826637a4616, 0x3e2427054565b344), (0xba34b49867a6db4f, 0xbdb1f5167f464cc1), (0x3a578760251f40d0, 0xbdb07b3a2cb21728), (0xb9d9c43afa0fe4e6, 0x3d3d4f453474c223), (0x39d2dacef909b870, 0x3d3403dd864cdceb), (0x394afae738fa0ade, 0xbcc1c09693482adf), (0xb955a0b7487878c3, 0xbcb2c193ec7672bc), (0xb8e991d90439ccb6, 0x3c40967d711ba719), (0xb8bd41e60b473ee2, 0x3c2bf18fb3b9d25e), (0x38559b44bb41d0b5, 0xbbb8a1e44dd80d7b), (0xb8300b6984de9d94, 0xbba0f0f498e20346), (0xb7be574e735a8cb7, 0x3b2d850a1c84b4b5), (0xb791e712d7e8c434, 0x3b10ece621e460f6), ], [ (0x3c21907f595a082c, 0xbfb7e656efb009ae), (0xb5d70ebcecd9fbaa, 0xb9348631c28e1012), (0xbc11907f595a0fca, 0x3fa7e656efb009ae), (0x3bcce5fd1ce60611, 0xbf2bec6b33efcb49), (0x3bcf8f1c97773b2d, 0xbf6fd932c26aad94), (0x3b80b8964e3bc289, 0x3ef6504d7e054d50), (0xbbb3c0e78ce81095, 0x3f20f77ce6105150), (0x3b3d95f66e8bcdc7, 0xbea972e573db9593), (0x3b4458e98ac8a7d0, 0xbec35ba58bf2f993), (0x3ad1d824fbf1c841, 0x3e4e1246a53112c6), (0xbacbe1b18e34adb3, 0x3e5b7850b3bc8175), (0x3a8ea247bf864770, 0xbde5c8dcec477a4f), (0xba8c8c74de40c8c9, 0xbdea905348b49249), (0xba0bd92b052944e0, 0x3d7558a1f12cdd8b), (0xba1c00a1d58c8cfb, 0x3d729edf3b285f5a), (0xb992a01268eb295d, 0xbcfe2f9cdddcaae8), (0xb996b7f5d81cfb6a, 0xbcf3c947b927c569), (0xb925ba6791e41b2f, 0x3c8020bb87a79ea9), (0xb90e7d0294d49287, 0x3c707b5b9c74c0fe), (0x38890499436f4660, 0xbbfaf62358105eee), (0xb88dc52f6583904b, 0xbbe619a4100326eb), (0x37f0135f77fb4dbd, 0x3b721cbe450a51a8), (0xb7e6ee90d9e1aa8a, 0x3b582e655a55f7e3), (0xb7348781a2c50334, 0xbae44663af3f368d), ], [ (0xb6020e4a1b2a8f8d, 0x396ab0500de5301b), (0xbc529270d2a71e93, 0x3fb7a597e9550934), (0xbbd42472048d4d2c, 0xbf44486c0b012534), (0xbc2ac52ac43275af, 0xbf8f848eec0e0e6b), (0x3b684f3433759ef3, 0x3f1b077fae06adc6), (0xbbce518d0ac3eb8f, 0x3f49310d6e6842c6), (0x3b230b8e78861165, 0xbed597a5befbd70e), (0x3b9e1e122fd16318, 0xbef32a855e4e113b), (0xbb1d74885153e029, 0x3e8069ba0b1a612d), (0xbb3a50c31550125c, 0x3e9100c97ba8e22d), (0xbaaea70ea0155098, 0xbe1d15b5350404fa), (0x3ac3cb5036af1144, 0xbe23bc775cca4413), (0xba5b1e821a17c11c, 0x3db0da51f94c98eb), (0xba50d67d4e601934, 0x3db0252dc33a4d71), (0xb9c1e859398b6f43, 0xbd3b84d751a3586e), (0xb9df2f53d258d2cf, 0xbd339ce8224cadca), (0xb9601e564eee8b92, 0x3cc0ad1ba9bada71), (0x393bd1c6476589ac, 0x3cb262b8db685d38), (0x38d88290cd473175, 0xbc3f2ec74017a50b), (0x38cc155000aaf19d, 0xbc2b66eb4fd1abd4), (0xb84d6b52f7a6d523, 0x3bb72adeccad55cf), (0xb81b307d97df219d, 0x3ba09e84d1e5cbd9), (0x37cfdfe2f1e86ba7, 0xbb2bc6df8963705f), (0x37bd47c432afc7ac, 0xbb10899f2f554f23), ], ]; pxfm-0.1.23/src/bessel/j0_coeffs_taylor.rs000064400000000000000000001642431046102023000165350ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Taylor expansion at zeros and extremums for J0. Generated by SageMath: ```python mp.prec = 180 def print_taylor_coeffs(poly): print("[") for i in range(0, 24): coeff = poly[i] print_double_double("", coeff) print("],") def print_taylor_coeffs_dyad(poly): print("[") for i in range(0, 24): coeff = poly[i] print_dyadic(coeff) print("],") print(f"pub(crate) static J0_COEFFS_TAYLOR: [[(u64, u64); 24]; {len(j0_zeros)}] = [") prev_zero = 0 for i in range(0, len(j0_zeros)): k_range = j0_zeros[i] range_diff = k_range - prev_zero mp.prec = 180 x0 = mp.mpf(k_range) from mpmath import mp, j0, taylor poly = taylor(lambda val: j0(val), x0, 24) print_taylor_coeffs(poly) # print(poly) prev_zero = j0_zeros[i] print("];") ``` **/ pub(crate) static J0_COEFFS_TAYLOR: [[(u64, u64); 24]; 47] = [ [ (0xb5be985fa7f83cc3, 0xb91cba5b78f9bcd0), (0xbc8ac8cc3d6bafa4, 0xbfe09cdb36551280), (0xbc5b50b1160e9078, 0x3fbba1deea029494), (0x3c4bc98bcfdc7a7f, 0x3facfae864368d70), (0xbc1a87a5518aec0c, 0xbf81bb1cbe1a4071), (0x3bcf770ef9886bfc, 0xbf61f992590d12bd), (0x3ba05114c54b25ab, 0x3f315382ba06cc47), (0x3ba2b401cd6c68ec, 0x3f06ed3b9f07eb28), (0xbb46fe17c9b10921, 0xbed232c77d228ab6), (0x3b479fbd07230860, 0xbea1cce302821846), (0x3ac3ee3080fdf4d2, 0x3e67ff99166c20b8), (0x3ad99d2c20223b95, 0x3e32951bd4726a93), (0xba982691b667ba5c, 0xbdf5c2c38b2a278c), (0x3a44e89952bc724c, 0xbdbbdc468c1a817a), (0x3a0ebde93f245a29, 0x3d7cd41cf248a22e), (0x39aeeb56633d8ce6, 0x3d3f70b0201c12a4), (0xb98e8ed54af59db8, 0xbcfd22d8ef70f1aa), (0x394a95ebfce4a435, 0xbcbbaa352d8622af), (0xb91ff1b0b50e7818, 0x3c773612afd5db30), (0xb8dd29c3a1d1250e, 0x3c3382933550f440), (0xb8840afcc88fadb8, 0xbbede7dcd5e6dab6), (0x384023453882217b, 0xbba68bbe41057f40), (0x37e0c3131ee8f030, 0x3b5fce24eb23551c), (0x379a6895f9086a05, 0x3b15bc1becd9a431), ], [ (0x3c62de1143765a96, 0xbfd9c6cf582cbf7f), (0xb56eab9a5fff323e, 0x38d9a91f973ec303), (0xbc52de1143765a96, 0x3fc9c6cf582cbf7f), (0xbc3b84c5dde43674, 0xbf91f06d14e11e02), (0x3c27767d9698b536, 0xbf8b589d1da13905), (0x3beae1afe6c3eeda, 0x3f50f9103cf5b152), (0x3bd3e8ae8dea10a7, 0x3f386445621cc085), (0x3b8a8905b308cb21, 0xbefa2a033ccf2705), (0xbb6859e8c0ae37ce, 0xbed83a06e30c4109), (0xbb3d54a069e9c64a, 0x3e96a4fd997104b3), (0x3af989d32babfca4, 0x3e6ec03c7b7d1357), (0xbab1ecf377bfa04f, 0xbe295db03343bc40), (0xba90b0b6e5fe7551, 0xbdfb1e242e3fafb5), (0x3a3fd469738e9f05, 0x3db3fa9bccb27cd1), (0xba1b0f91d98a1070, 0x3d8195cae4f67f9d), (0xb9ba66f04112da4a, 0xbd3762afe2a5cc10), (0xb99f157bfc6eaf25, 0xbd017a40c9422e17), (0x39512dfe72026e3a, 0x3cb52a10c3c6a274), (0x390b50bb7a057314, 0x3c7b78e32c0ddf7a), (0x38b2f2ab795ef554, 0xbc2e86449ded35db), (0x3886128863c137b0, 0xbbf180413173c4a1), (0x3830411cc8598621, 0x3ba1f599693c21d5), (0x38061e9b17fc3c4e, 0x3b62704bba47e657), (0x37ba5ced95be86b1, 0xbb119329ee1d3fb9), ], [ (0xb5bc6f55d4dac0c2, 0xb916caed64280f3e), (0xbc6af17f78e58353, 0x3fd5c6e60a097823), (0xbc22c1940b65933b, 0xbf9f8f72e7a848e0), (0x3c39226a6968a5d4, 0xbfab2150cb41e8c1), (0xbc0ead94b776cda6, 0x3f72f7ffe90256bb), (0xbbdc44bdbe1112fc, 0x3f627e31fe9a9779), (0xbbc64599a8123499, 0xbf26f641f41956f7), (0xbb948616b6922642, 0xbf0863f481a43036), (0x3b680f8935f5af0c, 0x3ecad77d748a06db), (0x3b3cc25f06059d1b, 0x3ea32e6d99c6af7d), (0xbac3305a73e5ec68, 0xbe62da37e38435b9), (0xbad5c613351595f6, 0xbe341d72d9392e0e), (0xba9c8106c7bc6fb7, 0x3df1d0433d9a0e49), (0x3a54e8ace2031b36, 0x3dbe2f3389aa5f69), (0x3a1a0f5d1cba1387, 0xbd78498ffdebdd63), (0x39c72f8fafe52f38, 0xbd410477aeae347a), (0x398287fc3bba485f, 0x3cf911a8d781ae91), (0x395788d424859469, 0x3cbde68af47fa3dd), (0xb914472b326b8d7e, 0xbc744b3881dbc1de), (0x38d8ef43414cc878, 0xbc350be81f6c25f7), (0x388738457ea68eb1, 0x3bea7a3cd386daef), (0x381867e5c9a67b59, 0x3ba845cae670510a), (0xb7fd1902fcb38c68, 0xbb5c71de4246f315), (0xb7bbe92f443184c2, 0xbb175a569f596544), ], [ (0x3c7af22d033ee0a4, 0x3fd33518b3874e8a), (0xb5a1c201a4cbcd4f, 0x390f8a0b194e92aa), (0xbc6af22d033ee0a5, 0xbfc33518b3874e8a), (0xbc006437c8a4bc6d, 0x3f7d34125d59d8ff), (0x3c276d8715df682d, 0x3f880c83bdeee5b0), (0x3be68431910b0ef3, 0xbf4483c20f1cb1cf), (0xbbb05a9f39ef055c, 0xbf36ffa5fc8cad74), (0x3b913c3053e04d46, 0x3ef2ccf7b21fff81), (0x3b34763d026d3263, 0x3ed796a751f89051), (0x3b28d27038a5d6ff, 0xbe91e850e4c28d2e), (0xbb0dacba8ae06269, 0xbe6e6a49ae425df4), (0x3abf3eddd6df5c90, 0x3e254c4387ef6820), (0xba918835ce9eaca7, 0x3dfb084d1fe8eb88), (0x3a5d71d0cc12f311, 0xbdb177e06f2957d2), (0x3a128331bef5dabb, 0xbd8198853f2794c4), (0xb9d9afdf19b00f9a, 0x3d350c2b4db26303), (0x399d5420c79c50f5, 0x3d0183edbb8ef55e), (0x3950904a54f66bdd, 0xbcb376d167cfd12b), (0x3900fa2cc4b5e6f2, 0xbc7b8a653f1cd809), (0x38c18dc8b4e37444, 0x3c2c8b097fe47227), (0x38721faa0c98eabc, 0x3bf189c13e615d1f), (0x384e91176ed97cac, 0xbba1041440ddec2d), (0x380179051848c349, 0xbb6276b7a23c8925), (0x37b217667c662a42, 0x3b10d45d32f264a5), ], [ (0xb5a271a164439dcf, 0x39091ad14f5534e3), (0x3c70b85158068ef8, 0xbfd15f7977a772d4), (0x3c1371b46642ace0, 0x3f900f7fcf183e0d), (0xbc44d97f9ccedb81, 0x3fa68b984ec6493c), (0x3c042ebf64ab2f7d, 0xbf648e63600d8418), (0xbbeee6fe26323549, 0xbf60e0d60385a6f0), (0x3baeef0ba4a3d132, 0x3f1d796052775aab), (0xbba7aac08a2ef0bb, 0x3f07800bc550673c), (0xbb5a88016ef7845c, 0xbec3324842f7d51c), (0xbb4a5fc6166e08e4, 0xbea30e8cc35f2086), (0x3ae456e8b4cd8ab1, 0x3e5ceda479a13c54), (0xbad32f77090cf486, 0x3e34582cb217a0ff), (0xba896f49e7d71906, 0xbdecade19f5ddb10), (0x3a21bb7dfbc8d1d7, 0xbdbedafbed1c0039), (0x3a0e246bb345d838, 0x3d743c230e74f083), (0xb9ef2b99a0d63f0b, 0x3d41820d4a50e7ac), (0x39930eba3f48ee4f, 0xbcf56d4abfa3f75e), (0xb9404cba8724060b, 0xbcbee1c963b55043), (0x38e5999953118f29, 0x3c71b059736ac012), (0xb8670d7b409cc9b1, 0x3c35c975cfa56031), (0x38874e8a77d0b989, 0xbbe76ff93efd4a1a), (0xb846172c476991f2, 0xbba9288634dcae38), (0xb7c3ad53cba7bf5d, 0x3b597e272f8ae371), (0xb793a523f540949e, 0x3b183832a1cf9585), ], [ (0xbc5052a3a2541c57, 0xbfcff654544ebcd1), (0xb59d2cb904ed26e5, 0xb8f8cdeedd7089d9), (0x3c4052a3a2541c57, 0x3fbff654544ebcd1), (0xbc1261ff874d8f29, 0xbf70c17ff72afae7), (0x3c123a275590a85f, 0xbf84b0c5d5da6789), (0xbbda98843bd20bfa, 0x3f394154be70ed46), (0x3bd7d4055bf0fe2a, 0x3f34e12c3067bef4), (0x3b83b9ba50d44e92, 0xbee9f32fc25ad134), (0x3b7dd3415a058d7b, 0xbed63c5475439cb2), (0xbb2e30b182db0623, 0x3e8adbafdf1415b1), (0xbb03faa98b08aa74, 0x3e6d601d278516f5), (0xba8bdda43ca62c5a, 0xbe20eedcab593552), (0x3a9e2fad33581bf9, 0xbdfa84fedb589fe9), (0xba43dc502b3bc37b, 0x3dacf8e343fe2283), (0x3a20042e6b66d5ce, 0x3d81702cfaaee589), (0x399e7a30f53ca26c, 0xbd320271d8cd44dc), (0x39a5f9316e1c5efa, 0xbd01797e5eacddfb), (0xb9547c274818e871, 0x3cb10ed3b5c9be93), (0x390484c268c0ce85, 0x3c7b98f45921983a), (0x38c24e5982383c83, 0xbc297cbf7079afbf), (0x389b277576e91bd0, 0xbbf1a00382f67f4b), (0xb81f48467ddb418e, 0x3b9ed8b7eb419122), (0x37fcd9d0b0e535bf, 0x3b629700d2c00fd9), (0x379a08401f2ad096, 0xbb0ee1e52f6de1ed), ], [ (0x35857c582b5ea1c9, 0x390bee0ed8c1329b), (0xbc56d72d40e790b3, 0x3fcdc13e66ac2e77), (0xbc17a0058564dc78, 0xbf842ff0cdc58463), (0xbc4ea7eea5885b06, 0xbfa38d1dd8992e04), (0xbbe0000f328100a7, 0x3f5a55e9b346edc1), (0xbbf1ad5da35cf264, 0x3f5e2e16f97d0a81), (0x3bba0bf2d8b00c54, 0xbf13dfc3782af205), (0x3baf5778b0601b70, 0xbf05ce7f496656d0), (0x3b554dd7e814f538, 0x3ebbb178da9c4ac0), (0x3b4faa40f4ef4735, 0x3ea2346d74940be8), (0x3afda3f1a9c16a33, 0xbe5612f2e799b732), (0x3ab1ff4f9f08910e, 0xbe33d79882e5df9f), (0xba8b82d54967fe42, 0x3de6dbc112bdb279), (0x3a54c5a3f521e570, 0x3dbe88c4d898d665), (0x3a0aab5610ed8408, 0xbd70ad880fc1e195), (0x39ecb4a2ad16ceb5, 0xbd4180d64e2c4131), (0xb99c77042f820598, 0x3cf22094137f7e15), (0xb94dafad35b07003, 0x3cbf18a8509fa48c), (0x390d0551dfd7b655, 0xbc6e8dc12bc24aba), (0x38c7f144bd8a3779, 0xbc360ce090718b01), (0x3887e3ff32f169c4, 0x3be4947b20d26a23), (0x384fdb50bbf01aa8, 0x3ba98e129bc0f8a1), (0xb7f91bc574623289, 0xbb56b091d8385139), (0x37b564d63f3376cc, 0xbb18aa3f6c83b7e7), ], [ (0x3c6c8c66d2e42062, 0x3fcbf3337873a7d8), (0xb540e662913e9721, 0xb8b8ae14acc03cc2), (0xbc5c8c66d2e42062, 0xbfbbf3337873a7d8), (0x3bfaea5f3639483f, 0x3f66604d91f926ee), (0xbc24192692d7c9db, 0x3f8251858011816b), (0xbbdcdb12750487fd, 0xbf314bc11a32c246), (0x3bd50548750ad314, 0xbf32e7decd1f73a5), (0xbb847a9ca039b976, 0x3ee293b4c9a24966), (0x3b6e3a426e412d42, 0x3ed4a6704d05ad0b), (0x3b1253e91cb63be7, 0xbe843ca9b71b6996), (0x3afbda58c238f16a, 0xbe6bddfbf35630ba), (0x3aba3f365a5e64b5, 0x3e1aae76737061da), (0x3a96b049b0e48195, 0x3df992424643ff64), (0x3a42ad17879fc5b9, 0xbda7aad4b0989ad6), (0xba22956ea0fa52e3, 0xbd81051e84a7a86a), (0x39c7f26c2e23f425, 0x3d2e49ae1a0e9424), (0xb998466ad52efa61, 0x3d013585a9b7473f), (0xb93c2bb2beb0ccde, 0xbcad5c6820d4c19c), (0xb90356383e63d305, 0xbc7b5bcfc1f36461), (0xb8714991402d4264, 0x3c2659e097d2d299), (0x3893b54f82b6acd5, 0x3bf18eefb530cdde), (0x380fec88aec6bc4b, 0xbb9b78694703192c), (0x37fadce1d8598d3f, 0xbb6296435cd2331f), (0xb7a9cd5a8e59cb5f, 0x3b0bdae97028e6a9), ], [ (0x35ac59c6428de284, 0x390f184285843311), (0x3c32010996eec734, 0xbfca701d0f967500), (0xbc1331fb2bff5c30, 0x3f7c54b930fef892), (0x3c44240355876f9f, 0x3fa17798aa09f11f), (0xbbf91cbfe509a337, 0xbf52a2151407dd09), (0xbbeaf2596bf8cd55, 0xbf5b541f829bfb41), (0x3b9678567dcb0401, 0x3f0cc0bda19ffe34), (0x3b7cc73ae3f8a72f, 0x3f041f3b0662f49e), (0x3b50b073a3604389, 0xbeb4b230b114b149), (0xbb39f6a1ea249aed, 0xbea1223e2bd0689f), (0xbad9dcc2b787e5e9, 0x3e511963968a437f), (0xbade1245aa3f79f6, 0x3e32ffb8dedaa0e5), (0xba7ddb5234f87c44, 0xbde24c47f1c46f88), (0x3a4b24f96f04dc6f, 0xbdbda527540ac89a), (0x3a002159e830fd60, 0x3d6b75eeb2587be0), (0x39a7a5cb88cfcf0b, 0x3d412dcf9e14b526), (0x39536a23b6e364bc, 0xbcee8dc94e61fd9e), (0x39406182c6b2e611, 0xbcbec6e9eeb29dec), (0xb8fb12be3176058a, 0x3c6a411ab303dfdb), (0xb8da27a89b185f00, 0x3c35f7175a19426f), (0x388abe97716ef10a, 0xbbe1f8d987025207), (0x383e3b32dc10b94d, 0xbba99550856225f2), (0xb7e9ddb15c3ea3e0, 0x3b5415925aa1431b), (0x3795803255a3ea0c, 0x3b18c98cea89bbf7), ], [ (0x3c6e9557ccd1703f, 0xbfc925c6fca08f55), (0x35a0840c3eb5c8e9, 0x3909bb79105907c8), (0xbc5e9557ccd1703f, 0x3fb925c6fca08f55), (0xbbf0bd4a4617bca0, 0xbf6049377403bcb4), (0xbc1dac1b118bb946, 0xbf809463bbd0367f), (0xbbbd1ccb5b6a209d, 0x3f297b354706c53c), (0xbbdfefc73ab9ea4c, 0x3f314dd4404e5fcc), (0xbb7689ff8e8b648e, 0xbedbf665d5afcb1e), (0xbb55632e0e751036, 0xbed32cb00ee8c1f3), (0x3b168e07e41d973b, 0x3e7f50fa815b542a), (0xbaeb09f8b87a4826, 0x3e6a4339e5f906ee), (0x3ab370c114b8364e, 0xbe1541c07333f998), (0x3a95f92ca4cd1f66, 0xbdf86c0bb112e485), (0x3a3d7a90841bd326, 0x3da35fba37d1f6f7), (0xba2b575752323f67, 0x3d80700770cc15dd), (0xb9557a6df0847bf2, 0xbd2963b203086961), (0x3994060b8e456ec8, 0xbd00c58770231c0a), (0x3934b091af50e5cb, 0x3ca91e0b939f2d33), (0xb91ee976639f1136, 0x3c7adb6f69ceb591), (0xb8b63616ac9c64e9, 0xbc2373e3cab8e402), (0x387455d8787bd080, 0xbbf156093877495b), (0x3823f244d844aa0f, 0x3b9842736a626a94), (0x37f3628fad20886f, 0x3b626f881139ee38), (0x379bb0027a1cd34e, 0xbb08e814b7cab6b6), ], [ (0xb59e68fd63ab1a3d, 0xb8fc6246c85a6640), (0x3c4a4f96a2520bad, 0x3fc8077f56c9b782), (0xbbf97f76587fd9cb, 0xbf75467eb535deaa), (0x3c28681fd3a1faac, 0xbf9fd7c3ad6f59e0), (0x3be0e0f0ccfb4015, 0x3f4c1b47c809c5eb), (0x3bf6295d17a16103, 0x3f59166c7d3eaa7c), (0xbba4cf48882a0699, 0xbf05f0152478f5f6), (0x3ba861e7d6d89ac5, 0xbf02aa939fd9fc9b), (0xbb5e0f27f02ffdbc, 0x3eb0129708ec2410), (0x3b4393e44832fa90, 0x3ea01716dc9f2e1b), (0x3acfaffff96cb541, 0xbe4b227eef409a9c), (0xbadf064b85fdb242, 0xbe32101c49d611c3), (0xba4ba7b2c5f1707c, 0x3dddb1e8b7adba5e), (0x3a5a73ba24830cae, 0x3dbc80aab1d9322c), (0xba00db3fc0b0c1ba, 0xbd66c2b17ab71886), (0x39e8d291d0b4d27a, 0xbd40ad5f60b542e8), (0x3973527417cabd58, 0x3ce9d02ffd593bab), (0xb950911cb567e2a5, 0x3cbe1eda1d51b8b7), (0xb8f1f756b53acec7, 0xbc668e76453989dd), (0x38c7df6bb93ac8ec, 0xbc35a3dd5c2dd312), (0x387c31c12e84cbf7, 0x3bdf55d5df5603a5), (0x381a4e01bffe5027, 0x3ba95785174d99bc), (0xb7f4002fdaa22aa2, 0xbb51bb3ba4b3316a), (0xb7b1fe1d3a814203, 0xbb18a987773fb87c), ], [ (0x3c62da0057f84d3c, 0x3fc70c511227d5aa), (0xb590c69cd835e65a, 0xb8fbdadd24cf38cb), (0xbc52da0057f84d3c, 0xbfb70c511227d5aa), (0x3bfe726f70245274, 0x3f5910ebe1f1cbcd), (0xbc0e61277dedf705, 0x3f7e7dc08e70e99a), (0x3bb740aaea2c85b5, 0xbf23bd7d159e09a5), (0x3bc9abf12a21a247, 0xbf300357a187375c), (0x3b7cab62f60660b1, 0x3ed5ec73302455b1), (0xbb76a66de44f6f2b, 0x3ed1e5d2836c8d99), (0xbad13f153900acfb, 0xbe78f41b94dfba1f), (0xbaff3652c8e5edf0, 0xbe68c11aada79ae8), (0xbaa209f480ef1062, 0x3e1141423452a28d), (0x3a9e19c8e523a095, 0x3df73ef6f4772772), (0xba405794c4ab8e4d, 0xbda007403efd2c9a), (0xb9c2a7b0a727a022, 0xbd7f93ab6667901d), (0xb9c5c7ae4a96c60d, 0x3d25638d0e0d9767), (0xb942fb1c3cc08579, 0x3d003d0592185f1c), (0x39373a63f1b5e963, 0xbca5832b6c129523), (0xb916b9966d8ed631, 0xbc7a2e88ff86af9c), (0x38c0ec56239fb4ce, 0x3c20e8839dc5443a), (0x3884c544300024fc, 0x3bf0ff71f08432b7), (0x3829d5c62bdc57b6, 0xbb955cc426feea1c), (0xb7ff81402cdf65ad, 0xbb6229c7418b10f0), (0x3773be52416792c2, 0x3b062f08720eaee7), ], [ (0x35a8346aa8f5b4bb, 0xb909c0fc24f65a67), (0xbc6444d3d89ac00f, 0xbfc62d93aa9d05bb), (0xbc1afb8f729be80a, 0x3f70ba9ce88929f2), (0xbc2f64ee23828a95, 0x3f9d7073daebb02c), (0x3bd6ad884b57cbba, 0xbf462813c7f58733), (0xbbc1c5da610ae750, 0xbf574a948d05638e), (0x3ba7816485085533, 0x3f01695765f13bbf), (0x3b9157b692bbea45, 0x3f0170ab5eeb0e4e), (0x3b2715c0e1d13855, 0xbea9c8e418a20315), (0x3b394c7caa0cf226, 0xbe9e4d893dce335e), (0xbaee8ffa7c53b5fb, 0x3e460f73a6ccb16f), (0x3ad92747d94d94d7, 0x3e312782f0f2448a), (0x3a5745f5f5b1bc73, 0xbdd881d5842ec670), (0xba53516c45370c96, 0xbdbb4c521a316133), (0x39f845348a27f4b9, 0x3d63132da6b9ef80), (0xb9e1395c98d19f4a, 0x3d4019364d86610c), (0xb973bba720cb85bf, 0xbce5f4ab616b4a7d), (0xb92365a073b465df, 0xbcbd47ca99f425b7), (0xb90304c2a5a66771, 0x3c637371b17caa3a), (0xb8dc112a193fb5f1, 0x3c352a819018d0f2), (0x387a7ad3dc13170e, 0xbbdb5c2ea7518f33), (0xb848fe010506d44a, 0xbba8eaf2df7cede6), (0xb7e6b127ce015440, 0x3b4f4fdfa642b717), (0xb7a66fe7bcf681da, 0x3b185bcb7268f7c2), ], [ (0x3c6a47ab4241a9f5, 0xbfc5664e13b70622), (0xb5ac924d5c123479, 0x3900f098dc38e480), (0xbc5a47ab4241a9f5, 0x3fb5664e13b70622), (0x3bddc134f1d74a51, 0xbf540ee3940b092f), (0xbbffe75afd6ce0fa, 0xbf7c5e1ad9fb2f40), (0xbbab866102da4707, 0x3f1fb8a98ef4a243), (0xbbc018bed7b77750, 0x3f2de9be58a373e2), (0xbb75089b2cae9b03, 0xbed1bec95415e630), (0x3b447f8eea3cc056, 0xbed0cf264341409e), (0x3ac71d5b65310e89, 0x3e74677d9e214cd4), (0x3b026d69949fca90, 0x3e6766cc63507104), (0xba902c01ede1dfd5, 0xbe0c905882b94f65), (0xba995672d0443f95, 0xbdf62157963573dc), (0xba18987abee2ab90, 0x3d9ae2e0cbb67b06), (0x3a01b88c86e07d4b, 0x3d7e456a1c8dbf40), (0xb9a82e3122996ca9, 0xbd222e4736637ff5), (0x397f896eb454c48a, 0xbcff56a09da19f70), (0xb939b4426eb8647c, 0x3ca28607cce512f7), (0x38da5f520ae3c80c, 0x3c796a2f3d059107), (0xb8bff36f14735622, 0xbc1d78e82e3dfe4c), (0xb8985995658ccf15, 0xbbf096501f12c820), (0x381ac1859ffca23b, 0x3b92d35996fa684b), (0xb808697949d6df60, 0x3b61ce65ead2f56a), (0x37a076885f254fcf, 0xbb03bf2c7d52312b), ], [ (0x357834c50798eee0, 0xb9046916861c7cbe), (0xbc6e5d93454f99e3, 0x3fc4b2a2ebf61ece), (0x3bf37b02bd5f53a6, 0xbf6b3297fdae7902), (0x3c2eb354a6313bb4, 0xbf9b8105d59b114c), (0x3bb9bab6138b6903, 0x3f420a3f8c12a1ff), (0xbbf48ec1e2fa78e5, 0x3f55d18d69de6cfb), (0x3b0ad2f6c6600043, 0xbefc79db4b341e8e), (0x3b70c098a1ba083c, 0xbf00679c92c303b2), (0xbb4af505f8420dfd, 0x3ea53ac4ecd4be2d), (0x3b3bd880347c15c4, 0x3e9ca7507840c04b), (0xbadbc0ebcece96aa, 0xbe4253415f09767a), (0x3a8f2f3402a0f194, 0xbe305141505c9f00), (0xba73147caddad17a, 0x3dd4919940f05339), (0x3a20801c08cd53d5, 0x3dba20de95780e25), (0x3a0aad83cdc61600, 0xbd602fff3daabeb6), (0xb9cd95539d508286, 0xbd3f01d18581b85a), (0x3986a1dccaaee4ac, 0x3ce2d78e0d95c2b1), (0xb9420e56b2382383, 0x3cbc5cc76fc4031e), (0x390db41e1b715d4d, 0xbc60e00793400a38), (0xb8d97d5c56eaa5d3, 0xbc349c9cebd4542b), (0xb87767b6f54f3ae0, 0x3bd7fb7ba24468a5), (0x384f6e8dcd984b87, 0x3ba861a49c8b4594), (0xb7a3310c04ca52f6, 0xbb4bb5b1358f5d66), (0xb7bf2be7dc5aa7d5, 0xbb17ef6c51c02185), ], [ (0x3c6316f8ffd294bc, 0x3fc40f90793605bb), (0xb57f9e2ffd50aa0c, 0xb8e84b55d671e3ab), (0xbc5316f8ffd294bc, 0xbfb40f90793605bb), (0x3bf7017919c133d4, 0x3f5085775a5529c9), (0xbbe51eb6f09db1a0, 0x3f7aa0ce0421d1a8), (0x3bb34ca5aae2a0a8, 0xbf1a32a28e4bc82e), (0x3b829f8de1c1e358, 0xbf2c26ebca0e46de), (0xbb655efa83f66d77, 0x3ecd7400876206d0), (0x3b4cb5b0088841fe, 0x3ecfc1bbf57e3ae2), (0xbb1b0133a27f94ef, 0xbe710c7090487d3e), (0x3aef5fb8bc32c77a, 0xbe6634db39e4a305), (0x3aa91e07a77165aa, 0x3e0810d7e4efab49), (0x3a839aaf703b3d25, 0x3df51b513b3c4cf1), (0x3a336ceec537a192, 0xbd96dd877beb3775), (0xba0a1b2154c0dad9, 0xbd7d06057acf98a1), (0xb9b49d50f1878b22, 0x3d1f3b007c53631a), (0x3998369e87f01d70, 0x3cfe341812329072), (0x394269c561f0abb0, 0xbca0119135f2618c), (0x390e03cff1d48846, 0xbc789daf7e05bf20), (0xb89d5c1dd0bd003d, 0x3c19d09c42c2fd20), (0xb89ec3091d0a20a5, 0x3bf023bdfeef2b62), (0x383eea157ba50462, 0xbb90a443b12390a2), (0x380faad5050249de, 0xbb6165e9e44cf4fc), (0x37ac0bb1b2874365, 0x3b019b4693645186), ], [ (0xb563251dec0c8419, 0xb90190e21085c59e), (0x3c5948539688f9cf, 0xbfc37aac8c1aeabb), (0x3c0e1b9871576e7b, 0x3f66ac0d2e2f2f87), (0xbc3e2c9f8f0de524, 0x3f99e74e754ea71f), (0x3bc834f161e5b53a, 0xbf3e1c0589e32bb1), (0x3bfe8b15bd1b2805, 0xbf5496158dc5f7ff), (0x3b66422c8ac686b8, 0x3ef7d55405348ca9), (0x3b9138881216a9f6, 0x3eff0b30f4506228), (0xbb49c5af94afc68e, 0xbea1d9e3629b98ec), (0x3b31cbe80255f739, 0xbe9b35ef28e9de24), (0x3ac5335f73a99784, 0x3e3f0200e2650870), (0xbacc80c87bd0e106, 0x3e2f1fb225e849cb), (0xba76daf9021379d3, 0xbdd187928a64d042), (0xba42b8804ba3e9e1, 0xbdb908ba84482af1), (0xb9f798e4ea85d67c, 0x3d5bd0a97427e582), (0x39ae28268a102015, 0x3d3dd98a1888cb0d), (0x39800b32153c5fbf, 0xbce05368fdb3dbd3), (0x395973c2e28b46eb, 0xbcbb6e7eba27d4df), (0xb8fd64860bbe4d9f, 0x3c5d7e5c8f77a962), (0x388996f5c1af67cd, 0x3c34063c16fd02be), (0x386cbbfcf555cb4a, 0xbbd52213fb27642b), (0x384eb9fd51a68df4, 0xbba7c8fd7f555061), (0xb7c915bb96c79ac0, 0x3b489cfc43bd06a7), (0x37bcc11a3c54068e, 0x3b177056c238889b), ], [ (0x3c689d1f48185c7e, 0xbfc2f2072e638cf4), (0xb5952cb9317551e1, 0x3901222bb44bcf14), (0xbc589d1f48185c7e, 0x3fb2f2072e638cf4), (0x3be64a78bbbb198f, 0xbf4bd42b64fc5bed), (0x3c082c4cf012e7aa, 0xbf792bb5e1e159fc), (0x3ba0f7052b5160b8, 0x3f161ace3386dfd7), (0xbbc911bb758a62b7, 0x3f2aa8d1cf8db852), (0x3b53e6d95cbd37f7, 0xbec8ef624c36fc32), (0x3b54f1d79d1c68cf, 0xbece26d3747fe829), (0x3b0b9f4f6af339a7, 0x3e6d010d2bdb6fa2), (0xbb08db6527b88cec, 0x3e65272828ae4057), (0x3a509976106e8349, 0xbe0497b03c4482e4), (0x3a79f5e122b84d8f, 0xbdf42e35495a0b9f), (0x39cbebe4937d13e3, 0x3d93b2e62efa9ef3), (0x3a14579198fd4bcf, 0x3d7bdc7867dae011), (0xb9bf0d7f81848e9e, 0xbd1b1acb454ca400), (0xb97ccb74999a40d8, 0xbcfd1ce7997b3c0d), (0xb9380511e3a7c101, 0x3c9c1b1fc8c0e04f), (0x38cac264c6c80d21, 0x3c77d2b971f6828b), (0xb8b8eacaf1c3a530, 0xbc16c0313e58129c), (0xb85cf03733411e25, 0xbbef5c5d17f54410), (0x3815be1ad7496a82, 0x3b8d8dcf1e84a9c2), (0xb7e5c044edc6060a, 0x3b60f6f0c4603224), (0x379126e0d0da66b9, 0xbaff7e6aff22be1e), ], [ (0xb5627bd5768d6ae9, 0x38cc4a2cf6a18867), (0xbc389c717cff1eba, 0x3fc27407dfadee6d), (0x3c01b3998e2560e2, 0xbf6346950bfd91f1), (0x3c3dd532243e7d0c, 0xbf988d48d1d4eb7b), (0x3bcf03d11aeaafca, 0x3f399e6923ada922), (0x3bf2c9a985cf61c7, 0x3f538984b76cdf4a), (0x3b96fc0cb69470ac, 0xbef452194b75f3c7), (0xbb929abb7ce27bd1, 0xbefd855d7b8f0243), (0x3b33da9849a0f970, 0x3e9e8a88601ff296), (0x3aebb8f5815fd80b, 0x3e99f1bd69b16e6b), (0x3ac86d0d07634a8b, 0xbe3aa483fce054e3), (0x3ac5ab23f0a90bfb, 0xbe2dc4c02391c504), (0x3a69996a456ab65e, 0x3dce48dc1b4db792), (0x3a30cc58e232dc0c, 0x3db807112e6636fd), (0x39f6e9562163f106, 0xbd582c0e5f51b3f0), (0xb9c5c661501e7ee5, 0xbd3cc1592707b4bb), (0x3966aa764333f3df, 0x3cdc8f29e796ad34), (0xb95785ee30c62c1f, 0x3cba864ef1faff74), (0xb8ff8a02ad81ef19, 0xbc59f854cbd9efdc), (0x384627f385cebec8, 0xbc336efc940e4c98), (0xb87617b5b0e9289b, 0x3bd2bbd3c0ba4c14), (0xb84c5ed87745f0e5, 0x3ba72a3898c03cd9), (0x37e4b8d60a63fdb3, 0xbb45f681005965fc), (0xb7a7ad15bf5e48a5, 0xbb16e75915fef489), ], [ (0x3c51f9b16832f362, 0x3fc1ff5eec6a01cd), (0xb59a05b7856c4a22, 0xb8ff07a73b062717), (0xbc41f9b16832f362, 0xbfb1ff5eec6a01cd), (0xbbe5f2ed43d9b503, 0x3f47daf64983af9d), (0xbc19a4b7b3ed5b9d, 0x3f77ed5fffc1c774), (0xbbafa9d6f1d224d2, 0xbf12f947962314a1), (0x3bba27855de20282, 0xbf296027ea1d6e5c), (0xbb585d6672f6864b, 0x3ec57486c67fbc78), (0x3b6dbae692eab5c3, 0x3eccc11a59e13739), (0x3b07ece30b8718ed, 0xbe690ade515567ae), (0x3afec36878fc6271, 0xbe6438a7e22c9734), (0x3aac5fba9cf90508, 0x3e01db6d29a7d048), (0x3a9c694efcaf05a9, 0x3df3588cd299009a), (0xba304f511d090519, 0xbd912b3d3f46a11d), (0xba1f96e81c9933ce, 0xbd7aca95934e0ad5), (0x39a4c6d8ef3baa67, 0x3d17c19e5c2a3a3a), (0xb98de02178f2e8a7, 0x3cfc15e96b25adba), (0x3904b1879dbd8e47, 0xbc98c7e06842ee3d), (0xb8f76e2dea2e96ba, 0xbc770ecfbf61ca0d), (0x38b68e1efbe2a988, 0x3c142e95d318b6f5), (0xb874c2ceb9ea4228, 0x3bee73932c419ab8), (0x37f46e3304b4ae0c, 0xbb8a60b7a857ccc0), (0x380c4d64ccf85fc7, 0xbb608626d8e04736), (0xb7990c5c39207c1f, 0x3afc47487352322d), ], [ (0x35ab7cbed9b6b1f4, 0x390239f235357955), (0x3c6f5f4b08a76fd4, 0xbfc192f23ce3e051), (0x3bdee957b8603928, 0x3f60a668185c01b1), (0x3c39de5fb6906a4e, 0x3f9764141d652089), (0x3bd0a73bf1673e03, 0xbf3624437a2fe76a), (0xbbe29f0dad749d08, 0xbf52a184be0d9891), (0x3b92247582470aeb, 0x3ef196de0eeef190), (0x3b54bbca179d7e5e, 0x3efc317f854112ad), (0xbb3c4937a266ae2b, 0xbe9a8019ef772196), (0x3b1fa8fc16fd89b6, 0xbe98d38497beea33), (0x3ad1777abda5cdbe, 0x3e37318410813eeb), (0xbaa199670acf66d4, 0x3e2c8d9d45d76323), (0x3a61c9a46bc0a86d, 0xbdca782c1acc5d80), (0xba47414175e77281, 0xbdb71bbb74f830ea), (0x39fb21ba4fd0050e, 0x3d5539502b6b0d41), (0x39bde0e950bf1a4a, 0x3d3bbc22cd6ef8b2), (0xb951eab6630258a6, 0xbcd933a6402470d3), (0xb90f7f72f87b85f2, 0xbcb9a8f9bcb762d2), (0xb8f0fd489e307f2b, 0x3c5709caa1708994), (0xb8bf22055786ef23, 0x3c32db59b73d17f0), (0xb84510913d0bb141, 0xbbd0b5801d4ebd68), (0xb83e3fe31926f1ed, 0xbba68b53041d22be), (0xb7ecd50940caefad, 0x3b43b217fd3ffb23), (0x37a50bcc9d97c7ac, 0x3b165a991dfc9832), ], [ (0x3c6e71c482be67bd, 0xbfc12dd57bf18ada), (0x35745b4d4ccbb68f, 0x38d7a991cf97ce2e), (0xbc5e71c482be67bd, 0x3fb12dd57bf18ada), (0x3bd11b1ac52dc1e2, 0xbf44bebeff7b7f02), (0xbc1286f932bea2b2, 0xbf76d9afe88301fa), (0x3b859ae0593310ce, 0x3f10842d50687949), (0xbbc5025e938d5cb6, 0x3f2841d86b9b92f4), (0x3b45bc90ed56ac34, 0xbec2b5caad1f2b9a), (0xbb3771ef99211bfa, 0xbecb86bad42fc220), (0x3ac3d72243d64739, 0x3e65e5117a965bcf), (0x3b07539fc5e6a80e, 0x3e6364a25cc7309d), (0x3a51d7761a4ff87d, 0xbdff53dcc9459e76), (0x3a99aab279c470e8, 0xbdf297f421bb27bc), (0xba27ed296e5c55e5, 0x3d8e3c9c7289c65b), (0xba1d2b7fc29cc174, 0x3d79cfbae2bdc016), (0xb99b7a6311b584d8, 0xbd1502858f3b1429), (0x399664d160d01e32, 0xbcfb20c42e642ccd), (0x391ef844bb66595d, 0x3c9604b99922c587), (0xb91aa631f65ad96a, 0x3c7654ba0a2b4ab4), (0xb8bee3929b6ac229, 0xbc120523ef69f26a), (0xb88fba8fecf60808, 0xbbed920e28727809), (0x3816d4cbcfecdce6, 0x3b87ab7af32311cf), (0xb7f2f0febd96b7f0, 0x3b60169fdd2f6938), (0x3782a08850768123, 0xbaf9808bbbe92c37), ], [ (0x359dd81c30ee48fe, 0xb8f151a3aeac900c), (0x3c53f099a5f56db3, 0x3fc0cf3ed059c573), (0xbbff3cb9b807fae1, 0xbf5d242aa529931c), (0x3beb544962a1a242, 0xbf96613d93b0180b), (0x3bde039e229b4e70, 0x3f33627f261f5116), (0x3bf7fb39963ccff5, 0x3f51d69ca0d88394), (0xbb384fc5c48bb913, 0xbeeed574afab70fd), (0xbb95a44313a48eb8, 0xbefb06384e48ee5b), (0xbb387c094254f81d, 0x3e97452c65235728), (0xbaf881554ea8f625, 0x3e97d51f133b6843), (0xbad89e4d3b4b48e5, 0xbe346ac67a7e0c7c), (0x3ac74865f688f55b, 0xbe2b75d66a8d7fbb), (0x3a6411700cfe955c, 0x3dc75f5a5db478ef), (0xba50702b7e55e69b, 0x3db64531ca4ef464), (0x39b8d5aa5d138d2b, 0xbd52ceac14a86c69), (0xb9b1503306d5d1c3, 0xbd3aca497ff206bc), (0xb972644a7dcc9d17, 0x3cd66b96eb20b32f), (0xb954b544843ae3aa, 0x3cb8d889b2e2fb84), (0xb8e75b07f541d7cb, 0xbc5494ff17910999), (0x38c576f2b4ee6110, 0xbc324dc265486d0f), (0xb85a9820119b4156, 0x3bcdfc7ea51b3fad), (0x38430f69314493a8, 0x3ba5eff892c2d831), (0xb7dc83562058d69b, 0xbb41c095467f781e), (0x37bbc403c5629dc3, 0xbb15ce2e25be6e38), ], [ (0x3c61a13e2fee5687, 0x3fc076826cc2c191), (0xb5391b2ea81aa5bf, 0x38c00dbc5df9a26a), (0xbc51a13e2fee5687, 0xbfb076826cc2c191), (0x3be79f62aa488a9d, 0x3f4241b03eaaf5d9), (0xbc15dbe9d7210c2e, 0x3f75e7f53001e4b1), (0x3ba5f4ab61cd1e51, 0xbf0d17978e2d0336), (0xbbb79a683ed1c80a, 0xbf2745b0df80666a), (0x3b63b64ff7d7f045, 0x3ec0803f7f7fe323), (0xbb50168184fb2a2f, 0x3eca7006e6ad9cfe), (0xbb09b47df06e299a, 0xbe63590d57d48525), (0xbad3c549213b58f2, 0xbe62a7084b42b890), (0x3a391d2842dc92cf, 0x3dfbc0dd5a22c9a6), (0xba9fb98847ec903b, 0x3df1e9e4e20477cd), (0xba2be602f82a15a9, 0xbd8ade1de2460eb2), (0x3a17881703d93302, 0xbd78ea3bc5e51ddd), (0x397ca6386538b34a, 0x3d12bb86a88ccf82), (0x399525cc1707dd4e, 0x3cfa3d6bcad0c3fc), (0x393d78e1fc33fbc8, 0xbc93b476152074ba), (0x39110f06e5116481, 0xbc75a59813c6ee3d), (0x38bc4c43696de6db, 0x3c1030bae23c4e59), (0xb844d08b5dab4a58, 0x3becba7872c6d35c), (0x37cead7255599d43, 0xbb855a77ed00896a), (0x37e2184f9f8c0595, 0xbb5f548425ac1d81), (0x3797f6a7c6e97b07, 0x3af71a13b7056576), ], [ (0x357bf96ef321056c, 0x38e8be4b9ac053ef), (0x3c665439df5bb54c, 0xbfc0230b9797a7b3), (0x3bd7d914863ddca7, 0x3f59c8083b2b753a), (0xbc3c455b2fe151b8, 0x3f957d3203befd90), (0xbbd3de5214e17418, 0xbf3127cba22892de), (0x3bf0c5ff9d698a77, 0xbf51234471455a6c), (0xbb8a9c280a18d4c7, 0x3eeb4fe26ec3e489), (0xbb9cd17c659ae229, 0x3ef9fc5254f1086c), (0xbb3a46913af4f447, 0xbe94a44c6506c43f), (0x3b3f5055c4929bc5, 0xbe96f17dd184ad59), (0x3a9912b1a43a7c95, 0x3e3225640a6a9328), (0xbab880b364397a7e, 0x3e2a7943505d15ed), (0x3a4ecbcb0eff2849, 0xbdc4d296ecea7b61), (0x3a453c61fa23edd4, 0xbdb58177059b1ee7), (0x39e59e5790859f3e, 0x3d50cd71be5428ab), (0xb9dab853aa81b7a6, 0x3d39eafac486dfeb), (0x39594ed10e15fb80, 0xbcd417df1a94b2d2), (0xb940b5960ba1aada, 0xbcb81583d885c1c9), (0xb8fa5f714b1f1036, 0x3c52822e3f56f84b), (0xb8da3a40678675b0, 0x3c31c75f9fd23d85), (0x38595afb542f1092, 0xbbcb0fe75f5fce5e), (0xb8206d9263935574, 0xbba55a4472710434), (0x37b1baa0847432ef, 0x3b4014997c5c3405), (0xb7baecc415e584a1, 0x3b1544b15eb627ac), ], [ (0x3c5d7cc4171715a0, 0xbfbfa8b41711c83a), (0x357640b3baebf195, 0xb8d6a301383ff88d), (0xbc4d7cc4171715a0, 0x3fafa8b41711c83a), (0x3bca510f3e4f0ba8, 0xbf403a8d0f110fe1), (0x3c195ccf34fc85bb, 0xbf7511c6dadaaa12), (0xbb6fad55e36d2414, 0x3f09e040fc62c87e), (0x3bb45c7350ce4d8a, 0x3f266582f66d8d4c), (0xbb2c8a29c78431da, 0xbebd62a18e287536), (0x3b667f7ad529fbab, 0xbec976fb023f0f79), (0x3b0f3a432d46b94e, 0x3e6141188eda6cd5), (0x3afac6e99d820d1b, 0x3e61fc77546c2a70), (0xba3e756c586379ea, 0xbdf8ccadf7842b28), (0xba8280b1979ddc28, 0xbdf14c0515097baa), (0x3a1187e8ad78c9df, 0x3d8810b7fe5b7aae), (0xba14e29f33da57b3, 0x3d78181478442ce9), (0xb9b79ebe6761a2d6, 0xbd10d30b1ed6e857), (0xb995f6bc31063165, 0xbcf96afe82155a3c), (0x3927bc733591bf77, 0x3c91c038cd6a8753), (0xb8f984f4b5077d41, 0x3c7501961b5bf1bf), (0xb8a4dc2a78afb902, 0xbc0d4372ee42b73d), (0xb88b4f0dd2f40637, 0xbbebee0a131ab576), (0xb81ffd82b16be530, 0x3b835cde101c242e), (0x37ec5511ff967fb0, 0x3b5e84462bfb49f0), (0x378914b866c350ff, 0xbaf50552417f971d), ], [ (0xb556b1f952a5712e, 0xb8d6808df2a13f7c), (0x3c581bdf89b0a8b1, 0x3fbf13faf32c8e0a), (0xbbee91046256d1d1, 0xbf570558dddb7d46), (0xbc326d6d43908d3c, 0xbf94b24d7a933972), (0xbbb5423c2da87eef, 0x3f2ea52a21487a11), (0xbbf33353f135e755, 0x3f50834d8f3fdd5b), (0x3b8f2ed165228a36, 0xbee86941a4b43bea), (0xbb93d8441684ef00, 0xbef90e32cef3e900), (0xbb24c39a94ebc802, 0x3e92785f6385b273), (0xbaf58f1dccae728c, 0x3e962482bf9d2bb8), (0xbab1b25f4a923de6, 0xbe3043125386ac84), (0x3acbae29202faa10, 0xbe29943c303e31c2), (0xba689e50e7b79f94, 0x3dc2b2457a1921b4), (0xba5fc1c10645d26a, 0x3db4ce82afcbf544), (0x39e8d1c21f25be80, 0xbd4e3dcde42d462d), (0x39cd7cc147b1feaa, 0xbd391cdf33ca55c9), (0x396660b123953dac, 0x3cd220c06f5ae707), (0xb95a54474bf84f20, 0x3cb75f9d03ccf4de), (0x38e97ead5ea85772, 0xbc50be9744b83b69), (0x38d4e9dad41717fb, 0xbc3148975b0a87db), (0x38499800271bb705, 0x3bc88e2038a62c01), (0xb84c766c188201e5, 0x3ba4cb4d904c6a21), (0x37d9528d3a53acbd, 0xbb3d4587fbb07d3a), (0x37aa22e47790bf77, 0xbb14bfb26c12f06a), ], [ (0x3c0020b4016594ac, 0x3fbe8727daa3daed), (0x357bd9f848327b9d, 0xb8d74664ec9bed14), (0xbbf020b4016594ac, 0xbfae8727daa3daed), (0xbbae628434d2d25b, 0x3f3d19c52e070d9f), (0xbc1361836c532514, 0x3f74524d4813cc25), (0xbb7cb5b9aae4885e, 0xbf0735f790b535f3), (0xbbcfed1fabeeb9ac, 0xbf259c8f9f0a3484), (0xbb45b8692da7d38c, 0x3eba619ffc5a3ad0), (0x3b69523f4f9b3609, 0x3ec896d7dc819faf), (0xbaac3c0f5c29d085, 0xbe5f04efbdfeacf4), (0x3afee241ecc24fbe, 0xbe6162253f3024f4), (0xba6d1ca080c948cb, 0x3df653d736c3ef75), (0xba92d3e20a44098b, 0x3df0bc406f716b40), (0x3a244bdd54062834, 0xbd85b5420be0cc44), (0x3a0a9968781f3a0f, 0xbd77573e801c99fe), (0x39a0139e52f2e139, 0x3d0e6b725d3b2ae6), (0xb99e56935f64b195, 0x3cf8a83e6e4c168c), (0x392ead92886f9ee6, 0xbc90163396acd7b1), (0x391d3d6b8efb3080, 0xbc74685be0d8a97e), (0xb8a6ef909392303e, 0x3c0a9718712afa89), (0x385c475ef4355891, 0x3beb2d18cd37a98f), (0x382d92b3e5d0a3a0, 0xbb81a4a7bc85c3b0), (0x37e8bb074772c480, 0xbb5dbd9c4b52231d), (0x3792acc4acbf596f, 0x3af335a8be4bc776), ], [ (0x35982ed3998876be, 0xb8f5dc9ed9d5e051), (0xbc5a45a53b37a59e, 0xbfbe018d99f5da1b), (0x3be001e9c4dcf8a1, 0x3f54b85897b36265), (0xbc32db4ef3821944, 0x3f93fc442153435d), (0xbbcf201dea326b1a, 0xbf2b9694d71486e3), (0xbbef8e2381ba7f64, 0xbf4fe6fdc644ddde), (0x3b87d6d0f34bdbc3, 0x3ee5fd096e4523fb), (0xbb6b1063264f1631, 0x3ef83770c9a84498), (0x3b3a40ab832d99d2, 0xbe90a6f6f7e05f1b), (0xbb3f771b18195677, 0xbe956ad4a35eb0ad), (0x3ab57ad37dd35a78, 0x3e2d5bea474ca54f), (0xbac551a8f3695cff, 0x3e28c39f68d21b3c), (0x3a3d3669caabf1d6, 0xbdc0e73408ce7d88), (0xba59b3ea5bc5c592, 0xbdb42a6dedaa1a20), (0xb9ddcafa3dca5d8b, 0x3d4b640f953cb953), (0x397af903fd708234, 0x3d385e74fde5ce1a), (0x397d0253626bd0a6, 0xbcd0740945699eba), (0x39554011a8afef74, 0xbcb6b622427cf222), (0x38d2f100ca9a88c8, 0x3c4e76f4da90ff0f), (0x38d40ee48b131878, 0x3c30d15eeed4b2da), (0xb86bd3c37ebf7704, 0xbbc6647780d4dd5f), (0x384830339986f999, 0xbba44386be6e1434), (0x37b288dd01211d3e, 0x3b3ac32d5099a684), (0xb7bdc2d6cb33959c, 0x3b14400df422e81f), ], [ (0xbc5cb1f28997ca39, 0xbfbd8293aa55d18f), (0x35ac5e4a18056845, 0x39005c1969d4e17b), (0x3c4cb1f28997ca39, 0x3fad8293aa55d18f), (0x3bb680f417abeace, 0xbf3a48fe4afedcc8), (0xbc16c091c5e2bd3b, 0xbf73a5ccbc12a67b), (0xbba33c90d1ef4886, 0x3f04f91e41eee9bc), (0xbb9b30870eff030b, 0x3f24e72224db2c0e), (0xbb169834dfa01495, 0xbeb7dac8202ad4fb), (0x3b6372510d6e3ed7, 0xbec7cbd49c315be0), (0x3aee3c01a205f644, 0x3e5c1396b62b0f84), (0x3af43728856e7e95, 0x3e60d5c64a9c427f), (0x3a8951d1fb56f9e5, 0xbdf43c4a5d5a74a1), (0x3a9dff3a9a1305b7, 0xbdf038cb3f5e324b), (0xba2227a6954a8107, 0x3d83b473da8d9c7c), (0x3a00f6b33cdc63fd, 0x3d76a5d59f9a81dd), (0xb988bc6d23c00f13, 0xbd0ba9a1977e4129), (0x398765f6255cb3d1, 0xbcf7f3d211d80ca6), (0x392695fb30ce2147, 0x3c8d5107593c868e), (0xb917c43ab17af1b0, 0x3c73d94e8dd594b7), (0x3898ca359e8db05d, 0xbc08484736827c1c), (0xb8762b3eb4479bca, 0xbbea7775ae8da32a), (0x37fbcf628aa86234, 0x3b80264bfaa20223), (0x37e271fa49b2756e, 0x3b5d00eb74cea235), (0x379f3f3a922be29c, 0xbaf1a063ed726ac9), ], [ (0x35854b02b59f20a5, 0xb8e34bc17457894f), (0x3c5f215e77086bf5, 0x3fbd09b210b30217), (0x3bfc1f6fd559ad63, 0xbf52c74f6d120291), (0x3c0587bb3b3049f5, 0xbf9357bfc2be5860), (0xbbca26f6fb2c1060, 0x3f2901e4c495acea), (0x3bdfa22468c2245a, 0x3f4ee2a36979f905), (0xbb819f064e6a387e, 0xbee3f0cb93a497a4), (0x3b845c631a25decc, 0xbef7748921871bcc), (0x3af9ba7ee835a985, 0x3e8e39a085fc522a), (0x3b168e73edf85eb9, 0x3e94c1b7a6b2509f), (0xbacb21d04553bf28, 0xbe2aabe92ddd7d73), (0x3ac83c7d3d064b50, 0xbe2804c5ad3234f3), (0x3a2c4059ace3745e, 0x3dbec02b4af63bb7), (0x3a5e5f6d54d90428, 0x3db3938387c8ea5e), (0xb9a027aa900640db, 0xbd48f3df4c861285), (0xb9a31a1b83cb9055, 0xbd37ae3cd67c3467), (0x3962c6e3f82d4e4a, 0x3cce075e0968692d), (0x395097056b18178c, 0x3cb61833a4f480be), (0x38dbe00af812e106, 0xbc4bda71ed3079b1), (0xb8dbcc3ff8d7603a, 0xbc30616db3cfc278), (0x38543a30e58a4f05, 0x3bc483dc2d93ca5e), (0x383474a59c970c7b, 0x3ba3c2fe3717b507), (0xb7ce38a86dc4a340, 0xbb3892749970c097), (0xb7b9f0d1aaa91069, 0xbb13c62adb209305), ], [ (0xbc49df1f0f8d2108, 0x3fbc96700bf039e2), (0xb59b9f4f3b516a10, 0xb900369fa71bf644), (0x3c39df1f0f8d2108, 0xbfac96700bf039e2), (0xbbb8cb9fe6e6c906, 0x3f37e5647d30fea8), (0x3c06397704521ddc, 0x3f73095734a24496), (0xbb56346f9ac2b6d1, 0xbf0312a4db537d5b), (0x3bc2ab35cecaca9f, 0xbf24424a96e62373), (0xbb5dc2fd60429a9d, 0x3eb5b4a6639fb7be), (0xbb533d879080abe9, 0x3ec712e4d44c4a74), (0xba8a3e2fc66990c5, 0xbe59917dedf003d7), (0x3b0b520e9010331b, 0xbe6055757b098917), (0x3a8b72c27ccfb937, 0x3df2728cdc02e18c), (0x3a7adc897bdb4467, 0x3def80393fe2fc80), (0xb9fad4f603343968, 0xbd81fcaa37a8b374), (0x3a03afc083aed050, 0xbd760225681cd60a), (0x39753518ad0e9b45, 0x3d0949ef9ee5d1b2), (0xb979524731c89f4a, 0x3cf74c654a2656ac), (0x391010895dc3b28c, 0xbc8ad88e518a28d9), (0xb9155499f6d680c6, 0xbc7353b6d93fd106), (0x38a0ae7b9e53be9c, 0x3c0646e795fc374a), (0x3872458a3118ee05, 0x3be9cca80299b7b1), (0xb81bebc11d5a928d, 0xbb7db0b7e5620486), (0xb7fe8030136a44be, 0xbb5c4e2a3f8819a4), (0x379be3a580646aab, 0x3af03c8d0fb251d3), ], [ (0x359ca6ecae51f0ce, 0x38f785cd60d2c1ed), (0xbc37a2663626dcab, 0xbfbc28612a3bc18b), (0xbbf422f2d193784d, 0x3f511f52577ff6ba), (0x3c3976e0041aa23b, 0x3f92c21da135f56c), (0xbbc90eddb54be50c, 0xbf26ce18f8229e00), (0xbbed07e9f503136f, 0xbf4df586d8b786e1), (0xbb8f298c77e80033, 0x3ee230fede9c5ad4), (0xbb94e2ce3149cc01, 0x3ef6c2a7558fc928), (0xbb0453950e023ff5, 0xbe8b97329e667f58), (0x3b301d8210db0b8e, 0xbe9426ecfd66cd08), (0xbab764b9a347914a, 0x3e285e012a388a8c), (0x3aca4092574b7b84, 0x3e27557143798fcd), (0x3a3440e2c63fef00, 0xbdbc1f9f6fa068be), (0xba5fe0095953ab69, 0xbdb30842b25be60a), (0xb9d755f288da184b, 0x3d46d9757263a003), (0xb9bbfc5a456628aa, 0x3d370aced616e601), (0xb94bab13fb9e7f92, 0xbccb8986f8682a20), (0x3943b3e29fa75536, 0xbcb584e49cbf1ef2), (0x38ea081cc361bec5, 0x3c499540a7d48541), (0xb8c430149fc9b075, 0x3c2ff0b7143f7ffe), (0xb853ec9906091bb5, 0xbbc2e028bd3c8a70), (0xb83e36c66c5cd25b, 0xbba34986a6eaad8f), (0x37c533e5238e3cf1, 0x3b36a6785a72ecd5), (0x37a56b5d17159660, 0x3b1352244bd5f525), ], [ (0x3c58fff4515190b5, 0xbfbbbf246914235f), (0xb538ee4bd006c414, 0xb8bef99392c87f53), (0xbc48fff4515190b5, 0x3fabbf246914235f), (0x3b9cd1da1498a8c8, 0xbf35d923e8470178), (0xbbfbef9e896a9a49, 0xbf727a96f174b6d1), (0xbb885ae82e4dfd87, 0x3f01715e4bbb00e7), (0xbbcb52802ba3fd33, 0x3f23abacdb5106b5), (0xbb5ee3261cd7bab4, 0xbeb3dc30d27849d7), (0x3b6dfe5ed028776c, 0xbec6698d6ee99eb9), (0x3aeb6c016c328002, 0x3e576911a4642dff), (0xbaedb58a3fa04f2e, 0x3e5fbf415682210b), (0x3a8ffce5bcffc5e8, 0xbdf0e7d3674631fb), (0x3a850b7e524d421f, 0xbdeea1cbf2d9d28f), (0x3a0972a562b54d3c, 0x3d80805ad6510626), (0x3a139fee7249181d, 0x3d756aaba545a661), (0xb994ba8b6414df04, 0xbd073ab529b32537), (0x39993a6f276892ca, 0xbcf6b0b8fe737496), (0x39299d1bde722fbd, 0x3c88b1cfe8649fd4), (0x391ed1ce51d7dd6c, 0x3c72d6d686eeb22f), (0xb8a7b2dc61e1a2b3, 0xbc0486115598b4ec), (0x38788c9ff45e0eaa, 0xbbe92c11b4ee051b), (0x380d5cd889980784, 0x3b7b6646fc1094e2), (0xb7d3fbaf9d9205e6, 0x3b5ba50d4ef914aa), (0x377a30dc81384d5d, 0xbaee055a0471899a), ], [ (0xb51bc83c3a0e0aea, 0xb8afa7c9add8202e), (0x3c5d0edcbac85112, 0x3fbb5a6219b35e14), (0x3be54c0ba9407e4c, 0xbf4f645fdb1a8c89), (0x3c37a2e3fd65164b, 0xbf923940d01de8e9), (0x3bb0148b1871872e, 0x3f24e86a1e6384ff), (0xbbe17bbc96485963, 0x3f4d1c6a18c7ed95), (0xbb8c8ebe0fad0153, 0xbee0aeec61621923), (0xbb99391cbe507ac5, 0xbef61f7d30244338), (0xbaa992f34ae4f53d, 0x3e8950f781c1c41c), (0x3b3c536bd805608d, 0x3e93989942e07175), (0x3acb7edf5e20bddc, 0xbe265fd114ee2251), (0xbab668c775bebb6a, 0xbe26b3bd4dfd4b81), (0xba547f4392b0f26c, 0x3db9d8a1bbe00799), (0xba342c15e8cbe561, 0x3db2875c16e44880), (0xb9e8058b52e08699, 0xbd4505775bc7f118), (0x399839569d133457, 0xbd3672e2d4f2963b), (0x39448b9b5bdc1385, 0x3cc95d609dd374b0), (0x3922fcd538cfb114, 0x3cb4fb4d36b42032), (0xb8dba4f56475a1e4, 0xbc4798bab4a35bfe), (0xb8cbc77ae9cc73f8, 0xbc2f2b65eca95481), (0x38680bd8b9d2b683, 0x3bc16f8b2574d5ff), (0xb81bbb799c6ddbe9, 0x3ba2d6d14c18aef1), (0xb778386cee84a709, 0xbb34f49f286455da), (0x37858cd2c19af21f, 0xbb12e3e607d95973), ], [ (0xbc5024304247ada3, 0x3fbaf9cb49c4f935), (0xb59f12f721a3d64f, 0x38fd67b1800cc2aa), (0x3c4024304247ada3, 0xbfaaf9cb49c4f935), (0xbbdc12274808bdaf, 0x3f3413b75ce0cc1b), (0x3c06b1ae600584f2, 0x3f71f7a8fec6eba8), (0xbbac4403ae7487a8, 0xbf0008442739ebfc), (0xbbc9d63344ad0f44, 0xbf23215dab7537c6), (0xbb3addfeaaf586b0, 0x3eb242e9e6bab199), (0xbb4ca6d60de07627, 0x3ec5cdc48f5d75eb), (0x3afbb75278987302, 0xbe5589cf32f43f3a), (0xbafb7ec07d34bce4, 0xbe5ee5f0d63c1125), (0x3a7c35d35717242c, 0x3def216eedb0f95e), (0x3a8f8e312b763d9b, 0x3dedd414a7d8c97f), (0x3a0cada00b33585e, 0xbd7e69fdff844763), (0x3a13060575a01497, 0xbd74de15be6889e6), (0x3953d8e70538cd11, 0x3d056e1418ad8cf1), (0x399662b0ae22d5ef, 0x3cf61fa985a16926), (0xb91ad31c7ecc6374, 0xbc86cf250611e72c), (0xb90005c6530d9799, 0xbc7261f414b70fcc), (0xb88ee36933bdb2e6, 0x3c02fb5ddae9e3c7), (0xb876a7ccb4b4f8e6, 0x3be895055837a30a), (0x37c443af13e1d435, 0xbb7960ab422d80c4), (0xb7d0c27f905f8955, 0xbb5b052425ccb1af), (0x37393e1ef7ae32d2, 0x3aebd91e8263d1bb), ], [ (0xb5841211c9e4fbf8, 0x38e6aabd721697ea), (0x3c508b7cc7933a75, 0xbfba9d1835947d70), (0xbbcfb3814e43eef7, 0x3f4cea253049a85b), (0x3c3e993cf753c741, 0x3f91bb71f665dcdf), (0x3bc6de474edb7971, 0xbf23427f4797ae90), (0x3bab43046c577e07, 0xbf4c54a7bd6f30c1), (0xbb74fee4e6b715a1, 0x3edebe9e65809919), (0xbb914661eec5967d, 0x3ef58924fa089950), (0xbb1b1ce67962bafd, 0xbe87564501e7bcdc), (0xbb32d2083a6e1367, 0xbe9315306e5bb42b), (0x3abb19a5dd98b1c8, 0x3e24a32382dea2a5), (0xbacf847c762942f2, 0x3e261e0ee5367a22), (0xba5d25a1687ec831, 0xbdb7db8537582634), (0x3a40dc676669750a, 0xbdb20facb4a9bb8b), (0xb9e774de35526b14, 0x3d436bd6f0001ffb), (0x39c4a236b9d81483, 0x3d35e552618cbf26), (0x39679d0392cc254a, 0xbcc7754c8d46f92d), (0x394ad96fb5f59779, 0xbcb47a92b94007d3), (0xb8ef6b6af098cfd0, 0x3c45d920844ef181), (0xb8c4d1cfab1f2a0c, 0x3c2e71f74fd91a7e), (0xb86232b9682bb59c, 0xbbc02a09e0e77777), (0xb83a4f51c8d25c89, 0xbba26a7e606b3d3b), (0x37ac0d8d0af00df2, 0x3b33742f43880b52), (0x37b2cfe1ad3e0ef1, 0x3b127b3f3a3c24de), ], [ (0xbc55d35a88f1e0a3, 0xbfba4407e04298d1), (0xb57a12f3e3faa5bd, 0xb8ebd844c546d1fe), (0x3c45d35a88f1e0a3, 0x3faa4407e04298d1), (0xbbdfcf49ead39f19, 0xbf3288694b34ab21), (0x3c1c3cb8ccc39cf1, 0xbf717f0266db2149), (0x3b7370deeb1fc99d, 0x3efd9a9a1d05433b), (0xbbc76ae488c15a1a, 0x3f22a1c916a2d5a1), (0xbb55855b88c468bb, 0xbeb0dd9e92661e07), (0xbb0d6efd0446126a, 0xbec53dd972d8f232), (0x3af0ee48a1c77965, 0x3e53e6e553aac740), (0xbadd40df09e40809, 0x3e5e1cc65033998a), (0xba32b59db0216721, 0xbdecc8a3f36b4e82), (0xba8b62a99a7fbe14, 0xbded152ceac3373c), (0x3a1c9ccca0c04104, 0x3d7c249e1f309fe3), (0x3a0ef225196657ba, 0x3d745b3c1804be30), (0xb9afb28e8d2ffa7d, 0xbd03d90bb0238840), (0xb97d594b3ede144b, 0xbcf598302ab3ac8a), (0xb92a26a4f451568c, 0x3c85259cd87cdd6c), (0xb912f6ad38a9745a, 0x3c71f460abad18ae), (0x388ed6abd853f84f, 0xbc019e5f6867ef21), (0xb8739b58b6a444ab, 0xbbe806d32d68c464), (0x380a7ea4b739cc38, 0x3b77958de1803c3e), (0x37ef37708fa55952, 0x3b5a6deb944c06b2), (0xb78f61f40b1c77dc, 0xbae9ea1590f503a9), ], [ (0x357379a2bd7c52ce, 0xb8fbc8219db67734), (0x3c2748c82bad8c51, 0x3fb9ee5ee937fc89), (0x3bebaa9c093c19b6, 0xbf4abf28ad5bf6da), (0x3bf098a110e151ad, 0xbf9147481084ae0f), (0xbbcb58642b32be0e, 0x3f21d137345cfee5), (0x3bdbab7a25ecf8c2, 0x3f4b9c10ddf62464), (0x3b707cd222ddff83, 0xbedc72c9d49c6d7a), (0x3b9799bc03c5acb7, 0xbef4fe0b363ccc66), (0x3b2f6ffbbd8a09bd, 0x3e859a1c336b7506), (0xbb3843707d4c5068, 0x3e929b6632cc324d), (0xbaa20857a0292715, 0xbe231cd6e7991df9), (0xbab28b65ed5397d3, 0xbe25930872001f69), (0xba5cf09bb859c9ae, 0x3db61befbaafa006), (0xba2fa8cd2c2d9dc1, 0x3db1a038446ec46c), (0x39d429e8620217b4, 0xbd42030319ffc086), (0x39d5f3fcc28971f9, 0xbd35611796700e22), (0xb921b9f1f88c6b8d, 0x3cc5c664f879c556), (0x395775c1e2792ff0, 0x3cb401eb6a61fbc2), (0x38ead4ec597eb512, 0xbc444cf4a7922ede), (0x389608d2d57a3ecf, 0xbc2dc380c95ab35d), (0xb85138d52c6d34af, 0x3bbe1244da523859), (0x3811c5c33ebcb580, 0x3ba2042743d87f84), (0x37c0000bf1ca678b, 0xbb321df42759daa3), (0xb7b3e51de8fa1afc, 0xbb1217eed90481cc), ], [ (0x3c5728ab934a26a0, 0x3fb99be744018c90), (0x359a217cfc0fd73f, 0x38f8cb0a4bb92b1c), (0xbc4728ab934a26a0, 0xbfa99be744018c90), (0xbbc84fc91475651a, 0x3f312d4e1c1ca4c3), (0x3c0f281d89ca12e4, 0x3f710f5ca51f98b0), (0x3b9fa3d9c46c2f87, 0xbefb71417476a570), (0xbb82784bcc79df7f, 0xbf222b9fa8dfd762), (0xbb2378ade6a74c3f, 0x3eaf471061b7dd7e), (0x3b688d4663776f74, 0x3ec4b862279de756), (0x3ae406b21b8c7a34, 0xbe52763f34a53566), (0xbafcf6291cf32841, 0xbe5d61e605e8e69a), (0x3a86957e31ae2fc6, 0x3deab7331a682502), (0x3a8a902f91e8c962, 0x3dec637428f3fda4), (0x39f24e732a100c1c, 0xbd7a236ad0b3eb49), (0xba105ad2fccf3d78, 0xbd73e11cef6eae93), (0xb995c95ce2902dca, 0x3d0272cbaef43092), (0xb995e32a69772db7, 0x3cf519623b4e50ac), (0xb9292fc5f6cbd421, 0xbc83ac6109d4a7c0), (0xb916701f83b25b26, 0xbc718d7ac32164f8), (0xb8a62d82d427d871, 0x3c0068369bb2c654), (0x388344bf0ff0ace9, 0x3be780d0943d0646), (0xb7f8d6f94baf1bf3, 0xbb75fc6a10345edb), (0xb7d82ddcd0a763ae, 0xbb59ded950660f9a), (0x378e6b4fc0afac52, 0x3ae82fa57e04df35), ], [ (0xb59824ff875a6f4d, 0xb8fef5ad62580f34), (0xbc4e31356cad466d, 0xbfb94c6f54aef04b), (0xbbe68528f64c6571, 0x3f48d6371f018ef0), (0xbbf705a06948ad50, 0x3f90db975fd7dc47), (0x3bc06e812fbec708, 0xbf208bd1634353c9), (0x3beeb410edf15681, 0xbf4af0d3d4cd140d), (0x3b6d81ec6351ba6b, 0x3eda6c8e7c9d023e), (0xbb94f5f0c3884299, 0x3ef47cddcdac15d7), (0xbaee0980702c7029, 0xbe8412394fc50e0a), (0xbb3fb63544124d21, 0xbe922a21cb1edfe9), (0xbac10c16da7fd9d1, 0x3e21c417dedcf50f), (0xbaadc343b535f5ab, 0x3e25117f3061daaa), (0xba52f41f6480b3af, 0xbdb49009a6c8ef27), (0xba1394b790b42720, 0xbdb13823dda87c57), (0x39ecf2b99857d12c, 0x3d40c350b60502a2), (0x39d16c5f3587dedc, 0x3d34e54a89ae3a78), (0xb96e84c18fd85bb6, 0xbcc447dde87e69d6), (0xb92fa9fc1fe799a6, 0xbcb3909fa7a78345), (0x38e1d450f52eeca1, 0x3c42ec7e57d796d5), (0x38bc5414c0376e8d, 0x3c2d1f245967f392), (0x384f6a4fc5c93b04, 0xbbbc0ef954471f60), (0xb8436aa08a547d96, 0xbba1a364a86e2ed4), (0xb7c059ecba8db4c0, 0x3b30ebf4b4f1127f), (0xb792d76142a8ff7b, 0x3b11b9abb3510b7f), ], [ (0x3c5e213a1a4b3671, 0xbfb8ffc9bd24fe08), (0x3568e6cd71e05784, 0xb8c846638d0f2565), (0xbc4e213a1a4b3671, 0x3fa8ffc9bd24fe08), (0xbbcd36327411471d, 0xbf2ff51b38eef42c), (0xbc0f532ddb23dab4, 0xbf70a7a725d3fbc4), (0xbb834bf088b48836, 0x3ef988128728122a), (0xbbb5bd608899de58, 0x3f21bdc846a09e43), (0x3b3013850114c517, 0xbead1b60a4812ac4), (0xbb5a77447ea6fe43, 0xbec43c2d8e698c10), (0x3ad8023dfb41774f, 0x3e512fd6ccdafecc), (0xbaf62e671fb10d65, 0x3e5cb3bb8802e835), (0xba859d9d3a171da7, 0xbde8e1dd09a92324), (0x3a8ce00fffe0e74e, 0xbdebbd84404b6237), (0x3a0700486612292d, 0x3d785bcfd7db3db0), (0x3a131220e196908b, 0x3d736ed760739d88), (0x399d6eab7135136a, 0xbd01343464751bc4), (0x399a9e6748bc0bea, 0xbcf4a26ef2219c2c), (0x3916fec76005e868, 0x3c825c3fff5cf7ca), (0xb8f4e1647a2b0045, 0x3c712caee4bc257a), (0xb895bdf1f04f1575, 0xbbfea67f8d5490ce), (0x388017eb7fef7e93, 0xbbe7025c0acb6ed2), (0xb80d402134b327c6, 0x3b748e326c33fa45), (0xb7f36f706b3d34ec, 0x3b595763182ec3fa), (0xb77ee821070f844b, 0xbae6a29de364d58e), ], [ (0xb52b322a93406970, 0xb8e11567e5257506), (0x3c35e8738ef1b9ca, 0x3fb8b5ccad12d632), (0xbbd18507f867922a, 0xbf4724d0185980d2), (0x3c1f6ab95e49bd79, 0xbf907764ae2b1eeb), (0x3bbea971bec7b60e, 0x3f1ed6acc18fdf29), (0x3bca7600bd731e34, 0x3f4a51693df2efbb), (0x3b5424c5adeb27a5, 0xbed8a0ec61e4df7b), (0xbb2fcebf02eeb8d6, 0xbef4047f31fae045), (0xbb244d41e0ecfe16, 0x3e82b668af276950), (0x3b3cad4603e7028e, 0x3e91c07467ed6403), (0xbac9f09027e17c0c, 0xbe2091d32eea7f0f), (0xbacf61c0a2077065, 0xbe24987294de7d1e), (0x3a4c64cfb1cdc317, 0x3db32fe6ab220655), (0xba52d5ac79807dc5, 0x3db0d6b127f8ac22), (0x39d08853ae95a955, 0xbd3f4d16b8cb00ea), (0x39c9258c596bcdf2, 0xbd34711e3d50f99d), (0xb9607956efca23e8, 0x3cc2f28e5de9b115), (0x394e73cc5f03a293, 0x3cb326098eabb602), (0x38c9a844bf92f26d, 0xbc41b1699659661e), (0x38c79ee3937d0522, 0xbc2c84136a790cfd), (0xb84d287adf77e7fa, 0x3bba415dab11fbcc), (0x3843b689e4f1e579, 0x3ba147d23398faea), (0x37b913ca23ec4cc0, 0xbb2fb26f3c616548), (0x37a819aab969975c, 0xbb1160299cd9ebeb), ], [ (0x3c5b1c9821974148, 0x3fb86e51be0a9153), (0xb5720ba7256e1fdc, 0x38ee1da34bfeb8e0), (0xbc4b1c9821974148, 0xbfa86e51be0a9153), (0xbbcc79e50a2dc677, 0x3f2dd3c244b53279), (0xbbe9cfc1363faa0e, 0x3f7046fc5a218a86), (0x3b47339108bed763, 0xbef7d51accbfba76), (0x3bbac27d1a98311f, 0xbf2157556c0e1b1a), (0xbb2e6885549f0df6, 0x3eab2d01c12c8227), (0xbb685c37a3fcd2ca, 0x3ec3c838897d0a1e), (0xbaf6ac2b47952135, 0xbe500d37aa536a8b), (0x3afe13ef178fd248, 0xbe5c10ecf088eac6), (0x3a640bc972bc618d, 0x3de73f8d1af57f4c), (0xba7d1502b5443bc9, 0x3deb2227fe94022c), (0xba0e6bfbee228ee6, 0xbd76c5390bcf017b), (0xba1975f49279a432, 0xbd7303a6ded9ee03), (0x399abf56810fc89c, 0x3d0017772c8c0084), (0x399af156baca0aee, 0x3cf4329cf32bcb6e), (0xb9219214145d8323, 0xbc812f535b46fd28), (0x3904bff1857123e5, 0xbc70d1776a208c18), (0x3888ba3ef05e5fd1, 0x3bfcb5a589ad0a5c), (0x3871815404beb4a9, 0x3be68adf143f5d78), (0xb8166a2869445d1c, 0xbb734508c6e2f203), (0x37edd1f20932a7cc, 0xbb58d702f0f1cb76), (0xb774cc6cd565f7bf, 0x3ae53cf6ad4248fb), ], [ (0x3586adcfc24a15bd, 0x38fb4b40fa7659d2), (0x3c40ee4d5b1b8050, 0xbfb829356999a097), (0x3be3831592c6b168, 0x3f45a280e033eb59), (0x3c215c764657672c, 0x3f9019dba8336e48), (0x3b986e85a6375663, 0xbf1cd4559d95e619), (0xbbc0173a9412da83, 0xbf49bc857750335e), (0xbb63dae6774006f7, 0x3ed70706580693f9), (0x3b838496a72af1a4, 0x3ef393fc6cf8481f), (0xbaf56d91a42ef902, 0xbe81800af4665cb3), (0xbb2c21f37756b0a2, 0xbe915d91a2289a30), (0x3aa04b0681616769, 0x3e1f009c83572407), (0x3ab8eb4169a44614, 0x3e2427054565b344), (0xba4aede413980977, 0xbdb1f5167f464cc6), (0xba42c3010298ffea, 0xbdb07b3a2cb21729), (0xb9d5250b5c48f994, 0x3d3d4f453474d39c), (0x39d7de25bab32cb7, 0x3d3403dd864ce1b5), (0xb959c7b70a761729, 0xbcc1c096935c0515), (0x3949cfca62e35a95, 0xbcb2c193ec80c816), (0x38d72ce5fb9c0118, 0x3c40967d8ee82f54), (0x38b2d922c1971637, 0x3c2bf18fd1afe1de), (0x385409db53827004, 0xbbb8a21d0c689575), (0x384dc5f7e6e04311, 0xbba0f11083b9c847), (0x37ce8f2e696187cf, 0x3b2dc3272d23ffd6), (0xb7b0e86cfd0bfa4f, 0x3b110b1caef3d73d), ], [ (0x3c21907f595a082a, 0xbfb7e656efb009ae), (0xb590e3abdd6e7404, 0x38f3c9c05fc68dd7), (0xbc11907f595a082a, 0x3fa7e656efb009ae), (0x3bcce5fd1ce6de53, 0xbf2bec6b33efcb49), (0x3bcf8f1c9736150f, 0xbf6fd932c26aad94), (0x3b80b8964c190cdc, 0x3ef6504d7e054d50), (0xbbb3c0e77f493518, 0x3f20f77ce6105150), (0x3b3d95fb56d1d86f, 0xbea972e573db9593), (0x3b44588b63a38eb3, 0xbec35ba58bf2f993), (0x3ad1cbaf2f9e7b25, 0x3e4e1246a53112c6), (0xbac8e1b1b14782dd, 0x3e5b7850b3bc8175), (0xba87c131e73bb3fd, 0xbde5c8dcec477a4e), (0xba84c1608c9f12fa, 0xbdea905348b4924d), (0x39e529efb683a910, 0x3d7558a1f12cdd3f), (0x3a18c3b5cbcd2fee, 0x3d729edf3b2865f3), (0x399e9dec38211b14, 0xbcfe2f9cdddbe89c), (0x3991f206b8c5d3a1, 0xbcf3c947b936c2fd), (0xb926d15a781493eb, 0x3c8020bb8706a05b), (0x391b89b4941b2fbc, 0x3c707b5bb2f1e971), (0x3875331d8b43e31b, 0xbbfaf6220e4137a4), (0x388fbf932efdfa5c, 0xbbe619cedd775137), (0xb7f15f7042e6e287, 0x3b721c04bebc0bb5), (0x37f3601b48c231f4, 0x3b585d398a9b6f0b), (0x378dd18a95cb152b, 0xbae3f99b23077622), ], [ (0x352bf89ec4e05302, 0x38c2beead70ae7d0), (0xbc529270d2a71e91, 0x3fb7a597e9550934), (0xbbd42472048d4fe5, 0xbf44486c0b012534), (0xbc2ac52ac4327de6, 0xbf8f848eec0e0e6b), (0x3b684f34372ed852, 0x3f1b077fae06adc6), (0xbbce518d0a756962, 0x3f49310d6e6842c6), (0x3b230b8888fa2afa, 0xbed597a5befbd70e), (0x3b9e1e12047ef68f, 0xbef32a855e4e113b), (0xbb1d73ebaa41845b, 0x3e8069ba0b1a612d), (0xbb3a5058b2aec6be, 0x3e9100c97ba8e22d), (0xbab085381e3747da, 0xbe1d15b5350404fa), (0x3ac28b1288705592, 0xbe23bc775cca4413), (0x3a5ffd971088266f, 0x3db0da51f94c98f0), (0x3a5dfce6ace7ab08, 0x3db0252dc33a4d7a), (0xb9dc3fdc25aa9e9a, 0xbd3b84d751a36bd2), (0x39b47e26246286bb, 0xbd339ce8224cc6de), (0x395a80d541531404, 0x3cc0ad1ba9d01451), (0xb95b7f3b36aa04cc, 0x3cb262b8db934833), (0x38dc5e49fddd8fdf, 0xbc3f2ec77da02f0e), (0x38a348be97d223b5, 0xbc2b66ebaf597acc), (0x385369dda16c7b7d, 0x3bb72b1780503c41), (0x3840d18df6c3b214, 0x3ba09ec633447fba), (0xb7afbf9889f21003, 0xbb2c0312119c246e), (0xb7bc1892f4c2e089, 0xbb10ba3b452a59bb), ], ]; pxfm-0.1.23/src/bessel/j0f.rs000064400000000000000000000251571046102023000137640ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j0f_coeffs::{J0_ZEROS, J0_ZEROS_VALUE, J0F_COEFFS}; use crate::double_double::DoubleDouble; use crate::polyeval::{f_polyeval9, f_polyeval10, f_polyeval12, f_polyeval14}; use crate::sin_helper::cos_small; use crate::sincos_reduce::rem2pif_any; /// Bessel of the first kind J0 /// /// Max ulp 0.5 pub fn f_j0f(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffff; if (x.to_bits() & 0x0007_ffff) == 0 { if f32::from_bits(x_abs) == 0. { // J0 value at 0 return f64::from_bits(0x3ff0000000000000) as f32; } if x.is_infinite() { return 0.; } if x.is_nan() { return x + x; } } if x_abs <= 0x4295999au32 { // 74.8 if x_abs <= 0x3e800000u32 { // 0.25 return j0f_maclaurin_series(x); } if x_abs == 0x401a42e8u32 { return f32::from_bits(0xbb3b2f69u32); } return small_argument_path(x); } // Exceptions if x_abs == 0x65ce46e4 { return f32::from_bits(0x1eed85c4); } else if x_abs == 0x7e3dcda0 { return f32::from_bits(0x92b81111); } else if x_abs == 0x76d84625 { return f32::from_bits(0x95d7a68b); } else if x_abs == 0x6bf68a7b { return f32::from_bits(0x1dc70a09); } else if x_abs == 0x7842c820 { return f32::from_bits(0x17ebf13e); } else if x_abs == 0x4ba332e9 { return f32::from_bits(0x27250206); } j0f_asympt(x) } /** Generated by SageMath: ```python # Maclaurin series for j0 def print_expansion_at_0_f(): print(f"pub(crate) const J0_MACLAURIN_SERIES: [u64; 9] = [") from mpmath import mp, j0, taylor mp.prec = 60 poly = taylor(lambda val: j0(val), 0, 18) z = 0 for i in range(0, 18, 2): print(f"{double_to_hex(poly[i])},") print("];") print(f"poly {poly}") print_expansion_at_0_f() ``` **/ #[inline] fn j0f_maclaurin_series(x: f32) -> f32 { pub(crate) const C: [u64; 9] = [ 0x3ff0000000000000, 0xbfd0000000000000, 0x3f90000000000000, 0xbf3c71c71c71c71c, 0x3edc71c71c71c71c, 0xbe723456789abcdf, 0x3e002e85c0898b71, 0xbd8522a43f65486a, 0x3d0522a43f65486a, ]; let dx = x as f64; f_polyeval9( dx * dx, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), ) as f32 } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] fn small_argument_path(x: f32) -> f32 { let x_abs = f32::from_bits(x.to_bits() & 0x7fff_ffff) as f64; // let avg_step = 74.6145 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6299043751549631; let fx = x_abs * INV_STEP; const J0_ZEROS_COUNT: f64 = (J0_ZEROS.len() - 1) as f64; let idx0 = fx.min(J0_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(J0_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(J0_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(J0_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return j0f_maclaurin_series(x); } // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(J0_ZEROS_VALUE[idx]) as f32; } let c = &J0F_COEFFS[idx - 1]; let r = (x_abs - found_zero.hi) - found_zero.lo; let p = f_polyeval14( r, f64::from_bits(c[0]), f64::from_bits(c[1]), f64::from_bits(c[2]), f64::from_bits(c[3]), f64::from_bits(c[4]), f64::from_bits(c[5]), f64::from_bits(c[6]), f64::from_bits(c[7]), f64::from_bits(c[8]), f64::from_bits(c[9]), f64::from_bits(c[10]), f64::from_bits(c[11]), f64::from_bits(c[12]), f64::from_bits(c[13]), ); p as f32 } #[inline] pub(crate) fn j1f_rsqrt(x: f64) -> f64 { (1. / x) * x.sqrt() } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - PI/4 - alpha(x)) */ #[inline] fn j0f_asympt(x: f32) -> f32 { let x = x.abs(); let dx = x as f64; let alpha = j0f_asympt_alpha(dx); let beta = j0f_asympt_beta(dx); let angle = rem2pif_any(x); const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651); const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_cos = cos_small(r0); let z0 = beta * m_cos; let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx); (scale * z0) as f32 } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied. Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(0, x, 50) Q = Qn_asymptotic(0, x, 50) R_series = (-Q/P) # alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)]) alpha_series = arctan_series_Z(R_series) # see the series print(alpha_series) ``` **/ #[inline] pub(crate) fn j0f_asympt_alpha(x: f64) -> f64 { const C: [u64; 12] = [ 0x3fc0000000000000, 0xbfb0aaaaaaaaaaab, 0x3fcad33333333333, 0xbffa358492492492, 0x403779a1f8e38e39, 0xc080bd1fc8b1745d, 0x40d16b51e66c789e, 0xc128ecc3af33ab37, 0x418779dae2b8512f, 0xc1ec296336955c7f, 0x4254f5ee683b6432, 0xc2c2f51eced6693f, ]; let recip = 1. / x; let x2 = recip * recip; let p = f_polyeval12( x2, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), f64::from_bits(C[10]), f64::from_bits(C[11]), ); p * recip } /** Beta series Generated by SageMath: ```python #generate b series def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x', default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(0, x, 50) Q = Qn_asymptotic(0, x, 50) def sqrt_series(s): val = S.valuation() lc = S[val] # Leading coefficient b = lc.sqrt() * x**(val // 2) for _ in range(5): b = (b + S / b) / 2 b = b return b S = (P**2 + Q**2).truncate(50) b_series = sqrt_series(S).truncate(30) #see the series print(b_series) ``` **/ #[inline] pub(crate) fn j0f_asympt_beta(x: f64) -> f64 { const C: [u64; 10] = [ 0x3ff0000000000000, 0xbfb0000000000000, 0x3fba800000000000, 0xbfe15f0000000000, 0x4017651180000000, 0xc05ab8c13b800000, 0x40a730492f262000, 0xc0fc73a7acd696f0, 0x41577458dd9fce68, 0xc1b903ab9b27e18f, ]; let recip = 1. / x; let x2 = recip * recip; f_polyeval10( x2, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), ) } #[cfg(test)] mod tests { use crate::f_j0f; #[test] fn test_j0f() { assert_eq!(f_j0f(3123.), 0.012329336); assert_eq!(f_j0f(0.1), 0.99750155); assert_eq!(f_j0f(15.1), -0.03456193); assert_eq!(f_j0f(f32::INFINITY), 0.); assert_eq!(f_j0f(f32::NEG_INFINITY), 0.); assert!(f_j0f(f32::NAN).is_nan()); } } pxfm-0.1.23/src/bessel/j0f_coeffs.rs000064400000000000000000000675611046102023000153160ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** J0 zeros and extremums. Generated by SageMath: ```python # searching for zeros and extremums R120 = RealField(120) zeros = [] mp.prec = 150 step = mpf("0.001") epsilon = mpf("1e-35") x = mpf("0.0") def j0_prime(x): return diff(lambda t: besselj(0, t), x) previous_zero = R120(0) j0_zeros = [] while x < mpf("76.0"): f1 = besselj(0, x) f2 = besselj(0, x + step) if f1 * f2 < 0: zero = findroot(lambda t: j0(t), (x, x + step), solver='bisect', tol=mp.mpf("1e-41")) previous_zero = zero j0_zeros.append(zero) if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon: zeros.append(previous_zero) x += step j0_extrema = [] x = mpf("0.0") while x < mpf("76.0"): d1 = mp.diff(lambda t: j0(t), x) d2 = mp.diff(lambda t: j0(t), x + step) if d1 * d2 < 0: extremum = findroot(lambda t: mp.diff(lambda u: j0(u), t), (x, x + step), solver='bisect', tol=mp.mpf("1e-41")) j0_extrema.append(extremum) x += step # Print results for i, z in enumerate(j0_zeros): print(f"Zero {i+1}: x ≈ {z}") print("Extrema (peaks/valleys) of J0(x):") for e in j0_extrema: print(f"nExtrema: {e}") j0_zeros.extend(j0_extrema) j0_zeros = sorted(j0_zeros) # Print results for i, z in enumerate(j0_zeros): print(f"Peak or zero {i+1}: x ≈ {z}") print("") print("pub(crate) static J0_ZEROS: [(u64, u64); 48] = [") print(f"(0x0, 0x0),") for z in j0_zeros: k = split_double_double(z) hi = double_to_hex(k[1]) lo = double_to_hex(k[0]) print(f"({lo}, {hi}),") print("];") ``` **/ pub(crate) static J0_ZEROS: [(u64, u64); 48] = [ (0x0, 0x0), (0xbca0f539d7da258e, 0x40033d152e971b40), (0xbca60155a9d1b256, 0x400ea75575af6f09), (0x3c975054cd60a517, 0x4016148f5b2c2e45), (0xbc9b226d9d243827, 0x401c0ff5f3b47250), (0xbcb51970714c7c25, 0x40214eb56cccdeca), (0x3cc02610a51562b6, 0x402458d0d0bdfc29), (0x3cb444fd5821d5b1, 0x40279544008272b6), (0x3cb2bce7fd18e693, 0x402aa5baf310e5a2), (0xbcc9796609364e85, 0x402ddca13ef271d2), (0xbcdd2a68e88ab317, 0x4030787b360508c5), (0xbcd165fd108f46ff, 0x403212313f8a19f6), (0xbcd21830197e9e86, 0x40339da8e7416ca4), (0x3cc1d2dfa1c3b5a8, 0x4035362dd173f792), (0xbcc1bf33afef88f1, 0x4036c294e3d4d8ac), (0x3cd0847c620015e0, 0x40385a3b930156dd), (0x3cc1a2686480d882, 0x4039e7570dcea106), (0x3cdd2b3714972b28, 0x403b7e54a5fd5f11), (0xbcb42ce39ec976fb, 0x403d0bfcf471fccc), (0xbcc36bbabc1c9f31, 0x403ea27591cbbed2), (0xbcdbe3a1cd066b66, 0x404018476e6b2bf0), (0x3cda326cf4307839, 0x4040e34e13a66fe6), (0xbced5fbbff045068, 0x4041aa890dc5e97c), (0xbcd0b6068f861c6f, 0x404275637a9619ec), (0x3cc9eafeca0ca4fd, 0x40433cc523d5cb69), (0xbcb34c86f4e27936, 0x4044077a7ed6293a), (0x3cc489bd556e510a, 0x4044cefcf1734b62), (0x3cced48fe99f45ef, 0x40459992c65d0d8d), (0x3ce4f716f3179d90, 0x404661315d6b133f), (0xbcd05a7a0525058f, 0x40472bac0f810810), (0xbcef3950a842db79, 0x4047f36312028ad6), (0x3ce575dc7f8a031a, 0x4048bdc6293f0657), (0x3ce85d7bdb30baf1, 0x404985928f96d51e), (0xbcdfa16a338bbaee, 0x404a4fe0ee444c7b), (0x3ce3d41e041caa68, 0x404b17c038c2018c), (0xbce43e4a90356acf, 0x404be1fc41a4c607), (0x3cda139ce2cd08ac, 0x404ca9ec5a82324b), (0x3ce0f4b1c9544480, 0x404d74180c9e41f6), (0xbcb12e6ef2e594e1, 0x404e3c1731d64f1e), (0x3ceff10a69607aab, 0x404f06343d0971d4), (0x3cdfd1ee8286358a, 0x404fce40efb1156e), (0xbcf8991ca07c84c0, 0x40504c28621f11e6), (0x3ced3cacfc720419, 0x4050b034dde75b42), (0xbcee90a52cffc26f, 0x40511536cb22d72b), (0xbcee669304bfe748, 0x40517948db63675c), (0xbcf5328276c045f2, 0x4051de4554a1c2dd), (0x3cf8eb4a94b63936, 0x4052425c7dcacdf6), (0x3cff05f585843675, 0x4052a753fa820480), ]; /** Roots and values for extremums and J0 zeros. Generated by MPFR: ```text let mut arr = vec![]; for zeros in J0_ZEROS.iter() { let mpfr = Float::with_val(107, f64::from_bits(zeros.1)).j0(); arr.push(mpfr.to_f64().to_bits()); } println!( "arr: [{}]", arr.iter() .map(|x| format!("0x{:016x}", x)) .collect::>() .join(", ") ); ``` **/ pub(crate) static J0_ZEROS_VALUE: [u64; 48] = [ 0x3ff0000000000000, 0xbc919b7921f03c8e, 0xbfd9c6cf582cbf7f, 0xbc7fbb40985f6e34, 0x3fd33518b3874e8a, 0xbc96e8eeb22e5818, 0xbfcff654544ebcd1, 0xbc92d8ed368e0843, 0x3fcbf3337873a7d8, 0xbca50be2ef09843e, 0xbfc925c6fca08f55, 0x3caa2122af76659e, 0x3fc70c511227d5aa, 0x3c98b4b912da2218, 0xbfc5664e13b70622, 0xbca55e059345b430, 0x3fc40f90793605bb, 0x3cb1c17abe35eaae, 0xbfc2f2072e638cf4, 0x3c966608ac164dbd, 0x3fc1ff5eec6a01cd, 0x3cacc62c8409daa7, 0xbfc12dd57bf18ada, 0x3ca18e7b1f5c77ae, 0x3fc076826cc2c191, 0xbc8376cc57901722, 0xbfbfa8b41711c83a, 0xbc9df12b66b26573, 0x3fbe8727daa3daed, 0xbc9eab3b2bf5813d, 0xbfbd8293aa55d18f, 0xbcb3795064667200, 0x3fbc96700bf039e2, 0xbcabd526bce38ac7, 0xbfbbbf246914235f, 0x3cb14dbc2a692434, 0x3fbaf9cb49c4f935, 0x3cac341b9f831174, 0xbfba4407e04298d1, 0xbcb9e23f9c9ca91e, 0x3fb99be744018c90, 0xbcc3725f95922088, 0xbfb8ffc9bd24fe08, 0x3cb79a2187735244, 0x3fb86e51be0a9153, 0xbcc0012df1d3ef73, 0xbfb7e656efb009ae, 0xbcc6ecd27843db59, ]; /** Taylor coefficients for J0 [0; 74.62] Generated by SageMath with Sollya: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = (zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i]) + 0.83 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05 b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(j0_zeros) # print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 500; bessel_j0 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_j0(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RR(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return degree = 13 print(f"pub(crate) static J0F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print("[") for c in coeffs: print(double_to_hex(c) + ",") print("],") print("];") ``` **/ pub(crate) static J0F_COEFFS: [[u64; 14]; 47] = [ [ 0xbca69de51bcc0120, 0xbfe09cdb3655127d, 0x3fbba1deea029925, 0x3facfae8643687e7, 0xbf81bb1cbe1caeb6, 0xbf61f992590d3f89, 0x3f315382bbf1a06b, 0x3f06ed3ba591e6da, 0xbed232c8d8aba5cc, 0xbea1cceb52db45ee, 0x3e68006b6b5682ca, 0x3e329cc1da0793f0, 0xbdf5dbb0053da32b, 0xbdc04e14e5d96539, ], [ 0xbfd9c6cf582cbf7f, 0x3cb1d608597b5d8f, 0x3fc9c6cf582cbf55, 0xbf91f06d14e12b29, 0xbf8b589d1da0f7e4, 0x3f50f9103d00ae93, 0x3f38644561ce9290, 0xbefa2a034c749192, 0xbed83a0686fd1dd2, 0x3e96a5085d7844b5, 0x3e6ebfcaacd49b87, 0xbe2964b9932b57f3, 0xbdfad73cf4701511, 0x3db5acbea609d3e5, ], [ 0xbc6a1105f9dbcdd5, 0x3fd5c6e60a097826, 0xbf9f8f72e7a8471e, 0xbfab2150cb41ece4, 0x3f72f7ffe901b59c, 0x3f627e31fe9ddafb, 0xbf26f641f369bbbd, 0xbf0863f485fc7e89, 0x3ecad77cbbb32bcd, 0x3ea32e705af41964, 0xbe62d9d2bb447e35, 0xbe341f0e4f4dc44a, 0x3df198b51eee9749, 0x3dbec8f104a030ca, ], [ 0x3fd33518b3874e8a, 0xbca7f56ee546a569, 0xbfc33518b3874e3b, 0x3f7d34125d59fb96, 0x3f880c83bdee71b4, 0xbf4483c20f2abbd1, 0xbf36ffa5fc0ccc0f, 0x3ef2ccf7bbc1d620, 0x3ed796a6caa245fc, 0xbe91e85738cfdd42, 0xbe6e69b581df4be3, 0x3e2550287122730e, 0x3dfab73cc2e87ac7, 0xbdb250809ed630ba, ], [ 0x3c684670459725e1, 0xbfd15f7977a772d5, 0x3f900f7fcf183c65, 0x3fa68b984ec64b1d, 0xbf648e63600c54a1, 0xbf60e0d6038721a4, 0x3f1d7960512fb682, 0x3f07800bc7410c66, 0xbec3324799a7e0fb, 0xbea30e8df2325ca1, 0x3e5cecefe3d75abb, 0x3e3458cbaa06ef8d, 0xbdec4dd6cf551d07, 0xbdbefa0975b65713, ], [ 0xbfcff654544ebcd1, 0x3ca0ffc636e7373a, 0x3fbff654544ebc20, 0xbf70c17ff72b1352, 0xbf84b0c5d5d9e7c9, 0x3f394154be849b76, 0x3f34e12c2fdccc3a, 0xbee9f32fcfbab067, 0xbed63c53e4cc158b, 0x3e8adbb88b7826d7, 0x3e6d5f825ac22ee0, 0xbe20f17a50351084, 0xbdfa326458f60fce, 0x3dae0e0c6fa040ee, ], [ 0xbc648b5c145d146f, 0x3fcdc13e66ac2e78, 0xbf842ff0cdc58194, 0xbfa38d1dd8992ef5, 0x3f5a55e9b344ea02, 0x3f5e2e16f97e7f5f, 0xbf13dfc37714f92e, 0xbf05ce7f4a51d917, 0x3ebbb177bc7895b4, 0x3ea2346df84ab988, 0xbe56125b44798bd5, 0xbe33d7cc75fbdd4e, 0x3de68bc84d67bb0a, 0x3dbe749161c75b7f, ], [ 0x3fcbf3337873a7d8, 0xbc999eb31028b75f, 0xbfbbf3337873a725, 0x3f66604d91f94ba7, 0x3f8251858010ffd8, 0xbf314bc11a41832e, 0xbf32e7decc933381, 0x3ee293b4d39e1d9e, 0x3ed4a66fbc1f8e7c, 0xbe843cb02661be36, 0xbe6bdd61e41af9d3, 0x3e1ab24db7abbdd7, 0x3df940cc3ecafe33, 0xbda870435d8d1863, ], [ 0x3c6110461d393f0c, 0xbfca701d0f967501, 0x3f7c54b930fef3e4, 0x3fa17798aa09f194, 0xbf52a21514062f70, 0xbf5b541f829ca99f, 0x3f0cc0bd9fd11443, 0x3f041f3b06c79efa, 0xbeb4b22fc3292c98, 0xbea1223e5773d27c, 0x3e5118e5cf14a591, 0x3e32ffb6478c2281, 0xbde20a2b34bd7e9f, 0xbdbd77afc051bc6c, ], [ 0xbfc925c6fca08f54, 0x3c941bba0a9908a3, 0x3fb925c6fca08ea3, 0xbf6049377403d97d, 0xbf809463bbcfb70d, 0x3f297b35471ddd4a, 0x3f314dd43fc4bda8, 0xbedbf665e54737fe, 0xbed32caf8123dd12, 0x3e7f510484fa37ba, 0x3e6a42a3b8b1effd, 0xbe1544b8d56d77a8, 0xbdf81cfb72892ddb, 0x3da3f5749b01c5c3, ], [ 0xbc5c64a3611bf4cb, 0x3fc8077f56c9b782, 0xbf75467eb535dac4, 0xbf9fd7c3ad6f5a3e, 0x3f4c1b47c806f9c6, 0x3f59166c7d3ee8f7, 0xbf05f01522f72552, 0xbf02aa939ff2e34a, 0x3eb0129642c0eedc, 0x3ea01716d7274ce0, 0xbe4b21ada69ec1ec, 0xbe320ffbd6f367e8, 0x3ddd441699eaa4df, 0x3dbc46351a30e033, ], [ 0x3fc70c511227d5aa, 0xbc903dd711e6b7a7, 0xbfb70c511227d4fe, 0x3f5910ebe1f1fa45, 0x3f7e7dc08e6ff244, 0xbf23bd7d15b0a88f, 0xbf300357a101d595, 0x3ed5ec733cb20d5b, 0x3ed1e5d1fa4386ae, 0xbe78f423a07fedeb, 0xbe68c089aeb3a360, 0x3e1143a2a87b28be, 0x3df6f2d06548607b, 0xbda07d7d6f49ddb9, ], [ 0x3c57d1baaf487c60, 0xbfc62d93aa9d05bb, 0x3f70ba9ce88926ac, 0x3f9d7073daebb038, 0xbf462813c7f32d76, 0xbf574a948d055ffc, 0x3f01695764ad01fd, 0x3f0170ab5ed77aa3, 0xbea9c8e2cba34328, 0xbe9e4d88f9ebcadb, 0x3e460ec3e9bbfca2, 0x3e312751ad8cf2c9, 0xbdd825b2017389c1, 0xbdbb0b4f2fdaca95, ], [ 0xbfc5664e13b70621, 0x3c8adfee580612ab, 0x3fb5664e13b7057b, 0xbf540ee3940b2f9d, 0xbf7c5e1ad9fa40ad, 0x3f1fb8a98f136a0c, 0x3f2de9be57a255f8, 0xbed1bec95e73b04b, 0xbed0cf25bf302fd8, 0x3e746784408bf531, 0x3e676640f349bd8a, 0xbe0c944164ad511b, 0xbdf5d837e7a07aba, 0x3d9ba3ab0edd6dab, ], [ 0xbc543722dc20f623, 0x3fc4b2a2ebf61ecd, 0xbf6b3297fdae7373, 0xbf9b8105d59b1125, 0x3f420a3f8c10a2c5, 0x3f55d18d69de4109, 0xbefc79db490d157b, 0xbf00679c92947f5d, 0x3ea53ac3d1de0eb7, 0x3e9ca750128116cf, 0xbe4252ac12ff61fa, 0xbe3051067c8a6420, 0x3dd4435be57e146d, 0x3db9dcd0ca8a2a1d, ], [ 0x3fc40f90793605bb, 0xbc86a24c27e99837, 0xbfb40f907936051b, 0x3f5085775a554a25, 0x3f7aa0ce0420ebfd, 0xbf1a32a28e65afde, 0xbf2c26ebc916e22b, 0x3ecd740098d21c07, 0x3ecfc1baf78438dd, 0xbe710c76235f5aa1, 0xbe663455427d9c57, 0x3e08141f4d843200, 0x3df4d5216dec0df1, 0xbd977e29b16d5fdb, ], [ 0x3c5158813dc387f0, 0xbfc37aac8c1aeabb, 0x3f66ac0d2e2f2ac1, 0x3f99e74e754ea6d8, 0xbf3e1c0589dfbd21, 0xbf5496158dc5b2be, 0x3ef7d554035ae72e, 0x3eff0b30f3d1fb7e, 0xbea1d9e26f5a608f, 0xbe9b35eeaebb5fed, 0x3e3f010034c79a0b, 0x3e2f1f31b65b3b40, 0xbdd1445486f07cd4, 0xbdb8c39615e71112, ], [ 0xbfc2f2072e638cf3, 0x3c8361a1f631cd41, 0x3fb2f2072e638c5a, 0xbf4bd42b64fc9353, 0xbf792bb5e1e07ce1, 0x3f161ace339d0b73, 0x3f2aa8d1ce9fa384, 0xbec8ef625b21b762, 0xbece26d28032c92c, 0x3e6d0116b3ae24e4, 0x3e6526a75ee1fb24, 0xbe049a7cd1a8b231, 0xbdf3eac7c4ed94be, 0x3d943b63ca10efa6, ], [ 0xbc4e15276b2257f6, 0x3fc27407dfadee6d, 0xbf6346950bfd8dcc, 0xbf988d48d1d4eb20, 0x3f399e6923aaadf2, 0x3f538984b76c8a40, 0xbef4521949da5854, 0xbefd855d7afc24f7, 0x3e9e8a86b94090aa, 0x3e99f1bce3767a28, 0xbe3aa3a4df470ca3, 0xbe2dc43a0da754d3, 0x3dcdd3f81803822b, 0x3db7c1fb1e948790, ], [ 0x3fc1ff5eec6a01cd, 0xbc80d20b3aa154f7, 0xbfb1ff5eec6a0139, 0x3f47daf64983dfb0, 0x3f77ed5fffc0f26a, 0xbf12f9479636506c, 0xbf296027e938174a, 0x3ec57486d36f86d5, 0x3eccc1196ea00471, 0xbe690ae6942f1564, 0xbe64382bea1931c6, 0x3e01ddd9b1b7300f, 0x3df317ad2d0ae68b, 0xbd91a1072249bec4, ], [ 0x3c4a5ad4fde0c9d8, 0xbfc192f23ce3e050, 0x3f60a668185bfe0f, 0x3f9764141d652022, 0xbf3624437a2d49f0, 0xbf52a184be0d3982, 0x3ef196de0d85b64c, 0x3efc317f84a19048, 0xbe9a80187c3c9493, 0xbe98d3840a83aa5f, 0x3e3730c02a4a94ac, 0x3e2c8d1491c62663, 0xbdca1189016a9692, 0xbdb6d754fe28a395, ], [ 0xbfc12dd57bf18ad9, 0x3c7d8e82da6b051b, 0x3fb12dd57bf18a4a, 0xbf44bebeff7ba93d, 0xbf76d9afe882346d, 0x3f10842d50795e09, 0x3f2841d86abe55fe, 0xbec2b5cab87b5693, 0xbecb86b9f14c3df8, 0x3e65e518bb040851, 0x3e63642ad66ee13c, 0xbdff581d7497507c, 0xbdf2596d87b9a5f8, 0x3d8f0ac4f8bd7787, ], [ 0xbc47483488f843f0, 0x3fc0cf3ed059c573, 0xbf5d242aa5298caf, 0xbf96613d93b0179b, 0x3f33627f261d008d, 0x3f51d69ca0d81e39, 0xbeeed574ad2bb0d3, 0xbefb06384da1c6bc, 0x3e97452b1c4c76e9, 0x3e97d51e823013c9, 0xbe346a18e9324483, 0xbe2b754cf5bbe0eb, 0x3dc70467e00ca1a0, 0x3db601d42e3f412d, ], [ 0x3fc076826cc2c191, 0xbc7a319136b9885b, 0xbfb076826cc2c107, 0x3f4241b03eab1b46, 0x3f75e7f530011e0e, 0xbf0d17978e4af2b0, 0xbf2745b0deaaa29c, 0x3ec0803f899002ed, 0x3eca70060b7e6d91, 0xbe635913c3c95352, 0xbe62a694daaaf841, 0x3dfbc4a0d8050004, 0x3df1ad85820a38f2, 0xbd8b942dd09eb308, ], [ 0x3c44bc1f080e9694, 0xbfc0230b9797a7b2, 0x3f59c8083b2b6f7f, 0x3f957d3203befd1b, 0xbf3127cba226824c, 0xbf5123447144f140, 0x3eeb4fe26c88e56e, 0x3ef9fc5254458847, 0xbe94a44b3f692077, 0xbe96f17d3ebae645, 0x3e3224c9056773e9, 0x3e2a78ba4580cd4b, 0xbdc481589f7c80a5, 0xbdb53f51ba6e502a, ], [ 0xbfbfa8b41711c839, 0x3c776c1e8f7fbdf3, 0x3fafa8b41711c72d, 0xbf403a8d0f113157, 0xbf7511c6dad9e9ce, 0x3f09e040fc7d8bd2, 0x3f266582f59eaade, 0xbebd62a1a025f4b0, 0xbec976fa2e25f4ab, 0x3e61411e4c00a8c3, 0x3e61fc07a47b587f, 0xbdf8d00a9e1b01e2, 0xbdf1119f53145e82, 0x3d88b3165222eaa1, ], [ 0xbc429a344bf53c30, 0x3fbf13faf32c8e0a, 0xbf570558dddb7821, 0xbf94b24d7a9338fa, 0x3f2ea52a2144c44d, 0x3f50834d8f3f71fa, 0xbee86941a2b2f276, 0xbef90e32ce46341a, 0x3e92785e5b786d2a, 0x3e9624822c6837c1, 0xbe304286df6c8e25, 0xbe2993b44677fad8, 0x3dc2692b9cb4de6f, 0x3db48dab755272e9, ], [ 0x3fbe8727daa3daec, 0xbc75105fe04e17a2, 0xbfae8727daa3d9e9, 0x3f3d19c52e0749cd, 0x3f74524d481311c0, 0xbf0735f790cd464b, 0xbf259c8f9e41a823, 0x3eba61a00c8699ad, 0x3ec896d70eee04c2, 0xbe5f04fa0ee2b2df, 0xbe6161b9029aa2c1, 0x3df656dc5e9fcd6d, 0x3df083ab26947d7d, 0xbd8646da85095b0a, ], [ 0x3c40c6e5f0cb085b, 0xbfbe018d99f5da1b, 0x3f54b85897b35dc0, 0x3f93fc44215342e3, 0xbf2b9694d7112c4c, 0xbf4fe6fdc6440535, 0x3ee5fd096c74d7eb, 0x3ef83770c8f9fca0, 0xbe90a6f608ea2259, 0xbe956ad410ba57f4, 0x3e2d5aedc8414c7c, 0x3e28c319213f9f62, 0xbdc0a501a42574f9, 0xbdb3eaef334996a5, ], [ 0xbfbd8293aa55d18f, 0x3c731f5b2ff0d80c, 0x3fad8293aa55d093, 0xbf3a48fe4aff1369, 0xbf73a5ccbc11f183, 0x3f04f91e4204c18c, 0x3f24e72224187971, 0xbeb7dac82ed8c06b, 0xbec7cbd3d4a2512f, 0x3e5c13a012cfa9d9, 0x3e60d55d3c7a1e36, 0xbdf43f07dbc0afd9, 0xbdf001e1c5b3f199, 0x3d8438754303f506, ], [ 0xbc3e721cd5615376, 0x3fbd09b210b30217, 0xbf52c74f6d11fe58, 0xbf9357bfc2be57e6, 0x3f2901e4c492a05d, 0x3f4ee2a36979201d, 0xbee3f0cb91fe387d, 0xbef7748920d95467, 0x3e8e399ed3001c0e, 0x3e94c1b715414ff1, 0xbe2aab03479a9f97, 0xbe2804415514f135, 0x3dbe479692aefaf1, 0x3db3555d82fea6b2, ], [ 0x3fbc96700bf039e1, 0xbc71712327ccc0e1, 0xbfac96700bf038ec, 0x3f37e5647d31307c, 0x3f73095734a194a7, 0xbf0312a4db676954, 0xbf24424a9628de60, 0x3eb5b4a67102dd95, 0x3ec712e41250bc42, 0xbe59918677637160, 0xbe60550f5e9164bb, 0x3df2750c65ef60c0, 0x3def157ced5a6a13, 0xbd8274ea409a4ed7, ], [ 0x3c3bc4a30293d67b, 0xbfbc28612a3bc18a, 0x3f511f52577ff2df, 0x3f92c21da135f4f3, 0xbf26ce18f81fd4cd, 0xbf4df586d8b6aeb3, 0x3ee230fedd1a2b84, 0x3ef6c2a754e321b0, 0xbe8b973110796ae8, 0xbe9426ec6d82a4f4, 0x3e285d2ec3ed03c3, 0x3e2754eefd1cc277, 0xbdbbb13bcfd1095a, 0xbdb2cb6d2f5a71d0, ], [ 0xbfbbbf246914235e, 0x3c6ff848b8004f4e, 0x3fabbf2469142270, 0xbf35d923e8472f22, 0xbf727a96f1740b8b, 0x3f01715e4bcd425f, 0x3f23abacda98c7ab, 0xbeb3dc30debc954f, 0xbec6698cb2175b00, 0x3e57691976ae1f76, 0x3e5fbe7a90c59bea, 0xbdf0ea1d3534d622, 0xbdee39eb617c4576, 0x3d80ee68d9ec5553, ], [ 0xbc396e9c97e8f53c, 0x3fbb5a6219b35e14, 0xbf4f645fdb1a8578, 0xbf923940d01de870, 0x3f24e86a1e60f65a, 0x3f4d1c6a18c716ef, 0xbee0aeec5fff60bb, 0xbef61f7d2f793aca, 0x3e8950f6140dd479, 0x3e939898b4cca68e, 0xbe265f0fa2e22f9c, 0xbe26b33d2f34a7ca, 0x3db9731a4bc752ba, 0x3db24bcd6b2996ce, ], [ 0x3fbaf9cb49c4f934, 0xbc6d6d35ce7e44b9, 0xbfaaf9cb49c4f84c, 0x3f3413b75ce0f622, 0x3f71f7a8fec644b8, 0xbf000844274ab940, 0xbf23215daac1a429, 0x3eb242e9f204ac2f, 0x3ec5cdc3d7570c8d, 0xbe5589d6656d4bd3, 0xbe5ee52f2093b13f, 0x3def25a4c863585f, 0x3ded6edb90588bb5, 0xbd7f34526b242536, ], [ 0x3c37650e44849b1d, 0xbfba9d1835947d6f, 0x3f4cea253049a1d9, 0x3f91bb71f665dc68, 0xbf23427f47955327, 0xbf4c54a7bd6e5c2f, 0x3edebe9e62f23b54, 0x3ef58924f95f83e9, 0xbe875643b068495f, 0xbe93152fe242208c, 0x3e24a270e811a32a, 0x3e261d90f63d69a9, 0xbdb77dbf375b3033, 0xbdb1d55983193fd8, ], [ 0xbfba4407e04298d1, 0x3c6b2fc36b7bca2c, 0x3faa4407e04297ee, 0xbf3288694b34d1f5, 0xbf717f0266da7e64, 0x3efd9a9a1d244e54, 0x3f22a1c915f39e35, 0xbeb0dd9e9cd3be0d, 0xbec53dd8bf4c31dc, 0x3e53e6ebf97ad18c, 0x3e5e1c0952edd05e, 0xbdeccc874da25bb3, 0xbdecb26ccd2d18eb, 0x3d7cdf4dbb3c6f9d, ], [ 0xbc359685a4f3dcbc, 0x3fb9ee5ee937fc88, 0xbf4abf28ad5bf0d6, 0xbf9147481084ad98, 0x3f21d137345ad0c1, 0x3f4b9c10ddf55248, 0xbedc72c9d23eafc6, 0xbef4fe0b3595e36e, 0x3e859a1afaceaec9, 0x3e929b65a8c65855, 0xbe231c3162eaeee6, 0xbe25928cb280552e, 0x3db5c4ff841acff7, 0x3db167146fe195c5, ], [ 0x3fb99be744018c90, 0xbc694d1606868f19, 0xbfa99be744018bb2, 0x3f312d4e1c1cc8e5, 0x3f710f5ca51ef993, 0xbefb714174938907, 0xbf222b9fa834b14b, 0x3eaf47107520863c, 0x3ec4b861783e33d4, 0xbe5276456457a7e2, 0xbe5d612d705e69ee, 0x3deabad16a1c7f4d, 0x3dec0302ce313ca1, 0xbd7ad13436da91d1, ], [ 0x3c33fe4be92d3d54, 0xbfb94c6f54aef04b, 0x3f48d6371f01895c, 0x3f90db975fd7dbd2, 0xbf208bd163414db7, 0xbf4af0d3d4cc449e, 0x3eda6c8e7a6a50d9, 0x3ef47cddcd0777cf, 0xbe8412382d315a8f, 0xbe922a214336182c, 0x3e21c37df131e495, 0x3e25110597bc5108, 0xbdb43f276f813535, 0xbdb10022868bfde2, ], [ 0xbfb8ffc9bd24fe07, 0x3c67889977473d30, 0x3fa8ffc9bd24fd2f, 0xbf2ff51b38ef3764, 0xbf70a7a725d36032, 0x3ef988128742f09f, 0x3f21bdc845f948f5, 0xbead1b60b68e1dce, 0xbec43c2ce2f40a20, 0x3e512fdc8d93240a, 0x3e5cb30713086e1b, 0xbde8e53a40557273, 0xbdeb5f3c07e7903e, 0x3d78fd3f37268235, ], [ 0xbc3292fab12602d5, 0x3fb8b5ccad12d631, 0xbf4724d018597ba3, 0xbf907764ae2b1e77, 0x3f1ed6acc18c1a89, 0x3f4a51693df22314, 0xbed8a0ec5fd8948c, 0xbef4047f31589663, 0x3e82b667a039f6a4, 0x3e91c073e21e1306, 0xbe209143960c8785, 0xbe2497fb13bc2530, 0x3db2e4699f6adc63, 0x3db09fc4db2b9fa9, ], [ 0x3fb86e51be0a9153, 0xbc65fa6f95d443a0, 0xbfa86e51be0a907f, 0x3f2dd3c244b5713f, 0x3f7046fc5a20f248, 0xbef7d51accd8d1f8, 0xbf2157556b6a5aec, 0x3eab2d01d207a4bc, 0x3ec3c837e1b45aa2, 0xbe500d3d097d314b, 0xbe5c103c5b331300, 0x3de742b129024e6b, 0x3deac5e6c8a70206, 0xbd775bdd14ccde28, ], [ 0x3c314cbdbd279267, 0xbfb829356999a096, 0x3f45a280e033e683, 0x3f9019dba8336dd6, 0xbf1cd4559d92616b, 0xbf49bc85774f69b2, 0x3ed70706561ca508, 0x3ef393fc6c586d81, 0xbe818009f70f6704, 0xbe915d911e7ad3a2, 0x3e1eff8fd0ef6949, 0x3e24268fd4573ff9, 0xbdb1ae6de683a236, 0xbdb0455820923c5a, ], [ 0xbfb7e656efb009ad, 0x3c649ee393402ee6, 0x3fa7e656efb008de, 0xbf2bec6b33f0062e, 0xbf6fd932c269835b, 0x3ef6504d7e1cd7db, 0x3f20f77ce56ff037, 0xbea972e583ac028d, 0xbec35ba4e79f8507, 0x3e4e1250b982c251, 0x3e5b77a3c340d6b3, 0xbde5cbcf474ee83d, 0xbdea35fa30652af1, 0x3d75e5f83583c368, ], [ 0xbc375f30b05ffab2, 0x3fb7a597e9550932, 0xbf44486c0b011f0f, 0xbf8f848eec0e0c40, 0x3f1b077fae02763b, 0x3f49310d6e6682f5, 0xbed597a5bccfeb73, 0xbef32a855d113180, 0x3e8069b8fa206f26, 0x3e9100c89784eeac, 0xbe1d14a175c009c5, 0xbe23bbc9bff27ef1, 0x3db0950fae2cbe6f, 0x3dafc6492b94025c, ], ]; pxfm-0.1.23/src/bessel/j1.rs000064400000000000000000000543031046102023000136120ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![allow(clippy::excessive_precision)] use crate::bessel::alpha1::{ bessel_1_asympt_alpha, bessel_1_asympt_alpha_fast, bessel_1_asympt_alpha_hard, }; use crate::bessel::beta1::{ bessel_1_asympt_beta, bessel_1_asympt_beta_fast, bessel_1_asympt_beta_hard, }; use crate::bessel::i0::bessel_rsqrt_hard; use crate::bessel::j1_coeffs::{J1_COEFFS, J1_ZEROS, J1_ZEROS_VALUE}; use crate::bessel::j1_coeffs_taylor::J1_COEFFS_TAYLOR; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::{f_polyeval8, f_polyeval9, f_polyeval12, f_polyeval19}; use crate::sin_helper::{sin_dd_small, sin_dd_small_fast, sin_f128_small}; use crate::sincos_reduce::{AngleReduced, rem2pi_any, rem2pi_f128}; /// Bessel J 1st order in f64 /// /// Note about accuracy: /// - Close to zero Bessel have tiny values such that testing against MPFR must be done exactly /// in the same precision, since any nearest representable number have ULP > 0.5, /// for example `J1(0.000000000000000000000000000000000000023509886)` in single precision /// have 0.7 ULP for any number with extended precision that would be represented in f32 /// Same applies to J1(4.4501477170144018E-309) in double precision and some others subnormal numbers pub fn f_j1(x: f64) -> f64 { if !x.is_normal() { if x == 0. { return x; } if x.is_infinite() { return 0.; } if x.is_nan() { return x + x; } } let ax: u64 = x.to_bits() & 0x7fff_ffff_ffff_ffff; if ax < 0x4052a6784230fcf8u64 { // 74.60109 if ax < 0x3feccccccccccccd { // 0.9 return j1_maclaurin_series_fast(x); } return j1_small_argument_fast(x); } j1_asympt_fast(x) } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - 3*PI/4 - alpha(x)) discarding 1*PI/2 using identities gives: J1 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) to avoid squashing small (-PI/4 - alpha(x)) into a large x actual expansion is: J1 = sqrt(2/(PI*x)) * beta(x) * sin((x mod 2*PI) - PI/4 - alpha(x)) */ #[inline] fn j1_asympt_fast(x: f64) -> f64 { let origin_x = x; static SGN: [f64; 2] = [1., -1.]; let sign_scale = SGN[x.is_sign_negative() as usize]; let x = x.abs(); const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let recip = if x.to_bits() > 0x7fd000000000000u64 { DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_safe_div(4.0, x), 0.25) } else { DoubleDouble::from_recip(x) }; let alpha = bessel_1_asympt_alpha_fast(recip); let beta = bessel_1_asympt_beta_fast(recip); let AngleReduced { angle } = rem2pi_any(x); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_sin = sin_dd_small_fast(r0); let z0 = DoubleDouble::quick_mult(beta, m_sin); let r_sqrt = DoubleDouble::from_rsqrt_fast(x); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let p = DoubleDouble::quick_mult(scale, z0); let err = f_fmla( p.hi, f64::from_bits(0x3be0000000000000), // 2^-65 f64::from_bits(0x3a60000000000000), // 2^-89 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64() * sign_scale; } j1_asympt(origin_x, recip, r_sqrt, angle) } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - 3*PI/4 - alpha(x)) discarding 1*PI/2 using identities gives: J1 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) to avoid squashing small (-PI/4 - alpha(x)) into a large x actual expansion is: J1 = sqrt(2/(PI*x)) * beta(x) * sin((x mod 2*PI) - PI/4 - alpha(x)) */ fn j1_asympt(x: f64, recip: DoubleDouble, r_sqrt: DoubleDouble, angle: DoubleDouble) -> f64 { let origin_x = x; static SGN: [f64; 2] = [1., -1.]; let sign_scale = SGN[x.is_sign_negative() as usize]; const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let alpha = bessel_1_asympt_alpha(recip); let beta = bessel_1_asympt_beta(recip); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_sin = sin_dd_small(r0); let z0 = DoubleDouble::quick_mult(beta, m_sin); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let r = DoubleDouble::quick_mult(scale, z0); let p = DoubleDouble::from_exact_add(r.hi, r.lo); let err = f_fmla( p.hi, f64::from_bits(0x3bc0000000000000), // 2^-67 f64::from_bits(0x39c0000000000000), // 2^-99 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64() * sign_scale; } j1_asympt_hard(origin_x) } /** Generated in Sollya: ```text pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x)/x; d = [0, 0.921]; w = 1; pf = fpminimax(f, [|0,2,4,6,8,10,12,14,16,18,20,22,24|], [|107, 107, 107, 107, 107, D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x); pf1 = pf * x; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do { print("'", coeff(pf, i), "',"); }; ``` See ./notes/bessel_sollya/bessel_j1_at_zero_fast.sollya **/ #[inline] pub(crate) fn j1_maclaurin_series_fast(x: f64) -> f64 { const C0: DoubleDouble = DoubleDouble::from_bit_pair((0x3b30e9e087200000, 0x3fe0000000000000)); let x2 = DoubleDouble::from_exact_mult(x, x); let p = f_polyeval12( x2.hi, f64::from_bits(0xbfb0000000000000), f64::from_bits(0x3f65555555555555), f64::from_bits(0xbf0c71c71c71c45e), f64::from_bits(0x3ea6c16c16b82b02), f64::from_bits(0xbe3845c87ec0cbef), f64::from_bits(0x3dc27e0313e8534c), f64::from_bits(0xbd4443dd2d0305d0), f64::from_bits(0xbd0985a435fe9aa1), f64::from_bits(0x3d10c82d92c46d30), f64::from_bits(0xbd0aa3684321f219), f64::from_bits(0x3cf8351f29ac345a), f64::from_bits(0xbcd333fe6cd52c9f), ); let mut z = DoubleDouble::mul_f64_add(x2, p, C0); z = DoubleDouble::quick_mult_f64(z, x); // squaring error (2^-56) + poly error 2^-75 let err = f_fmla( x2.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3b40000000000000), // 2^-75 ); let ub = z.hi + (z.lo + err); let lb = z.hi + (z.lo - err); if ub == lb { return z.to_f64(); } j1_maclaurin_series(x) } /** Generated in Sollya: ```text pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x)/x; d = [0, 0.921]; w = 1; pf = fpminimax(f, [|0,2,4,6,8,10,12,14,16,18,20,22,24|], [|107, 107, 107, 107, 107, D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x); pf1 = pf * x; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do { print("'", coeff(pf, i), "',"); }; ``` See ./notes/bessel_sollya/bessel_j1_at_zero.sollya **/ pub(crate) fn j1_maclaurin_series(x: f64) -> f64 { let origin_x = x; static SGN: [f64; 2] = [1., -1.]; let sign_scale = SGN[x.is_sign_negative() as usize]; let x = x.abs(); const CL: [(u64, u64); 5] = [ (0xb930000000000000, 0x3fe0000000000000), (0x39c8e80000000000, 0xbfb0000000000000), (0x3c05555554f3add7, 0x3f65555555555555), (0xbbac71c4eb0f8c94, 0xbf0c71c71c71c71c), (0xbb3f56b7a43206d4, 0x3ea6c16c16c16c17), ]; let dx2 = DoubleDouble::from_exact_mult(x, x); let p = f_polyeval8( dx2.hi, f64::from_bits(0xbe3845c8a0ce5129), f64::from_bits(0x3dc27e4fb7789ea2), f64::from_bits(0xbd4522a43f633af1), f64::from_bits(0x3cc2c97589d53f97), f64::from_bits(0xbc3ab8151dca7912), f64::from_bits(0x3baf08732286d1d4), f64::from_bits(0xbb10ac65637413f4), f64::from_bits(0xbae4d8336e4f779c), ); let mut p_e = DoubleDouble::mul_f64_add(dx2, p, DoubleDouble::from_bit_pair(CL[4])); p_e = DoubleDouble::mul_add(dx2, p_e, DoubleDouble::from_bit_pair(CL[3])); p_e = DoubleDouble::mul_add(dx2, p_e, DoubleDouble::from_bit_pair(CL[2])); p_e = DoubleDouble::mul_add(dx2, p_e, DoubleDouble::from_bit_pair(CL[1])); p_e = DoubleDouble::mul_add(dx2, p_e, DoubleDouble::from_bit_pair(CL[0])); let p = DoubleDouble::quick_mult_f64(p_e, x); let err = f_fmla( p.hi, f64::from_bits(0x3bd0000000000000), // 2^-66 f64::from_bits(0x3a00000000000000), // 2^-95 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return j1_maclaurin_series_hard(origin_x); } p.to_f64() * sign_scale } /** Taylor expansion at 0 Generated by SageMath: ```python def print_expansion_at_0(): print(f"static C: [DyadicFloat128; 13] = ") from mpmath import mp, j1, taylor, expm1 poly = taylor(lambda val: j1(val), 0, 26) real_i = 0 print("[") for i in range(1, len(poly), 2): print_dyadic(poly[i]) real_i = real_i + 1 print("],") print("];") mp.prec = 180 print_expansion_at_0() ``` **/ #[cold] #[inline(never)] fn j1_maclaurin_series_hard(x: f64) -> f64 { static SGN: [f64; 2] = [1., -1.]; let sign_scale = SGN[x.is_sign_negative() as usize]; let x = x.abs(); static C: [DyadicFloat128; 13] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -148, mantissa: 0xb60b60b6_0b60b60b_60b60b60_b60b60b6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -155, mantissa: 0xc22e4506_72894ab6_cd8efb11_d33f5618_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -162, mantissa: 0x93f27dbb_c4fae397_780b69f5_333c725b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -170, mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -178, mantissa: 0x964bac6d_7ae67d8d_aec68405_485dea03_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -187, mantissa: 0xd5c0f53a_fe6fa17f_8c7b0b68_39691f4e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -196, mantissa: 0xf8bb4be7_8e7896b0_58fee362_01a4370c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -205, mantissa: 0xf131bdf7_cff8d02e_e1ef6820_f9d58ab6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -214, mantissa: 0xc5e72c48_0d1aec75_3caa2e0d_edd008ca_u128, }, ]; let rx = DyadicFloat128::new_from_f64(x); let dx = rx * rx; let mut p = C[12]; for i in (0..12).rev() { p = dx * p + C[i]; } (p * rx).fast_as_f64() * sign_scale } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] pub(crate) fn j1_small_argument_fast(x: f64) -> f64 { static SIGN: [f64; 2] = [1., -1.]; let sign_scale = SIGN[x.is_sign_negative() as usize]; let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); // let avg_step = 74.60109 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6300176043004198; let fx = x_abs * INV_STEP; const J1_ZEROS_COUNT: f64 = (J1_ZEROS.len() - 1) as f64; let idx0 = fx.min(J1_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(J1_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(J1_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(J1_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return j1_maclaurin_series_fast(x); } let r = DoubleDouble::full_add_f64(-found_zero, x_abs); // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(J1_ZEROS_VALUE[idx]) * sign_scale; } let is_zero_too_close = dist.abs() < 1e-3; let c = if is_zero_too_close { &J1_COEFFS_TAYLOR[idx - 1] } else { &J1_COEFFS[idx - 1] }; let p = f_polyeval19( r.hi, f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), f64::from_bits(c[9].1), f64::from_bits(c[10].1), f64::from_bits(c[11].1), f64::from_bits(c[12].1), f64::from_bits(c[13].1), f64::from_bits(c[14].1), f64::from_bits(c[15].1), f64::from_bits(c[16].1), f64::from_bits(c[17].1), f64::from_bits(c[18].1), f64::from_bits(c[19].1), f64::from_bits(c[20].1), f64::from_bits(c[21].1), f64::from_bits(c[22].1), f64::from_bits(c[23].1), ); let mut z = DoubleDouble::mul_f64_add(r, p, DoubleDouble::from_bit_pair(c[4])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[3])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[2])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[1])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[0])); let err = f_fmla( z.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3bf0000000000000), // 2^-64 ); let ub = z.hi + (z.lo + err); let lb = z.hi + (z.lo - err); if ub == lb { return z.to_f64() * sign_scale; } j1_small_argument_dd(sign_scale, r, c) } fn j1_small_argument_dd(sign_scale: f64, r: DoubleDouble, c0: &[(u64, u64); 24]) -> f64 { let c = &c0[15..]; let p0 = f_polyeval9( r.to_f64(), f64::from_bits(c[0].1), f64::from_bits(c[1].1), f64::from_bits(c[2].1), f64::from_bits(c[3].1), f64::from_bits(c[4].1), f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), ); let c = c0; let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(c[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c10000000000000), // 2^-62 f64::from_bits(0x3a00000000000000), // 2^-95 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return j1_small_argument_path_hard(sign_scale, r, c); } p.to_f64() * sign_scale } #[cold] #[inline(never)] fn j1_small_argument_path_hard(sign_scale: f64, r: DoubleDouble, c: &[(u64, u64); 24]) -> f64 { let mut p = DoubleDouble::from_bit_pair(c[23]); for i in (0..23).rev() { p = DoubleDouble::mul_add(r, p, DoubleDouble::from_bit_pair(c[i])); p = DoubleDouble::from_exact_add(p.hi, p.lo); } p.to_f64() * sign_scale } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - 3*PI/4 - alpha(x)) discarding 1*PI/2 using identities gives: J1 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) to avoid squashing small (-PI/4 - alpha(x)) into a large x actual expansion is: J1 = sqrt(2/(PI*x)) * beta(x) * sin((x mod 2*PI) - PI/4 - alpha(x)) This method is required for situations where x*x or 1/(x*x) will overflow */ #[cold] #[inline(never)] fn j1_asympt_hard(x: f64) -> f64 { static SGN: [f64; 2] = [1., -1.]; let sign_scale = SGN[x.is_sign_negative() as usize]; let x = x.abs(); const SQRT_2_OVER_PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcc42299e_a1b28468_7e59e280_5d5c7180_u128, }; const MPI_OVER_4: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let x_dyadic = DyadicFloat128::new_from_f64(x); let recip = DyadicFloat128::accurate_reciprocal(x); let alpha = bessel_1_asympt_alpha_hard(recip); let beta = bessel_1_asympt_beta_hard(recip); let angle = rem2pi_f128(x_dyadic); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_sin = sin_f128_small(r0); let z0 = beta * m_sin; let r_sqrt = bessel_rsqrt_hard(x, recip); let scale = SQRT_2_OVER_PI * r_sqrt; let p = scale * z0; p.fast_as_f64() * sign_scale } #[cfg(test)] mod tests { use super::*; #[test] fn test_j1() { assert_eq!(f_j1(73.81695991658546), -0.06531447184607607); assert_eq!(f_j1(0.01), 0.004999937500260416); assert_eq!(f_j1(0.9), 0.4059495460788057); assert_eq!( f_j1(162605674999778540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008686943178258183 ); assert_eq!(f_j1(3.831705970207517), -1.8501090915423025e-15); assert_eq!(f_j1(-3.831705970207517), 1.8501090915423025e-15); assert_eq!(f_j1(-6.1795701510782757E+307), 8.130935041593236e-155); assert_eq!( f_j1(0.000000000000000000000000000000000000008827127), 0.0000000000000000000000000000000000000044135635 ); assert_eq!( f_j1(-0.000000000000000000000000000000000000008827127), -0.0000000000000000000000000000000000000044135635 ); assert_eq!(f_j1(5.4), -0.3453447907795863); assert_eq!( f_j1(77.743162408196766932633181568235159), 0.09049267898021947 ); assert_eq!( f_j1(84.027189586293545175976760219782591), 0.0870430264022591 ); assert_eq!(f_j1(f64::NEG_INFINITY), 0.0); assert_eq!(f_j1(f64::INFINITY), 0.0); assert!(f_j1(f64::NAN).is_nan()); } } pxfm-0.1.23/src/bessel/j1_coeffs.rs000064400000000000000000002037411046102023000151410ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** J1 zeros and extremums on [-76;76] Generated in SageMath: ```python from mpmath import mp, mpf, findroot, j1 from sage.all import * import struct DR = RealField(52) DD = RealField(190) def double_to_hex(f): packed = struct.pack('>d', float(f)) return '0x' + packed.hex() def split_double_double(x): x_hi = DR(x) # convert to f64 x_lo = x - DD(x_hi) return (x_lo,x_hi) def print_double_double(mark, x): splat = split_double_double(x) print(f"{mark}({double_to_hex(splat[0])}, {double_to_hex(splat[1])}),") zeros = [] # Step size to detect sign changes mp.prec = 150 step = mpf("0.001") epsilon = mpf("1e-35") x = mpf("0.0") previous_zero = R120(0) j1_zeros = [] while x < mpf("76.0"): f1 = besselj(1, x) f2 = besselj(1, x + step) if f1 * f2 < 0: zero = findroot(lambda t: j1(t), (x, x + step), solver='bisect', tol=mp.mpf("1e-41")) previous_zero = zero j1_zeros.append(zero) if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon: zeros.append(previous_zero) x += step j1_extrema = [] x = mpf("0.0") while x < mpf("76.0"): d1 = mp.diff(lambda t: j1(t), x) d2 = mp.diff(lambda t: j1(t), x + step) if d1 * d2 < 0: extremum = findroot(lambda t: mp.diff(lambda u: j1(u), t), (x, x + step), solver='bisect', tol=mp.mpf("1e-41")) j1_extrema.append(extremum) x += step j1_zeros.extend(j1_extrema) j1_zeros = sorted(j1_zeros) print("static J1_ZEROS: [(u64, u64); 46] = [") for z in j1_zeros: k = split_double_double(DD(z)) hi = double_to_hex(k[1]) lo = double_to_hex(k[0]) print(f"({lo}, {hi}),") print("];") ``` See notes/bessel_j1_taylor.ipynb **/ pub(crate) static J1_ZEROS: [(u64, u64); 48] = [ (0x0, 0x0), (0x3c5616d820cfdaeb, 0x3ffd757d1fec8a3a), (0xbca60155a9d1b257, 0x400ea75575af6f09), (0x3ca5c646a75d7539, 0x40155365bc032467), (0xbc9b226d9d243828, 0x401c0ff5f3b47250), (0xbca63e17ec20a31d, 0x402112980f0b88a1), (0x3cc02610a51562b6, 0x402458d0d0bdfc29), (0x3cc9a84d3a5fedc1, 0x40276979797ee5ac), (0x3cb2bce7fd18e693, 0x402aa5baf310e5a2), (0xbcc6932b987094f1, 0x402dba284a17ac59), (0xbcdd2a68e88ab318, 0x4030787b360508c5), (0xbca022f6b2b54db9, 0x403203f9a24e6527), (0xbcd21830197e9e86, 0x40339da8e7416ca4), (0x3cdeaafeaf8ec1af, 0x40352a1424a1a9fa), (0xbcc1bf33afef88f2, 0x4036c294e3d4d8ac), (0xbcb2d773b50cf8b9, 0x40384fb31dee1635), (0x3cc1a2686480d882, 0x4039e7570dcea106), (0x3cd0bdee27293d79, 0x403b75014427514d), (0xbcb42ce39ec976fb, 0x403d0bfcf471fccc), (0x3cbda49c2c143483, 0x403e9a179fba532a), (0xbcdbe3a1cd066b67, 0x404018476e6b2bf0), (0xbce6b00c1279ef0a, 0x4040df82ebd54e32), (0xbced5fbbff045068, 0x4041aa890dc5e97c), (0x3cd7d864bbf17a30, 0x404271eb1b80430e), (0x3cc9eafeca0ca4fc, 0x40433cc523d5cb69), (0xbce5cecac300a9a1, 0x40440447e50db184), (0x3cc489bd556e5109, 0x4044cefcf1734b62), (0x3cdd0fd96f29c211, 0x4045969bc7271083), (0x3ce4f716f3179d90, 0x404661315d6b133f), (0xbce158b763edd0e8, 0x404728e892a88fc9), (0xbcef3950a842db79, 0x4047f36312028ad6), (0x3ce97656bbc2396e, 0x4048bb2fa2037de3), (0x3ce85d7bdb30baf1, 0x404985928f96d51e), (0xbce71f8560ac9f18, 0x404a4d71fcb56f8c), (0x3ce3d41e041caa68, 0x404b17c038c2018c), (0xbcde6d04716d8d21, 0x404bdfb06eb790aa), (0x3cda139ce2cd08ac, 0x404ca9ec5a82324b), (0x3cc8b5cc7b4501c1, 0x404d71eb98682f07), (0xbcb12e6ef2e594e2, 0x404e3c1731d64f1e), (0x3cb399bfca430021, 0x404f0423f99b4b53), (0x3cdfd1ee8286358a, 0x404fce40efb1156e), (0x3c800660b51502f0, 0x40504b2cfcbb084d), (0x3ced3cacfc720418, 0x4050b034dde75b42), (0x3cc4b877d4f6d900, 0x40511446f60f1458), (0xbcee669304bfe748, 0x40517948db63675c), (0x3cfad20ca758a714, 0x4051dd600b743a9b), (0x3cf8eb4a94b63936, 0x4052425c7dcacdf6), (0xbcfa196892f68386, 0x4052a67859bc641e), ]; /** Precomputed values in exact Bessel J1 zero. Generated by MPFR: ```text let mut arr = vec![]; for zeros in J1_ZEROS.iter() { let mpfr = Float::with_val(107, f64::from_bits(zeros.1)).j1(); arr.push(mpfr.to_f64().to_bits()); } println!( "arr: [{}]", arr.iter() .map(|x| format!("0x{:016X}", x)) .collect::>() .join(", ") ); ``` **/ pub(crate) static J1_ZEROS_VALUE: [u64; 48] = [ 0x0000000000000000, 0x3FE29EA3D19F035F, 0xBC91B9C1C3FB286F, 0xBFD626EE83500BF2, 0x3C8049770CE74C2E, 0x3FD17DBF09D40D25, 0x3CA0212F4E592523, 0xBFCDDCEB4CE1BF4A, 0xBC905DCC62D0D222, 0x3FCA7F63FEA81F26, 0xBCB6EB905BA2ABFA, 0xBFC810F50225B04B, 0x3CAA10B2F7B4E69D, 0x3FC633E7F7F05301, 0xBC97BC6D5A660382, 0xBFC4B71D4CA2CC69, 0xBC961C29FAC28FDF, 0x3FC37DFA8F5A550A, 0xBC87E3B01386785F, 0xBFC2768D29C69936, 0x3CAF5EFD41F756B6, 0x3FC194EBA75B32F9, 0xBCBF89DCEDB3EA9B, 0xBFC0D0D36473E98C, 0xBC9AAAF726A29E97, 0x3FC02455675AB6D2, 0x3C9451B6225ACBFB, 0xBFBF161D0C28B48C, 0xBCB40032091A4E00, 0x3FBE0357C158B119, 0xBCBCCB5A05A6E4AA, 0xBFBD0B36E5737458, 0xBCB5C457E4A6A2F1, 0x3FBC29AE8400A320, 0x3CB13169F65EFC7C, 0xBFBB5B8273B75055, 0xBCA5FB7DBD93E256, 0x3FBA9E13A0DB6429, 0xBC7C3482175F80D7, 0xBFB9EF3BB2213B0B, 0xBCA977092852774B, 0x3FB94D3276914E51, 0x3CB6D73591BFEB5D, 0xBFB8B67A2481077D, 0x3CB735BC851F7831, 0x3FB829D06FEE9266, 0x3CC29C7C75EEB12F, 0xBFB7A62320798175, ]; /** Following search for J1 (see [J1_ZEROS]) zeros and extremums: at each zero and extremum we're doing Taylor series expansion one that should be enough to cover whole interval between zero or peak which is PI/4 Generated in SageMath and Sollya: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = (zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i]) + 0.83 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05 b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(j1_zeros) # print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 500; bessel_j1 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RealField(500)(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return def print_remez_coeffs(poly): print("J1TaylorExtendedSeries {") print_double_double("a0: ", poly[0]) print_double_double("a1: ", poly[1]) print_double_double("a2: ", poly[2]) print_double_double("a3: ", poly[3]) print_double_double("a4: ", poly[4]) print_double_double("a5: ", poly[5]) print_double_double("a6: ", poly[6]) print_double_double("a7: ", poly[7]) print_double_double("a8: ", poly[8]) print_double_double("a9: ", poly[9]) print_double_double("a10: ", poly[10]) print_double_double("a11: ", poly[11]) print_double_double("a12: ", poly[12]) print_double_double("a13: ", poly[13]) print("c: [") for i in range(14, len(poly)): coeff = poly[i] print(f"{double_to_hex(coeff)},") print("],") print("},") degree = 23 print(f"pub(crate) static J1_COEFFS: [J1TaylorExtendedSeries; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print_remez_coeffs(coeffs) print("];") ``` **/ pub(crate) static J1_COEFFS: [[(u64, u64); 24]; 47] = [ [ (0x3c61f1c324453b22, 0x3fe29ea3d19f035f), (0x35fa0d84854cf50d, 0xb9a948d98c79544d), (0xbc6e3631ae170265, 0xbfca41115c5df243), (0xbc18acc50ffb929f, 0x3f78d1448e6fed48), (0x3c0e85a7cffdb986, 0x3f8c441a2f9de22b), (0x3bd94ca1957aa906, 0xbf386671c18b088a), (0x3bd950ccbdd65736, 0xbf39e2504ddc7608), (0xbb61b3ae884e8323, 0x3ee34ccbca0c75d1), (0x3b7ab8f6e0e5328c, 0x3eda4973784d1087), (0x3b1f40e6cc67a3d5, 0xbe81045322aaab45), (0x3b06ea738f9ecf6a, 0xbe70fae0da6cdcef), (0xbabbaad3785f91ec, 0x3e13546cef5ed00e), (0x3a89c3da0f7d1467, 0x3dfe5ee82e6676f1), (0xba262fd170d5dbad, 0xbd9ec80cc8b644d5), (0xba23036bcf1b50d2, 0xbd83eb2e99627fad), (0xb9cc7616af2b9f56, 0x3d222bfcdb211968), (0xb9909fcb58b04d57, 0x3d03fb337676fc98), (0x3946bee5d8936909, 0xbca0901290ec992d), (0x391f5d570e3a4795, 0xbc7fa6a8aa2582e5), (0xb8b23101eae00b2a, 0x3c18078252545e8a), (0x386d13c8640abb7d, 0x3bf44b354a191eee), (0xb827a697c66ddb50, 0xbb8c75d1f25f35fc), (0x380d5a5801772dad, 0xbb6549fce4790a31), (0x378246c0eb5ba71c, 0x3affdbc62c23326e), ], [ (0x35f9dfa8e2931f8b, 0xb95730bb59760ac5), (0x3c62de1143765a99, 0xbfd9c6cf582cbf7f), (0xbc46b8d73329a70b, 0x3faae8a39f51ad04), (0xbc47767d9698b3c4, 0x3fab589d1da13905), (0x3c0e65e41f715973, 0xbf7537544c331da7), (0x3bc117d1587f9833, 0xbf624b3409959064), (0x3bb8c81b4b053820, 0x3f26e4c2d5354224), (0x3b9859e946b98719, 0x3f083a06e30c4109), (0x3b51fd9c02e20b11, 0xbec9799d4c9f2549), (0xbb4ffc0b40a079e5, 0xbea33825cd2e2c16), (0x3aeb5032c6339f4e, 0x3e617069233e916c), (0x3a80c496c8db027f, 0x3e34569b22afc3c8), (0xba9a374b068a8d41, 0xbdf03b9e9651056f), (0x3a4c5798959dc28e, 0xbdbec62310af5fa2), (0xba11dc4cca029308, 0x3d75ec84e47b7d9e), (0x39d2cf2c8d7c612a, 0x3d417a40c942a964), (0x3971ff6b4d2284f1, 0xbcf67cb1d01a03c7), (0xb943da1ee0003f81, 0xbcbee7ff9372e125), (0xb8f9e098c8ea9826, 0x3c721fb8d23ce65d), (0x38d89765c4f16618, 0x3c35e053c1413792), (0xb8575b3ab1c49578, 0xbbe79265a43bea11), (0xb82c7bf56bef062f, 0xbba95d6cc94f810f), (0xb7f5bad532a4cc34, 0x3b59332b7e688450), (0x37ac610ae03b7f77, 0x3b1a2c1db24ae655), ], [ (0xbc782d627160714a, 0xbfd626ee83500bf2), (0x35e215832cad36da, 0x39465d6b7a56edac), (0x3c6ae8952e6f1d78, 0x3fc55f6bec9ef962), (0x3c0d30f1a30544cb, 0xbf83d23336fd10e4), (0x3c2695c3589d6e1d, 0xbf88c77a983a0814), (0x3bea1200f42f4b09, 0x3f45cdc98db1cbe2), (0x3bd343248aee865b, 0x3f373576ff46ee3b), (0x3b8a8cd3c63aa60b, 0xbef2461447d7b423), (0x3b6a8a9edacbe6fe, 0xbed7b853456b6eaa), (0xbaff3625eaafdafc, 0x3e90abfc68274a98), (0xbaea64c013116245, 0x3e6ea7a1ee26124d), (0x3acef44f1141cf97, 0xbe235c0413e01419), (0xba7020655e19f397, 0xbdfb5c5d512fbafe), (0x3a2522345bdc9b62, 0x3daf4c5e26fd6f49), (0xba1a9c1d9fde6bb0, 0x3d81e4c43397bb8d), (0x39aead7c3865323c, 0xbd32addefc4e427f), (0x399ef826261673f0, 0xbd01e4fadc073884), (0xb9584f8fae96d4c1, 0x3cb12a0b89e91563), (0x3911cf3d91af7eef, 0x3c7c4246886f561c), (0xb8932b17cb520173, 0xbc290ee1bd0b60e5), (0x388f8ba7ff012875, 0xbbf21116fef61a90), (0x38093d7080102807, 0x3b9dcbd61b5fcfcc), (0xb7ddad88c94d63e2, 0x3b62f7833d3a6e0a), (0xb7a7e960c2811c48, 0xbb0f75a3322d6adb), ], [ (0x35d923fac9298498, 0xb943ab00450c21a5), (0x3c7af22d033ee0a8, 0x3fd33518b3874e8a), (0xbc23b4d62984701e, 0xbf95e70dc60362bf), (0xbc476d8715df734e, 0xbfa80c83bdeee5b0), (0x3c03dac20aaf9d3e, 0x3f69a4b292e3de42), (0x3bd887eed7bf2f4a, 0x3f613fbc7d698217), (0xbbac52a914699396, 0xbf207358bbdbff91), (0xbb64764498326fe8, 0xbf0796a751f89051), (0xbb6df66e2a5b80ce, 0x3ec4255b015aded4), (0xbb3ae5bbd6b6b7b2, 0x3ea3026e0ce97ab9), (0xbaf53c3132b45416, 0xbe5d48dcdae92f2c), (0x3ac329ab58cdf5c8, 0xbe344639d7eeb0a6), (0xba7227361e36b492, 0x3dec62ccb4a32eb2), (0x3a436c156b981e3c, 0x3dbecae92e85448e), (0xba15900bb4077790, 0xbd73bb6898d7381b), (0x39ceeaf13516632f, 0xbd4183edbb8f3baa), (0xb946b19e901a3f2a, 0x3cf4ae3e7e418192), (0x395392c9d1b10508, 0x3cbefbb1e7e7f06a), (0xb91d78a8cbca8fc8, 0xbc70f28d91f2bb8c), (0xb8c1412abdb69981, 0xbc35ec327b001a36), (0x3866c77527da5dfe, 0x3be65536194079a9), (0x37d83c37616b601d, 0x3ba9644a2a48ce1f), (0xb7fc2f10d93b3bda, 0xbb58069a9c48e50d), (0x37b28c16423dadcd, 0xbb18f8666a0fbd52), ], [ (0xbc7d48dbfa0ea1a4, 0x3fd17dbf09d40d25), (0xb5f12f0e1a0ea25f, 0xb95b2c846748c809), (0xbc61eb914d33c2b5, 0xbfc1404bf647c28f), (0x3c098a23a393f866, 0x3f74f4df2769f830), (0x3c24ae93dcb9bf99, 0x3f85c6285429b66d), (0x3bdddb259c934d19, 0xbf3d68ab722881bd), (0xbbd8cd731b94002b, 0xbf356acb6452d860), (0x3b60d2c0a7987aa7, 0x3eec10b47cf7ef69), (0xbb3cc8bfc9cf9d54, 0x3ed67eaae97bbc86), (0x3b021d7ef8f06ed1, 0xbe8bb6530c63f2df), (0xbaf7d003a6f8a38a, 0xbe6d87201e450edd), (0xba5df682e9056c25, 0x3e20f47c83ec550b), (0x3a784cc2fbcd5b3c, 0x3dfa98331f6ea797), (0x3a3af02acc5d445a, 0xbdac70414a236ade), (0xba1ac139214727ff, 0xbd817c057a5fc937), (0x39abeb4e52ce6eb7, 0x3d316fea14d29892), (0x39a6a5fe18553faf, 0x3d0189bd3eb9f3c6), (0x3946aa341fe1b254, 0xbcb05af44bb23c5f), (0x39010e85f5ece2bd, 0xbc7bbdb45d92e4fc), (0xb89b4dc8ed25771b, 0x3c284360a40ed89d), (0x38779d6e01f88769, 0x3bf1bfb967530933), (0xb82198845d1335e3, 0xbb9d37a860a66a8e), (0xb806974ac174343c, 0xbb62a0bbacab19c8), (0x37906170939ea2eb, 0x3b0e5619160fd338), ], [ (0xb60ab4d43f876701, 0xb969264876fdf3dc), (0xbc5052a3a2541c57, 0xbfcff654544ebcd1), (0xbc01b402d42eae53, 0x3f89223ff2c0785b), (0xbc323a2755909c5f, 0x3fa4b0c5d5da6789), (0x3bb3ea54acd19ff8, 0xbf5f91a9ee0d2897), (0x3bfc41f7f5f8cde0, 0xbf5f51c2489b9e6f), (0x3bad7af9dcc67129, 0x3f16b4c9ca0f770d), (0xbbadd341169fa322, 0x3f063c5475439cb2), (0x3b59f6ed48ce32ee, 0xbebe3725daf69867), (0x3b21f00381a6cb34, 0xbea25c1238b32e59), (0xbaebcfa91cc88fb7, 0x3e57486f6b9aa951), (0x3adb600d25e5d0fc, 0x3e33e3bf248277ee), (0xba5d774620c03673, 0xbde78a38a73e7c07), (0x3a59e464c4822ecc, 0xbdbe844eb6b211d0), (0x3a19b0c1a7646942, 0x3d70e24abb406b2c), (0x39d0a87b33c9afed, 0x3d41797e5ead05d1), (0x397bece1bd73373b, 0xbcf21fc0f119f3a6), (0x39422a1731e7d087, 0xbcbf0c12e4c83411), (0x390bbdff1dae57a0, 0x3c6e44232fae84a9), (0x38d9844b6a7d039c, 0x3c360804e71ba342), (0x38824f2c3cf7a869, 0xbbe43e13e137bab9), (0xb8314bfff0c04984, 0xbba9903092d3c1c6), (0xb7e5d3b1cb26c861, 0x3b56091b8d2a60e0), (0x37988d9bfceddedd, 0x3b18e8b26041597f), ], [ (0x3c50f8942d3f902b, 0xbfcddceb4ce1bf4a), (0xb62c35de62add74d, 0x3982dff6c1e15731), (0x3c433d5334b42b3d, 0x3fbda52116c0a640), (0xbbe72468a28b4443, 0xbf6a9da4603b67ea), (0xbc0c5e0831771de5, 0xbf8331e74ea59ab8), (0xbbdac4579b1b1f5c, 0x3f33e5cb6eba6eaa), (0x3bd0ad97399a9309, 0x3f33885fe9afa541), (0xbb74d732b8ca0df8, 0xbee494c0f4b0680b), (0x3b783e803ffeb597, 0xbed512b9d37762d7), (0x3b1382127dd60cd6, 0x3e85a861082bfb7f), (0xbb05de78d8bef340, 0x3e6c323ea0a042c3), (0xbaba616d9a2d0acd, 0xbe1bcc962f7b91eb), (0xba9907e5c13d4bf5, 0xbdf9bc94e2f29a4f), (0xba4dd160d698c980, 0x3da82bc6fcfa8ee1), (0xba0febc61d1c4bb8, 0x3d81141ce7b77ff8), (0xb9b71ce5b90d51b7, 0xbd2e79ccb186eec5), (0xb9729b55c285b0b8, 0xbd013e1fbe002f34), (0x394b7b4b328dbd37, 0x3cad36d12c86586f), (0x3913c4bb8b85fa48, 0x3c7b66070cb3ac2c), (0x38cf4dafb0ab1446, 0xbc260cbaacd645d2), (0xb892f6df683de3de, 0xbbf19605537cf4ab), (0xb806112791bea534, 0x3b9aed6b864dcd18), (0xb7dc24510173386c, 0x3b627eca9f946e65), (0xb79c60e9a1146a47, 0xbb0bfef86c0d63d6), ], [ (0x3601c162477c9abb, 0x396159aca5db6572), (0x3c6c8c66d2e42063, 0x3fcbf3337873a7d8), (0x3c25e81c4baa875d, 0xbf80c83a2d7add33), (0x3c44192692d7c60a, 0xbfa251858011816b), (0x3bd0475c48fd4015, 0x3f559eb160bf72d8), (0x3b9e04d420af1ac6, 0x3f5c5bce33af2d77), (0x3b7eb4916c85fb39, 0xbf10413e306e0039), (0xbb9e3a42c4a3fc86, 0xbf04a6704d05ad0b), (0xbb5a4f57a7a75039, 0x3eb6c43eedfed6c9), (0x3b2d30c35715c7fa, 0x3ea16abd7815de74), (0xbae381d774667710, 0xbe5257f16f5d4346), (0xbad24f76ba3d2cac, 0xbe332db1b4b2ff8b), (0xba886b6bef46e0df, 0x3de33acccf7bfdcb), (0x3a40f79d1cb77e70, 0x3dbdc8f5682566ce), (0xb9f02059cbf2dc1b, 0xbd6c6513386da08e), (0xb9aee6c6f049704d, 0xbd413585a9b760a0), (0x396399b887813c07, 0x3cef322ea2ca7028), (0x3957137aaf1256dd, 0x3cbec749ba83ed87), (0xb90e8d0898b37a61, 0xbc6a8aba908ced81), (0xb8d53fcac77872af, 0xbc35f2abf33d3a06), (0xb881d148fd35588c, 0x3be206e2b69fc921), (0xb8490f14e83f785c, 0x3ba98eef781c5c36), (0xb7ea20a48a9f15a7, 0xbb53df43cc1537c9), (0x37b0c3f1e8cb94e8, 0xbb18d93abc409fbc), ], [ (0xbc26397095487bbc, 0x3fca7f63fea81f26), (0x35c7769fcbedbba7, 0xb94670973020cb53), (0x3c4341d92ebaf230, 0xbfba60afb06640cf), (0x3c0aa0cf7ee02729, 0x3f62c1e930935d3c), (0x3c2253175b5c623d, 0x3f814506466d7f1f), (0x3bcf594f6bbbe6b1, 0xbf2cca8c0c0eaa3f), (0xbbc23306b101db0c, 0xbf31df821cc1377e), (0xbb6f426f813ba1cf, 0x3edee8814ed0ac45), (0x3b3530e090190f04, 0x3ed3a365a4199dd1), (0xbb253c7c31f63d20, 0xbe80ed2f9c3e458e), (0xbae6d6e3d35d7af7, 0xbe6ab3b37c5271b3), (0xbab5876ea3da2c96, 0x3e1684d6e62b5c66), (0xba61146a8712cc76, 0x3df8b105a5120ecf), (0x3a497e08482e4f36, 0xbda42dc5991b9d46), (0xba1c93b9ca69994f, 0xbd808d6405ffdf4d), (0xb9bb9c06669b183b, 0x3d2a152033665a46), (0x39a7ab21a3b60319, 0x3d00d7c118b17a82), (0x39456872094da304, 0xbca984ffd3ac0d7d), (0x3909c82687cc959e, 0xbc7aecb2b37b54c2), (0xb8cf42b62c996f29, 0x3c2397005ee8dd8b), (0xb886e35dc2991042, 0x3bf15c9c692b5bb4), (0xb832ecad9f92b6aa, 0xbb98431fbb78646d), (0x38062f0967c8bd95, 0xbb62529cf346132a), (0x37a9a4acee74819c, 0x3b0964837b2ece97), ], [ (0x360120a78f21538d, 0xb97c8b54640b722a), (0x3c6e9557ccd17041, 0xbfc925c6fca08f55), (0x3c091bef692396e7, 0x3f786dd32e059b0e), (0x3c3dac1b118bbe70, 0x3fa09463bbd0367f), (0x3be231ff192e138d, 0xbf4fda0298c8768b), (0xbbf0185527f60d8b, 0xbf59f4be60758fb1), (0xbbac474076e2749b, 0x3f0877991af9d1bb), (0x3b85632e8431fcaa, 0x3f032cb00ee8c1f3), (0x3b46a07ad1a2663e, 0xbeb19d8ce8c35f58), (0x3b443944f6114d11, 0xbea06a042fbba455), (0xbaeb45186aece340, 0x3e4d3a689e677731), (0xbadf9a18bdd365cc, 0x3e325108c4ce2b64), (0xba6505bb4a19817a, 0xbddf7b8e9ab5314c), (0x3a5ad487a5bbd7ab, 0xbdbcc40d05652650), (0xb9dcf99ac25c15c5, 0x3d67cd76e2d7d943), (0xb9d024e4f22a308b, 0x3d40c58770232cfe), (0x3952f8f057a0b1c2, 0xbceaafec4cc364ff), (0x3933c2290c85768f, 0xbcbe36dd573e6a63), (0xb8dfd609484ae481, 0x3c67199e5ff69f74), (0x388f3830f4ff63d7, 0x3c35ab8bb9a71dac), (0x387ca89ca7c948bf, 0xbbdfd6f8b70e778b), (0xb844329e8362812f, 0xbba9598a6da0f2c3), (0x37fd2c2ab7de98e2, 0x3b51c436362641e5), (0x37b80a5354c74c14, 0x3b18a9fec4d5983d), ], [ (0x3c2a5f1938003f60, 0xbfc810f50225b04b), (0x35f6ee82870d84bf, 0xb97d05564a508c39), (0x3c5462bc86c50e66, 0x3fb7fdf97ac36b1f), (0x3beaefb0d3cf3530, 0xbf5c3c256a8caa05), (0xbc191dbdbe49d9f5, 0xbf7f98feb7286b47), (0xbbcd0c6b4ea34036, 0x3f25f6559e5686e2), (0xbbd9de4a690cb448, 0x3f3080f57ac215af), (0xbb69ed0a7174b68e, 0xbed80c51397e5eba), (0x3ae06f2933360b4a, 0xbed256db543cd140), (0x3b1af76fcd5528a0, 0x3e7af7598a219824), (0x3b06515217062c3a, 0x3e69398226ca2305), (0xba795db0bb871535, 0xbe1260985d92587d), (0xba74a82a307b019b, 0xbdf792bb3eea6f67), (0x3a3817c8f7ec2b4c, 0x3da0d862695e1ab2), (0xba1b8749aa4dca22, 0x3d7fe52adc2ba19c), (0x39cda3a73a18530c, 0xbd263801377428c8), (0xb997a6607141db31, 0xbd005a1befd1620e), (0x394738fbaf9e72c3, 0x3ca620504263602e), (0x3919acd0b705176b, 0x3c7a4e14e3f85acf), (0x38bbce9a9cbe0c23, 0xbc213ef23a1a245a), (0x389387792bae4d33, 0xbbf10cae24ff432c), (0x383135b979266427, 0x3b95a41b5b0291e9), (0x380630df36241504, 0x3b62113e229c18af), (0x3779c024d092ed81, 0xbb06d663d6acddea), ], [ (0xb5e79c1121733c06, 0xb97dd765a46686aa), (0x3c62da0057f84d3f, 0x3fc70c511227d5aa), (0xbbfb574e506cd46d, 0xbf72ccb0e97558da), (0x3c2e61277dedefa5, 0xbf9e7dc08e70e99a), (0x3ba77952d9976f3f, 0x3f48acdc5b058c0e), (0xbbf340f4df902276, 0x3f580503724ad30a), (0xbba115f68568f545, 0xbf032ee4ca1fcafb), (0x3ba6a66dcfa3c51f, 0xbf01e5d2836c8d99), (0xbb2b2738baeaafd8, 0x3eac129f077bb163), (0x3b33825b34f3c4e4, 0x3e9ef161591181a2), (0x3ae4e499d619d66a, 0xbe47b9bb07f19f82), (0x3ac1a055b5da7ef9, 0xbe316f3937595d96), (0xba7ad6f9f1cbf4a9, 0x3dda0bc8665b6876), (0xba4fc8c4f001bcc9, 0x3dbba135f99a9e23), (0xba00713e44285b86, 0xbd640d543d2cb545), (0xb9d8806fb4e057c8, 0xbd403d0592186aa2), (0x3976ebbceb30453a, 0x3ce6db5e22c00286), (0xb95cfcc8d365b2a3, 0x3cbd745a1f9b2cc0), (0xb8e84bda052a24a4, 0xbc64141c2da5de65), (0x38cd92252322f7fa, 0xbc353f4e8c94bba5), (0xb8715b904e388e03, 0x3bdc0988ad3d45d6), (0xb7f1437e75284c5c, 0x3ba8f98a7bde325e), (0xb7e5101387db5e8b, 0xbb4fa52f2ce39750), (0x37b59c36f27d26bd, 0xbb1859ec268d8e36), ], [ (0xbc6b166d180d579d, 0x3fc633e7f7f05301), (0x35ffee1a88c4c7db, 0x39597a12d5b67dc0), (0xbc100659a075cf2f, 0xbfb6273784c1c06e), (0x3bfcb74bd087b3a0, 0x3f563ae94ade18d4), (0x3c02a45d712493c7, 0x3f7d4666536c88b9), (0x3b825e9ac0d7a01e, 0xbf216d528345ca11), (0x3bbb9405cb89e345, 0xbf2ec0dcdbb7c5fe), (0xbb7cb6decc20866e, 0x3ed34e966b0b09f8), (0xbb7a79f0d76f0cbb, 0x3ed135c64dc2d8d0), (0x3b01209dcbada35f, 0xbe75f7bc78b5fc2b), (0xbaf600f169603982, 0xbe67dc35b0764096), (0xba9e587e011af4be, 0x3e0e6d697361ea54), (0x3a9d43cb8e00cb1a, 0x3df679e3704987b1), (0xba3d2f784a54c5d4, 0xbd9c595f278a4dc9), (0x3a0e613d8bf8177d, 0xbd7ea36aef56e594), (0x39bad5b0fa90b31d, 0x3d22fd66b4e699f0), (0xb983e4c916a5d37c, 0x3cffa04c9f95e420), (0xb929ce3db1f0e449, 0xbca32f47f100cd0a), (0x38d1dc8a519c68bb, 0xbc7996582817ca81), (0x38bd0c28a3f651c5, 0x3c1e4c27a12867d7), (0x3893ddf51221f64b, 0x3bf0aafd1db63771), (0x383228e1d6fab232, 0xbb933b296a9fe2c2), (0xb8026ac12c9d03cc, 0xbb61bce573aebd8d), (0x37a6fcc6415460a7, 0x3b0476ec3eb1a5b8), ], [ (0xb605d92a84ac636d, 0x396c0a10d4b8d049), (0x3c6a47ab4241a9f3, 0xbfc5664e13b70622), (0x3c04d78c254f378c, 0x3f6e16555e108dc6), (0x3c1fe75afd6ceb7e, 0x3f9c5e1ad9fb2f40), (0x3be099fe50ede362, 0xbf43d369f958e56a), (0xbbf3ed70de3ce58d, 0xbf566f4ec27a96e9), (0xbb9b30f0921d946f, 0x3eff0de0532652d5), (0xbb747f8e74699e57, 0x3f00cf264341409e), (0x3b4f302f945bfb6b, 0xbea6f46d51e5766f), (0xbb37090d5299f2bd, 0xbe9d407f7c248d45), (0xbaeee2a1b6297a03, 0x3e43a33cd9df6696), (0x3ad36edf4ce5ba78, 0x3e309901b0a816e5), (0xba69797c9a665948, 0xbdd5d856a58443f0), (0x3a581a0de548434c, 0xbdba7cbcd8fc075f), (0x39f4161aad5502dc, 0x3d610b62c2fd4020), (0x39b2429685721bb6, 0x3d3f56a09da1af17), (0xb986edb5e42e4df0, 0xbce3ae6849a19196), (0xb956860a8cce360d, 0xbcbc977524bd849e), (0x3904f25392c2b4b0, 0x3c617fc9c0a81a86), (0xb8b42258c6440740, 0x3c34bbe439c863fb), (0x385dba6e1d13451b, 0xbbd8b5326e15f6b7), (0xb84cacd442a85cbe, 0xbba87bd53addeb1f), (0xb7ed606f4edc8467, 0x3b4c2aa54d8d8127), (0xb788c3a332c0e10d, 0x3b17efec97ba8f61), ], [ (0xbc4f6f339127993c, 0xbfc4b71d4ca2cc69), (0x35ca4f8d42ff3858, 0x3971bd20421445e5), (0x3c5422c1a1ae8e1c, 0x3fb4ae245697fba6), (0xbbf4ff572c18ea0c, 0xbf5215e4e1a5f1d6), (0xbbf259ec9aa6f76a, 0xbf7b633ed6d9cf61), (0x3bab33aa4933effd, 0x3f1c7f17b4b7dbbd), (0xbb79333bf7f0a288, 0x3f2ce01b8b6aa34c), (0x3b5f4e5959a7242e, 0xbecfced71b11e35b), (0x3b57f36535a55c97, 0xbed03c9d5823261d), (0xbb15ca3a5fd6e4c3, 0x3e724508091063b2), (0x3b0278797fb483cd, 0x3e66a2d20111e303), (0x3aa462d914cbe692, 0xbe0995a18f8e6888), (0xba92d2f68fe7bbf3, 0xbdf572d1a074f644), (0xba3d2febd6b25c97, 0x3d981df03c191241), (0xba1df51a16a51cab, 0x3d7d6895e48f3e4a), (0x3979fc3e189a5876, 0xbd205887f0b4463d), (0xb99ef66a10579222, 0xbcfe86703dca7086), (0xb93a92c2e3662797, 0x3ca0b3c70d522804), (0xb91294d0f373d163, 0x3c78d28b840bbf9e), (0xb8a3ac6e917d987d, 0xbc1aa928bdc7c69b), (0xb889057510b0376b, 0xbbf03e6bbda694dd), (0xb83da10a22fdbcd6, 0x3b9117421c5b8302), (0xb804a226000323af, 0x3b615b28f6d151e7), (0x378448f5a65efa22, 0xbb02540c2640944f), ], [ (0x35f8435be9512d0c, 0x39596a809853afc4), (0x3c6316f8ffd294bc, 0x3fc40f90793605bb), (0xbbd411ad350e3915, 0xbf68c833077fbeae), (0x3c051eb6f09da299, 0xbf9aa0ce0421d1a8), (0xbbec0fe78ad65dee, 0x3f405fa598ef5d1d), (0x3bff2085596f93c4, 0x3f551d30d78ab526), (0x3b92b31b50a0ff60, 0xbef9c5807675c5f6), (0xbb7cb5b05cc545a3, 0xbeffc1bbf57e3ae2), (0x3b3cc24f7215eccc, 0x3ea32dfea2518ce6), (0x3b18c92945575b15, 0x3e9bc212085dcbc6), (0xbaecddf3334d6159, 0xbe408b946d64c5c2), (0x3ac0b1a7f29c826b, 0xbe2fa8f9d8da736a), (0xba756320d1b782d7, 0x3dd293fe14af1d0b), (0xba5e3bcddd76a2bf, 0x3db96544cb75a592), (0x39f0a916b1e33716, 0xbd5d4750748e1ec5), (0x3992aa2022ba01f9, 0xbd3e341812329adf), (0x396e5a994597409d, 0x3ce112aa494174e0), (0x395a9a5bb21cd5ce, 0x3cbbb1656dd4f875), (0x38fd92cb597fcae9, 0xbc5ea7b95ef8e08b), (0x38c2aa6384ba6bbe, 0xbc342cad8878d4a5), (0xb868a671070d345c, 0x3bd5d76ac6e68151), (0xb82311f5dacdef0c, 0x3ba7ec1ff36b8002), (0xb7db96a9ba77f2bd, 0xbb491cad22e089cd), (0xb7b0a5b54e7f6cac, 0xbb177445429e42ae), ], [ (0x3c4f5ffd019535e1, 0x3fc37dfa8f5a550a), (0xb5aaaff7214acba6, 0xb93cb5c70d300ac5), (0xbc5c4cd2161ee66e, 0xbfb3775c1a04f09c), (0x3bd3d562913491bc, 0x3f4e2b4810a46c60), (0xbc1b976f331a69fb, 0x3f79d151a72b83a8), (0x3bbcef8b51459dfe, 0xbf17d8e5a090e4e6), (0xbbcb7ef1646f65dc, 0xbf2b49a6427386a0), (0x3b592486856820bb, 0x3ecac10957ddd2eb), (0x3b424317f186fd5b, 0x3ececa620745d3d3), (0xbaf34eef3c6c9553, 0xbe6eefc7e795dcdd), (0x3ae4b6734611daf2, 0xbe658c5d2a0da41d), (0x3aa97ce5a3d8c757, 0x3e05d4721f44a8f9), (0xba9b1942d77688ab, 0x3df481ce2314af57), (0x3a2ac654ac1c449a, 0xbd94c0d3279e9252), (0xba1f470c6e36c705, 0xbd7c3ea70752fc73), (0xb97829121cc317d9, 0x3d1c61d5b166a9e5), (0xb989ebd713c25b94, 0x3cfd72bf188712ae), (0xb9078152b026b94d, 0xbc9d427a9891c892), (0xb904e8f099d7cfab, 0xbc780c9634dc0029), (0x38b5c69bf0be9c48, 0x3c178e382c9b5ff2), (0x38536f9bd3face06, 0x3bef99f1b78427a0), (0xb828de3e89d5fd1e, 0xbb8e7352b4b18839), (0xb805ad010982fbed, 0xbb60f1a2b1d2a86e), (0x37abf1ea36b06bd9, 0x3b00708aca8b132c), ], [ (0xb5c06f78c8d4a275, 0xb93d524b57168b9f), (0x3c689d1f48185c7e, 0xbfc2f2072e638cf4), (0x3c0f48257333a5e0, 0x3f64df208bbd44f1), (0xbc282c4cf012e4f5, 0x3f992bb5e1e159fc), (0x3bb5967313f39524, 0xbf3ba181c06897cd), (0xbbea6566cfb71c2e, 0xbf53fe9d5baa4a3d), (0xbb98b4ff32e89d05, 0x3ef5d17602b01cac), (0xbb84f1d77f1fffd7, 0x3efe26d3747fe829), (0xbb47896f2e82c323, 0xbea0509768ab6ecb), (0xbb30ede6356a7015, 0xbe9a70f232d9d06c), (0x3ade8fe4e5a1ed7e, 0x3e3c509252de33f9), (0x3ac6ae9c749edc67, 0x3e2e454fee07116e), (0x3a73b1f5bbe63372, 0xbdd0015b062ba122), (0xba44c8407e1ecc95, 0xbdb860e95adf8412), (0x39fddd4f18607329, 0x3d59691e90f7ccfc), (0x39d00120e60006cf, 0x3d3d1ce7997b42b4), (0x39682a77f2b9ac62, 0xbcdddcd1c52fea1b), (0xb95c20e8a1ea2f57, 0xbcbacd10a03d8921), (0xb8f1731302036655, 0x3c5b043a4e72efe2), (0xb8d6d22b4e2f1fae, 0x3c3399ba323db8d6), (0x385b209322c8d73d, 0xbbd364e661355e9a), (0x3838be7c1f6126ff, 0xbba75381cf058174), (0x37d1ce55ad6a8310, 0x3b46755328d7d302), (0xb7b75f604bab0893, 0x3b16ee50ed715cef), ], [ (0xbc6b9fbd89653a0a, 0xbfc2768d29c69936), (0x35ca97e1f25db68b, 0xb93ffabfa86ef843), (0xbc592c5350d4d817, 0x3fb271811730b0ef), (0xbbcd42067c35395a, 0xbf49a8df96a1225e), (0xbbde8196594d5f87, 0xbf787c81cf1c6fc4), (0x3ba098686a079be4, 0x3f14549cdbb77978), (0xbbcc0c93813e02ce, 0x3f29ed2568116e19), (0xbb638a1fa72a2206, 0xbec6e4136f033ace), (0xbb692b62efc42c9a, 0xbecd53330316cde7), (0x3af835560f2b31cd, 0x3e6a983b5782dfca), (0x3b0d287b84d78d98, 0x3e64952ba7c5a1dc), (0xba72905636bd36a9, 0xbe02df3ad6f82e0d), (0x3a99c062ae844d27, 0xbdf3a70f9a89d2c0), (0x3a3c9ffd5cdbf957, 0x3d920e086c17f618), (0x3a1e25413f7cf79b, 0x3d7b29a554c10cda), (0x39b937b07d944fb1, 0xbd18dbe08f4b3b70), (0x399966ea8cf6d238, 0xbcfc6bd9fc31d25f), (0xb9310d7ab87b2019, 0x3c99ce5a745e4984), (0xb918ade94c5553fb, 0x3c774addf0c26059), (0x38be87d79b895c6e, 0xbc14eb89eaaa0820), (0x388e01622132e11d, 0xbbeeb605f9932592), (0x37f1d8f9c78e8f53, 0x3b8b3a602349f9f9), (0x37fda89d6c3f2718, 0x3b6084d788afe5ac), (0x379093629c8ee8ea, 0xbafd92b61b88c69e), ], [ (0xb61e3a4d721e8324, 0xb970e12b7d27cf07), (0x3c51f9b16832f365, 0x3fc1ff5eec6a01cd), (0xbc0f89ce0d1cad55, 0xbf61e438b722c3b5), (0x3c39a4b7b3ed5aa3, 0xbf97ed5fffc1c774), (0xbbdc35d9a8eaece6, 0x3f37b7997babd9ca), (0xbbe39da40664c597, 0x3f53081def9612c5), (0x3b8551b9d43f8119, 0xbef2c5f5edafc4e9), (0xbb9dbae69d6d1983, 0xbefcc11a59e13739), (0x3b35152e3ec9bcce, 0x3e9c2c3a1b8014a3), (0xbb333a08049d2a47, 0x3e9946d1dab7bd01), (0x3ad9a43f93c7a3c8, 0xbe388db61946be64), (0x3ac51a4e1f57e228, 0xbe2d04d33be580e8), (0xba5f39a3631ac3ea, 0x3dcbe64386d2c5c9), (0xba50e72fbf713685, 0x3db77142e0e4497d), (0x39f05d87c3131a89, 0xbd56458476678b0a), (0x39dcadde2840dbd3, 0xbd3c15e96b25b19b), (0xb970bb70de53f974, 0x3cda545e6eacddb5), (0x39573a21f1dd7482, 0x3cb9f0a9b7519cb4), (0xb8f26c0a88ddf73c, 0xbc57f751c3434bc5), (0x38dba5906a1609ba, 0xbc33083bfa2b9853), (0xb876257782c7fb32, 0x3bd14f52f8c40156), (0xb8455e6398eb5536, 0x3ba6b866ba0cd5f9), (0xb7dd533054211520, 0xbb442a164ec53a73), (0xb7b5895e0b2acd11, 0xbb1663bd8ed78f9c), ], [ (0x3c54fa3fb220c497, 0x3fc194eba75b32f9), (0x36084c365974fe27, 0xb97351f4ef13fe26), (0x3c59f5fdd12caab1, 0xbfb190f7dc27362b), (0xbbd96244746b5f38, 0x3f462bb47a5c5f7f), (0x3c106edbe0b8c444, 0x3f7756ef20f5d2e2), (0x3bb1231bc38d74fa, 0xbf1198b0ba97ecfb), (0xbbafcaf470009ca5, 0xbf28be8cf9358d55), (0x3b341ae8492fe909, 0x3ec3dd6f7c8cc3c0), (0xbb227b6134d4cb1b, 0x3ecc09c80ee7f9af), (0xbb0404bf1dcee0f4, 0xbe6728e46a451e32), (0xbb0524de73bc4a47, 0xbe63b91113508622), (0xba958725ca8bba0a, 0x3e0080fddad62bf8), (0xba979be80a70704c, 0x3df2e111e88dae1d), (0x3a16d9f11e8a571a, 0xbd8fbae88bdab281), (0x3a026df37d7f2f86, 0xbd7a2a4fbea86012), (0x39b683e401b5c962, 0x3d15f540e97728a3), (0xb95202b2fa6547b4, 0x3cfb74c0b254e833), (0xb938463548f90bb3, 0xbc96eb75a8c251ef), (0x391ab9d89901dd33, 0xbc76910c0073cf6f), (0x38b57304713e6ec7, 0x3c12af37349ec30d), (0x388e4a0ca7b6a403, 0x3bedd6cb83761ce6), (0xb82fbe9670a0583a, 0xbb88745a179736e3), (0x37f9ae92b9c8d8b8, 0xbb60180931dceaf3), (0xb78cba499e17a878, 0x3afab192c9241f99), ], [ (0x35cbb600d4239a22, 0x39251b64cfa537e4), (0x3c6e71c482be67bd, 0xbfc12dd57bf18ada), (0xbbe9a8a827c4bbb7, 0x3f5f1e1e7f393e83), (0x3c3286f932bea35e, 0x3f96d9afe88301fa), (0xbbd360330de30bf2, 0xbf34a538a482979b), (0x3bef838ddd50c780, 0xbf52316250b4ae37), (0xbb94c13fc989fce7, 0x3ef05f11577b4627), (0x3b6771efd22cab1c, 0x3efb86bad42fc220), (0x3b1a6ca937a8bc13, 0xbe98a1b3a9e92749), (0x3b32d767937947d7, 0xbe983dcaf3f8fcc5), (0x3aba8d8d67ac9dda, 0x3e3589a7ca5fdcf1), (0x3ac9ad46d29f3be0, 0x3e2be3ee3298bb99), (0xba6e973d129d8f1f, 0xbdc8913f1d0ff123), (0x3a203a3c6881bd79, 0xbdb695c386660814), (0x39fb47463477c5c8, 0x3d53b25d3647586b), (0xb98bb89b4c085acf, 0x3d3b20c42e642e99), (0x397afedf65fe5bfe, 0xbcd76505329d2147), (0x3958669626edb388, 0xbcb91f514b70dc66), (0xb8ecf324e9269490, 0x3c55661a888ce787), (0xb8b1401ccd948cf2, 0x3c327b48d4454d52), (0xb8698f6cf1c5e01c, 0xbbcf10cd4224310e), (0x384b17d2f0b22cb7, 0xbba61f092d4fb132), (0xb7db3b4d370a111b, 0x3b422f16a2b51a21), (0x37ace9fba95b7f40, 0x3b15d89abfbbc58c), ], [ (0xbc27736b1f56d6fe, 0xbfc0d0d36473e98c), (0xb5eeec74a121164b, 0xb94d417ee84a02e1), (0xbc517d3bbb8e77ff, 0x3fb0cda9974abe2b), (0xbbe2a43b589bb30c, 0xbf4367f38f201c25), (0xbc17d132300354c7, 0xbf7656b75e3c242e), (0x3b94b9f5aa61b16a, 0x3f0ed82abf7489f1), (0xbbcb0bedfa6ed1b8, 0x3f27b4e5b83eeb36), (0x3b0620c0f4833a16, 0xbec171fd0fb670e7), (0xbb638b5f7ce177c8, 0xbecae62b4ad017fb), (0x3b0b87c8b1ba0970, 0x3e64648495a7b49e), (0x3b05b3200be63707, 0x3e62f42a577135ad), (0xba91dadfc29e6554, 0xbdfd286e7fa32656), (0x3a9d8beeb2cb7298, 0xbdf22dbcbf76a1c5), (0x3a2a43a2ea6cef43, 0x3d8c222accc0d332), (0xba0327331125a6e3, 0x3d793fc7f6c8caef), (0xb9acf6791f2a444c, 0xbd138c7e1f6709fa), (0x399fac78a0046126, 0xbcfa8e4efc5ad38f), (0x3933d41876c7d322, 0x3c947e808f83bea6), (0xb91b783f58eeeb68, 0x3c75e0f0594a5008), (0xb86c4cbf1e35e546, 0xbc10c8678c595f1c), (0xb87ae60cd98137bf, 0xbbecffab1af4612b), (0x382a6f17570f961d, 0x3b86111d5963e0eb), (0x37f00fe3e9f49b7c, 0x3b5f5ac4d0ed3683), (0x377ece1c4a712e4e, 0xbaf8306e05270fd5), ], [ (0xb60d733c7a7e52a7, 0x3970250757e24008), (0x3c61a13e2fee5687, 0x3fc076826cc2c191), (0xbbcb789ffb6667b2, 0xbf5b62885e0070c6), (0x3c35dbe9d7210bbe, 0xbf95e7f53001e4b1), (0xbbddb8eb1d2bf603, 0x3f322ebeb8dc2202), (0xbbf72618e8704270, 0x3f517444a7a04cd0), (0x3b7b01e86b4a3da0, 0xbeece06f1f1fcd7e), (0x3b8016817bdb5904, 0xbefa7006e6ad9cfe), (0x3b13ab2699f50e0a, 0x3e95c42f02cf15ca), (0x3b08b6ecfe623226, 0x3e9750ca5e1366b4), (0xbabee952793294d7, 0xbe3314982df7eaa2), (0x3abefa05a9bee7a7, 0xbe2aded75306b3b3), (0x3a67ece2ba1179c1, 0x3dc5d47847d8ebeb), (0xba5c6d6993547389, 0x3db5ccf44d287a22), (0x39e36e4501d8e34a, 0xbd518fce3e03f8ff), (0xb9a320cde8d9c336, 0xbd3a3d6bcad0c437), (0xb976652eddf4a16e, 0x3cd4efbd765ccd7d), (0x392c39469b09709e, 0x3cb85a4b163d5fb1), (0xb8fcb83bb2002a51, 0xbc5339ddcc1bcec2), (0xb8d45b1a219ef1df, 0xbc31f48b401dcae3), (0xb86e5c376fb9eb81, 0x3bcc067f698492f8), (0x384a2903db3f0c8f, 0x3ba58a055bf542b9), (0xb7e2ee806b9979fc, 0xbb4078cceb371d66), (0xb7bbbf36698a9adf, 0xbb154fa9d8bb2e05), ], [ (0x3c61a6e02553980e, 0x3fc02455675ab6d2), (0xb5c5f31d846909a7, 0x3920fd28a7ab34ea), (0xbc5a58b3083e7da5, 0xbfb021c155a720df), (0xbbea19c1039cb49f, 0x3f412be56fc1449a), (0x3c01bad3e8f49c57, 0x3f75749d556ad61c), (0xbb75621379d06ca1, 0xbf0b51f1f9bea93e), (0x3bc81ccb322d1126, 0xbf26c96a07e236bd), (0xbb21804e8cca606d, 0x3ebef3a7abd5ac6b), (0xbb6f6eedeef435f9, 0x3ec9e207c257433a), (0xbaf0b5ea62a8de24, 0xbe6220b96eef8058), (0xbad2fa9552352869, 0xbe624317cb296737), (0xba7c0f987894ba0a, 0x3df9fc2f2cd3917f), (0xba7936059699e1c2, 0x3df18ae8347e8254), (0x3a1573486603ca10, 0xbd892540423f2e30), (0xba1e19de8fd09a84, 0xbd78687dcdc2db72), (0xb97684a35e3ea9dc, 0x3d1187909104433c), (0x39630ebfb454443d, 0x3cf9b8362860195d), (0x38c1923b5504cc9f, 0xbc92711ece62b404), (0xb903c12865011bca, 0xbc753b340e1ec1f7), (0xb8a22b4edd218aaf, 0x3c0e50ed1c32be11), (0x387ce89517a6eb64, 0x3bec3274fc0c19bf), (0x382cd7af1eec7b55, 0xbb8401a453695584), (0xb7f9f56cebafb7ea, 0xbb5e8c7520273be2), (0xb794336346140121, 0x3af602279247901e), ], [ (0x35eae2ce139b755d, 0x396742f004f756a7), (0x3c5d7cc41717159f, 0xbfbfa8b41711c83a), (0x3bf6219a48a24bc6, 0x3f5857d3969997d1), (0xbc395ccf34fc8573, 0x3f9511c6dadaaa12), (0x3bd13cc55aed0677, 0xbf302c289dbdbd4f), (0xbbde8aacf938011b, 0xbf50cc2238d229f9), (0x3b831f1c6dd9cc15, 0x3ee9b64d5c63668f), (0xbb967f7ad298da49, 0x3ef976fb023f0f79), (0xbb26429ad31066a5, 0xbe93693ba0b5ba70), (0xbb30bc57284d2f2f, 0xbe967b952987350c), (0x3adfd4fe0a523682, 0x3e310cb79a2addab), (0x3abbd4987c3e4ca2, 0x3e29f2079f8e397f), (0xba6750593e1e01e8, 0xbdc38d957eaa53a8), (0x3a5878f2c117ca3c, 0xbdb51511e93ba74c), (0x39d6e8ba61764a78, 0x3d4f8bb4d9d2e233), (0x39d8bdf5fdad66d3, 0x3d396afe82155942), (0x39700aa17bd0529e, 0xbcd2dc3c5a2d6062), (0x39264d3a8a0c9e0a, 0xbcb7a1c8dec30b78), (0xb8fa02e0c4da574e, 0x3c51600c1fbbd4ea), (0xb8dd822a2730dcdd, 0x3c3174c6425ae3bb), (0x38597c34fcb10a17, 0xbbc969aad5156298), (0xb84606c1cf335ef0, 0xbba4fad8aa607bb2), (0xb78af3fa0ad5b88d, 0x3b3df9a69e01b8c9), (0x37a075924edc374d, 0x3b14caa46ecb07e4), ], [ (0x3c50e4250a158a23, 0xbfbf161d0c28b48c), (0x3611a74b58e68914, 0x3973ee78b8c079ca), (0x3c421e360c4c6fb3, 0x3faf11d837aa6f64), (0x3bd18f48c3538dba, 0xbf3eab76da4d07a0), (0x3c1ebe3b989625cd, 0xbf74ab329f067aea), (0xbb5e80c38d8ec580, 0x3f086ada57bc1c51), (0x3bc03960e72796ae, 0x3f25f6e78f11ab9a), (0x3b5e771583ebe81e, 0xbebbb271f54c8965), (0x3b5cfd56b457272d, 0xbec8f85328c26cb7), (0x3b05a90e2d074d12, 0x3e603f82aebdeac1), (0x3b0054f935b9aa08, 0x3e61a3010279a195), (0x3a5b79af494102ab, 0xbdf75660809cdedf), (0x3a8b7a2894daf42e, 0xbdf0f6931774a05d), (0x3a13e36d17ff7a01, 0x3d86a2e612670759), (0x3a1478f3b027f12a, 0x3d77a2a8e0311432), (0x39a89f64fe6a7cac, 0xbd0fa4c8e3cec9ee), (0x399791d5ae2f24c9, 0xbcf8f1926f3bf5c9), (0xb90779dd9b4f4523, 0x3c90b165b307c656), (0x38c874530c0e61a2, 0x3c749fd30e4702fb), (0xb8a3d520095f9475, 0xbc0b864b8eb17f2d), (0xb887f6b35d01d945, 0xbbeb6fef448f9ec9), (0xb82c404eab8fd764, 0x3b8238c2939c0306), (0xb7cf45b246f68cc2, 0x3b5dc6a5afbef1d7), (0x37879b3e205ae80b, 0xbaf41b15e5934cd1), ], [ (0x35e2402b29b452e6, 0xb95669e940f0e62d), (0x3c0020b4016594be, 0x3fbe8727daa3daed), (0xbbea4d873618607e, 0xbf55d353e2854a37), (0x3c3361836c5324f0, 0xbf94524d4813cc25), (0xbbb70735fac009ce, 0x3f2d037574e28370), (0x3bf7f1d7c0f3582e, 0x3f50356bb747a763), (0x3b73015c49ea72dd, 0xbee7156bfccef376), (0xbb99523f50a17202, 0xbef896d7dc819faf), (0x3b307ed5444cfe33, 0x3e9172c6dadf4149), (0xbb334d67f3854d6b, 0x3e95baae8efc2e31), (0x3abbd2db893ce2b0, 0xbe2eb347eb4d6941), (0x3acc3ffb82d08806, 0xbe291a60a72a20e0), (0x3a62e32cc76420f9, 0x3dc1a345a9a6a5f2), (0xba511d514fc93073, 0x3db46c56b01906be), (0x39eb5948642788cd, 0xbd4c84bb3767683a), (0xb9c6dbefdede6e96, 0xbd38a83e6e4c14a6), (0xb960551193c229eb, 0x3cd11796d0057ab1), (0xb952ad5a14be2d5e, 0x3cb6f5675ceddd1b), (0xb8d70078fb2fe673, 0xbc4f936ccfdc26d8), (0xb8bf16cd40d79f50, 0xbc30fc2f7536e2fb), (0xb82fad0a6a231690, 0x3bc727e83d15ee4b), (0x3807b3ed34c03c50, 0x3ba472426379c0dd), (0xb7d0fc2af29aaf50, 0xbb3b644d13049235), (0xb7a0b4b41cc19800, 0xbb144a95537eaf6c), ], [ (0xbc5b4c98f0d3c4c3, 0x3fbe0357c158b119), (0xb60d0c75a77e2033, 0xb967816058366b9c), (0xbc410072ccb8850d, 0xbfadffc2fc1a91f5), (0x3bd769e0c0dcd2d3, 0x3f3b9b82ae07da44), (0xbc02d8dbfa1e178d, 0x3f73f64e05320ac6), (0x3bafe44f6d4ea208, 0xbf05fe4b66cf19d9), (0xbbc540e87c50de38, 0xbf2539518e1b00f5), (0xbb397c57bc8091bf, 0x3eb8f8d01c487905), (0xbb5e179d1aaec556, 0x3ec825045b97e2dc), (0xbad3613aacf5b7ad, 0xbe5d565f3bb61dea), (0x3af7612fa1765a21, 0xbe611186586f4f74), (0xba999c78eb7ba93a, 0x3df51a669158191c), (0x3a8fdeaddc76e697, 0x3df06ef52f6715a9), (0xb9f43ddc362f0509, 0xbd848215e95caabe), (0xb9e3ce8533da1d00, 0xbd76ec8422019334), (0xb977fdbacbb88faa, 0x3d0cbaf5fc1449cc), (0xb994adec13653643, 0x3cf8393ffa3d864a), (0xb920340fd1f6eaf4, 0xbc8e6232fcacc946), (0xb91a15a57d08156b, 0xbc740e69a1eec644), (0xb882efe890d1719f, 0x3c091cd31485cd1d), (0xb87204ec8daa0e68, 0x3beab83a7b21fd23), (0x37ee5c4a3769c7c2, 0xbb80ab43d4957dfa), (0x37d0433b7ef63b8f, 0xbb5d0a0f23f73309), (0xb76e179e9a438fab, 0x3af2707876868cba), ], [ (0x3610ef51183cb002, 0x3972fe6576610a9d), (0xbc5cb1f28997ca3a, 0xbfbd8293aa55d18f), (0xbbd0e0b711c1383a, 0x3f53b6beb83f2596), (0x3c36c091c5e2bd45, 0x3f93a5ccbc12a67b), (0x3bc80bb5067d449d, 0xbf2a3765d26aa42b), (0x3bc464654b3effa9, 0xbf4f5ab33748c215), (0xbb86c3ad3a1d34af, 0x3ee4df6f1c257a5c), (0xbb9372510da194bb, 0x3ef7cbd49c315be0), (0x3b1dfd4ff2a51cd9, 0xbe8f96098cf07175), (0x3b0aec441511ad05, 0xbe950b37dd43531f), (0x3aa7073eee76aad1, 0x3e2bd2e6405c605d), (0xbaba14df19ca3ca5, 0x3e285530df0d4b70), (0xba5940f4b5dbe91a, 0xbdc0029e21930f20), (0x3a40c5ac889e279f, 0xbdb3d11aeba731a1), (0x39b3628671f6f9fe, 0x3d49ef077e064e5f), (0x39cb6ce5407798b1, 0x3d37f3d211d80a08), (0xb947488a9811c854, 0xbccf2617ceaee07b), (0x39261e70e580a2ad, 0xbcb654785f893e5c), (0xb8d177e15b92fb85, 0x3c4cd5d45e8ed84c), (0x38da56fe6bb5e9e1, 0x3c308aa980f020fb), (0x38655215f7c6e0cd, 0xbbc53213f4bfc10c), (0x3846a2e45c9c7024, 0xbba3f087bcfff455), (0xb7bf1d6ed9e53a8a, 0x3b3922460f936d70), (0x37bd5d3f90200af4, 0x3b13cfffa188113e), ], [ (0xbc57ac02118ce034, 0xbfbd0b36e5737458), (0x35e5dbf97ada5b8e, 0x39455ca750ec6752), (0xbc494ec699987d83, 0x3fad082ce3c6b59b), (0x3bdbdb6b7d6ce172, 0xbf3905d00c5e6800), (0xbc14d8fddd6666b4, 0xbf7352b073fdac7b), (0x3ba8a390ec67540a, 0x3f03f1ccfec2fc88), (0xbb8f74934a18e861, 0x3f248d74583834bc), (0x3b536c48c738b669, 0xbeb6a9ef0d896bae), (0xbb686cf2b10eb75c, 0xbec764d9798d6a80), (0xbaf45b48c636943c, 0x3e5aa785d6736f5c), (0x3b032808a4ecc777, 0x3e608cae36118cdb), (0x3a954183d5d06233, 0xbdf332ddfb39cd01), (0xba85b57db0ba4e83, 0xbdefe502ff1a8f08), (0x3a0e117f9b9a2106, 0x3d82afc83348eef3), (0x3a1f9e55699c4976, 0x3d764468c0a30d64), (0xb9800b377972327f, 0xbd0a399e849ce64d), (0xb987e7e0201e1a08, 0xbcf78e09771972ad), (0xb92e0978fe137b3a, 0x3c8bc9dea78f9166), (0x3917220a53df58e4, 0x3c738663c7562da0), (0x3893066b32284ca1, 0xbc07042b3fa91e95), (0x3880dae944b873e0, 0xbbea0b14ac68d97e), (0x3816034e3ccdafa3, 0x3b7e9f946caccd4b), (0x37ee935573e4975e, 0x3b5c56e575651cdb), (0x378326c82431dace, 0xbaf0f996416a3127), ], [ (0xb5cba20478c84ae1, 0xb941c202ce623e76), (0xbc49df1f0f8d2107, 0x3fbc96700bf039e2), (0x3bd298b7ed2d3ac6, 0xbf51ec0b5de4befe), (0xbc26397704521dc0, 0xbf93095734a24496), (0xbbbe43e7480a487e, 0x3f27d74e12285cb2), (0x3bbff97a4e7b98d7, 0x3f4e636fe259352c), (0x3b74153ba07b8f20, 0xbee2fe11972bc0c6), (0x3b833d8792db4991, 0xbef712e4d44c4a74), (0xbb0f1553b4c20b5d, 0x3e8cc3adabae0452), (0x3b2bb2d302a59ebb, 0x3e946ad2d9cbeb5c), (0x3abbcd480e0362ce, 0xbe295d81ae83f621), (0xbab3ff4398d1910c, 0xbe27a02aefea3d60), (0xba59673869d1d69f, 0x3dbd3a949a722395), (0xba4dc28fd0eb18e2, 0x3db341e0bb193b48), (0xb9c0a6ee415a5306, 0xbd47b550a4f76700), (0x3994e75cd4e25783, 0xbd374c654a26537e), (0x396bf6b9da90343a, 0x3ccc86173683ecb7), (0xb9343315e10774e3, 0x3cb5be2db45fdd99), (0xb8dd50a28dc1737f, 0xbc4a7432d3c802d5), (0xb89104cb13cbb909, 0xbc301fe8f4a0a59a), (0x3862fc2b2f292a7c, 0x3bc37bcc945caecc), (0x383f40a66926ee1f, 0x3ba375a2264aec44), (0x37876edaf3b8c254, 0xbb3726c4f48ef3c9), (0x37bfb858dba2f507, 0xbb135b197250609d), ], [ (0x3c2c279ff462c3be, 0x3fbc29ae8400a320), (0x35cbc9db3681c2a9, 0x396a5c619f751287), (0xbc47ac9bcf3441f8, 0xbfac27138da31c2b), (0xbbbe5ab192ad8423, 0x3f36d141fcbea853), (0x3c12b724fd73605f, 0x3f72bdc71062acd6), (0x3baf5f2a5e20af51, 0xbf0231cf643ffc17), (0x3b6e53f73e07f7ec, 0xbf23f0bf3b3fe8be), (0xbb4cfe2786564eab, 0x3eb4b05e955de175), (0x3b6d19da721e7488, 0x3ec6b52b868fa5e2), (0x3afd657f133da2a0, 0xbe585a7aa3e84cc3), (0x3afd8305110d0415, 0xbe6012d3384c9164), (0x3a82a12fcbf74576, 0x3df18f8c4872544f), (0x3a83ddc6dcd20390, 0x3deeffc4029f2f01), (0x3a2a5f86153ccacb, 0xbd811d5a3daf7136), (0x3a1939ffd2f149a3, 0xbd75a8d84ce122b1), (0x39948d45aa4f471b, 0x3d080dfa27f2ad6a), (0x397ee5f9b8f0f308, 0x3cf6eec07f0d91c7), (0xb92b05e0bbac3b01, 0xbc8987d6f4b58a17), (0xb90c392890cae7e7, 0xbc7307194fcc3abc), (0xb894aeaf37740080, 0x3c052f0ff8dc5a44), (0x3880e377a138ed87, 0x3be96804c6d0c4c3), (0xb7fb165b04bc999e, 0xbb7c3d1f829825de), (0x37fc727aeddf2fd2, 0xbb5bad09acad456f), (0xb74fed0f6e3c7260, 0x3aef5d6f1dc95101), ], [ (0xb5e9f9b32cc9c472, 0xb94f1c4dc0fd7ad0), (0x3c58fff4515190b5, 0xbfbbbf246914235f), (0xbbb59d638f72d376, 0x3f5062daee35411a), (0x3c1bef9e896a99ca, 0x3f927a96f174b6d1), (0x3bc79c688e87e02d, 0xbf25cdb5dea9c121), (0x3bd1f78082ed604a, 0xbf4d818348f98a0f), (0xbb8cf93ec0b60def, 0x3ee160aab829409d), (0xbb9dfe5ed21cbf06, 0x3ef6698d6ee99eb9), (0xbb0db19c59160d9d, 0xbe8a5633d8f0b3bf), (0x3b3148c171a390c6, 0xbe93d788d61154a7), (0xbabd69ba99ca8de9, 0x3e273ec2ae0084b9), (0x3a4e64bbbfd099bd, 0x3e26f958f6235deb), (0x3a5eece34fec9144, 0xbdbad0939c43a9f7), (0xba3e162f724391e6, 0xbdb2bd56309cf194), (0xb9d6bdc444caeccb, 0x3d45c709d717e64d), (0x39923c04d3fffb00, 0x3d36b0b8fe7370f7), (0x39668435dfe7dada, 0xbcca3cece6ce50aa), (0x3928e245f64dcddd, 0xbcb531b157c3eb03), (0x38d9c8cd5a159ad6, 0x3c485f346abae02a), (0xb8c42e265a4503fd, 0x3c2f771606e9b677), (0x3869cf65db30f118, 0xbbc1faf5bae17a4f), (0x3843ce2b3bffa99c, 0xbba3015dbdae4304), (0x37d01253f07a747a, 0x3b356721e926aabc), (0x37ab991b20a5ed5f, 0x3b12ebe23c0e019c), ], [ (0xbc4b1bd5a08c4697, 0xbfbb5b8273b75055), (0xb5fc5d98089f691c, 0xb9617b443b19e784), (0xbc19066393ec8b4b, 0x3fab59418c36a684), (0x3bd4c6e4a4b5908a, 0xbf34eafeaa92aa79), (0xbc1e8c2463f5dff7, 0xbf7235801af9be44), (0x3b9bcf2d229387a5, 0x3f00af9747d0be92), (0xbbaf4068b21f5f13, 0x3f23611db0e1566f), (0xbb5fa296ae418fd9, 0xbeb2fbe414da1250), (0xbb6579a7a7d2b7a9, 0xbec613ccbb9cbe59), (0xbafb9e935c5d4727, 0x3e565cf274e84d31), (0xbae9f705bc9fc3a8, 0x3e5f452996e3dc2b), (0x3a88db40653fa6ad, 0xbdf023f5382da3ad), (0xba87d1ea787e96d5, 0xbdee2be24fbad63a), (0x39e1374c2f3e53a0, 0x3d7f7ed3740f8d64), (0x39f934955bbeefc4, 0x3d75187e998a123d), (0x39aeb3c518f70011, 0xbd06293c9e78a94a), (0xb980e7fd6e1aba60, 0xbcf65a49785b93de), (0xb925d4c892512e3e, 0x3c878dbf031e576d), (0xb912bf351c2e7bd2, 0x3c728fde13655c16), (0xb8aaed4885e1dc5d, 0xbc0392b9e7067906), (0x3814e81144aa2192, 0xbbe8ce75f24e6d2f), (0xb81d860830f44f3e, 0x3b7a224d38043629), (0xb7ef6d218b7f22e1, 0x3b5b0c2b72afb1a5), (0xb7213d15be1c6e9a, 0xbaed12d5bc6b57ab), ], [ (0xb61ce6cbc1f04255, 0x397036fa5f6395cb), (0xbc5024304247ada4, 0x3fbaf9cb49c4f935), (0x3bd43675d81a335c, 0xbf4e1d930b513228), (0xbc26b1ae60058494, 0xbf91f7a8fec6eba8), (0xbbccaafb65fcb92e, 0x3f240a55310866fc), (0xbbe93eb318fd63c7, 0x3f4cb20c812fd3aa), (0x3b7bc11f9b0249b7, 0xbedff51953c6b6cc), (0x3b7ca6d618312011, 0xbef5cdc48f5d75eb), (0xbb1e5d2044572b21, 0x3e883b091952c721), (0x3b392f30805656b3, 0x3e934fb685e58ab7), (0x3abdef10942d29ba, 0xbe2566fc4369ab71), (0x3ac87311849ba940, 0xbe265f0f7de29720), (0x3a589755adec28c8, 0x3db8b61e5f9b79f9), (0xba46ab4cdf8eab9f, 0x3db24253069b78a8), (0xb9d3414dfa14e877, 0xbd441732d722a86f), (0xb9c20d9bc0b7d20e, 0xbd361fa985a1652f), (0xb962a44c7096efd1, 0x3cc83c1756587290), (0xb94098c5fbe9b36b, 0x3cb4ae329744cc53), (0xb8e5a6b655add69f, 0xbc468a7f4c14db50), (0xb8c263b696f21145, 0xbc2eba469216c470), (0x386c7b9219cb3b7a, 0x3bc0a74a6d599cb0), (0x383259264f03f94d, 0x3ba2936d1cb0c961), (0xb7de00e6c53ea913, 0xbb33da81fd8c724e), (0x37a15c8a04c7e7ef, 0xbb128235bc0c47ff), ], [ (0x3c5ffacf3e2418f7, 0x3fba9e13a0db6429), (0x360c15fcefbc6cf7, 0xb96b692a38880539), (0xbc305f5aef32722d, 0xbfaa9c1ca2161b9b), (0xbbd5ab98ac975e2e, 0x3f3344a09efdc635), (0x3be8bf0e555b3029, 0x3f71b82c430a2381), (0xbb93a994567a3c7b, 0xbefebfb97bca01f2), (0xbb991369e36b1830, 0xbf22dcdb1bc1d038), (0x3b5ea31075526d31, 0x3eb180047f0b79ae), (0x3b46ada0a01da18a, 0x3ec57eeeee84d0d0), (0xbadb2a1ce7632789, 0xbe54a0c699c8318b), (0x3addd02fc0b7c908, 0xbe5e7594e8a2c760), (0xba80e5f270287d53, 0x3dedccbbb4c0ba7f), (0x3a7ca797a3565ecd, 0x3ded6766337b5c91), (0x3a1ab23ec0eb4599, 0xbd7d1a05cea18a69), (0x39e1f4b5b52d14cc, 0xbd74922fb50a22bf), (0x395024c9150c0f64, 0x3d047fa35bf6ab34), (0x3985f2bf77091074, 0x3cf5cfa08701ca2f), (0xb9266c2a76db875b, 0xbc85d0099455bd99), (0xb91f43baef384b49, 0xbc72200ae9780072), (0xb8a3a3083fb87713, 0x3c02265fdf769ade), (0x38836fad8505e902, 0x3be83dc86da8bc25), (0x37ea0aade21b140f, 0xbb78447b5e2dbf2f), (0xb7f62e5f79c1ca9c, 0xbb5a73de1878cbf9), (0x378acaea6a6d9658, 0x3aeb08df74d22d98), ], [ (0xb5d780da95d79b82, 0x395404a4367c1acf), (0xbc55d35a88f1e0a3, 0xbfba4407e04298d1), (0x3bdf6dddc07aba4f, 0x3f4bcc9df0cf00b2), (0xbc3c3cb8ccc39d2a, 0x3f917f0266db2149), (0x3ba3d974ad41d7db, 0xbf2280a052234a05), (0x3bb902b66919d00f, 0xbf4bf2ada1f44071), (0xbb64ad3ffb27706b, 0x3edd83d58032b48d), (0x3b3d6efc3f5aa589, 0x3ef53dd972d8f232), (0xbb230bc40c1510e8, 0xbe8663c1fe202028), (0xbb26dba834dbae96, 0xbe92d1fbf2203ff6), (0x3ac7c87693a0820a, 0x3e23c9f0b759c5f9), (0x3ac4688bb194b145, 0x3e25cfe1b012696d), (0xba597597731528c4, 0xbdb6ddc0795781e2), (0x3a30fd07b7c74b96, 0xbdb1cfd495042669), (0xb9e56d22c0bed868, 0x3d429b7af52144d6), (0x39c7617697a68dba, 0x3d3598302ab3a84e), (0xb969ff73c4a2ed6f, 0xbcc677f6a5ebe777), (0x3900de58e64b147d, 0xbcb432ecc1192f3c), (0x38ee92d01dc42743, 0x3c44ec1126d1a78e), (0x38c2b1157c94ede8, 0x3c2e0887dbe88798), (0xb7d2d49d120bbb3a, 0xbbbef4037751e14b), (0x3837430b053ee391, 0xbba22b7609bcdbcb), (0x37d8cec91a9bdbe3, 0x3b327988001f32dc), (0x376c8d2e6d2182d4, 0x3b121ddd67c06d53), ], [ (0x3c423404089aea02, 0xbfb9ef3bb2213b0b), (0xb5c87de2f8cebd53, 0xb962e8408ad4e1a5), (0x3c342c5cb51f294f, 0x3fa9ed82007a9a45), (0xbbad41b75b8ea526, 0xbf31d2fdeeb29f8a), (0x3c18994595321a31, 0xbf71446866ff1b83), (0x3b94bf0ff8b9b23d, 0x3efc73b684f93259), (0xbbc79edfbf5325fb, 0x3f22628de594b6c9), (0xbb2befa01f9526e8, 0xbeb03303c1427449), (0x3b691967f42c542c, 0xbec4f51007c51087), (0x3af5410acbffa9a8, 0x3e531adfa36f2213), (0xbafc56975a6a16e6, 0x3e5db4f306b19095), (0x3a79c0979a0204dd, 0xbdeb9e33598f899e), (0xba765a4f110b219b, 0xbdecb09ed6ecb892), (0xb9f410899a06c92c, 0x3d7afe1183148af8), (0x39f78f1dd4b75a7f, 0x3d7414e442aa864a), (0xb99a9b988c884db4, 0xbd0307c12941fdc5), (0xb990c58e388b6028, 0xbcf54ddabc97b3bb), (0x390b34a178291a11, 0x3c84455c63029495), (0x391979fc805b19bd, 0x3c71b7024cd44274), (0x389e56ba399caf6e, 0xbc00e2d078dd0efb), (0xb82f4378acefe136, 0xbbe7b55bb497c4cb), (0x381a7fc1f4e5a681, 0x3b769ad969d0625b), (0xb7931840ec89fbc9, 0x3b59e3a726e2743d), (0x378455d827026a82, 0xbae936884740c735), ], [ (0x35fae2734bb315aa, 0x3968400e2d1b8167), (0x3c5728ab934a269f, 0x3fb99be744018c90), (0xbbdb8852614fe955, 0xbf49c3f52a2af724), (0xbc2f281d89ca125d, 0xbf910f5ca51f98b0), (0xbbc3c6681ad02312, 0x3f2126c8e8ca2766), (0x3babb471b2a0c061, 0x3f4b416f7d4fc313), (0xbb677b339729278d, 0xbedb5e2e5580e1ce), (0xbb988d465ffb2680, 0xbef4b862279de756), (0xbb2b440cbefcb86d, 0x3e84c5071b39dc13), (0xbb3de6305e87339f, 0x3e925d2fc3b19021), (0x3ac90d431ee8f3e6, 0xbe225df322279972), (0xbac3c7a2f5c16d4a, 0xbe254a971eb6fe3b), (0x3a515ee7ac48908a, 0x3db53cc6c9922f25), (0x3a5ec538d819665b, 0x3db164f95180d8bf), (0x39d2657db4413c0c, 0xbd414b9ef404e359), (0x39d5a070336f534a, 0xbd3519623b4e4c39), (0x396e222733381912, 0x3cc4e7271a5acddf), (0xb94d7cdd22f0028c, 0x3cb3bf2a1b7bb45e), (0xb8e550d76b23a690, 0xbc437bc0b629d672), (0x38b920c14a99cb5c, 0xbc2d61049bf3447b), (0x3855956d27abf79f, 0x3bbcdb091753dc1f), (0x384b894b04dc498b, 0x3ba1c91964954692), (0x37d5bcb82226b372, 0xbb313e10f59f02a2), (0x37bd81d4f7329d91, 0xbb11be93ca114b15), ], [ (0xbc54096ec8637e04, 0x3fb94d3276914e51), (0x35b1f799a74fb76a, 0x395d690fadf22a83), (0x3c4baee1d6c0d48a, 0xbfa94bac1950e319), (0x3bdbfe3ad50b9727, 0x3f308d4ff8f2059e), (0xbc1cca1c2772d45e, 0x3f70d90d29bfeecd), (0xbb987fee6366d20f, 0xbefa6d56162f7fb4), (0xbbc7e7232a191e61, 0xbf21f107da23807d), (0x3b42cbe0cc45eb3d, 0x3eae1a626277437b), (0x3b665f948e1d7ee0, 0x3ec474eafd0cc642), (0x3acb746c7398995a, 0xbe51c27144f42d78), (0x3af77d2dd1ae1ba3, 0xbe5d01999b1a4fe9), (0x3a77ecdd37e45371, 0x3de9b014801da87a), (0x3a855ec04282c8cc, 0x3dec061740bc8a41), (0x3a1fc05e7d7c7991, 0xbd791f8c297254d7), (0x3a0ace8e68225aa3, 0xbd739fb558b7a363), (0x398b465ba48d7de4, 0x3d01b9f74d482556), (0x399084cac0e412c2, 0x3cf4d425556e6c52), (0xb91cfaa8a45d49ae, 0xbc82e617aee470c1), (0xb91bd25d6d983a31, 0xbc71543271ff906d), (0xb89586b26f4fbcba, 0x3bff8440e63c211d), (0x386772bb21a29d94, 0x3be734945f8177cb), (0xb80904837292f3d9, 0xbb751e13261a9dc1), (0x37f62a65371653ca, 0xbb595b06b5ab1c41), (0x378aee2000820cbf, 0x3ae79434d2d5aa8d), ], [ (0x35fd3e35d9fc508f, 0x39692a03d61a6765), (0x3c5e213a1a4b3671, 0xbfb8ffc9bd24fe08), (0x3be5e8a5d70cddcc, 0x3f47f7d46ab33721), (0x3c2f532ddb23da23, 0x3f90a7a725d3fbc4), (0xbbb3f089aa77a72c, 0xbf1fea1728f216b4), (0xbbdf63ef331627c3, 0xbf4a9cac69f0ed64), (0x3b78f775a8392238, 0x3ed977f48ff1056b), (0x3b8a77447708dbe0, 0x3ef43c2d8e698c10), (0x3b293fa288b304e6, 0xbe8355d1a6765ea6), (0x3b17742d486c25ae, 0xbe91f0553501d121), (0xba8ae50dffeaa9a9, 0x3e211b47f6a44829), (0xbaa73bc70607579c, 0x3e24ce23303889a9), (0x3a5d5eb483ce8058, 0xbdb3ca98df62221a), (0x3a46a518fdfd8131, 0xbdb100fc746529d6), (0x39e722b8c5f7aad4, 0x3d4020f11e2dc07c), (0xb9d9956b0c21d835, 0x3d34a26ef221978f), (0x396850ab1f7d4d53, 0xbcc38203ff3d18df), (0x3945a4bf6ed3a626, 0xbcb35244c14991ae), (0xb8eeb070694cf5e7, 0x3c4232db9b60cb00), (0xb8a56af95593329b, 0x3c2cc2f2efd1e051), (0xb817a34eb41964e7, 0xbbbafa643c1fee7f), (0x38319c576c8452aa, 0xbba16bf81ee3b787), (0x37d076f627ec3422, 0x3b3022fbfe27424b), (0xb7a801683d487848, 0x3b116413b0cae3c2), ], [ (0x3c4123b2f0e7c9dd, 0xbfb8b67a2481077d), (0xb5edd5946b3cb2a5, 0x3946a50da827f406), (0xbc4b4ca91be60c39, 0x3fa8b51f21068ea2), (0x3bb25eeb0c76260b, 0xbf2ed935c7aefa31), (0xbbf1e976299c9c65, 0xbf707522a5037f2d), (0x3b9aa02b2a63445a, 0x3ef8a196061f8bbc), (0x3bc503ddc4900b75, 0x3f21874a47e3c1e3), (0x3b255f883f2d82a2, 0xbeac10cf34c04f17), (0xbb5b1d29b71073a0, 0xbec3fd6c2d4fa2a4), (0xbaeb8c54608e9282, 0x3e50906d55522785), (0xbac0c29c0a96e3da, 0x3e5c5a1c124dfa08), (0xba7aa4d02da2e1f4, 0xbde7f883b31a5f59), (0xba7747971035692d, 0xbdeb668cf53028e0), (0x3a1b938795c32e6d, 0x3d7775372d05b2b0), (0xba0cfec68b9fa162, 0x3d7331d871d67118), (0xb9ae3aa9398e5a58, 0xbd0090102489f480), (0xb99e9cec5597a630, 0xbcf461c4066d0e4a), (0x3914deb7f36c5b05, 0x3c81abf9941a3423), (0xb8df6670bd950fcb, 0x3c70f715e31f4f53), (0xb88076dcbbb6bbc6, 0xbbfd7ed45d36754d), (0x3884befa4b49ff70, 0xbbe6badf59009f89), (0xb817484bd8d9cd12, 0x3b73c80adb5c7d1b), (0x37e6bcd3e344ffce, 0x3b58d97e797244fc), (0x377002e0099ec551, 0xbae61ba441542113), ], [ (0xb5e15739920a6042, 0x3957411605b9cd8d), (0x3c5b1c9821974147, 0x3fb86e51be0a9153), (0xbbeaa494385da6b8, 0xbf465ed1b387e5da), (0x3c09cfc1363fac8e, 0xbf9046fc5a218a86), (0x3bbf17fc5592840d, 0x3f1dca617fefa913), (0xbbe411ddd3f3c7e1, 0x3f4a0300221528a7), (0xbb35922b096464c9, 0xbed7c7618906f1e2), (0x3b985c37a80f1f32, 0xbef3c838897d0a1e), (0xbb1cfd1e42294da1, 0x3e820ede9f9dd7dd), (0x3b3d337f0c931d76, 0x3e918a94165592bb), (0x3aba2064c2ef620a, 0xbe1ff76205118f09), (0x3ab62166ef13ed4e, 0xbe24599dfeef01a1), (0xba4104861aca6ff9, 0x3db2803e5998312f), (0x3a5eb79000c7671a, 0x3db0a33202feb041), (0x39ad6a6495675c7f, 0xbd3e2bff73866f0b), (0x39d02f8782470b05, 0xbd34329cf32bc6b1), (0xb94c1fab2f5d49d8, 0x3cc2424890e7103d), (0x395165f2cbeeb591, 0x3cb2eba6575a58fb), (0xb8ee488b45b19302, 0xbc410bda2b2fedfa), (0x38c169197f6744f6, 0xbc2c2d96bb6d554b), (0xb839df5ffc139231, 0x3bb94a6157935d73), (0x38438133f79f8aef, 0x3ba113b61477f5c4), (0xb7c400b9f75f31c1, 0xbb2e47f731863fb7), (0xb7bf6daddcc30386, 0xbb110e1251b8eda4), ], [ (0x3c48caabfef07d2b, 0x3fb829d06fee9266), (0xb61c7c2ce51dc943, 0xb97019a7cd7017ec), (0xbc46f7f24522358e, 0xbfa8289a526d7785), (0xbbbd55f5936024f5, 0x3f2cd680355c9eb6), (0x3c19dafafbc6423c, 0x3f7017d70f512861), (0x3b94ef9247fbd18a, 0xbef707978e2a0db8), (0xbbb84f6dc795e259, 0xbf21247ce15e7385), (0x3b3c154e3f91cb1f, 0x3eaa3f6125485ec1), (0xbb6485e10f66ec36, 0x3ec38da848401be9), (0xbae822e833951880, 0xbe4efe39d8db4cd8), (0xbaf0a59f02f9da6b, 0xbe5bbd40f1db0e94), (0x3a88e5731b6d2f4f, 0x3de66f7d49436f83), (0xba3e79da115ba52a, 0x3dead0e8148229af), (0xb999a0303d870988, 0xbd75f78595133d59), (0x39d279bb13e85151, 0xbd72ca9bb1031b0b), (0x398dc73294489cd5, 0x3cff09e49c89467c), (0xb98c493ba49ccabf, 0x3cf3f60eeb57dab2), (0xb928107dd8db2eda, 0xbc8091d68a71f568), (0x391a43591422376a, 0xbc709f3347db6cf2), (0xb88bd7e4b3dfccd4, 0x3bfbad357dd86bf0), (0x386a0a018ebdb436, 0x3be647b364d0856e), (0x381f08d09391197b, 0xbb72939f68459b07), (0xb7ea807173f17da8, 0xbb585e93fb40bea8), (0xb78b806a2be014c6, 0x3ae4c7339928aa1f), ], [ (0xb5dba30ce3053693, 0x3937ea2409abe46b), (0x3c21907f595a082a, 0xbfb7e656efb009ae), (0x3bea53822a52cdff, 0x3f44f15066f3d876), (0xbbef8f1c97361f96, 0x3f8fd932c26aad94), (0xbba4e6bbdef5d491, 0xbf1be460dd86a0a4), (0x3bdda15b3ef145a9, 0xbf49733b591879f8), (0x3b7b0e61e74c413c, 0x3ed64488c56022e0), (0xbb74588b74c5876f, 0x3ef35ba58bf2f993), (0xbb2d010d38a866aa, 0xbe80ea47bceb9a8f), (0xbb1839485029ea9f, 0xbe912b327055d0e9), (0xbab04b71fdf73b8a, 0x3e1df42fc4e2482c), (0xba732a2fe61d6156, 0x3e23ec3e76876dba), (0xba511e7db88fce7c, 0xbdb1580393f473be), (0xba5b5424c61c9156, 0xbdb04b0353c35933), (0xb9c9856b07421c8e, 0x3d3c4ca30ffe1933), (0x39c738eb74a7f61d, 0x3d33c947b936be26), (0xb9400509632244dc, 0xbcc122c73f63e006), (0x3916d7eae173a1b3, 0xbcb28ac72945c28e), (0xb8e73a0527a29464, 0x3c4002241bb36c01), (0x38cad2069d44143f, 0x3c2ba04276d6d12c), (0x385b64b543fd96d2, 0xbbb7c48f7753a6e6), (0xb848072abf17cd35, 0xbba0bffbbb75a502), (0xb7a49b7af751a348, 0x3b2c7ae054639d4d), (0x37b54394c52e23e8, 0x3b10bc481d251ae6), ], [ (0xbc2f952341a4610c, 0xbfb7a62320798175), (0x3608d7aa0df33a13, 0x396cf7a4a97dd69b), (0x3c4f5aadff868840, 0x3fa7a50ca4504bb8), (0xbbc425ed1e39553c, 0xbf2b095ccb50a68c), (0x3c0088e41716f14b, 0xbf6f80ef11daa37a), (0xbb8b1b49b7c35e54, 0x3ef59822dc75b064), (0x3bc22455d3c1fa15, 0x3f20c7e6a7c66630), (0x3b4cb7a0033a7704, 0xbea89e00b5c358d0), (0x3b4c5ee49818e61f, 0xbec324d5238b26d0), (0x3ae1d17d1c1f9459, 0x3e4d13a888d5dd30), (0xbac771ff3649d30b, 0x3e5b29f941a95b07), (0xba65c3a8faacb7ca, 0xbde50e6ebb3d1df7), (0xba5e1fa2b117348a, 0xbdea4434c6b929d9), (0x3a1aa33d3910c73c, 0x3d74a03fe2c47ae3), (0x39fc6f3d0c6f0177, 0x3d7269628f2df267), (0x3998d07708e4c6bf, 0xbcfd28cc08f5cbae), (0xb95557f1f159116a, 0xbcf390706324d249), (0x3901d36b70d2e2f4, 0x3c7f26c3f4d4f4a6), (0x38f56e280758755e, 0x3c704c1cbbe93d3e), (0xb86ceb268d238b88, 0xbbfa089cde4d22c5), (0xb889788b18499f22, 0xbbe5da907334a8cc), (0x38130abe343bca1e, 0x3b7181ee2ddebf21), (0x37f04d8f909b3d76, 0x3b57e93ad9acbcc3), (0x378249417d24489f, 0xbae648d6e71bec37), ], ]; pxfm-0.1.23/src/bessel/j1_coeffs_taylor.rs000064400000000000000000001640171046102023000165350ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** J1 taylor expansion at zeros and extremums. Generated by SageMath: ```python def print_taylor_coeffs(poly, x0): print("[") for i in range(0, 24): coeff = poly[i] print_double_double("", coeff) # print(f"{double_to_hex(coeff)},") print("],") print(f"pub(crate) static J1_COEFFS_TAYLOR: [(u64, u64); {len(j1_zeros)}] = [") for i in range(0, len(j1_zeros)): k_range = j1_zeros[i] range_diff = k_range - prev_zero g_c = 1 x0 = mp.mpf(k_range) from mpmath import mp, j1, taylor poly = taylor(lambda val: j1(val), x0, 25) print_taylor_coeffs(poly, CDR(k_range)) prev_zero = j1_zeros[i] print("];") ``` **/ pub(crate) static J1_COEFFS_TAYLOR: [[(u64, u64); 24]; 47] = [ [ (0x3c61f1c324453b30, 0x3fe29ea3d19f035f), (0xb5b2f6354c9ff45d, 0x392031b7410e0111), (0xbc6e3631ae171270, 0xbfca41115c5df243), (0xbc18acc5100eb0b3, 0x3f78d1448e6fed48), (0x3c0e85a7d0bc098f, 0x3f8c441a2f9de22b), (0x3bd94ca1b6912493, 0xbf386671c18b088a), (0x3bd950cc4e8482d1, 0xbf39e2504ddc7608), (0xbb61b481438e4089, 0x3ee34ccbca0c75d1), (0x3b7aba05e287d170, 0x3eda4973784d1087), (0x3b1ffacaebcbb72b, 0xbe81045322aaab45), (0x3b03dabae8fea73e, 0xbe70fae0da6cdcef), (0x3abc719b8692aa74, 0x3e13546cef5ed00a), (0xba8ac75d7c570055, 0x3dfe5ee82e667708), (0xba263b1d65111e4c, 0xbd9ec80cc8b63c39), (0xba145e6e27b1490b, 0xbd83eb2e99629b44), (0x39b7626e428b4f57, 0x3d222bfcdb19561c), (0xb98421e04d0e0d8c, 0x3d03fb3376a42e35), (0xb922e25ac68f0c81, 0xbca0901287d105ae), (0x391c50bf6cf518de, 0xbc7fa6a90c6a0c33), (0xb8b3ffd27bab3779, 0x3c180774f17c486b), (0x38976f3626c20293, 0x3bf44b79578fc6fb), (0xb82c4199c877aeaa, 0xbb8c6ab05fe77307), (0x380edbb8b3f4ef74, 0xbb65805fbd38e218), (0x3787f411d416c35b, 0x3afbed5bcea231a2), ], [ (0x356eab958ab851b5, 0xb8d9a91f973ec303), (0x3c62de1143765a96, 0xbfd9c6cf582cbf7f), (0xbc46b8d73329ae53, 0x3faae8a39f51ad04), (0xbc47767d9698b536, 0x3fab589d1da13905), (0x3c0e65e41f8b156f, 0xbf7537544c331da7), (0x3bc117d15907382b, 0xbf624b3409959064), (0x3bb8c81b03584e43, 0x3f26e4c2d5354224), (0x3b9859e8c0ae37ce, 0x3f083a06e30c4109), (0x3b51fe68ee4dfe26, 0xbec9799d4c9f2549), (0xbb4ffb11fda5bef3, 0xbea33825cd2e2c16), (0x3ae8a5cec4a77c6c, 0x3e617069233e916c), (0xbaabdbb69c094017, 0x3e34569b22afc3c8), (0x3a76236a521c1ecc, 0xbdf03b9e9651056a), (0xba58526061a7319e, 0xbdbec62310af5f52), (0x39f8c0813d01aca5, 0x3d75ec84e47b6f4f), (0x39df157bfc6eaf25, 0x3d417a40c9422e17), (0x399dbf21a6dd6ae2, 0xbcf67cb1d0030c9c), (0xb95f5d6974a310bb, 0xbcbee7ff918f9b69), (0xb8ed0057404186a7, 0x3c721fb8bdc4d7fa), (0x38a1a3560d39e992, 0x3c35e0517dd0b5c9), (0x388155451c853ffa, 0xbbe792595a1eec68), (0xb829a85503eb4baf, 0xbba95a682022dcb8), (0x37f61a6a78be1e62, 0x3b59438c464a0b99), (0x37ba49a9e0951317, 0x3b187f5c94382543), ], [ (0xbc782d627160714a, 0xbfd626ee83500bf2), (0x35a0f040f68d1816, 0x3909887c15bb2d86), (0x3c6ae8952e6f1d99, 0x3fc55f6bec9ef962), (0x3c0d30f1a30652af, 0xbf83d23336fd10e4), (0x3c2695c3589cdcfe, 0xbf88c77a983a0814), (0x3bea1200f3887332, 0x3f45cdc98db1cbe2), (0x3bd343248cea52bc, 0x3f373576ff46ee3b), (0x3b8a8cd6bedb881b, 0xbef2461447d7b423), (0x3b6a8a902c87e6bb, 0xbed7b853456b6eaa), (0xbaff7253673d7fa0, 0x3e90abfc68274a98), (0xbae9e22e3ad66ed4, 0x3e6ea7a1ee26124d), (0xbac56987dde26b61, 0xbe235c0413e01418), (0x3a9eb6867453dd1c, 0xbdfb5c5d512fbb00), (0x3a3a4481d08d2199, 0x3daf4c5e26fd6e90), (0xba21e34f6852a2b6, 0x3d81e4c43397be51), (0x39d14c360485170d, 0xbd32addefc4d51c5), (0xb9605d05ffcc6dea, 0xbd01e4fadc0e435c), (0xb923b05198207824, 0x3cb12a0b88508f37), (0x391a5ac22b8f14bd, 0x3c7c4246a0342e39), (0xb8ce78a27a5aabf3, 0xbc290ede5816f2ce), (0xb8986d234d468db8, 0xbbf211307906e314), (0x381bc4668970e7dc, 0x3b9dc7bf70396b28), (0x380949fa46f6dd76, 0x3b6316e7f158a264), (0xb79167d26945830c, 0xbb0d623edc3b24ac), ], [ (0x35a1c201de6b176a, 0xb90f8a0b194e92aa), (0x3c7af22d033ee0a5, 0x3fd33518b3874e8a), (0xbc23b4d6298472ae, 0xbf95e70dc60362bf), (0xbc476d8715df682d, 0xbfa80c83bdeee5b0), (0x3c03dac20ab22d50, 0x3f69a4b292e3de42), (0x3bd887eed6e6880a, 0x3f613fbc7d698217), (0xbbac52a925910e75, 0xbf207358bbdbff91), (0xbb64763d026d3263, 0xbf0796a751f89051), (0xbb6df65f1fdd48ef, 0x3ec4255b015aded4), (0xbb3ae816d26784fd, 0x3ea3026e0ce97ab9), (0xbaf57b3883b98fa3, 0xbe5d48dcdae92f2c), (0x3aca4c50b5ee02fb, 0xbe344639d7eeb0a6), (0xba8fd8f34b9ecafc, 0x3dec62ccb4a32eb5), (0xba5032cb87171f64, 0x3dbecae92e854457), (0xba1beb1ed7eaf160, 0xbd73bb6898d73cd2), (0xb9dd5420c79c50f5, 0xbd4183edbb8ef55e), (0x399a66b105ba2d65, 0x3cf4ae3e7e4cce3d), (0xb918cb92ea651e7f, 0x3cbefbb1e700730a), (0xb9146c2f2b670d08, 0xbc70f28da3efa3c7), (0x38c4ac35b8206d4a, 0xbc35ec318df9b467), (0x388be1913e828c5e, 0x3be6555a952345fa), (0x384ff998fe9bf37c, 0x3ba9633c7f133c92), (0x37f9fe5cad2d2342, 0xbb583145f93c70ae), (0x37bb7a15502058b2, 0xbb1881cb99e6a1d9), ], [ (0xbc7d48dbfa0ea1a4, 0x3fd17dbf09d40d25), (0x35a4427f3ab43500, 0x3910992c4b87a2c6), (0xbc61eb914d33c2fa, 0xbfc1404bf647c28f), (0x3c098a23a3934c81, 0x3f74f4df2769f830), (0x3c24ae93dcbae42e, 0x3f85c6285429b66d), (0x3bdddb259d6919ae, 0xbf3d68ab722881bd), (0xbbd8cd731f6bf3ff, 0xbf356acb6452d860), (0x3b60d2b8ff5b8f47, 0x3eec10b47cf7ef69), (0xbb3cc7e8d830a4e7, 0x3ed67eaae97bbc86), (0x3b0230ef0e6803fa, 0xbe8bb6530c63f2df), (0xbaf83f73085e8893, 0xbe6d87201e450edd), (0xbaaefe243bce74cc, 0x3e20f47c83ec550b), (0x3a995905da4f9c80, 0x3dfa98331f6ea799), (0x3a40b4039f32743f, 0xbdac70414a236a67), (0xba249d55aee4b10f, 0xbd817c057a5fcd3d), (0x39d02164b46fc11f, 0x3d316fea14d1fe7c), (0x39990498a42b8b9e, 0x3d0189bd3ec36234), (0x39512fd1dca06419, 0xbcb05af44aaf2ab4), (0x38fe8d7eea675e23, 0xbc7bbdb47ae6b94d), (0xb8b4cc5b1f63c320, 0x3c28435e8461ed37), (0x3882cf7a81930228, 0x3bf1bfd66fba7b36), (0xb828cec539879f22, 0xbb9d3526fa2c65e2), (0xb7f6bbe8d3df2731, 0xbb62c1e2b3f208cd), (0x376ec8c34abcf067, 0x3b0d1f12fb9ae97d), ], [ (0x359d2cb8a50a29e8, 0x38f8cdeedd7089d9), (0xbc5052a3a2541c57, 0xbfcff654544ebcd1), (0xbc01b402d42ea509, 0x3f89223ff2c0785b), (0xbc323a275590a85f, 0x3fa4b0c5d5da6789), (0x3bb3ea54ac68ef82, 0xbf5f91a9ee0d2897), (0x3bfc41f7f61682c1, 0xbf5f51c2489b9e6f), (0x3bad7af9f28c7680, 0x3f16b4c9ca0f770d), (0xbbadd3415a058d7b, 0x3f063c5475439cb2), (0x3b59f6c7b33666e7, 0xbebe3725daf69867), (0x3b21f2a7db95aa23, 0xbea25c1238b32e59), (0xbaeb35e7c5937061, 0x3e57486f6b9aa951), (0x3ad95c3e197deb05, 0x3e33e3bf248277ee), (0xba77b9fdb9bee258, 0xbde78a38a73e7c0a), (0xba480ea277e7ec50, 0xbdbe844eb6b211b0), (0x3a0c6dae4342e4f7, 0x3d70e24abb40708e), (0xb9e5f9316e1c5efa, 0x3d41797e5eacddfb), (0x398387d37934edf1, 0xbcf21fc0f1265a7c), (0xb95b8aad5aec742b, 0xbcbf0c12e445cb41), (0x390e42f5b55d3825, 0x3c6e4423559080b2), (0x38cc1d5a56b93a77, 0x3c36080463b41f1d), (0xb87dbc48deb40e7d, 0xbbe43e38b263073e), (0x38442a4086626b0d, 0xbba98fa121c815cb), (0x37e94a11e9993a14, 0x3b56325cba16fa62), (0x378f6607677ad6cb, 0x3b18b3fd438c6ab3), ], [ (0x3c50f8942d3f902b, 0xbfcddceb4ce1bf4a), (0xb5776203d5c7d545, 0x39009f7250661abf), (0x3c433d5334b42c83, 0x3fbda52116c0a640), (0xbbe72468a28942f7, 0xbf6a9da4603b67ea), (0xbc0c5e08317c5bc1, 0xbf8331e74ea59ab8), (0xbbdac4579bb7d320, 0x3f33e5cb6eba6eaa), (0x3bd0ad973dfed7a9, 0x3f33885fe9afa541), (0xbb74d72fe9613abb, 0xbee494c0f4b0680b), (0x3b783e70ffbfc8f8, 0xbed512b9d37762d7), (0x3b137aef41758720, 0x3e85a861082bfb7f), (0xbb059fce2a743f33, 0x3e6c323ea0a042c3), (0xbaaeb25b7edb5f5d, 0xbe1bcc962f7b91eb), (0x3a6a5caf0a45be46, 0xbdf9bc94e2f29a52), (0x3a4115f7a8e1da37, 0x3da82bc6fcfa8e89), (0x3a2ca2e9a78a230c, 0x3d81141ce7b78460), (0x399649188487057f, 0xbd2e79ccb1860d7a), (0x397e5f7602a25533, 0xbd013e1fbe0a5971), (0xb91843ce4e8dd1b6, 0x3cad36d12b0d249d), (0xb9191629f123918b, 0x3c7b66072bbdf478), (0x38cfbb54dd8d36aa, 0xbc260cb923a35433), (0x385274d20bfe6ac3, 0xbbf196237500b24e), (0x383559483b284848, 0x3b9aeba1005e1830), (0x380a4bb85b8cb2ba, 0x3b62a07d164c6a6f), (0xb76cc607fa3605e1, 0xbb0b27ac12f04a31), ], [ (0x3540e66d0c71e44c, 0x38b8ae14acc03cc2), (0x3c6c8c66d2e42062, 0x3fcbf3337873a7d8), (0x3c25e81c4baa84e9, 0xbf80c83a2d7add33), (0x3c44192692d7c9db, 0xbfa251858011816b), (0x3bd0475c4916a7f2, 0x3f559eb160bf72d8), (0x3b9e04d41bf0d87b, 0x3f5c5bce33af2d77), (0x3b7eb490c3282478, 0xbf10413e306e0039), (0xbb9e3a426e412d42, 0xbf04a6704d05ad0b), (0xbb5a4f33202681b2, 0x3eb6c43eedfed6c9), (0x3b2d2f110d38d23b, 0x3ea16abd7815de74), (0xbae416eabc41ca79, 0xbe5257f16f5d4346), (0xbad1043744ab6130, 0xbe332db1b4b2ff8b), (0xba872ca31e31d0a7, 0x3de33acccf7bfdce), (0x3a00b03336c2218e, 0x3dbdc8f5682566ba), (0xb9e9cd15ad06d38b, 0xbd6c6513386daae2), (0x39d8466ad52efa61, 0xbd413585a9b7473f), (0xb9408c90ab21329f, 0x3cef322ea2e20db6), (0x3952e07fa31826b3, 0x3cbec749ba31d0ed), (0x3904a43ae3e1adf7, 0xbc6a8abab44a5a16), (0x38bd7572726e9fd6, 0xbc35f2aba27d0156), (0xb8753cce6cac9ae4, 0x3be20705169a0885), (0x38458824bb426ee4, 0x3ba98e9c9fa1064a), (0xb7e6e8cdd35eeba7, 0xbb540557c89d65c9), (0x3759f423b384f394, 0xbb18c41cdedb0d3e), ], [ (0xbc26397095487bb8, 0x3fca7f63fea81f26), (0xb579a23f3e01c02a, 0x3900cbe4fe15df81), (0x3c4341d92ebaf0e5, 0xbfba60afb06640cf), (0x3c0aa0cf7edfc4af, 0x3f62c1e930935d3c), (0x3c2253175b5dc28b, 0x3f814506466d7f1f), (0x3bcf594f6cb1e048, 0xbf2cca8c0c0eaa3f), (0xbbc23306ba391f44, 0xbf31df821cc1377e), (0xbb6f4273eb18d486, 0x3edee8814ed0ac45), (0x3b3531e00c0b1e91, 0x3ed3a365a4199dd1), (0xbb2539aeb3d4946a, 0xbe80ed2f9c3e458e), (0xbae7dc7c41800a98, 0xbe6ab3b37c5271b3), (0xbabe3080b40ebc8e, 0x3e1684d6e62b5c66), (0xba980fe8dabe0c36, 0x3df8b105a5120ed2), (0xba34afb054573ddf, 0xbda42dc5991b9d01), (0x3a24e165917f0851, 0xbd808d6405ffe3dc), (0xb9bea36c059d9a67, 0x3d2a15203365a9e0), (0x397717476aec9541, 0x3d00d7c118bbeb37), (0x39474ba7f9cdad9c, 0xbca984ffd2857b4d), (0xb8f090df156cf8ee, 0xbc7aecb2d322693f), (0xb8b29f8b4dabfed8, 0x3c2396ff2d246042), (0xb86310d4b1263ad5, 0x3bf15cbae441ca24), (0xb8388b6c6238abda, 0xbb9841be044fa28d), (0xb7f60da5e67d9193, 0xbb627467b799ccfc), (0xb7ab569bc7745d94, 0x3b08c28575d745a7), ], [ (0xb5a0840c646e7364, 0xb909bb79105907c8), (0x3c6e9557ccd1703f, 0xbfc925c6fca08f55), (0x3c091bef69239af0, 0x3f786dd32e059b0e), (0x3c3dac1b118bb946, 0x3fa09463bbd0367f), (0x3be231ff19225462, 0xbf4fda0298c8768b), (0xbbf0185527e9208e, 0xbf59f4be60758fb1), (0xbbac474063460803, 0x3f0877991af9d1bb), (0x3b85632e0e751036, 0x3f032cb00ee8c1f3), (0x3b46a0371f5eb5de, 0xbeb19d8ce8c35f58), (0x3b44398edcd31b46, 0xbea06a042fbba455), (0xbaeabb097c7d4aab, 0x3e4d3a689e677731), (0x3adf851e84662874, 0x3e325108c4ce2b63), (0x3a700c6a94a96471, 0xbddf7b8e9ab53152), (0xb9e39398140885a8, 0xbdbcc40d05652642), (0xb9debdd38ee83cbd, 0x3d67cd76e2d7e2cb), (0xb9d4060b8e456ec8, 0x3d40c58770231c0a), (0xb986fdcd6522fa14, 0xbceaafec4cd92006), (0x395ac6a53012f35d, 0xbcbe36dd57088c43), (0xb90acfe289832416, 0x3c67199e80bb8ec3), (0xb8d65ad3a5a6b128, 0x3c35ab8b86951bb2), (0xb87d16fd2ded0f9a, 0xbbdfd7377ba12be2), (0xb83aa7858e0cbb98, 0xbba9595b17afa78d), (0xb7f5f340e3e25bf0, 0x3b51e6cee419b353), (0xb7a44c40cb1a1e24, 0x3b18a74f87d027a4), ], [ (0x3c2a5f1938003f5d, 0xbfc810f50225b04b), (0x358a4e47631896a5, 0xb8fd56c48838f152), (0x3c5462bc86c50f0a, 0x3fb7fdf97ac36b1f), (0x3beaefb0d3d06c9d, 0xbf5c3c256a8caa05), (0xbc191dbdbe4ca6d9, 0xbf7f98feb7286b47), (0xbbcd0c6b4f6c3ad8, 0x3f25f6559e5686e2), (0xbbd9de4a645cf978, 0x3f3080f57ac215af), (0xbb69ed06d60efe89, 0xbed80c51397e5eba), (0x3ae04eb6bd1f24a9, 0xbed256db543cd140), (0x3b1af2db1b084be5, 0x3e7af7598a219824), (0x3b0693a9fa38dfa0, 0x3e69398226ca2305), (0x3a95f5676bd10cd5, 0xbe1260985d92587d), (0x3a8d5612be0b4b05, 0xbdf792bb3eea6f6a), (0x3a4432d95d96cbda, 0x3da0d862695e1a7a), (0x39d7cd101d99d4e5, 0x3d7fe52adc2baacf), (0x39baa545a1a5eb63, 0xbd263801377398f0), (0xb90a458f0e1e2682, 0xbd005a1befdbe42c), (0x39473f5560f8b44e, 0x3ca6205041739aa5), (0x38f53ca728fe9101, 0x3c7a4e1503b6d0e4), (0x38a22b93c20b3937, 0xbc213ef141f6d641), (0x3854274bba40b623, 0xbbf10ccc96cd4c02), (0x382225ebf160c143, 0x3b95a2fe023aea26), (0x380398ff54fa8423, 0x3b6232d7c90d33bc), (0x37acf10d8068ed39, 0xbb0656435697f160), ], [ (0x3590c69d1d5ad990, 0x38fbdadd24cf38cb), (0x3c62da0057f84d3c, 0x3fc70c511227d5aa), (0xbbfb574e506cf75b, 0xbf72ccb0e97558da), (0x3c2e61277dedf705, 0xbf9e7dc08e70e99a), (0x3ba77952da42c6eb, 0x3f48acdc5b058c0e), (0xbbf340f4df9939b5, 0x3f580503724ad30a), (0xbba115f69745949b, 0xbf032ee4ca1fcafb), (0x3ba6a66de44f6f2b, 0xbf01e5d2836c8d99), (0xbb2b264207f7cf59, 0x3eac129f077bb163), (0x3b3381f3bd8fb4b6, 0x3e9ef161591181a2), (0x3ae466d818a45b43, 0xbe47b9bb07f19f82), (0x3ac2d952a84a8f21, 0xbe316f3937595d96), (0xba7571ae406938c3, 0x3dda0bc8665b687b), (0x3a588295d4921561, 0x3dbba135f99a9e19), (0xb9ff299934254ca8, 0xbd640d543d2cbdf0), (0x3982fb1c3cc08579, 0xbd403d0592185f1c), (0xb925c1461a28ff32, 0x3ce6db5e22d3be75), (0xb939bcdb12fd3c24, 0x3cbd745a1f778590), (0xb8f8314c949b4d69, 0xbc64141c4b5a4105), (0x38a825ab0fff4716, 0xbc353f4e6ca53f65), (0x387f0bb5f3376671, 0x3bdc09c1732e9344), (0x3845a8dc1ed995e7, 0x3ba8f971fa1f374a), (0xb7ce30cb1f02717b, 0xbb4fe39c23f51b6c), (0x37b9858646741b7e, 0xbb1862f419e2ba54), ], [ (0xbc6b166d180d579d, 0x3fc633e7f7f05301), (0x356d48b037092f86, 0x38f9187186657edf), (0xbc100659a075d9a7, 0xbfb6273784c1c06e), (0x3bfcb74bd0872e23, 0x3f563ae94ade18d4), (0x3c02a45d712a2f91, 0x3f7d4666536c88b9), (0x3b825e9acb600ae8, 0xbf216d528345ca11), (0x3bbb9405b8c58d57, 0xbf2ec0dcdbb7c5fe), (0xbb7cb6e04f4b97e8, 0x3ed34e966b0b09f8), (0xbb7a79e09bd0a7d3, 0x3ed135c64dc2d8d0), (0x3b01284c6af65eda, 0xbe75f7bc78b5fc2b), (0xbaf68597192a53a4, 0xbe67dc35b0764096), (0xbaab08d1b3bdd3d7, 0x3e0e6d697361ea54), (0x3a825acf92327a4e, 0x3df679e3704987b4), (0x3a25a180ac4a289b, 0xbd9c595f278a4d6c), (0xba0b8a094432fbc2, 0xbd7ea36aef56eec0), (0x39c8d7c90342cb95, 0x3d22fd66b4e62185), (0xb99cefe59fbb0bf2, 0x3cffa04c9faacec1), (0x3947eb4362c2f94b, 0xbca32f47f03857d7), (0x3912dc0b9f745208, 0xbc799658479ebb31), (0xb8ab4e5c1533c13c, 0x3c1e4c26032e5de5), (0x389fabe9c1dc18b3, 0x3bf0ab1b47f9c785), (0xb83bf6eec6ed25da, 0xbb933a3c78295756), (0xb7f90ac82d0d0179, 0xbb61de19b957005d), (0x37ab71627757371c, 0x3b040e310c05ed67), ], [ (0x35ac924d3bf8bf5b, 0xb900f098dc38e480), (0x3c6a47ab4241a9f5, 0xbfc5664e13b70622), (0x3c04d78c254f4422, 0x3f6e16555e108dc6), (0x3c1fe75afd6ce0fa, 0x3f9c5e1ad9fb2f40), (0x3be099fe50e43632, 0xbf43d369f958e56a), (0xbbf3ed70de366684, 0xbf566f4ec27a96e9), (0xbb9b30f071ce70bb, 0x3eff0de0532652d5), (0xbb747f8eea3cc056, 0x3f00cf264341409e), (0x3b4f2ff7c971467d, 0xbea6f46d51e5766f), (0xbb3708c3f9c7bd34, 0xbe9d407f7c248d45), (0xbaee70df563a5b0f, 0x3e43a33cd9df6696), (0x3ad300d61c332fb0, 0x3e309901b0a816e5), (0x3a69fdf1dd8c15b3, 0xbdd5d856a58443f5), (0xba3f02f5ec08db44, 0xbdba7cbcd8fc0758), (0xb9fcaa58f7c81511, 0x3d610b62c2fd47f6), (0xb9bf896eb454c48a, 0x3d3f56a09da19f70), (0xb97cb0796a5c153d, 0xbce3ae6849b36426), (0x39389530ecefefbd, 0xbcbc977524a64328), (0x390af889f4247b24, 0x3c617fc9db74cefd), (0x38de6ffabef002da, 0x3c34bbe426d77a28), (0x387b388027811ac5, 0xbbd8b5659628a8e3), (0xb83cddf274f119b8, 0xbba87bcc22e21171), (0x37ec559bf73a5d47, 0x3b4c62cff42626ad), (0x37656c3911a78ec3, 0x3b1800b5df5b52ae), ], [ (0xbc4f6f339127993d, 0xbfc4b71d4ca2cc69), (0x359c1da4eb8655d5, 0xb8f3a018f8f76877), (0x3c5422c1a1ae8ec4, 0x3fb4ae245697fba6), (0xbbf4ff572c18742a, 0xbf5215e4e1a5f1d6), (0xbbf259ec9ab217a9, 0xbf7b633ed6d9cf61), (0x3bab33aa46f3e729, 0x3f1c7f17b4b7dbbd), (0xbb79333ace27b68d, 0x3f2ce01b8b6aa34c), (0x3b5f4e5e8507bc88, 0xbecfced71b11e35b), (0x3b57f324d6293b07, 0xbed03c9d5823261d), (0xbb15cd82948c15bb, 0x3e724508091063b2), (0x3b02ba31739f7dac, 0x3e66a2d20111e303), (0x3aae84f884334dbd, 0xbe0995a18f8e6888), (0x3a67a35968d37628, 0xbdf572d1a074f647), (0xba3a336c953bedde, 0x3d981df03c1911f1), (0xba104dc5bcacab30, 0x3d7d6895e48f475d), (0x39c36eea9cd69feb, 0xbd205887f0b3df78), (0xb98ded8dfba53f0d, 0xbcfe86703ddf1bbb), (0x394a6d81e9b745de, 0x3ca0b3c70ca73df2), (0xb91aba894f18e42b, 0x3c78d28ba328c189), (0x38aea5b88a7dff57, 0xbc1aa9275d6882a0), (0xb88b4724ad7898dc, 0xbbf03e89774aa977), (0x3836acf6717c7348, 0x3b911679204a4a38), (0xb7fc2c9e5a53a6f2, 0x3b617bd36a04e549), (0x37a2112e77b7283b, 0xbb01fc50745d8566), ], [ (0x357f9e30ee0b6fbb, 0x38e84b55d671e3ab), (0x3c6316f8ffd294bc, 0x3fc40f90793605bb), (0xbbd411ad350e6def, 0xbf68c833077fbeae), (0x3c051eb6f09db1a0, 0xbf9aa0ce0421d1a8), (0xbbec0fe78acda469, 0x3f405fa598ef5d1d), (0x3bff2085596ae958, 0x3f551d30d78ab526), (0x3b92b31b33779fc8, 0xbef9c5807675c5f6), (0xbb7cb5b0088841fe, 0xbeffc1bbf57e3ae2), (0x3b3cc2b42d9f0f1a, 0x3ea32dfea2518ce6), (0x3b18c85914c086a8, 0x3e9bc212085dcbc6), (0xbaed44a5431df5e5, 0xbe408b946d64c5c2), (0x3ac14bfc6bd39224, 0xbe2fa8f9d8da736a), (0xba679104007a668d, 0x3dd293fe14af1d0f), (0x3a2b5ef4a8a2fdf9, 0x3db96544cb75a58d), (0xb9d2b2107643b642, 0xbd5d4750748e2ce8), (0xb9d8369e87f01d70, 0xbd3e341812329072), (0x398c6f9e47f04995, 0x3ce112aa495187a4), (0xb950e224f8078ca7, 0x3cbbb1656dc67704), (0x38e16eb1b3f03824, 0xbc5ea7b98f478c96), (0x38b9cf2d9132a338, 0xbc342cad7eaaf63a), (0xb82267864912b80e, 0x3bd5d798d87eadd4), (0xb83715c9cdc64b23, 0x3ba7ec2199e9d0da), (0xb7e050cf70a270e2, 0xbb494f3573e03531), (0x379b105713845f41, 0xbb178a4eaef852c1), ], [ (0x3c4f5ffd019535e2, 0x3fc37dfa8f5a550a), (0xb5701036f2fd5ce7, 0x38d71a135ef735e1), (0xbc5c4cd2161ee713, 0xbfb3775c1a04f09c), (0x3bd3d562913301ed, 0x3f4e2b4810a46c60), (0xbc1b976f3317abb9, 0x3f79d151a72b83a8), (0x3bbcef8b523f5a0b, 0xbf17d8e5a090e4e6), (0xbbcb7ef16d9cb057, 0xbf2b49a6427386a0), (0x3b59248209e494f4, 0x3ecac10957ddd2eb), (0x3b424396e09f7471, 0x3ececa620745d3d3), (0xbaf3438d41f60802, 0xbe6eefc7e795dcdd), (0x3ae3b35ebff03a32, 0xbe658c5d2a0da41d), (0x3aa0b413dedd34fc, 0x3e05d4721f44a8f9), (0x3a892a275db60362, 0x3df481ce2314af59), (0x3a3feec436d1ef8f, 0xbd94c0d3279e920d), (0x3a19e07a129c683f, 0xbd7c3ea707530563), (0x39a52b925c059e39, 0x3d1c61d5b165f7da), (0xb94e05a7550119da, 0x3cfd72bf189b67b4), (0xb9108732c7d2e8ad, 0xbc9d427a9769e9ed), (0xb91f784bb6f88124, 0xbc780c9653705698), (0x38b8d964fc9666c3, 0x3c178e36fc02b9df), (0x38865f872c0449a7, 0x3bef9a2c168b6442), (0x38235589e9a3fa21, 0xbb8e71f82f6f0229), (0x37fbb8f42441d570, 0xbb6111ac11e28162), (0x377b5f7617aeeb8e, 0x3b0025a92b5f22a5), ], [ (0x35952cb8f89f3c55, 0xb901222bb44bcf14), (0x3c689d1f48185c7e, 0xbfc2f2072e638cf4), (0x3c0f48257333acd5, 0x3f64df208bbd44f1), (0xbc282c4cf012e7aa, 0x3f992bb5e1e159fc), (0x3bb5967313b48e35, 0xbf3ba181c06897cd), (0xbbea6566cfb06bed, 0xbf53fe9d5baa4a3d), (0xbb98b4ff1892c87c, 0x3ef5d17602b01cac), (0xbb84f1d79d1c68cf, 0x3efe26d3747fe829), (0xbb47899cac28d06e, 0xbea0509768ab6ecb), (0xbb30edc18e594fda, 0xbe9a70f232d9d06c), (0x3adf4967ed4b405c, 0x3e3c509252de33f9), (0x3ac643cb92fae2ea, 0x3e2e454fee07116e), (0xba7c2d5f536fab40, 0xbdd0015b062ba125), (0xba43993ecbbb44ab, 0xbdb860e95adf840f), (0x39fd1ca7896c45b4, 0x3d59691e90f7d9c0), (0x39bccb74999a40d8, 0x3d3d1ce7997b3c0d), (0x397d856301e23d11, 0xbcdddcd1c54cee54), (0xb958f0d58afd0876, 0xbcbacd10a03552dc), (0xb8f2692f00e7abd7, 0x3c5b043a7a08961a), (0x38a216228008b2d7, 0x3c3399ba2ef94a8a), (0xb87b2260cea416f3, 0xbbd3650fec070f67), (0xb84885e84e43eded, 0xbba7538b0e0444f1), (0x37e7ac0e69e3062b, 0x3b46a2dce760f8a5), (0x37b02054fc976f06, 0x3b1707ea3ba222e3), ], [ (0xbc6b9fbd89653a0b, 0xbfc2768d29c69936), (0xb5883d7e7aae0fdd, 0xb8ec8fe2d361f507), (0xbc592c5350d4d775, 0x3fb271811730b0ef), (0xbbcd42067c3280c8, 0xbf49a8df96a1225e), (0xbbde819659787fc8, 0xbf787c81cf1c6fc4), (0x3ba0986868518e75, 0x3f14549cdbb77978), (0xbbcc0c937839cf2f, 0x3f29ed2568116e19), (0xbb638a1daff4bf5c, 0xbec6e4136f033ace), (0xbb692b821c2e6f36, 0xbecd53330316cde7), (0x3af82b5a8a9ea4e0, 0x3e6a983b5782dfca), (0x3b0d6817ea51c39b, 0x3e64952ba7c5a1dc), (0x3a858779f386d0c6, 0xbe02df3ad6f82e0d), (0xba85be3593e2be88, 0xbdf3a70f9a89d2c2), (0xba32f63410f44e43, 0x3d920e086c17f5dc), (0xb9feeb5c5526cc87, 0x3d7b29a554c1159f), (0xb9b6a518f14f6a05, 0xbd18dbe08f4a9f69), (0x396f8eba4a78c6ed, 0xbcfc6bd9fc45c380), (0x390a2175db343220, 0x3c99ce5a735b2911), (0x390e5b428d8e3c26, 0x3c774ade0ebbb04a), (0x38a68dee1fa00957, 0xbc14eb88e02b008f), (0x3835846ba71a1987, 0xbbeeb63f264071fb), (0x38105020072f2234, 0x3b8b39319da680c5), (0xb80e1b59bc2fb16c, 0x3b60a4325ae8cea7), (0xb79ae8092aa3eb9d, 0xbafd11021ccd9832), ], [ (0x359a05b7bb6a66e7, 0x38ff07a73b062717), (0x3c51f9b16832f362, 0x3fc1ff5eec6a01cd), (0xbc0f89ce0d1cb83e, 0xbf61e438b722c3b5), (0x3c39a4b7b3ed5b9d, 0xbf97ed5fffc1c774), (0xbbdc35d9a8dca8fd, 0x3f37b7997babd9ca), (0xbbe39da4066981e2, 0x3f53081def9612c5), (0x3b8551b9a497b582, 0xbef2c5f5edafc4e9), (0xbb9dbae692eab5c3, 0xbefcc11a59e13739), (0x3b351580930803f5, 0x3e9c2c3a1b8014a3), (0xbb333a214b9dbd86, 0x3e9946d1dab7bd01), (0x3ad8fc5f68299915, 0xbe388db61946be64), (0x3ac5620984f97782, 0xbe2d04d33be580e8), (0xba6d7f1c30d157b7, 0x3dcbe64386d2c5d0), (0xba48b7e9cdf3e557, 0x3db77142e0e4497b), (0x39fe42ca4fdc0820, 0xbd56458476679697), (0x39cde02178f2e8a7, 0xbd3c15e96b25adba), (0xb96d7f2805e659cb, 0x3cda545e6ec71d21), (0xb95169031622e59c, 0x3cb9f0a9b74e034f), (0xb8f6c8c4cb1d2951, 0xbc57f751eaad5943), (0x38b9f3826864d2b2, 0xbc33083bfba900b3), (0xb83ad0a2f62d2470, 0x3bd14f7886799e5e), (0xb846ea6a99d583b1, 0x3ba6b8756a3461ea), (0xb7bff8edb785364b, 0xbb44533c12e31410), (0x37b9373ae2b3a681, 0xbb167fc01d26c703), ], [ (0x3c54fa3fb220c497, 0x3fc194eba75b32f9), (0x35968efa101689a5, 0x38fdc9a2706a3090), (0x3c59f5fdd12caa11, 0xbfb190f7dc27362b), (0xbbd96244746ca1b2, 0x3f462bb47a5c5f7f), (0x3c106edbe0bb689e, 0x3f7756ef20f5d2e2), (0x3bb1231bc44f6f51, 0xbf1198b0ba97ecfb), (0xbbafcaf4935a1752, 0xbf28be8cf9358d55), (0x3b341ada5c144f0c, 0x3ec3dd6f7c8cc3c0), (0xbb22797862876f18, 0x3ecc09c80ee7f9af), (0xbb04005395d49e04, 0xbe6728e46a451e32), (0xbb056333198576a9, 0xbe63b91113508622), (0xbaa195a6693f0d85, 0x3e0080fddad62bf8), (0x3a8352e1bf38cbc8, 0x3df2e111e88dae1f), (0xba2109236d67d65e, 0xbd8fbae88bdab215), (0x39fdc60e2c5c7d37, 0xbd7a2a4fbea868a8), (0x39b8e39633481264, 0x3d15f540e9769e8b), (0x39976a66d79bb910, 0x3cfb74c0b2686df3), (0xb92c1d434c75162e, 0xbc96eb75a7dd13a2), (0x390c7fe154372598, 0xbc76910c1dc865c3), (0xb8a43f5790d81d03, 0x3c12af36490b5c71), (0x3886f89d2e40041f, 0x3bedd7036ea48d55), (0xb82a048b55f91332, 0xbb88734f1fdd1068), (0xb7dfa5ba1f878585, 0xbb6036af368c39fc), (0xb7993db41d2f7ce5, 0x3afa3fd8a11def52), ], [ (0xb5745b4e1af1b85e, 0xb8d7a991cf97ce2e), (0x3c6e71c482be67bd, 0xbfc12dd57bf18ada), (0xbbe9a8a827c4a2d4, 0x3f5f1e1e7f393e83), (0x3c3286f932bea2b2, 0x3f96d9afe88301fa), (0xbbd360330deffaa0, 0xbf34a538a482979b), (0x3bef838ddd540b11, 0xbf52316250b4ae37), (0xbb94c13fb3eaf5ab, 0x3ef05f11577b4627), (0x3b6771ef99211bfa, 0x3efb86bad42fc220), (0x3b1a6b7e5cebbbf8, 0xbe98a1b3a9e92749), (0x3b32d778489fadef, 0xbe983dcaf3f8fcc5), (0x3abceef7b37a414b, 0x3e3589a7ca5fdcf1), (0x3ac97ff4495956a4, 0x3e2be3ee3298bb99), (0x3a6770b1a9ab05ca, 0xbdc8913f1d0ff12a), (0x3a430c1f9492528b, 0xbdb695c386660813), (0xb9fd8f50c7d974dd, 0x3d53b25d364762e7), (0xb9d664d160d01e32, 0x3d3b20c42e642ccd), (0x397bc60dbe38d043, 0xbcd7650532b4f1e0), (0xb920283e56ce5b47, 0xbcb91f514b70b40a), (0x38fcae3e188ec691, 0x3c55661aac4dcfde), (0xb8b0ad982f98ebec, 0x3c327b48d9478b06), (0x38441168fe323c23, 0xbbcf11115f1e0760), (0x383a0b5e44af3cea, 0xbba61f1bd02130ad), (0x37eb4e4f03156997, 0x3b4254646f0f97c7), (0x37b0ea6aa46492cb, 0x3b15f63be5634cd2), ], [ (0xbc27736b1f56d701, 0xbfc0d0d36473e98c), (0x356c9dc61ea15303, 0xb90248314540cb10), (0xbc517d3bbb8e7764, 0x3fb0cda9974abe2b), (0xbbe2a43b589b29f9, 0xbf4367f38f201c25), (0xbc17d1323005eae7, 0xbf7656b75e3c242e), (0x3b94b9f5a7acb7cc, 0x3f0ed82abf7489f1), (0xbbcb0bedf1c81292, 0x3f27b4e5b83eeb36), (0x3b0621247626b416, 0xbec171fd0fb670e7), (0xbb638b7d64b281f7, 0xbecae62b4ad017fb), (0x3b0b83d61a6ff722, 0x3e64648495a7b49e), (0x3b05f0212db7e5c2, 0x3e62f42a577135ad), (0xba76b0fd54cd9d5a, 0xbdfd286e7fa32656), (0xba30ca02b11abb11, 0xbdf22dbcbf76a1c7), (0x3a27e83235238ba2, 0x3d8c222accc0d2d2), (0x3a056929761e3d77, 0x3d793fc7f6c8d355), (0x39bc237122bbb790, 0xbd138c7e1f668eb4), (0xb99070434bc7e0cc, 0xbcfa8e4efc6deb61), (0x3935816fed04585f, 0x3c947e808eb72ce3), (0xb91069ce4b7c1dbd, 0x3c75e0f075f73393), (0xb8ab681bd123ab34, 0xbc10c866ba43aebb), (0xb87344f73adf2486, 0xbbecffe1c0e02083), (0x3821df2bad78c005, 0x3b86102f988e0a87), (0xb7f3ec5f37bb8303, 0x3b5f96a57efd09fb), (0x379def01809beed4, 0xbaf7cbac5fb57a91), ], [ (0x35391b3b00fc7751, 0xb8c00dbc5df9a26a), (0x3c61a13e2fee5687, 0x3fc076826cc2c191), (0xbbcb789ffb667f58, 0xbf5b62885e0070c6), (0x3c35dbe9d7210c2e, 0xbf95e7f53001e4b1), (0xbbddb8eb1d2032f3, 0x3f322ebeb8dc2202), (0xbbf72618e87154fc, 0x3f517444a7a04cd0), (0x3b7b01e81c8c370d, 0xbeece06f1f1fcd7e), (0x3b80168184fb2a2f, 0xbefa7006e6ad9cfe), (0x3b13ac36b9efbb35, 0x3e95c42f02cf15ca), (0x3b08b69b698a2f2f, 0x3e9750ca5e1366b4), (0xbac08a205d6fbd27, 0xbe3314982df7eaa2), (0x3abf2c98d7c5b0b0, 0xbe2aded75306b3b3), (0xba2551d965dce668, 0x3dc5d47847d8ebf1), (0x3a2b475ee50f9af2, 0x3db5ccf44d287a21), (0x39d9490ac846b5fb, 0xbd518fce3e04028a), (0xb9d525cc1707dd4e, 0xbd3a3d6bcad0c3fc), (0x39615f1fc81188f8, 0x3cd4efbd76727c05), (0x3954cf183e4c6eef, 0x3cb85a4b163fcc04), (0xb8eb35201a650448, 0xbc5339ddeca79d0a), (0xb8df2fda8e574f19, 0xbc31f48b47bc4419), (0x384d7bc59effa619, 0x3bcc06bd6710b45b), (0xb84a385b5ed821eb, 0x3ba58a1ad9e65449), (0xb7c4e5225bdf41b3, 0xbb409abe2b8be0ed), (0xb7ba1343bcfa4e16, 0xbb156e575d965e88), ], [ (0x3c61a6e02553980f, 0x3fc02455675ab6d2), (0x35884b224ed40dc9, 0x38eb5eb0626a64d4), (0xbc5a58b3083e7e3d, 0xbfb021c155a720df), (0xbbea19c1039d30bd, 0x3f412be56fc1449a), (0x3c01bad3e8f9abb9, 0x3f75749d556ad61c), (0xbb75621370147dfe, 0xbf0b51f1f9bea93e), (0x3bc81ccb29b6a851, 0xbf26c96a07e236bd), (0xbb218064e9ecad2c, 0x3ebef3a7abd5ac6b), (0xbb6f6ed0aeaecba4, 0x3ec9e207c257433a), (0xbaf0aed16a93326e, 0xbe6220b96eef8058), (0xbad4d7e3d546f2c4, 0xbe624317cb296737), (0xba91f73fb3d22bed, 0x3df9fc2f2cd3917f), (0x3a9403e6cf9143a4, 0x3df18ae8347e8256), (0x3a2f17c7d5411c26, 0xbd892540423f2dda), (0x3a04a4080028f5b2, 0xbd78687dcdc2e3a9), (0x39a201bd34791753, 0x3d1187909103d474), (0x39844a97e12dfc96, 0x3cf9b8362872c324), (0x393da5147587382e, 0xbc92711ecdaaeca0), (0x38fae8f5aa2732b8, 0xbc753b342a24814e), (0x388ad67623e40669, 0x3c0e50eba2ee4760), (0xb86ad1f354cf2e6b, 0x3bec32aa5f596a62), (0xb8257b3c1a8fb2c7, 0xbb8400cf17d2fcd3), (0x37f2a48d3485143a, 0xbb5ec6ef456ce7f9), (0xb79fa0988ef64e6e, 0x3af5a82ff0aad8bd), ], [ (0xb57640b478e02a1f, 0x38d6a301383ff88d), (0x3c5d7cc4171715a0, 0xbfbfa8b41711c83a), (0x3bf6219a48a25ba1, 0x3f5857d3969997d1), (0xbc395ccf34fc85bb, 0x3f9511c6dadaaa12), (0x3bd13cc55ae24369, 0xbf302c289dbdbd4f), (0xbbde8aacf935744f, 0xbf50cc2238d229f9), (0x3b831f1c91d27574, 0x3ee9b64d5c63668f), (0xbb967f7ad529fbab, 0x3ef976fb023f0f79), (0xbb26431725df20f0, 0xbe93693ba0b5ba70), (0xbb30bc5202714831, 0xbe967b952987350c), (0xbadfac3d160cee71, 0x3e310cb79a2addac), (0x3abbc10a636cca3c, 0x3e29f2079f8e397f), (0xba6f1f3686791203, 0xbdc38d957eaa53ad), (0x3a5a464b4d5f0cbd, 0xbdb51511e93ba74c), (0xb9d76cb5fc51dd5d, 0x3d4f8bb4d9d2f3a4), (0x39d5f6bc31063165, 0x3d396afe82155a3c), (0xb9789c1d34756db7, 0xbcd2dc3c5a412fc8), (0x394e5ac9a5d43674, 0xbcb7a1c8dec76ff7), (0x38fa62b937a855d9, 0x3c51600c3d779ccc), (0x3891168a3d883e25, 0x3c3174c64bf0b16a), (0xb8380d11dc898cc6, 0xbbc969e37524ef7c), (0xb8337a7c5fb777c9, 0xbba4faf03e3cc2d5), (0x37d9f91b76239dc9, 0x3b3e37a63e276939), (0x37b81fff9e082645, 0x3b14e9f8e51a9731), ], [ (0x3c50e4250a158a22, 0xbfbf161d0c28b48c), (0x3588b2630fb1ecb4, 0xb8fcdc55525190c5), (0x3c421e360c4c70dd, 0x3faf11d837aa6f64), (0x3bd18f48c3547c45, 0xbf3eab76da4d07a0), (0x3c1ebe3b9893ac4d, 0xbf74ab329f067aea), (0xbb5e80c3b0d6f6c7, 0x3f086ada57bc1c51), (0x3bc03960ef6e6bc0, 0x3f25f6e78f11ab9a), (0x3b5e77180c5644f6, 0xbebbb271f54c8965), (0x3b5cfd1d7da5a2ee, 0xbec8f85328c26cb7), (0x3b05a5d710343230, 0x3e603f82aebdeac1), (0x3b008f5133b080df, 0x3e61a3010279a195), (0x3a8746b6f6e07b70, 0xbdf75660809cdedf), (0xba824b566432a315, 0xbdf0f6931774a05f), (0xb9f3c0bb6b052f2c, 0x3d86a2e61267070b), (0xba1950de7a0ba4a4, 0x3d77a2a8e0311c3a), (0xb9a048f7d1f2b252, 0xbd0fa4c8e3ce0140), (0x3973ca66f22df187, 0xbcf8f1926f4e33ae), (0x391f7bbe0252e068, 0x3c90b165b2615bc8), (0xb90630bee239e401, 0x3c749fd329a93d0e), (0xb8723f37b0afb367, 0xbc0b864a393597bd), (0xb88ea6b58b8f277b, 0xbbeb70236cfe6bd6), (0xb81ff9b7e892d837, 0x3b823801bcba96ae), (0xb7f460e58de7fcd8, 0x3b5dffc2deb31092), (0x379c28f920f7c081, 0xbaf3c9fe3b84a659), ], [ (0xb57bd9f791078c7d, 0x38d74664ec9bed14), (0x3c0020b4016594ac, 0x3fbe8727daa3daed), (0xbbea4d873618788f, 0xbf55d353e2854a37), (0x3c3361836c532514, 0xbf94524d4813cc25), (0xbbb70735fa989563, 0x3f2d037574e28370), (0x3bf7f1d7c0f30b41, 0x3f50356bb747a763), (0x3b73015c07f2d91b, 0xbee7156bfccef376), (0xbb99523f4f9b3609, 0xbef896d7dc819faf), (0x3b307f0e451ebc2a, 0x3e9172c6dadf4149), (0xbb334d6933f971d7, 0x3e95baae8efc2e31), (0x3aba01d72c453106, 0xbe2eb347eb4d6941), (0x3acc3dd30f660e51, 0xbe291a60a72a20e0), (0xba0f68f511402a90, 0x3dc1a345a9a6a5f7), (0x3a3173892dc95a66, 0x3db46c56b01906be), (0x39d1db37247899b5, 0xbd4c84bb37677838), (0x39de56935f64b195, 0xbd38a83e6e4c168c), (0xb968986bb0f698d5, 0x3cd11796d017a52c), (0x394e35cdfe4ad2e0, 0x3cb6f5675cf3bead), (0xb8e0c38450c266b7, 0xbc4f936d06630982), (0xb8da35936b142aeb, 0xbc30fc2f8042c9f9), (0x38692f73e25e293e, 0x3bc7281c276f90d6), (0xb8390095011ee718, 0x3ba4725b73c87824), (0xb7a6c2d5c298847c, 0xbb3b9d22918ceeba), (0x37901e1a341f19f8, 0xbb146a436f16dfe0), ], [ (0xbc5b4c98f0d3c4c3, 0x3fbe0357c158b119), (0x3583cebeaacf2fa8, 0xb8efc7d3f760c89c), (0xbc410072ccb88630, 0xbfadffc2fc1a91f5), (0x3bd769e0c0dbfe1c, 0x3f3b9b82ae07da44), (0xbc02d8dbfa194096, 0x3f73f64e05320ac6), (0x3bafe44f6e4f7a6d, 0xbf05fe4b66cf19d9), (0xbbc540e88468d2a5, 0xbf2539518e1b00f5), (0xbb397c60f4bd9fcd, 0x3eb8f8d01c487905), (0xbb5e1765287d55c8, 0x3ec825045b97e2dc), (0xbad349d279137fbd, 0xbe5d565f3bb61dea), (0x3af6ef17211ae45b, 0xbe611186586f4f74), (0x3a9d5c753068eefb, 0x3df51a669158191b), (0xba9c8af441d79379, 0x3df06ef52f6715ac), (0x3a0be37a7ebfa57f, 0xbd848215e95caa77), (0xba12aea2c5547dd9, 0xbd76ec8422019b0d), (0xb995ce432bf4ea43, 0x3d0cbaf5fc139339), (0xb9937ae255b6301e, 0x3cf8393ffa4f5afd), (0xb92ae7fb140219c1, 0xbc8e6232fb7e093b), (0xb8f4f418e0ddb215, 0xbc740e69bcb200c8), (0x38ab0659f3e0af92, 0x3c091cd1de02ebf5), (0x388ccf22ef87b9fa, 0x3beab86d72560db8), (0xb82e0b1ad1c5038b, 0xbb80aa949dd60551), (0xb7d9ff00c88f4aa2, 0xbb5d41db239438ec), (0xb79bfe1d2d6ef829, 0x3af2270328ec903e), ], [ (0xb5ac5e4a2e275705, 0xb9005c1969d4e17b), (0xbc5cb1f28997ca39, 0xbfbd8293aa55d18f), (0xbbd0e0b711c0f01a, 0x3f53b6beb83f2596), (0x3c36c091c5e2bd3b, 0x3f93a5ccbc12a67b), (0x3bc80bb5066b1aa8, 0xbf2a3765d26aa42b), (0x3bc464654b3f4248, 0xbf4f5ab33748c215), (0xbb86c3ad1bc53ee0, 0x3ee4df6f1c257a5c), (0xbb9372510d6e3ed7, 0x3ef7cbd49c315be0), (0x3b1dfc7e29b94af4, 0xbe8f96098cf07175), (0x3b0aec3564d78716, 0xbe950b37dd43531f), (0x3aaa5efe8cd0d0ca, 0x3e2bd2e6405c605d), (0xbab9fdafce391124, 0x3e285530df0d4b70), (0x3a6ec037594c88d5, 0xbdc0029e21930f25), (0xba5f6bee6aa06bbf, 0xbdb3d11aeba731a1), (0xb9ee33d66b9efc78, 0x3d49ef077e065d17), (0xb9c765f6255cb3d1, 0x3d37f3d211d80ca6), (0xb95ffeb5c7b606b6, 0xbccf2617ced04ef7), (0xb95d433df855b01a, 0xbcb654785f90474d), (0x38a47f029dbdf48b, 0x3c4cd5d490baf361), (0x38d6ed83985660af, 0x3c308aa98d1885fa), (0xb81200c557f40391, 0xbbc53243b8f4a2ce), (0x384da8d1f6aaa7a2, 0xbba3f0a1e04e0f85), (0x37ce2a379bc1d480, 0x3b39568fa5547980), (0xb7a7c00b2c409082, 0x3b13efd3e10a8faf), ], [ (0xbc57ac02118ce034, 0xbfbd0b36e5737458), (0x355dad3277703540, 0x38d5fb77d2e0e26b), (0xbc494ec699987c67, 0x3fad082ce3c6b59b), (0x3bdbdb6b7d6d9ed8, 0xbf3905d00c5e6800), (0xbc14d8fddd68c49d, 0xbf7352b073fdac7b), (0x3ba8a390eb7c2b92, 0x3f03f1ccfec2fc88), (0xbb8f7492cb6fd0c1, 0x3f248d74583834bc), (0x3b536c4ae37b379a, 0xbeb6a9ef0d896bae), (0xbb686d0e0d1bf502, 0xbec764d9798d6a80), (0xbaf460a4621e034f, 0x3e5aa785d6736f5c), (0x3b035fd3f6a4b201, 0x3e608cae36118cdb), (0x3a9d857819eb2176, 0xbdf332ddfb39cd01), (0x3a737fa058aa2bf7, 0xbdefe502ff1a8f0d), (0xb9e58926244b72c2, 0x3d82afc83348eeb2), (0x3a12be94371e2b16, 0x3d764468c0a31511), (0x39a6e4a5223f4dab, 0xbd0a399e849c3f2a), (0x3993f30753f88192, 0xbcf78e09772ae1e8), (0xb90378dd4b889265, 0x3c8bc9dea67a7452), (0xb90f40c403d002cc, 0x3c738663e180417e), (0xb8a2c55a9de7b5bb, 0xbc07042a23846064), (0x3863528c0f407011, 0xbbea0b467e151132), (0x38083d5af6007837, 0x3b7e9e53f034f206), (0xb7fe52cf6cca2436, 0x3b5c8d6dc762abf9), (0x3781845e75790839, 0xbaf0b68e9fe150d5), ], [ (0x359b9f4f66331222, 0x3900369fa71bf644), (0xbc49df1f0f8d2108, 0x3fbc96700bf039e2), (0x3bd298b7ed2d16c5, 0xbf51ec0b5de4befe), (0xbc26397704521ddc, 0xbf93095734a24496), (0xbbbe43e747e8c9b8, 0x3f27d74e12285cb2), (0x3bbff97a4e7e808e, 0x3f4e636fe259352c), (0x3b74153b68748e94, 0xbee2fe11972bc0c6), (0x3b833d879080abe9, 0xbef712e4d44c4a74), (0xbb0f13d0520649e9, 0x3e8cc3adabae0452), (0x3b2bb2db97d7803d, 0x3e946ad2d9cbeb5c), (0x3aba423494626154, 0xbe295d81ae83f621), (0xbab425671ce4734d, 0xbe27a02aefea3d60), (0xba5a8cbe07596457, 0x3dbd3a949a72239d), (0xba589ce4399c7b23, 0x3db341e0bb193b49), (0x39c60f1c6ee12738, 0xbd47b550a4f77497), (0x39b9524731c89f4a, 0xbd374c654a2656ac), (0x396b773706300926, 0x3ccc861736a2cb66), (0x393ffcb4d6c5437c, 0x3cb5be2db467cb27), (0xb8d79e659806e4b3, 0xbc4a7433021b81a8), (0x38d24a44d0a8359e, 0xbc301fe901a012cf), (0x385ca56d7686e059, 0x3bc37bf8ae8852f8), (0x3823e08435643d0a, 0x3ba375bd0bad91a1), (0x37af4610bb7d3555, 0xbb37570ac69055a0), (0x37aa35e716b3a1f5, 0xbb137aed9b4389e6), ], [ (0x3c2c279ff462c3c0, 0x3fbc29ae8400a320), (0x356e0e33fd319cb9, 0xb8d9231986c55c3a), (0xbc47ac9bcf34430d, 0xbfac27138da31c2b), (0xbbbe5ab192b0135a, 0x3f36d141fcbea853), (0x3c12b724fd75b152, 0x3f72bdc71062acd6), (0x3baf5f2a5ef8fa68, 0xbf0231cf643ffc17), (0x3b6e53f54e3bf9fc, 0xbf23f0bf3b3fe8be), (0xbb4cfe2b683d9564, 0x3eb4b05e955de175), (0x3b6d19f537fcf89e, 0x3ec6b52b868fa5e2), (0x3afd6a6cb52830e5, 0xbe585a7aa3e84cc3), (0x3afd15d476513524, 0xbe6012d3384c9164), (0x3a5b65df2e4e4330, 0x3df18f8c4872544f), (0xba81d06080a51e9d, 0x3deeffc4029f2f06), (0x3a249fcb796b8760, 0xbd811d5a3daf70fa), (0x3a00e5fc84cbd7e0, 0xbd75a8d84ce12a33), (0x39aac0f727b50a5e, 0x3d080dfa27f213b4), (0xb98deba8bfe45bc0, 0x3cf6eec07f1e9fed), (0x3926f40f27003ad3, 0xbc8987d6f3b6b977), (0xb900c69dbdeb6cd7, 0xbc7307196963d259), (0xb8970cc24a5ffc69, 0x3c052f0ef3a48697), (0xb82c63f97263dd39, 0x3be968357fda6848), (0x38062270d5c769fc, 0xbb7c3bf907642446), (0xb7f7074e3e5184fa, 0xbb5be25cb690eabb), (0xb76e99e1fa5b8f27, 0x3aeee27d7ef3ffc0), ], [ (0x3538ee4168591cac, 0x38bef99392c87f53), (0x3c58fff4515190b5, 0xbfbbbf246914235f), (0xbbb59d638f727e96, 0x3f5062daee35411a), (0x3c1bef9e896a9a49, 0x3f927a96f174b6d1), (0x3bc79c688e785f3a, 0xbf25cdb5dea9c121), (0x3bd1f78082ebf798, 0xbf4d818348f98a0f), (0xbb8cf93ea6c33ca2, 0x3ee160aab829409d), (0xbb9dfe5ed028776c, 0x3ef6698d6ee99eb9), (0xbb0db3033371a004, 0xbe8a5633d8f0b3bf), (0x3b3148bb33e218be, 0xbe93d788d61154a7), (0xbabbfbbbe3dfb01e, 0x3e273ec2ae0084b9), (0x3a5bb0a12307343a, 0x3e26f958f6235deb), (0x3a36a5b33f99627e, 0xbdbad0939c43a9fe), (0xba4257e147ffea34, 0xbdb2bd56309cf195), (0xb9e2488ea9163776, 0x3d45c709d717f2e4), (0xb9d93a6f276892ca, 0x3d36b0b8fe737496), (0x3964c91263a6ad47, 0xbcca3cece6eae9d2), (0xb95aac081c12d91a, 0xbcb531b157cc8875), (0xb8e3db9a4bc40ecb, 0x3c485f3495a556d9), (0xb8cf57e3f8bac92a, 0x3c2f771622298662), (0xb86da2770d25e277, 0xbbc1fb1e956ae1b4), (0x3836de845e2a3207, 0xbba30179264b3e35), (0xb7dd698f3e703bcd, 0x3b3593d8b3319ae7), (0xb79dcfbbb66501cd, 0x3b130b99b87c3b97), ], [ (0xbc4b1bd5a08c4698, 0xbfbb5b8273b75055), (0xb579007ca42ecf31, 0xb8f30640d843b3e4), (0xbc19066393ec82d1, 0x3fab59418c36a684), (0x3bd4c6e4a4b62a0c, 0xbf34eafeaa92aa79), (0xbc1e8c2463f82477, 0xbf7235801af9be44), (0x3b9bcf2d21045067, 0x3f00af9747d0be92), (0xbbaf406893c94ac9, 0x3f23611db0e1566f), (0xbb5fa294e3a6cf5c, 0xbeb2fbe414da1250), (0xbb6579c1dd810ff1, 0xbec613ccbb9cbe59), (0xbafba31f9ef26cbe, 0x3e565cf274e84d31), (0xbae9213eec3645d6, 0x3e5f452996e3dc2b), (0x3a93719707a6b39b, 0xbdf023f5382da3ad), (0x3a83d3a0c57bd4cc, 0xbdee2be24fbad63f), (0x3a1e0d9a1a424f4e, 0x3d7f7ed3740f8cf5), (0xba195448240988be, 0x3d75187e998a1997), (0xb9a83d289fab0c82, 0xbd06293c9e781b76), (0x399920ae46c70e84, 0xbcf65a49786c4515), (0xb9223154eb869eba, 0x3c878dbf0233422a), (0xb8db7350f762522d, 0x3c728fde2c70ddb7), (0x389a86a79f193b5b, 0xbc0392b8f6167154), (0xb883a3fc81fa37b9, 0xbbe8cea59f44a3e2), (0x37d28560a2d0c913, 0x3b7a213dbaca9263), (0xb7672b5585eddf9a, 0x3b5b40576765c08e), (0xb78ee5530750cce7, 0xbaeca1b39264a34b), ], [ (0x359f12f74a1a873e, 0xb8fd67b1800cc2aa), (0xbc5024304247ada3, 0x3fbaf9cb49c4f935), (0x3bd43675d81a390c, 0xbf4e1d930b513228), (0xbc26b1ae600584f2, 0xbf91f7a8fec6eba8), (0xbbccaafb65ee566e, 0x3f240a55310866fc), (0xbbe93eb318fc691a, 0x3f4cb20c812fd3aa), (0x3b7bc11f6acb6aed, 0xbedff51953c6b6cc), (0x3b7ca6d60de07627, 0xbef5cdc48f5d75eb), (0xbb1e5c798f5702c3, 0x3e883b091952c721), (0x3b392f384e40f60f, 0x3e934fb685e58ab7), (0x3abc9afeb4201722, 0xbe2566fc4369ab71), (0x3ac8555b1f6751cc, 0xbe265f0f7de29720), (0x3a505976fb73241a, 0x3db8b61e5f9b7a00), (0xba04a898dd824080, 0x3db24253069b78a9), (0x39bb5929dac6aff0, 0xbd441732d722b422), (0xb9d662b0ae22d5ef, 0xbd361fa985a16926), (0xb92bfd8dca36b2a6, 0x3cc83c175673059f), (0xb956fcc071485aba, 0x3cb4ae32974df1c6), (0xb8d5a8f989475dc8, 0xbc468a7f73f5be7c), (0xb8c1d7200f0ee470, 0xbc2eba46ae458bcc), (0xb8686a635728619a, 0x3bc0a770636ddc81), (0x3846e16decd06b9b, 0x3ba29388d9fcba28), (0xb7da9125321029a4, 0xbb34040dedb7bebe), (0x37af7783c5802665, 0xbb12a1bc8335b315), ], [ (0x3c5ffacf3e2418f7, 0x3fba9e13a0db6429), (0xb583910dd6018bba, 0x38e353089e99116d), (0xbc305f5aef327444, 0xbfaa9c1ca2161b9b), (0xbbd5ab98ac97faea, 0x3f3344a09efdc635), (0x3be8bf0e556cf4b8, 0x3f71b82c430a2381), (0xbb93a99455084734, 0xbefebfb97bca01f2), (0xbb99136a1ed7b5f9, 0xbf22dcdb1bc1d038), (0x3b5ea30ecc612715, 0x3eb180047f0b79ae), (0x3b46ae074e2d9e22, 0x3ec57eeeee84d0d0), (0xbadb1941bb0e0bc1, 0xbe54a0c699c8318b), (0x3adc2d735741fddf, 0xbe5e7594e8a2c760), (0xba8de62221d00ec8, 0x3dedccbbb4c0ba7f), (0x3a8cf847ee673438, 0x3ded6766337b5c95), (0xba0200bd41d3e51f, 0xbd7d1a05cea18a02), (0xba1f3622c8b76f5f, 0xbd74922fb50a29f1), (0xb99416959af186e5, 0x3d047fa35bf627ce), (0x3983729747e80125, 0x3cf5cfa087122294), (0xb90144302fbdaa10, 0xbc85d009937bf5ab), (0x3907a8b2df9e5ac3, 0xbc72200b01fdbf9d), (0xb8a0a7e595a1fb47, 0x3c02265f004c1d49), (0x387e52805deaab21, 0x3be83df71ae8ab7a), (0x37bb19a9df1aa0a8, 0xbb7843800001ddf6), (0xb7eb3ebd0a11156f, 0xbb5aa6f0e2f25140), (0x37780a266a5c06bb, 0x3aeaa04878c515a9), ], [ (0x357a12f34662767b, 0x38ebd844c546d1fe), (0xbc55d35a88f1e0a3, 0xbfba4407e04298d1), (0x3bdf6dddc07add4c, 0x3f4bcc9df0cf00b2), (0xbc3c3cb8ccc39cf1, 0x3f917f0266db2149), (0x3ba3d974ad0c21fe, 0xbf2280a052234a05), (0x3bb902b669103937, 0xbf4bf2ada1f44071), (0xbb64ad3fa1509171, 0x3edd83d58032b48d), (0x3b3d6efd0446126a, 0x3ef53dd972d8f232), (0xbb230c11b6006891, 0xbe8663c1fe202028), (0xbb26dbba4ce8bd7d, 0xbe92d1fbf2203ff6), (0x3ac866e6e348b7b7, 0x3e23c9f0b759c5f9), (0x3ac489ff33dfce8f, 0x3e25cfe1b012696d), (0x3a4981337ac7965a, 0xbdb6ddc0795781e9), (0xba4b13e076398cc3, 0xbdb1cfd49504266a), (0x39edb765a45cfad5, 0x3d429b7af5214fbc), (0x39bd594b3ede144b, 0x3d3598302ab3ac8a), (0xb96436f0bc69940b, 0xbcc677f6a604ab42), (0xb95aaa7d20415d1b, 0xbcb432ecc122bbc3), (0x38b6c227de389245, 0x3c44ec114bfb6bf7), (0x38b8822ee44d55d6, 0x3c2e0887f8c2f57d), (0x38569ce3e7c211fb, 0xbbbef44a37f84f12), (0x384d44f14e9f294c, 0xbba22b91f5f4449b), (0xb7c6e331300713b4, 0x3b32a03f80301aa2), (0xb7bc71f13c4d9d35, 0x3b123d23f8f7ad2f), ], [ (0x3c423404089aea01, 0xbfb9ef3bb2213b0b), (0x3564b334f22dc8c4, 0x38ec7aef8237b6d2), (0x3c342c5cb51f2b57, 0x3fa9ed82007a9a45), (0xbbad41b75b8a8df3, 0xbf31d2fdeeb29f8a), (0x3c189945952fed1e, 0xbf71446866ff1b83), (0x3b94bf0ff761bace, 0x3efc73b684f93259), (0xbbc79edfb80bfc5d, 0x3f22628de594b6c9), (0xbb2bef93c666f4ba, 0xbeb03303c1427449), (0x3b69194ecd6aac53, 0xbec4f51007c51087), (0x3af53d1fa2147ee3, 0x3e531adfa36f2213), (0xbafbf005f05fcc98, 0x3e5db4f306b19095), (0x3a88f72949d1398a, 0xbdeb9e33598f899e), (0xba8457c3274ebd59, 0xbdecb09ed6ecb896), (0xba159f6f24f8986e, 0x3d7afe1183148a99), (0x3a11bfaf9fbcb95f, 0x3d7414e442aa8d57), (0x39ae38a755a019d9, 0xbd0307c129418397), (0xb99de6576700d7e4, 0xbcf54ddabca7b729), (0xb91f28f4f591d3f4, 0x3c84455c62381679), (0xb913f1c98ec45b97, 0x3c71b70264da382d), (0xb8a8129bcf1d63a0, 0xbc00e2cfa963d4c5), (0xb8879c81e5b960aa, 0xbbe7b5896de3457b), (0xb8030217c1f78b40, 0x3b7699efca5cd8c8), (0x37e0b0e37cbd943a, 0x3b5a15ae188cedc6), (0xb78b8997136a2cc2, 0xbae8d5720aed06a6), ], [ (0xb59a217cd5a5fc59, 0xb8f8cb0a4bb92b1c), (0x3c5728ab934a26a0, 0x3fb99be744018c90), (0xbbdb8852614fe858, 0xbf49c3f52a2af724), (0xbc2f281d89ca12e4, 0xbf910f5ca51f98b0), (0xbbc3c6681ac39db5, 0x3f2126c8e8ca2766), (0x3babb471b2b6cf3f, 0x3f4b416f7d4fc313), (0xbb677b33eb16cea4, 0xbedb5e2e5580e1ce), (0xbb988d4663776f74, 0xbef4b862279de756), (0xbb2b43c42f7f04bd, 0x3e84c5071b39dc13), (0xbb3de6264de806d7, 0x3e925d2fc3b19021), (0x3ac879393dd83f28, 0xbe225df322279972), (0xbac3ec23ad6e970a, 0xbe254a971eb6fe3b), (0x3a5048109b74bd8a, 0x3db53cc6c9922f2b), (0xba43610ec595546e, 0x3db164f95180d8c1), (0x39e236638a339577, 0xbd414b9ef404ed89), (0x39d5e32a69772db7, 0xbd3519623b4e50ac), (0x396ac2c256389163, 0x3cc4e7271a71f23c), (0x39593e237428a68a, 0x3cb3bf2a1b859197), (0xb8e5a9f4a410aefa, 0xbc437bc0d8e44b83), (0x38afa844b04c9f72, 0xbc2d6104b94c47d8), (0xb85bd976332a8ad4, 0x3bbcdb4b3544bc80), (0xb81ec0f06119d6f0, 0x3ba1c93567462aba), (0xb7dbdd21527e43db, 0xbb31623ef293806e), (0x37b58068411a8ada, 0xbb11dd917bc85327), ], [ (0xbc54096ec8637e04, 0x3fb94d3276914e51), (0xb599a52e7e447fba, 0xb8f7c4d3a1091c64), (0x3c4baee1d6c0d38b, 0xbfa94bac1950e319), (0x3bdbfe3ad50b1c19, 0x3f308d4ff8f2059e), (0xbc1cca1c2770b225, 0x3f70d90d29bfeecd), (0xbb987fee6225f412, 0xbefa6d56162f7fb4), (0xbbc7e723313bf860, 0xbf21f107da23807d), (0x3b42cbddeb0faca2, 0x3eae1a626277437b), (0x3b665fad37433b79, 0x3ec474eafd0cc642), (0x3acb91aaa2286db9, 0xbe51c27144f42d78), (0x3af7189d5fa17ee0, 0xbe5d01999b1a4fe9), (0x3a35f0e0348c776a, 0x3de9b014801da87a), (0x3a8958b840cda80a, 0x3dec061740bc8a45), (0x3a16875708b7d88b, 0xbd791f8c2972547e), (0x3a1c0289b9700b84, 0xbd739fb558b7aa4d), (0x39a9d6b95b5ce534, 0x3d01b9f74d47b35f), (0x3992cf3210e813d7, 0x3cf4d425557e1f1c), (0x392e1b1b93526a26, 0xbc82e617ae27952e), (0x3913ab3cd31920c7, 0xbc715432898c29d0), (0x3894feceefbf4d3a, 0x3bff843f6347963f), (0x388afc3194a2db07, 0x3be734c130fc648e), (0xb81e9da93ee8d83a, 0xbb751d395949afbc), (0x37d1fb7f6ae8afc8, 0xbb598c0f03028f01), (0x3751f15d40f7c19d, 0x3ae739cc4684a5bc), ], [ (0xb568e6ce9dddcc62, 0x38c846638d0f2565), (0x3c5e213a1a4b3671, 0xbfb8ffc9bd24fe08), (0x3be5e8a5d70cf555, 0x3f47f7d46ab33721), (0x3c2f532ddb23dab4, 0x3f90a7a725d3fbc4), (0xbbb3f089aa8f2adf, 0xbf1fea1728f216b4), (0xbbdf63ef3319327c, 0xbf4a9cac69f0ed64), (0x3b78f775cf86e9c6, 0x3ed977f48ff1056b), (0x3b8a77447ea6fe43, 0x3ef43c2d8e698c10), (0x3b293f5e91559672, 0xbe8355d1a6765ea6), (0x3b177401cf3aa17c, 0xbe91f0553501d121), (0xba823a3e8101b9d1, 0x3e211b47f6a44829), (0xbaa6a02fffa2b5eb, 0x3e24ce23303889a9), (0xba42b03ad2eec174, 0xbdb3ca98df62221f), (0xba50afdcc563be7a, 0xbdb100fc746529d7), (0xb9edcbe05d10e11a, 0x3d4020f11e2dca08), (0xb9da9e6748bc0bea, 0x3d34a26ef2219c2c), (0x3957914c29f9b911, 0xbcc38203ff52c747), (0xb94441377b47cfd9, 0xbcb35244c153aa29), (0xb8ef173859510b43, 0x3c4232dbbbea35fb), (0x38b7c43340294390, 0x3c2cc2f30d7e4a86), (0xb850cdea356a6de6, 0xbbbafaa22e04387a), (0x38455c9d49ba1463, 0xbba16c1420a026bc), (0x37ce36d7bd132716, 0x3b3044e17b70797e), (0x37bc48ba65be1620, 0x3b1182c036f66e44), ], [ (0x3c4123b2f0e7c9dd, 0xbfb8b67a2481077d), (0xb54bc05ff5d82c4f, 0xb8f3f299f5be57c2), (0xbc4b4ca91be60b3e, 0x3fa8b51f21068ea2), (0x3bb25eeb0c780d24, 0xbf2ed935c7aefa31), (0xbbf1e97629a4fbd3, 0xbf707522a5037f2d), (0x3b9aa02b2936e0d6, 0x3ef8a196061f8bbc), (0x3bc503ddcb9034df, 0x3f21874a47e3c1e3), (0x3b255f9307a25ea3, 0xbeac10cf34c04f17), (0xbb5b1d5a1969a1af, 0xbec3fd6c2d4fa2a4), (0xbaeb932c5947d65c, 0x3e50906d55522785), (0xbabb5acdea3816e2, 0x3e5c5a1c124dfa08), (0xba561fcb9b3ed156, 0xbde7f883b31a5f59), (0xba75531c808efbb8, 0xbdeb668cf53028e4), (0x3a104761ec9ef33f, 0x3d7775372d05b25d), (0xba0f2cfa85a363c5, 0x3d7331d871d677e0), (0xb9a6539a2342e3af, 0xbd009010248989d3), (0x398a668272dab0b6, 0xbcf461c4067c742d), (0xb92d7ef952991dfa, 0x3c81abf993696e78), (0x3913091355b7de99, 0x3c70f715fa383b8a), (0x3875a2bcb94003ab, 0xbbfd7ed2f30db038), (0x388cafff31b61f18, 0xbbe6bb0b4da7d6b8), (0xb7ea731441eedbfd, 0x3b73c73f0e157e5c), (0xb7f38c8cb3f130f8, 0x3b5909945c395947), (0x37892d92eac220fa, 0xbae5c71cc3e16dfe), ], [ (0x35720ba7b8040a50, 0xb8ee1da34bfeb8e0), (0x3c5b1c9821974148, 0x3fb86e51be0a9153), (0xbbeaa494385dab26, 0xbf465ed1b387e5da), (0x3c09cfc1363faa0e, 0xbf9046fc5a218a86), (0x3bbf17fc55a88b96, 0x3f1dca617fefa913), (0xbbe411ddd3f224d7, 0x3f4a0300221528a7), (0xbb35922d57d34f24, 0xbed7c7618906f1e2), (0x3b985c37a3fcd2ca, 0xbef3c838897d0a1e), (0xbb1cfc9e9ef07548, 0x3e820ede9f9dd7dd), (0x3b3d338a91461c93, 0x3e918a94165592bb), (0x3ab91bf2c08f3e78, 0xbe1ff76205118f09), (0x3ab5cfc207f32cd7, 0xbe24599dfeef01a1), (0x3a40b7bcb17c141b, 0x3db2803e59983134), (0xba1b8c9ffd59054b, 0x3db0a33202feb043), (0x39bbb27b9c04cfb6, 0xbd3e2bff738680f8), (0xb9daf156baca0aee, 0xbd34329cf32bcb6e), (0xb95aa99554b94956, 0x3cc2424890fb6cfb), (0xb94757efb61f4861, 0x3cb2eba657649d9b), (0x38e0a8b550a3fb8e, 0xbc410bda49bebe27), (0xb8b5e1a905ee61d3, 0xbc2c2d96d94f34d6), (0x38596b550a29ba35, 0x3bb94a9b8509dda4), (0xb8120159994b4d70, 0x3ba113d205a63be1), (0x37caf2ee39614a11, 0xbb2e87a2990f48e9), (0xb7a8109d37f955d6, 0xbb112c694684c14b), ], [ (0x3c48caabfef07d2c, 0x3fb829d06fee9266), (0xb57d95eabe44a5ef, 0xb8d5c95908041d40), (0xbc46f7f245223685, 0xbfa8289a526d7785), (0xbbbd55f593621103, 0x3f2cd680355c9eb6), (0x3c19dafafbc85033, 0x3f7017d70f512861), (0x3b94ef924915594e, 0xbef707978e2a0db8), (0xbbb84f6dd554027b, 0xbf21247ce15e7385), (0x3b3c1549321f5896, 0x3eaa3f6125485ec1), (0xbb6485c950af11e4, 0x3ec38da848401be9), (0xbae81c7e658ccb44, 0xbe4efe39d8db4cd8), (0xbaf106727152dad2, 0xbe5bbd40f1db0e94), (0x3a7e01f9c4e4c0e2, 0x3de66f7d49436f83), (0xba6a9de5073f8785, 0x3dead0e8148229b3), (0xb9edea6b298d9cb4, 0xbd75f78595133d0b), (0x3a0ffda12b15058b, 0xbd72ca9bb10321b3), (0xb995d841a594fd98, 0x3cff09e49c887e91), (0xb993b69afd44cfe7, 0x3cf3f60eeb66f747), (0xb910a7c26357cc61, 0xbc8091d689cc53d3), (0x3912aa74818ab310, 0xbc709f335e86201a), (0x389d74a5732f64e7, 0x3bfbad342a8e077c), (0xb889c873abcae58c, 0x3be647de871fcaea), (0x380999f107e74e72, 0xbb7292e087988121), (0xb7dd56a4a524a0b3, 0xbb588dc30bd642e2), (0x373e8c81645a59c4, 0x3ae4781fefecc3ab), ], [ (0x3590e3abb994f19d, 0xb8f3c9c05fc68dd7), (0x3c21907f595a082a, 0xbfb7e656efb009ae), (0x3bea53822a52d942, 0x3f44f15066f3d876), (0xbbef8f1c9736150f, 0x3f8fd932c26aad94), (0xbba4e6bbdf1f5013, 0xbf1be460dd86a0a4), (0x3bdda15b3eedcfa3, 0xbf49733b591879f8), (0x3b7b0e620a04314f, 0x3ed64488c56022e0), (0xbb74588b63a38eb3, 0x3ef35ba58bf2f993), (0xbb2d0149456492a2, 0xbe80ea47bceb9a8f), (0xbb1839787899a71b, 0xbe912b327055d0e9), (0xbaaeacb6c41bd108, 0x3e1df42fc4e2482c), (0xba6bbde5a22c7137, 0x3e23ec3e76876dba), (0xba4c4c84b112be57, 0xbdb1580393f473c3), (0x3a22a6076d63b081, 0xbdb04b0353c35935), (0xb9c9681ae93e12c5, 0x3d3c4ca30ffe2a12), (0xb9d1f206b8c5d3a1, 0x3d33c947b936c2fd), (0xb963c18fe06a22d6, 0xbcc122c73f770a60), (0x39590514d9616a4d, 0xbcb28ac7295026a0), (0x38e4da699d53ec4a, 0x3c4002243876b909), (0x38b0a1100a850e1a, 0x3c2ba04294d52584), (0xb85e4caf2a0c3dac, 0xbbb7c4c63a56cf5d), (0x383d5bda7bf4fb51, 0xbba0c0178f4adc58), (0x37ba459191582324, 0x3b2cb6cf025ab9d0), (0x37b2a1b95a167cc0, 0x3b10da465bbcd445), ], [ (0xbc2f952341a4610f, 0xbfb7a62320798175), (0x3588b8c77a52cc96, 0xb8e354421b948434), (0x3c4f5aadff868986, 0x3fa7a50ca4504bb8), (0xbbc425ed1e2ffb88, 0xbf2b095ccb50a68c), (0x3c0088e41711bdb7, 0xbf6f80ef11daa37a), (0xbb8b1b49cdffecd8, 0x3ef59822dc75b064), (0x3bc22455dc1dd149, 0x3f20c7e6a7c66630), (0x3b4cb7b87c0d2237, 0xbea89e00b5c358d0), (0x3b4c5e752b8da3c2, 0xbec324d5238b26d0), (0x3ae195d9c7c418a5, 0x3e4d13a888d5dd30), (0xbac402a4638ae535, 0x3e5b29f941a95b07), (0x3a831332fd181280, 0xbde50e6ebb3d1df6), (0xba87a4d1a4734618, 0xbdea4434c6b929dd), (0x3a1460d05df6e757, 0x3d74a03fe2c47842), (0x3a08550d3cb8e7ab, 0x3d7269628f2df98c), (0x398caf5ddb7a6639, 0xbcfd28cc08ef4278), (0xb9786d9d39f281e6, 0xbcf390706334abc3), (0xb90ccf6b842a2b18, 0x3c7f26c3ea443ebe), (0xb909111db3c1a608, 0x3c704c1cd3344483), (0xb89c3b1307b1967f, 0xbbfa08922dcea305), (0x38837f0ef471dbfb, 0xbbe5dabbff6c2bfb), (0xb80bcc939f982679, 0x3b717bccb6cd02d3), (0x37fb40b6199ccfa5, 0x3b5818261a2214e1), (0xb78fcd71326e756b, 0xbae3485ef660d33a), ], ]; pxfm-0.1.23/src/bessel/j1f.rs000064400000000000000000000273011046102023000137560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j1_coeffs::{J1_ZEROS, J1_ZEROS_VALUE}; use crate::bessel::j1f_coeffs::J1F_COEFFS; use crate::double_double::DoubleDouble; use crate::polyeval::{f_polyeval7, f_polyeval10, f_polyeval12, f_polyeval14}; use crate::sin_helper::sin_small; use crate::sincos_reduce::rem2pif_any; /// Bessel J1 /// /// Max ULP 0.5 /// /// Note about accuracy: /// - Close to zero Bessel have tiny values such that testing against MPFR must be done exactly /// in the same precision, since any nearest representable number have ULP > 0.5. /// For example `J1(0.000000000000000000000000000000000000023509886)` in single precision /// have an error at least 0.72 ULP for any number with extended precision, /// that would be represented in f32. pub fn f_j1f(x: f32) -> f32 { if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return x; } if x.is_infinite() { return 0.; } if x.is_nan() { return x + x; } } let ax = x.to_bits() & 0x7fff_ffff; if ax < 0x429533c2u32 { // 74.60109 if ax < 0x3e800000u32 { // 0.25 return maclaurin_series(x); } return small_argument_path(x); } // Exceptional cases: if ax == 0x6ef9be45 { return if x.is_sign_negative() { f32::from_bits(0x187d8a8f) } else { -f32::from_bits(0x187d8a8f) }; } else if ax == 0x7f0e5a38 { return if x.is_sign_negative() { -f32::from_bits(0x131f680b) } else { f32::from_bits(0x131f680b) }; } j1f_asympt(x) as f32 } #[inline] fn j1f_rsqrt(x: f64) -> f64 { (1. / x) * x.sqrt() } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - 3*PI/4 - alpha(x)) discarding 1*PI/2 using identities gives: J1 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) to avoid squashing small (-PI/4 - alpha(x)) into a large x actual expansion is: J1 = sqrt(2/(PI*x)) * beta(x) * sin((x mod 2*PI) - PI/4 - alpha(x)) */ #[inline] fn j1f_asympt(x: f32) -> f64 { static SGN: [f64; 2] = [1., -1.]; let sign_scale = SGN[x.is_sign_negative() as usize]; let x = x.abs(); let dx = x as f64; let alpha = j1f_asympt_alpha(dx); let beta = j1f_asympt_beta(dx); let angle = rem2pif_any(x); const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651); const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_sin = sin_small(r0); let z0 = beta * m_sin; let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx); scale * z0 * sign_scale } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied. Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(1, x, 50) Q = Qn_asymptotic(1, x, 50) R_series = (-Q/P) # alpha is atan(R_series) so we're doing Taylor series atan expansion on R_series arctan_series_Z = sum([QQ(-1)**k * x**(QQ(2)*k+1) / RealField(700)(RealField(700)(2)*k+1) for k in range(25)]) alpha_series = arctan_series_Z(R_series) # see the series print(alpha_series) ``` See notes/bessel_asympt.ipynb for generation **/ #[inline] pub(crate) fn j1f_asympt_alpha(x: f64) -> f64 { const C: [u64; 12] = [ 0xbfd8000000000000, 0x3fc5000000000000, 0xbfd7bccccccccccd, 0x4002f486db6db6db, 0xc03e9fbf40000000, 0x4084997b55945d17, 0xc0d4a914195269d9, 0x412cd1b53816aec1, 0xc18aa4095d419351, 0x41ef809305f11b9d, 0xc2572e6809ed618b, 0x42c4c5b6057839f9, ]; let recip = 1. / x; let x2 = recip * recip; let p = f_polyeval12( x2, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), f64::from_bits(C[10]), f64::from_bits(C[11]), ); p * recip } /** Note expansion generation below: this is negative series expressed in Sage as positive, so before any real evaluation `x=1/x` should be applied Generated by SageMath: ```python def binomial_like(n, m): prod = QQ(1) z = QQ(4)*(n**2) for k in range(1,m + 1): prod *= (z - (2*k - 1)**2) return prod / (QQ(2)**(2*m) * (ZZ(m).factorial())) R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() def Pn_asymptotic(n, y, terms=10): # now y = 1/x return sum( (-1)**m * binomial_like(n, 2*m) / (QQ(2)**(2*m)) * y**(QQ(2)*m) for m in range(terms) ) def Qn_asymptotic(n, y, terms=10): return sum( (-1)**m * binomial_like(n, 2*m + 1) / (QQ(2)**(2*m + 1)) * y**(QQ(2)*m + 1) for m in range(terms) ) P = Pn_asymptotic(1, x, 50) Q = Qn_asymptotic(1, x, 50) def sqrt_series(s): val = S.valuation() lc = S[val] # Leading coefficient b = lc.sqrt() * x**(val // 2) for _ in range(5): b = (b + S / b) / 2 b = b return b S = (P**2 + Q**2).truncate(50) b_series = sqrt_series(S).truncate(30) # see the beta series print(b_series) ``` See notes/bessel_asympt.ipynb for generation **/ #[inline] pub(crate) fn j1f_asympt_beta(x: f64) -> f64 { const C: [u64; 10] = [ 0x3ff0000000000000, 0x3fc8000000000000, 0xbfc8c00000000000, 0x3fe9c50000000000, 0xc01ef5b680000000, 0x40609860dd400000, 0xc0abae9b7a06e000, 0x41008711d41c1428, 0xc15ab70164c8be6e, 0x41bc1055e24f297f, ]; let recip = 1. / x; let x2 = recip * recip; f_polyeval10( x2, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), f64::from_bits(C[6]), f64::from_bits(C[7]), f64::from_bits(C[8]), f64::from_bits(C[9]), ) } /** Generated in Sollya: ```python pretty = proc(u) { return ~(floor(u*1000)/1000); }; bessel_j1 = library("./cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x)/x; d = [0, 0.921]; w = 1; pf = fpminimax(f, [|0,2,4,6,8,10,12|], [|D...|], d, absolute, floating); w = 1; or_f = bessel_j1(x); pf1 = pf * x; err_p = -log2(dirtyinfnorm(pf1*w-or_f, d)); print ("relative error:", pretty(err_p)); for i from 0 to degree(pf) by 2 do { print("'", coeff(pf, i), "',"); }; ``` See ./notes/bessel_sollya/bessel_j1f_at_zero.sollya **/ #[inline] fn maclaurin_series(x: f32) -> f32 { let dx = x as f64; let x2 = dx * dx; let p = f_polyeval7( x2, f64::from_bits(0x3fe0000000000000), f64::from_bits(0xbfaffffffffffffc), f64::from_bits(0x3f65555555554089), f64::from_bits(0xbf0c71c71c2a74ae), f64::from_bits(0x3ea6c16bbd1dc5c1), f64::from_bits(0xbe384562afb69e7d), f64::from_bits(0x3dc248d0d0221cd0), ); (p * dx) as f32 } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] fn small_argument_path(x: f32) -> f32 { static SIGN: [f64; 2] = [1., -1.]; let sign_scale = SIGN[x.is_sign_negative() as usize]; let x_abs = f32::from_bits(x.to_bits() & 0x7fff_ffff) as f64; // let avg_step = 74.60109 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6300176043004198; let fx = x_abs * INV_STEP; const J1_ZEROS_COUNT: f64 = (J1_ZEROS.len() - 1) as f64; let idx0 = fx.min(J1_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(J1_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(J1_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(J1_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return maclaurin_series(x); } // We hit exact zero, value, better to return it directly if dist == 0. { return (f64::from_bits(J1_ZEROS_VALUE[idx]) * sign_scale) as f32; } let c = &J1F_COEFFS[idx - 1]; let r = (x_abs - found_zero.hi) - found_zero.lo; let p = f_polyeval14( r, f64::from_bits(c[0]), f64::from_bits(c[1]), f64::from_bits(c[2]), f64::from_bits(c[3]), f64::from_bits(c[4]), f64::from_bits(c[5]), f64::from_bits(c[6]), f64::from_bits(c[7]), f64::from_bits(c[8]), f64::from_bits(c[9]), f64::from_bits(c[10]), f64::from_bits(c[11]), f64::from_bits(c[12]), f64::from_bits(c[13]), ); (p * sign_scale) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_j1f() { assert_eq!( f_j1f(0.000000000000000000000000000000000000008827127), 0.0000000000000000000000000000000000000044135635 ); assert_eq!(f_j1f(5.4), -0.3453447907795863); assert_eq!( f_j1f(77.743162408196766932633181568235159), 0.09049267898021947 ); assert_eq!( f_j1f(84.027189586293545175976760219782591), 0.0870430264022591 ); assert_eq!(f_j1f(f32::INFINITY), 0.); assert_eq!(f_j1f(f32::NEG_INFINITY), 0.); assert!(f_j1f(f32::NAN).is_nan()); assert_eq!(f_j1f(-1.7014118e38), 0.000000000000000000006856925); } } pxfm-0.1.23/src/bessel/j1f_coeffs.rs000064400000000000000000000552601046102023000153100ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generating Taylor expansions for zero and extremums see [crate::bessel::j1_coeffs::J1_ZEROS] to start of explanation. Generated by SageMath and Sollya: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = (zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i]) + 0.83 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05 b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(j1_zeros) # print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 500; bessel_j1 = library("./pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_j1(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d, 1, 1e-25); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RR(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return degree = 13 print(f"pub(crate) static J1F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print("[") for c in coeffs: print(double_to_hex(c) + ",") print("],") print("];") ``` **/ pub(crate) static J1F_COEFFS: [[u64; 14]; 47] = [ [ 0x3fe29ea3d19f035d, 0xbce22d3695a081b6, 0xbfca41115c5deeab, 0x3f78d1448e710c46, 0x3f8c441a2f9a4f69, 0xbf386671c22a634e, 0xbf39e2504b2e7b5b, 0x3ee34ccc14eef789, 0x3eda49718b72405e, 0xbe810474efe3c9c6, 0xbe70fa29fb791201, 0x3e1362d76c062ab0, 0x3dfdd76f07295520, 0xbda1a753bf39cb58, ], [ 0xbc600f4743bf63e1, 0xbfd9c6cf582cbf8a, 0x3faae8a39f51ad73, 0x3fab589d1da1462b, 0xbf7537544c334c23, 0xbf624b34099ee01c, 0x3f26e4c2d53c4f46, 0x3f083a06ee794927, 0xbec9799d241e5d2b, 0xbea3382caabc394d, 0x3e617039a48bb9f6, 0x3e345a8c920dcd07, 0xbdf014c3bf3000a5, 0xbdc034aa4e0a0169, ], [ 0xbfd626ee83500bf2, 0x3cb26dfd317b25ec, 0x3fc55f6bec9ef90d, 0xbf83d23336fd2aca, 0xbf88c77a98398e83, 0x3f45cdc98dc64f81, 0x3f373576fec2e394, 0xbef24614559dc202, 0xbed7b852bb05a2ff, 0x3e90ac054c63ba46, 0x3e6ea70b302a9ba3, 0xbe23616f333984e9, 0xbdfb0a064790ebe6, 0x3db0d9e08e0394a8, ], [ 0xbc69b70cbe5811c2, 0x3fd33518b3874e8d, 0xbf95e70dc6036109, 0xbfa80c83bdeee89d, 0x3f69a4b292e2ab0d, 0x3f613fbc7d6bc462, 0xbf207358bb38afba, 0xbf0796a754e5c2d1, 0x3ec4255a5a67b552, 0x3ea3026fd5c83da8, 0xbe5d482c06555943, 0xbe34473271553ffa, 0x3dec0515656e1a0c, 0x3dbf11e1948b68d2, ], [ 0x3fd17dbf09d40d24, 0xbca5b86542306439, 0xbfc1404bf647c233, 0x3f74f4df276a170d, 0x3f85c628542932bb, 0xbf3d68ab724123eb, 0xbf356acb63c4c7d5, 0x3eec10b48d91d910, 0x3ed67eaa56c73092, 0xbe8bb65dbfeed0f6, 0xbe6d8683c673b075, 0x3e20f7b6316797c6, 0x3dfa451f70b9922a, 0xbdadce2c76e4d044, ], [ 0x3c65df812ede650d, 0xbfcff654544ebcd3, 0x3f89223ff2c07565, 0x3fa4b0c5d5da68d8, 0xbf5f91a9ee0b0e8a, 0xbf5f51c2489da5c1, 0x3f16b4c9c8efdfe6, 0x3f063c54768ebb67, 0xbebe3724b50493f9, 0xbea25c12f8827c9d, 0x3e5747d49182153b, 0x3e33e41718262cb9, 0xbde738f2d8f2cac8, 0xbdbe80a4948dbf09, ], [ 0xbfcddceb4ce1bf49, 0x3c9e79566c79eb3d, 0x3fbda52116c0a587, 0xbf6a9da4603b9358, 0xbf8331e74ea51630, 0x3f33e5cb6ecbca42, 0x3f33885fe920e6b8, 0xbee494c100626ece, 0xbed512b940a2ae49, 0x3e85a8688c9ba4ce, 0x3e6c31a31b773184, 0xbe1bd11439ffd259, 0xbdf96a9daeb33936, 0x3da9176221cc5aa0, ], [ 0xbc62383f10698557, 0x3fcbf3337873a7d9, 0xbf80c83a2d7adab7, 0xbfa251858011820e, 0x3f559eb160bdad7b, 0x3f5c5bce33b024a1, 0xbf10413e2f7af958, 0xbf04a6704d9a9d07, 0x3eb6c43df550ea17, 0x3ea16abdc27eeb92, 0xbe52576e7fc9d1e6, 0xbe332dc1c1ed3ee2, 0x3de2f6391206ebbc, 0x3dbda410af6fe5f4, ], [ 0x3fca7f63fea81f25, 0xbc9710bf367611f2, 0xbfba60afb0664019, 0x3f62c1e930937e24, 0x3f814506466cfd08, 0xbf2cca8c0c28fab3, 0xbf31df821c353039, 0x3edee8816088c0d5, 0x3ed3a365144be247, 0xbe80ed354ac60d34, 0xbe6ab31b90ea8e41, 0x3e168836e968cdd7, 0x3df8613c2e496c6b, 0xbda4daa0300cec8d, ], [ 0x3c5e59bc05abf185, 0xbfc925c6fca08f55, 0x3f786dd32e0596e8, 0x3fa09463bbd036c8, 0xbf4fda0298c57ed5, 0xbf59f4be6075f749, 0x3f0877991961e89e, 0x3f032cb00f1d1bde, 0xbeb19d8c17e4c965, 0xbea06a043bd432bf, 0x3e4d398ca8f49a5e, 0x3e3250f2ec743ceb, 0xbddf086f08c63838, 0xbdbc8e4fa8a9f9e9, ], [ 0xbfc810f50225b04a, 0x3c923e2f625151bc, 0x3fb7fdf97ac36a6f, 0xbf5c3c256a8cde19, 0xbf7f98feb7276ef1, 0x3f25f6559e6b5a2c, 0x3f3080f57a3a527d, 0xbed80c5147824d09, 0xbed256dac8ee5bae, 0x3e7af7628377d0c7, 0x3e6938ef2e239da2, 0xbe12633fe4f5465f, 0xbdf745af34a2de92, 0x3da15e1c189cc1e4, ], [ 0xbc59737d6e4fe431, 0x3fc70c511227d5aa, 0xbf72ccb0e975555d, 0xbf9e7dc08e70e9c5, 0x3f48acdc5b030cb1, 0x3f580503724ae80a, 0xbf032ee4c8c82218, 0xbf01e5d2836968fa, 0x3eac129da754f086, 0x3e9ef1612a209ee4, 0xbe47b90193cc5cb3, 0xbe316f0e2a3b6246, 0x3dd9aabe334f3655, 0x3dbb62c2bd937db8, ], [ 0x3fc633e7f7f05300, 0xbc8dba9947515d38, 0xbfb6273784c1bfc4, 0x3f563ae94ade4347, 0x3f7d4666536b9564, 0xbf216d528356c33f, 0xbf2ec0dcdab1fcc9, 0x3ed34e967676159e, 0x3ed135c5c78436c9, 0xbe75f7c3c6380689, 0xbe67dba82b616a97, 0x3e0e71b8431ababd, 0x3df62fc761d5cf41, 0xbd9d2fe54f4a496b, ], [ 0x3c558a68c87f4030, 0xbfc5664e13b70622, 0x3f6e16555e1087dd, 0x3f9c5e1ad9fb2f2d, 0xbf43d369f956c6bd, 0xbf566f4ec27a7a37, 0x3eff0de050de72b9, 0x3f00cf26431ce3a2, 0xbea6f46c2694b0df, 0xbe9d407f232dd5f2, 0x3e43a29f2e4c9c8a, 0x3e3098ca879e4471, 0xbdd585d6255bc3df, 0xbdba39fcc1ea78bf, ], [ 0xbfc4b71d4ca2cc69, 0x3c88c930c0b4c560, 0x3fb4ae245697fb03, 0xbf5215e4e1a6153c, 0xbf7b633ed6d8e543, 0x3f1c7f17b4d42a82, 0x3f2ce01b8a6eca10, 0xbecfced72e1b750f, 0xbed03c9cd706bc3a, 0x3e72450e1e5d9dd3, 0x3e66a249f63c5bc1, 0xbe0999366388212b, 0xbdf52ba007be60f3, 0x3d98ced5beb32a74, ], [ 0xbc526f6d035edf6d, 0x3fc40f90793605bb, 0xbf68c833077fb99d, 0xbf9aa0ce0421d16e, 0x3f405fa598ed8bab, 0x3f551d30d78a7993, 0xbef9c5807480a6e1, 0xbeffc1bbf50ca15b, 0x3ea32dfda14ee884, 0x3e9bc2119616c18d, 0xbe408b0d01f43d88, 0xbe2fa87db40715d8, 0x3dd24d20c9bf3988, 0x3db920af9a64d8b9, ], [ 0x3fc37dfa8f5a550a, 0xbc850d0284917193, 0xbfb3775c1a04efff, 0x3f4e2b4810a4a882, 0x3f79d151a72aa26d, 0xbf17d8e5a0a8f01d, 0xbf2b49a641814268, 0x3ecac10968085b43, 0x3ececa610eed952d, 0xbe6eefd23aebb19b, 0xbe658bda5ec8aafe, 0x3e05d77b1c39da47, 0x3df43d63ca6b9538, 0xbd9555dba21d3a76, ], [ 0x3c4fe3057c054c4c, 0xbfc2f2072e638cf3, 0x3f64df208bbd408f, 0x3f992bb5e1e159a9, 0xbf3ba181c0657121, 0xbf53fe9d5ba9fb4a, 0x3ef5d17600fd9483, 0x3efe26d373f4ffea, 0xbea0509689b62f58, 0xbe9a70f1b160bc28, 0x3e3c4fa74da61f57, 0x3e2e44cc2feeed24, 0xbdcf87b5a4255e18, 0xbdb81bebaaec3c7c, ], [ 0xbfc2768d29c69936, 0x3c822565e3c86e7f, 0x3fb271811730b057, 0xbf49a8df96a15635, 0xbf787c81cf1b96e9, 0x3f14549cdbcc339c, 0x3f29ed2567282f3d, 0xbec6e4137cf2411c, 0xbecd53321406f402, 0x3e6a98443cd6fc90, 0x3e6494adc7c6521b, 0xbe02e1d787962f20, 0xbdf3653d7772f823, 0x3d928dbabedf1d31, ], [ 0xbc4bd8c1a48b98b5, 0x3fc1ff5eec6a01cd, 0xbf61e438b722bfe0, 0xbf97ed5fffc1c711, 0x3f37b7997ba917ee, 0x3f53081def95b78f, 0xbef2c5f5ec3350b1, 0xbefcc11a59469f36, 0x3e9c2c3894e80d05, 0x3e9946d150444e47, 0xbe388ce82c32666d, 0xbe2d044ba8d28f8d, 0x3dcb7a77f047774e, 0x3db72cad88060e0b, ], [ 0x3fc194eba75b32f9, 0xbc7faef3b1a5e821, 0xbfb190f7dc273599, 0x3f462bb47a5c8cc1, 0x3f7756ef20f501d3, 0xbf1198b0baaa058c, 0xbf28be8cf854b2d7, 0x3ec3dd6f88b69c69, 0x3ecc09c72877c12b, 0xbe6728ec2da828ad, 0xbe63b897c2c7b139, 0x3e008344f3db34b5, 0x3df2a1a5ef6e57ff, 0xbd904c70dc90d3bc, ], [ 0x3c4888e51c985983, 0xbfc12dd57bf18ad9, 0x3f5f1e1e7f3937bf, 0x3f96d9afe883018e, 0xbf34a538a4802887, 0xbf52316250b44b33, 0x3ef05f11562b37ff, 0x3efb86bad38b7b43, 0xbe98a1b250bb7d2f, 0xbe983dca646511fe, 0x3e3588f1be962e6d, 0x3e2be36513882145, 0xbdc831edc515fa05, 0xbdb6520b1c14e6f6, ], [ 0xbfc0d0d36473e98c, 0x3c7bf69dcc64d467, 0x3fb0cda9974abd9e, 0xbf4367f38f204418, 0xbf7656b75e3b5a4f, 0x3f0ed82abf947b58, 0x3f27b4e5b765cd39, 0xbec171fd1a726d85, 0xbecae62a6c526e99, 0x3e64648b6f18fd5e, 0x3e62f3b53a117819, 0xbdfd2c72ca1c90f8, 0xbdf1f085bd0fab41, 0x3d8ce566a6478844, ], [ 0xbc45ca84b624bf30, 0x3fc076826cc2c191, 0xbf5b62885e006ac2, 0xbf95e7f53001e43e, 0x3f322ebeb8d9f78a, 0x3f517444a79fe500, 0xbeece06f1cc95449, 0xbefa7006e603acdb, 0x3e95c42dcf4cb755, 0x3e9750c9cbea6158, 0xbe3313f5f0d7c83f, 0xbe2ade4e1f9c8db0, 0x3dc57f801723eb46, 0x3db58a5b7895974e, ], [ 0x3fc02455675ab6d2, 0xbc78e3f9125495c0, 0xbfb021c155a72057, 0x3f412be56fc16829, 0x3f75749d556a12df, 0xbf0b51f1f9db1832, 0xbf26c96a07103bad, 0x3ebef3a7bef163ee, 0x3ec9e206eb2ce693, 0xbe6220bf8745e1a3, 0xbe6242a68bb3eb7f, 0x3df9ffc1c0ac86f0, 0x3df14fb8a5e39fac, 0xbd89d286115bf7a6, ], [ 0x3c4380441b0b0c6a, 0xbfbfa8b41711c839, 0x3f5857d39699926e, 0x3f9511c6dadaa99b, 0xbf302c289dbbcc5a, 0xbf50cc2238d1bf52, 0x3ee9b64d5a4aa86c, 0x3ef976fb01920f8b, 0xbe93693a8cc790fd, 0xbe967b9496685d1b, 0x3e310c25f77e4f25, 0x3e29f17f3e13ecd9, 0xbdc3414987038eec, 0xbdb4d3b9dc98b4b1, ], [ 0xbfbf161d0c28b48b, 0x3c765dc0b792167d, 0x3faf11d837aa6e5c, 0xbf3eab76da4d4788, 0xbf74ab329f05bdc5, 0x3f086ada57d5a903, 0x3f25f6e78e464093, 0xbebbb2720677d252, 0xbec8f8525854df7e, 0x3e603f882886871e, 0x3e61a293516bd71e, 0xbdf75995de0fcb8d, 0xbdf0bd411cec4c70, 0x3d873e4d136b8f8b, ], [ 0xbc418c91b7939a2c, 0x3fbe8727daa3daec, 0xbf55d353e285455c, 0xbf94524d4813cbac, 0x3f2d037574df02eb, 0x3f50356bb7473b5d, 0xbee7156bfaea76f5, 0xbef896d7dbd3810e, 0x3e9172c5e1abd5c6, 0x3e95baadfc18282d, 0xbe2eb240c0cc9c75, 0xbe2919d9b9e0a0b9, 0x3dc15e50952db326, 0x3db42c51c147e65d, ], [ 0x3fbe0357c158b118, 0xbc74361048923786, 0xbfadffc2fc1a90f5, 0x3f3b9b82ae081404, 0x3f73f64e05315346, 0xbf05fe4b66e63077, 0xbf2539518d55a85c, 0x3eb8f8d02bcc2897, 0x3ec825039164993f, 0xbe5d566920c2c9ab, 0xbe61111befe6e2b8, 0x3df51d4c70439a2f, 0x3df0375b8b7f66b3, 0xbd850e412a9bff06, ], [ 0x3c3fc518d24f616f, 0xbfbd8293aa55d18f, 0x3f53b6beb83f212f, 0x3f93a5ccbc12a602, 0xbf2a3765d26776da, 0xbf4f5ab33747e91e, 0x3ee4df6f1a6da3df, 0x3ef7cbd49b834b1a, 0xbe8f9607c8362a02, 0xbe950b374b4c0d92, 0x3e2bd1f7180ef6ba, 0x3e2854abbc0c7de8, 0xbdbf87db79765a71, 0xbdb3926b2e69585a, ], [ 0xbfbd0b36e5737457, 0x3c726585805a22d8, 0x3fad082ce3c6b4a2, 0xbf3905d00c5e9c91, 0xbf7352b073fcfa33, 0x3f03f1ccfed800a0, 0x3f248d74577878fa, 0xbeb6a9ef1ba885bb, 0xbec764d8b51b8b1c, 0x3e5aa78ed7e846ea, 0x3e608c46d6182272, 0xbdf33581106d6379, 0xbdef78fcff7e62ac, 0x3d832f39fadd44c1, ], [ 0xbc3cea65a1050db5, 0x3fbc96700bf039e1, 0xbf51ec0b5de4bafb, 0xbf93095734a2441c, 0x3f27d74e122576e6, 0x3f4e636fe2585c98, 0xbee2fe11959a4f56, 0xbef712e4d39f1e3a, 0x3e8cc3ac0e3e5a57, 0x3e946ad2493deefc, 0xbe295ca72f5034a9, 0xbe279fa7ce9e0732, 0x3dbcc7fe67868a0c, 0x3db30482af82a3e3, ], [ 0x3fbc29ae8400a31f, 0xbc70d624180ba1cb, 0xbfac27138da31b39, 0x3f36d141fcbed86f, 0x3f72bdc71061ff60, 0xbf0231cf645337e2, 0xbf23f0bf3a855d26, 0x3eb4b05ea24a407d, 0x3ec6b52ac7705590, 0xbe585a82e1962dc0, 0xbe60126ea6b0d3d5, 0x3df191f5eda7279d, 0x3dee96ae83ca14cd, 0xbd8191df21c5049c, ], [ 0x3c3a725871d54f1e, 0xbfbbbf246914235e, 0x3f5062daee353d6e, 0x3f927a96f174b658, 0xbf25cdb5dea7195a, 0xbf4d818348f8b2ae, 0x3ee160aab6b91ebc, 0x3ef6698d6e3dde27, 0xbe8a56325d99553d, 0xbe93d7884737e010, 0x3e273dfa1c71021f, 0x3e26f8d7f1f40cd1, 0xbdba675a7a73a904, 0xbdb28141631b6b6a, ], [ 0xbfbb5b8273b75054, 0x3c6ef081b4f49e8c, 0x3fab59418c36a598, 0xbf34eafeaa92d6ad, 0xbf7235801af9154a, 0x3f00af9747e26a9d, 0x3f23611db02b9d63, 0xbeb2fbe420b9b6ee, 0xbec613cc016f8c79, 0x3e565cfa070daeea, 0x3e5f4465aa2f3924, 0xbdf0262c878a66b9, 0xbdedc58772bf3be9, 0x3d802a5900529d85, ], [ 0xbc384aa4fbafc099, 0x3fbaf9cb49c4f934, 0xbf4e1d930b512b68, 0xbf91f7a8fec6eb30, 0x3f240a553105f569, 0x3f4cb20c812efe23, 0xbedff5195120ac4b, 0xbef5cdc48eb38532, 0x3e883b07bbc753fc, 0x3e934fb5f8f40030, 0xbe2566435ca657bc, 0xbe265e90a4422b0e, 0x3db85513c8865e5e, 0x3db2077cf853887e, ], [ 0x3fba9e13a0db6429, 0xbc6c8fc49071e774, 0xbfaa9c1ca2161ab5, 0x3f3344a09efdef03, 0x3f71b82c43097eb4, 0xbefebfb97beaa2a2, 0xbf22dcdb1b1095b7, 0x3eb180048a016cca, 0x3ec57eee38f33b34, 0xbe54a0cd96cea7fb, 0xbe5e74d5d6cab4bf, 0x3dedd0d2df39d680, 0x3ded0395b2b002c8, 0xbd7ddf4961633a0a, ], [ 0x3c366129d7cdda38, 0xbfba4407e04298d1, 0x3f4bcc9df0cefa78, 0x3f917f0266db20d1, 0xbf2280a052210834, 0xbf4bf2ada1f36d37, 0x3edd83d57dbfecdc, 0x3ef53dd97231158c, 0xbe8663c0bacd7255, 0xbe92d1fb6736ed8c, 0x3e23c94599131ea8, 0x3e25cf6504993c56, 0xbdb683e80faa06e8, 0xbdb19631ce482d25, ], [ 0xbfb9ef3bb2213b0a, 0x3c6a7968b4e09650, 0x3fa9ed82007a9965, 0xbf31d2fdeeb2c55d, 0xbf71446866fe7a9f, 0x3efc73b6851770db, 0x3f22628de4e7b12f, 0xbeb03303cb6b68e6, 0xbec4f50f5682c560, 0x3e531ae61db4a107, 0x3e5db4387e5cde8e, 0xbdeba1fde369500d, 0xbdec4f2d9a6ca338, 0x3d7bb4d1335b858d, ], [ 0xbc34b2fde0d60fa7, 0x3fb99be744018c90, 0xbf49c3f52a2af15f, 0xbf910f5ca51f983b, 0x3f2126c8e8c80fca, 0x3f4b416f7d4ef26a, 0xbedb5e2e533b6e90, 0xbef4b86226f8434d, 0x3e84c505ef1872eb, 0x3e925d2f3adca31c, 0xbe225d5434e81821, 0xbe254a1c99a03af6, 0x3db4e94bd07d8a6f, 0x3db12c7cbd69804c, ], [ 0x3fb94d3276914e50, 0xbc68a054fb407a48, 0xbfa94bac1950e23d, 0x3f308d4ff8f228ce, 0x3f70d90d29bf518f, 0xbefa6d56164ba1ad, 0xbf21f107d97a6716, 0x3eae1a62755de03b, 0x3ec474ea4fd020bb, 0xbe51c2774b54b19c, 0xbe5d00e34f95d0da, 0x3de9b39b1acf50d9, 0x3deba6dd96aebb23, 0xbd79c96d87e11eb2, ], [ 0x3c3336a57f397478, 0xbfb8ffc9bd24fe07, 0x3f47f7d46ab331c5, 0x3f90a7a725d3fb50, 0xbf1fea1728ee3283, 0xbf4a9cac69f01f7f, 0x3ed977f48dd3df20, 0x3ef43c2d8dc63c79, 0xbe8355d08ef44310, 0xbe91f054ae49cd66, 0x3e211ab3e0c31baf, 0x3e24cdaac969d4dd, 0xbdb37cc6ee5acaa3, 0xbdb0c99a10f9a149, ], [ 0xbfb8b67a2481077c, 0x3c66ff282f533f22, 0x3fa8b51f21068dcb, 0xbf2ed935c7af3be8, 0xbf707522a502e55b, 0x3ef8a1960639d120, 0x3f21874a473e56eb, 0xbeac10cf4666ac95, 0xbec3fd6b83d91ed3, 0x3e509072f594172b, 0x3e5c5969c0715bb8, 0xbde7fbce7fa1d168, 0xbdeb09679444c7c3, 0x3d7813cf0f88ee50, ], [ 0xbc31df60e9bfe4d4, 0x3fb86e51be0a9153, 0xbf465ed1b387e0dc, 0xbf9046fc5a218a13, 0x3f1dca617fec07ec, 0x3f4a030022145da6, 0xbed7c761870dcbbb, 0xbef3c83888dc1ceb, 0x3e820edd9a880dbb, 0x3e918a9391ba3964, 0xbe1ff64d38db85c5, 0xbe245927a9c55d79, 0x3db2377b4d9f1923, 0x3db06cdd9727d79f, ], [ 0x3fb829d06fee9265, 0xbc6580de45a47453, 0xbfa8289a526d76b3, 0x3f2cd680355cdc28, 0x3f7017d70f5091c7, 0xbef707978e429e47, 0xbf21247ce0bc7ead, 0x3eaa3f6135c91ad4, 0x3ec38da7a255e74a, 0xbe4efe445dfcd93f, 0xbe5bbc925c9c4b66, 0x3de6729121dc2aec, 0x3dea75b6fa634294, 0xbd768bad7f03cc70, ], [ 0x3c30ac9cf88bc679, 0xbfb7e656efb009ad, 0x3f44f15066f3d3cc, 0x3f8fd932c26aacb2, 0xbf1be460dd833bb1, 0xbf49733b5917b1ec, 0x3ed64488c387546b, 0x3ef35ba58b547387, 0xbe80ea46c863072a, 0xbe912b31edd1db5a, 0x3e1df32c5fd2f995, 0x3e23ebca247be24d, 0xbdb113cb7b7c70db, 0xbdb015b1107de244, ], [ 0xbfb7a62320798174, 0x3c9957b1463c023c, 0x3fa7a50ca4504ab9, 0xbf2b095ccb52d0c4, 0xbf6f80ef11d944d8, 0x3ef59822dd4acc8e, 0x3f20c7e6a7116068, 0xbea89e01408239eb, 0xbec324d470ec229a, 0x3e4d13ff680fb32a, 0x3e5b2943a9554368, 0xbde5283c9b463c57, 0xbde9e8488fabd47c, 0x3d7a620fb02a1ce9, ], ]; pxfm-0.1.23/src/bessel/jincpi.rs000064400000000000000000000334571046102023000145630ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![allow(clippy::excessive_precision)] use crate::bessel::alpha1::bessel_1_asympt_alpha_fast; use crate::bessel::beta1::bessel_1_asympt_beta_fast; use crate::bessel::j1_coeffs::{J1_COEFFS, J1_ZEROS, J1_ZEROS_VALUE}; use crate::bessel::j1_coeffs_taylor::J1_COEFFS_TAYLOR; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::polyeval::{f_polyeval9, f_polyeval19}; use crate::sin_helper::sin_dd_small_fast; /// Normalized jinc 2*J1(PI\*x)/(pi\*x) pub fn f_jincpi(x: f64) -> f64 { if !x.is_normal() { if x == 0. { return 1.0; } if x.is_infinite() { return 0.; } if x.is_nan() { return x + x; } } let ax: u64 = x.to_bits() & 0x7fff_ffff_ffff_ffff; if ax <= 0x3cb0000000000000u64 { // |x| <= f64::EPSILON // use series here j1(x*Pi)/(x*Pi) ~ 1 - Pi^2*x^2/8 + O(x^4) const MSQR_PI_OVER_16: f64 = f64::from_bits(0xbff3bd3cc9be45de); return f_fmla(MSQR_PI_OVER_16 * x, x, 1.); } if ax < 0x4052a6784230fcf8u64 { // 74.60109 if ax < 0x3fd3333333333333 { // 0.3 return jincpi_near_zero(f64::from_bits(ax)); } let scaled_pix = f64::from_bits(ax) * std::f64::consts::PI; // just test boundaries if scaled_pix < 74.60109 { return jinc_small_argument_fast(f64::from_bits(ax)); } } jinc_asympt_fast(f64::from_bits(ax)) } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - 3*PI/4 - alpha(x)) discarding 1*PI/2 using identities gives: J1 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) to avoid squashing small (-PI/4 - alpha(x)) into a large x actual expansion is: J1 = sqrt(2/(PI*x)) * beta(x) * sin((x mod 2*PI) - PI/4 - alpha(x)) */ #[inline] fn jinc_asympt_fast(ox: f64) -> f64 { const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); let x = DoubleDouble::quick_mult_f64(PI, ox); const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); // argument reduction assuming x here value is already multiple of PI. // k = round((x*Pi) / (pi*2)) let kd = (ox * 0.5).round(); // y = (x * Pi) - k * 2 let rem = f_fmla(kd, -2., ox); let angle = DoubleDouble::quick_mult_f64(PI, rem); let recip = x.recip(); let alpha = bessel_1_asympt_alpha_fast(recip); let beta = bessel_1_asympt_beta_fast(recip); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_sin = sin_dd_small_fast(r0); let z0 = DoubleDouble::quick_mult(beta, m_sin); let dx_sqrt = x.fast_sqrt(); let scale = DoubleDouble::div(SQRT_2_OVER_PI, dx_sqrt); let p = DoubleDouble::quick_mult(scale, z0); DoubleDouble::quick_mult(p, recip).to_f64() * 2. } #[inline] pub(crate) fn jincpi_near_zero(x: f64) -> f64 { // Polynomial Generated by Wolfram Mathematica: // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 8] = [ (0xbb2bddffe9450ca6, 0x3fe0000000000000), (0x3c3b0b0a7393eccb, 0xbfce4cd3c3c87615), (0xbc7f9f784e0594a6, 0xbfe043283b1e383f), (0xbc6af77bca466875, 0x3fcee46673cf919f), (0xbc0b62837b038ea8, 0x3fc0b7cc55c9a4af), (0x3c5c08841871f124, 0xbfb002b65231dcdd), (0xbc26cf2d89ea63bc, 0xbf849022a7a0712b), (0xbbe535d492c0ac1c, 0x3f740b48910d5105), ]; const Q: [(u64, u64); 8] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c4aba6577f3253e, 0xbfde4cd3c3c87615), (0x3c52f58f82e3438c, 0x3fcbd0a475006cf9), (0x3c36e496237d6b49, 0xbfb9f4cea13b06e9), (0xbbbbf3e4ef3a28fe, 0x3f967ed0cee85392), (0x3c267ac442bb3bcf, 0xbf846e192e22f862), (0x3bd84e9888993cb0, 0x3f51e0fff3cfddee), (0x3bd7c0285797bd8e, 0xbf3ea7a621fa1c8c), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = x2 * x2; let p0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[1]), x, DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[3]), x, DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[5]), x, DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[7]), x, DoubleDouble::from_bit_pair(P[6]), ); let q0 = DoubleDouble::mul_add(x2, p1, p0); let q1 = DoubleDouble::mul_add(x2, p3, p2); let p_num = DoubleDouble::mul_add(x4, q1, q0); let p0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[1]), x, DoubleDouble::from_bit_pair(Q[0]), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[3]), x, DoubleDouble::from_bit_pair(Q[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[5]), x, DoubleDouble::from_bit_pair(Q[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[7]), x, DoubleDouble::from_bit_pair(Q[6]), ); let q0 = DoubleDouble::mul_add(x2, p1, p0); let q1 = DoubleDouble::mul_add(x2, p3, p2); let p_den = DoubleDouble::mul_add(x4, q1, q0); DoubleDouble::quick_mult_f64(DoubleDouble::div(p_num, p_den), 2.).to_f64() } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] pub(crate) fn jinc_small_argument_fast(x: f64) -> f64 { const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); // let avg_step = 74.60109 / 47.0; // let inv_step = 1.0 / avg_step; let dx = DoubleDouble::quick_mult_f64(PI, x); const INV_STEP: f64 = 0.6300176043004198; let fx = dx.hi * INV_STEP; const J1_ZEROS_COUNT: f64 = (J1_ZEROS.len() - 1) as f64; let idx0 = fx.min(J1_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(J1_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(J1_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(J1_ZEROS[idx1]); let dist0 = (found_zero0.hi - dx.hi).abs(); let dist1 = (found_zero1.hi - dx.hi).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return jincpi_near_zero(x); } let r = DoubleDouble::quick_dd_sub(dx, found_zero); // We hit exact zero, value, better to return it directly if dist == 0. { return DoubleDouble::quick_mult_f64( DoubleDouble::from_f64_div_dd(f64::from_bits(J1_ZEROS_VALUE[idx]), dx), 2., ) .to_f64(); } let is_zero_too_close = dist.abs() < 1e-3; let c = if is_zero_too_close { &J1_COEFFS_TAYLOR[idx - 1] } else { &J1_COEFFS[idx - 1] }; let p = f_polyeval19( r.hi, f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), f64::from_bits(c[9].1), f64::from_bits(c[10].1), f64::from_bits(c[11].1), f64::from_bits(c[12].1), f64::from_bits(c[13].1), f64::from_bits(c[14].1), f64::from_bits(c[15].1), f64::from_bits(c[16].1), f64::from_bits(c[17].1), f64::from_bits(c[18].1), f64::from_bits(c[19].1), f64::from_bits(c[20].1), f64::from_bits(c[21].1), f64::from_bits(c[22].1), f64::from_bits(c[23].1), ); let mut z = DoubleDouble::mul_f64_add(r, p, DoubleDouble::from_bit_pair(c[4])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[3])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[2])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[1])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[0])); z = DoubleDouble::quick_mult_f64(DoubleDouble::div(z, dx), 2.); let err = f_fmla( z.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3bf0000000000000), // 2^-64 ); let ub = z.hi + (z.lo + err); let lb = z.hi + (z.lo - err); if ub == lb { return z.to_f64(); } j1_small_argument_dd(r, c, dx) } fn j1_small_argument_dd(r: DoubleDouble, c0: &[(u64, u64); 24], inv_scale: DoubleDouble) -> f64 { let c = &c0[15..]; let p0 = f_polyeval9( r.to_f64(), f64::from_bits(c[0].1), f64::from_bits(c[1].1), f64::from_bits(c[2].1), f64::from_bits(c[3].1), f64::from_bits(c[4].1), f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), ); let c = c0; let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(c[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let z = DoubleDouble::div(p, inv_scale); DoubleDouble::quick_mult_f64(z, 2.).to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_jincpi() { assert_eq!(f_jincpi(0.5000000000020244), 0.7217028449014163); assert_eq!(f_jincpi(73.81695991658546), -0.0004417546638317049); assert_eq!(f_jincpi(0.01), 0.9998766350182722); assert_eq!(f_jincpi(0.9), 0.28331697846510623); assert_eq!(f_jincpi(3.831705970207517), -0.036684415010255086); assert_eq!(f_jincpi(-3.831705970207517), -0.036684415010255086); assert_eq!( f_jincpi(0.000000000000000000000000000000000000008827127), 1.0 ); assert_eq!( f_jincpi(-0.000000000000000000000000000000000000008827127), 1.0 ); assert_eq!(f_jincpi(5.4), -0.010821736808448256); assert_eq!( f_jincpi(77.743162408196766932633181568235159), -0.00041799098646950523 ); assert_eq!( f_jincpi(84.027189586293545175976760219782591), -0.00023927934929850555 ); assert_eq!(f_jincpi(f64::NEG_INFINITY), 0.0); assert_eq!(f_jincpi(f64::INFINITY), 0.0); assert!(f_jincpi(f64::NAN).is_nan()); } } pxfm-0.1.23/src/bessel/jincpif.rs000064400000000000000000000201571046102023000147220ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j1_coeffs::{J1_ZEROS, J1_ZEROS_VALUE}; use crate::bessel::j1f::{j1f_asympt_alpha, j1f_asympt_beta}; use crate::bessel::j1f_coeffs::J1F_COEFFS; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::polyeval::{f_polyeval6, f_polyeval14}; use crate::sin_helper::sin_small; /// Normalized jinc 2*J1(PI\*x)/(pi\*x) /// /// ULP 0.5 pub fn f_jincpif(x: f32) -> f32 { if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return 1.; } if x.is_infinite() { return 0.; } if x.is_nan() { return x + x; } } let ax = x.to_bits() & 0x7fff_ffff; if ax <= 0x34000000u32 { // |x| <= f32::EPSILON // use series here j1(x*Pi)/(x*Pi) ~ 1 - Pi^2*x^2/8 + O(x^4) let dx = x as f64; let x2 = dx * dx; const MSQR_PI_OVER_16: f64 = f64::from_bits(0xbff3bd3cc9be45de); return f_fmla(MSQR_PI_OVER_16, x2, 1.) as f32; } if ax < 0x429533c2u32 { // 74.60109 if ax <= 0x3e800000u32 { // 0.25 return jincf_near_zero(f32::from_bits(ax)); } let scaled_pix = f32::from_bits(ax) * std::f32::consts::PI; // just test boundaries if scaled_pix < 74.60109 { return jincpif_small_argument(f32::from_bits(ax)); } } jincpif_asympt(f32::from_bits(ax)) as f32 } #[inline] fn j1f_rsqrt(x: f64) -> f64 { (1. / x) * x.sqrt() } #[inline] fn jincf_near_zero(x: f32) -> f32 { let dx = x as f64; // Generated in Wolfram Mathematica: // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval6( dx, f64::from_bits(0x3fe0000000000002), f64::from_bits(0xbfd46cd1822a5aa0), f64::from_bits(0xbfde583c923dc6f4), f64::from_bits(0x3fd3834f47496519), f64::from_bits(0x3fb8118468756e6f), f64::from_bits(0xbfafaff09f13df88), ); let p_den = f_polyeval6( dx, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfe46cd1822a4cb0), f64::from_bits(0x3fd2447a026f477a), f64::from_bits(0xbfc6bdf2192404e5), f64::from_bits(0x3fa0cf182218e448), f64::from_bits(0xbf939ab46c3f7a7d), ); (p_num / p_den * 2.) as f32 } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] fn jincpif_small_argument(ox: f32) -> f32 { const PI: f64 = f64::from_bits(0x400921fb54442d18); let x = ox as f64 * PI; let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); // let avg_step = 74.60109 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6300176043004198; let inv_scale = x; let fx = x_abs * INV_STEP; const J1_ZEROS_COUNT: f64 = (J1_ZEROS.len() - 1) as f64; let idx0 = fx.min(J1_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(J1_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(J1_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(J1_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return jincf_near_zero(ox); } // We hit exact zero, value, better to return it directly if dist == 0. { return (f64::from_bits(J1_ZEROS_VALUE[idx]) / inv_scale * 2.) as f32; } let c = &J1F_COEFFS[idx - 1]; let r = (x_abs - found_zero.hi) - found_zero.lo; let p = f_polyeval14( r, f64::from_bits(c[0]), f64::from_bits(c[1]), f64::from_bits(c[2]), f64::from_bits(c[3]), f64::from_bits(c[4]), f64::from_bits(c[5]), f64::from_bits(c[6]), f64::from_bits(c[7]), f64::from_bits(c[8]), f64::from_bits(c[9]), f64::from_bits(c[10]), f64::from_bits(c[11]), f64::from_bits(c[12]), f64::from_bits(c[13]), ); (p / inv_scale * 2.) as f32 } /* Evaluates: J1 = sqrt(2/(PI*x)) * beta(x) * cos(x - 3*PI/4 - alpha(x)) discarding 1*PI/2 using identities gives: J1 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) to avoid squashing small (-PI/4 - alpha(x)) into a large x actual expansion is: J1 = sqrt(2/(PI*x)) * beta(x) * sin((x mod 2*PI) - PI/4 - alpha(x)) */ #[inline] pub(crate) fn jincpif_asympt(x: f32) -> f64 { const PI: f64 = f64::from_bits(0x400921fb54442d18); let dox = x as f64; let dx = dox * PI; let inv_scale = dx; let alpha = j1f_asympt_alpha(dx); let beta = j1f_asympt_beta(dx); // argument reduction assuming x here value is already multiple of PI. // k = round((x*Pi) / (pi*2)) let kd = (dox * 0.5).round(); // y = (x * Pi) - k * 2 let angle = f_fmla(kd, -2., dox) * PI; const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651); const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_sin = sin_small(r0); let z0 = beta * m_sin; let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx); let j1pix = scale * z0; (j1pix / inv_scale) * 2. } #[cfg(test)] mod tests { use super::*; #[test] fn test_jincpif() { assert_eq!(f_jincpif(102.59484), 0.00024380769); assert_eq!(f_jincpif(100.08199), -0.00014386141); assert_eq!(f_jincpif(0.27715185), 0.9081822); assert_eq!(f_jincpif(0.007638072), 0.99992806); assert_eq!( f_jincpif(0.000000000000000000000000000000000000008827127), 1.0 ); assert_eq!(f_jincpif(5.4), -0.010821743); assert_eq!( f_jincpif(77.743162408196766932633181568235159), -0.00041799102 ); assert_eq!( f_jincpif(84.027189586293545175976760219782591), -0.00023927793 ); assert_eq!(f_jincpif(f32::INFINITY), 0.); assert_eq!(f_jincpif(f32::NEG_INFINITY), 0.); assert!(f_jincpif(f32::NAN).is_nan()); assert_eq!(f_jincpif(-1.7014118e38), -0.0); } } pxfm-0.1.23/src/bessel/k0.rs000064400000000000000000000521751046102023000136170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::i0::{bessel_rsqrt_hard, i0_exp}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::rational128_exp; use crate::logs::{fast_log_d_to_dd, log_dd}; use crate::polyeval::f_polyeval3; /// Modified Bessel of the second kind order 0 /// /// Max ULP 0.5 pub fn f_k0(x: f64) -> f64 { if x < 0. { return f64::NAN; } if !x.is_normal() { if x == 0. { return f64::INFINITY; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f64::NAN }; } if x.is_nan() { return x + x; } } let xb = x.to_bits(); if xb >= 0x40862e42fefa39f0u64 { // 709.7827128933841 return 0.; } if xb <= 0x3ff0000000000000 { return k0_small_dd(x); } k0_asympt(x) } /** Computes I0 on interval [0; 1] as rational approximation I0 = 1 + (x/2)^2 * Pn((x/2)^2)/Qm((x/2)^2)) Generated by Wolfram Mathematica: ```python <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i0_0_to_1_fast(x: f64) -> DoubleDouble { let dx = x; const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(dx, dx), ONE_OVER_4); const P: [(u64, u64); 3] = [ (0xbae20452afd5045b, 0x3ff0000000000000), (0xbc5b6ff3f140da20, 0x3fc93c83592c03de), (0x3c25b350e9128d49, 0x3f904f33ef2de455), ]; let ps_num = f_polyeval3( eval_x.hi, f64::from_bits(0x3f433805a2fabaaa), f64::from_bits(0x3ee5897e7f554966), f64::from_bits(0x3e731401f0bb5de4), ); let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 3] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c323fa63bef2b4e, 0xbfab0df29b4ff089), (0x3bfedbdf64ed3110, 0x3f564662064157d2), ]; let ps_den = f_polyeval3( eval_x.hi, f64::from_bits(0xbef6bdbb484fd0a4), f64::from_bits(0x3e8d6ced53309351), f64::from_bits(0xbe13cff13854e945), ); let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[0])); let p = DoubleDouble::div(p_num, p_den); let z = DoubleDouble::quick_mult(p, eval_x); DoubleDouble::full_add_f64(z, 1.) } /** K0(x) + log(x) * I0(x) = P(x^2) hence K0(x) = P(x^2) - log(x)*I0(x) Generated in Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k0_small_dd(x: f64) -> f64 { let dx = DoubleDouble::from_exact_mult(x, x); const P: [(u64, u64); 6] = [ (0x3c1be095d044e896, 0x3fbdadb014541eb2), (0x3c7321baa1d0a2d9, 0x3fd1b9f19bc9019a), (0xbc33ce33a244e5bd, 0x3f94ec39f8744183), (0x3bd7008dfc623255, 0x3f3d85175b25727d), (0xbb4aa2a1c4905d30, 0x3ed007a860ef3235), (0xbae8daa77abd6f7f, 0x3e4839e32c19f31a), ]; let ps_num = f_polyeval3( dx.hi, f64::from_bits(0x3f3d85175b25727d), f64::from_bits(0x3ed007a860ef3235), f64::from_bits(0x3e4839e32c19f31a), ); let mut p_num = DoubleDouble::mul_f64_add(dx, ps_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 3] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc2a82a292acdc83, 0xbf91be3a25c968d6), (0xbb9d2c37183a6496, 0x3f23bac6961619d8), ]; let ps_den = f_polyeval3( dx.hi, f64::from_bits(0xbeac315b81faa1bf), f64::from_bits(0x3e2ab2d2fbae0863), f64::from_bits(0xbd9be23550f83df7), ); let mut p_den = DoubleDouble::mul_f64_add(dx, ps_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(dx, p_den, f64::from_bits(0x3ff0000000000000)); let prod = DoubleDouble::div(p_num, p_den); let vi_log = fast_log_d_to_dd(x); let vi = i0_0_to_1_fast(x); let r = DoubleDouble::mul_add(vi_log, -vi, prod); let err = r.hi * f64::from_bits(0x3c00000000000000); // 2^-63 let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } k0_small_hard(x, vi) } /** K0(x) + log(x) * I0(x) = P(x^2) hence K0(x) = P(x^2) - log(x)*I0(x) Generated in Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[cold] #[inline(never)] fn k0_small_hard(x: f64, vi: DoubleDouble) -> f64 { let dx = DoubleDouble::from_exact_mult(x, x); const P: [(u64, u64); 6] = [ (0x3c1be095d044e896, 0x3fbdadb014541eb2), (0x3c7321baa1d0a2d9, 0x3fd1b9f19bc9019a), (0xbc33ce33a244e5bd, 0x3f94ec39f8744183), (0x3bd7008dfc623255, 0x3f3d85175b25727d), (0xbb4aa2a1c4905d30, 0x3ed007a860ef3235), (0xbae8daa77abd6f7f, 0x3e4839e32c19f31a), ]; let mut p_num = DoubleDouble::mul_add( dx, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(dx, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 6] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc2a82a292acdc83, 0xbf91be3a25c968d6), (0xbb9d2c37183a6496, 0x3f23bac6961619d8), (0xbb32032e14c6c2b2, 0xbeac315b81faa1bf), (0x3aa1a1dc04bfba96, 0x3e2ab2d2fbae0863), (0x3a3e0f678099fcff, 0xbd9be23550f83df7), ]; let mut p_den = DoubleDouble::mul_add( dx, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(dx, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(dx, p_den, f64::from_bits(0x3ff0000000000000)); let prod = DoubleDouble::div(p_num, p_den); let v_log = log_dd(x); let r = DoubleDouble::mul_add(v_log, -vi, prod); r.to_f64() } /** Generated in Wolfram Computes sqrt(x)*exp(x)*K0(x)=Pn(1/x)/Qm(1/x) hence K0(x) = Pn(1/x)/Qm(1/x) / (sqrt(x) * exp(x)) ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k0_asympt(x: f64) -> f64 { let recip = DoubleDouble::from_quick_recip(x); let e = i0_exp(x * 0.5); let r_sqrt = DoubleDouble::from_sqrt(x); const P: [(u64, u64); 12] = [ (0xbc9a6a11d237114e, 0x3ff40d931ff62706), (0x3cdd614ddf4929e5, 0x4040645168c3e483), (0xbd1ecf9ea0af6ab2, 0x40757419a703a2ab), (0xbd3da3551fb27770, 0x409d4e65365522a2), (0xbd564d58855d1a46, 0x40b6dd32f5a199d9), (0xbd6cf055ca963a8e, 0x40c4fd2368f19618), (0x3d4b6cdfbdc058df, 0x40c68faa11ebcd59), (0x3d5b4ce4665bfa46, 0x40bb6fbe08e0a8ea), (0xbd4316909063be15, 0x40a1953103a5be31), (0x3d12f3f8edf41af0, 0x4074d2cb001e175c), (0xbcd7bba36540264f, 0x40316cffcad5f8f9), (0xbc6bf28dfdd5d37d, 0x3fc2f487fe78b8d7), ]; let x2 = DoubleDouble::quick_mult(recip, recip); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcb9e8a5b17e696a, 0x403a485acd64d64a), (0x3cd2e2e9c87f71f7, 0x4071518092320ecb), (0xbd0d05bdb9431a2f, 0x4097e57e4c22c08e), (0x3d5207068ab19ba9, 0x40b2ebadb2db62f9), (0xbd64e37674083471, 0x40c1c0e4e9d6493d), (0x3d3efb7a9a62b020, 0x40c3b94e8d62cdc7), (0x3d47d6ce80a2114b, 0x40b93c2fd39e868e), (0xbd1dfda61f525861, 0x40a1877a53a7f8d8), (0x3d1236ff523dfcfa, 0x4077c3a10c2827de), (0xbcc889997c9b0fe7, 0x4039a1d80b11c4a1), (0x3c7ded0e8d73dddc, 0x3fdafe4913722123), ]; let e0 = DoubleDouble::mul_add_f64( recip, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let z = DoubleDouble::div(p_num, p_den); let r = DoubleDouble::div(z, e * r_sqrt * e); let err = r.hi * f64::from_bits(0x3c10000000000000); // 2^-62 let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub != lb { return k0_asympt_hard(x); } r.to_f64() } /** Generated in Wolfram Computes sqrt(x)*exp(x)*K0(x)=Pn(1/x)/Qm(1/x) hence K0(x) = Pn(1/x)/Qm(1/x) / (sqrt(x) * exp(x)) ```text <90] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline(never)] #[cold] fn k0_asympt_hard(x: f64) -> f64 { static P: [DyadicFloat128; 15] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa06c98ff_b1382cb2_be520f51_a7b8f970_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -122, mantissa: 0xc84d8d0c_7faeef84_e56abccc_3d70f8a2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0xd1a71096_3da22280_35768c9e_0d3ddf42_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xf202e474_3698aabb_05688da0_ea1a088d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -112, mantissa: 0xaaa01830_8138af4d_1137b2dd_11a216f5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -110, mantissa: 0x99e0649f_320bca1a_c7adadb3_f5d8498e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xb4d81657_de1baf00_918cbc76_c6974e96_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -108, mantissa: 0x8a9a28c8_a61c2c7a_12416d56_51c0b3d3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -108, mantissa: 0x88a079f1_d9bd4582_6353316c_3aeb9dc9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xa82e10eb_9dc6225a_ef6223e7_54aa254d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0xf5fc07fe_6b652e8a_0b9e74ba_d0c56118_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -113, mantissa: 0xc5288444_c7354b24_4a4e1663_86488928_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -116, mantissa: 0x96d3d226_a220ae6e_d6cca1ae_40f01e27_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -121, mantissa: 0xa7ab931b_499c4964_499c1091_4ab9673d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf8373d1a_9ff3f9c6_e5cfbe0a_85ccc131_u128, }, ]; static Q: [DyadicFloat128; 15] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -122, mantissa: 0xa05190f4_dcf0d35c_277e0f21_0635c538_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0xa8837381_94c38992_86c0995d_5e5fa474_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xc3a4f279_9297e905_f59cc065_75959de8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -112, mantissa: 0x8b05ade4_03432e06_881ce37d_a907216d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0xfd77f85e_35626f21_355ae728_01b78cbe_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0x972ed117_254970eb_661121dc_a4462d2f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xec9d204a_9294ab57_2ef500d5_59d701b7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xf033522d_cae45860_53a01453_c56da895_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0x9a33640c_9896ead5_1ce040d7_b36544f3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0xefe714fa_49da0166_fdf8bc68_57b77fa0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -113, mantissa: 0xd323b84c_214196b0_e25b8931_930fea0d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -116, mantissa: 0xbbb5240b_346642d8_010383cb_1e8a607e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -120, mantissa: 0x88dcfa2a_f9f7d2ab_dd017994_8fae7e87_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc891477c_526e0f5e_74c4ae9f_9d8732b5_u128, }, ]; let recip = DyadicFloat128::accurate_reciprocal(x); let e = rational128_exp(x); let r_sqrt = bessel_rsqrt_hard(x, recip); let mut p0 = P[14]; for i in (0..14).rev() { p0 = recip * p0 + P[i]; } let mut q = Q[14]; for i in (0..14).rev() { q = recip * q + Q[i]; } let v = p0 * q.reciprocal(); let r = v * e.reciprocal() * r_sqrt; r.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_k0() { assert_eq!(f_k0(0.11), 2.3332678776741127); assert_eq!(f_k0(0.643), 0.7241025575342853); assert_eq!(f_k0(0.964), 0.4433737413379138); assert_eq!(f_k0(2.964), 0.03621679838808167); assert_eq!(f_k0(423.43), 7.784461905543397e-186); assert_eq!(f_k0(0.), f64::INFINITY); assert_eq!(f_k0(-0.), f64::INFINITY); assert!(f_k0(-0.5).is_nan()); assert!(f_k0(f64::NEG_INFINITY).is_nan()); assert_eq!(f_k0(f64::INFINITY), 0.); } } pxfm-0.1.23/src/bessel/k0f.rs000064400000000000000000000133141046102023000137550ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::i0f::i0f_small; use crate::common::f_fmla; use crate::exponents::core_expf; use crate::logs::fast_logf; use crate::polyeval::{f_estrin_polyeval7, f_estrin_polyeval8}; /// Modified Bessel of the second kind order 0 /// /// Max ULP 0.5 /// /// This method have exactly one exception which is not correctly rounded with FMA. pub fn f_k0f(x: f32) -> f32 { if x < 0. { return f32::NAN; } if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return f32::INFINITY; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f32::NAN }; } if x.is_nan() { return x + x; } } let xb = x.to_bits(); if xb >= 0x42cbc4fbu32 { // 101.88473 return 0.; } if xb <= 0x3f800000u32 { // 1.0 return k0f_small(x); } k0f_asympt(x) } /** K0(x) + log(x) * I0(x) = P(x^2) hence K0(x) = P(x^2) - log(x)*I0(x) Polynomial generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k0f_small(x: f32) -> f32 { let v_log = fast_logf(x); let i0 = i0f_small(x); let dx = x as f64; let p = f_estrin_polyeval7( dx * dx, f64::from_bits(0x3fbdadb014541ece), f64::from_bits(0x3fd1dadb01453e9c), f64::from_bits(0x3f99dadb01491ac7), f64::from_bits(0x3f4bb90e82a4f609), f64::from_bits(0x3eef4749ebd25b10), f64::from_bits(0x3e85d5b5668593af), f64::from_bits(0x3e15233b0788618b), ); let c = f_fmla(-i0, v_log, p); c as f32 } /** Generated in Wolfram Computes sqrt(x)*exp(x)*K0(x)=Pn(1/x)/Qm(1/x) hence K0(x) = Pn(1/x)/Qm(1/x) / (sqrt(x) * exp(x)) ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k0f_asympt(x: f32) -> f32 { let dx = x as f64; let recip = 1. / dx; let e = core_expf(x); let r_sqrt = dx.sqrt(); let p_num = f_estrin_polyeval8( recip, f64::from_bits(0x3ff40d931ff62701), f64::from_bits(0x402d8410a62d9c17), f64::from_bits(0x404e9f1804dd7e54), f64::from_bits(0x405c076822dcd255), f64::from_bits(0x4057379c6932949f), f64::from_bits(0x403ffd64a0bd54b7), f64::from_bits(0x400cc53ed733fd97), f64::from_bits(0x3faf8cc8756944eb), ); let p_den = f_estrin_polyeval8( recip, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4027ccde1d27ffc9), f64::from_bits(0x40492418136fb90f), f64::from_bits(0x4057be8a00983906), f64::from_bits(0x4054cc77d2379b76), f64::from_bits(0x403fd218713ec08d), f64::from_bits(0x4011c77649d3f65f), f64::from_bits(0x3fc2080a59e87324), ); let v = p_num / p_den; let pp = v / (e * r_sqrt); pp as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_k0f() { assert_eq!(f_k0f(2.034804e-5), 10.918458); assert_eq!(f_k0f(0.010260499), 4.695535); assert_eq!(f_k0f(0.3260499), 1.2965646); assert_eq!(f_k0f(0.72341), 0.636511734); assert_eq!(f_k0f(0.), f32::INFINITY); assert_eq!(f_k0f(-0.), f32::INFINITY); assert!(f_k0f(-0.5).is_nan()); assert!(f_k0f(f32::NEG_INFINITY).is_nan()); assert_eq!(f_k0f(f32::INFINITY), 0.); } } pxfm-0.1.23/src/bessel/k1.rs000064400000000000000000000543561046102023000136230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::i0::{bessel_rsqrt_hard, i0_exp}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::rational128_exp; use crate::logs::{fast_log_d_to_dd, log_dd}; use crate::polyeval::f_polyeval3; /// Modified Bessel of the second kind order 1 /// /// Max ULP 0.5 pub fn f_k1(x: f64) -> f64 { if x < 0. { return f64::NAN; } if !x.is_normal() { if x == 0. { return f64::INFINITY; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f64::NAN }; } if x.is_nan() { return x + x; } } let xb = x.to_bits(); if xb >= 0x4086140538aa7d38u64 { // 706.5025494880165 return 0.; } if xb <= 0x3ff0000000000000 { return k1_small(x); } k1_asympt(x) } // Generated by Wolfram Mathematica: // <60] // poly=Numerator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] #[inline] fn i1_fast(x: f64) -> DoubleDouble { let dx = x; const ONE_OVER_4: f64 = 1. / 4.; let eval_x = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(dx, dx), ONE_OVER_4); const P: [(u64, u64); 3] = [ (0x3c5555555553c008, 0x3fb5555555555555), (0x3c06f1014b703de8, 0x3f6dfda17d0a2cef), (0xbbc2594d655d84db, 0x3f21b2c299108f7b), ]; let ps_num = f_polyeval3( eval_x.hi, f64::from_bits(0x3ec37625c178f5e2), f64::from_bits(0x3e5843215f0d5088), f64::from_bits(0x3dd97f1f45f47244), ); let mut p_num = DoubleDouble::mul_f64_add(eval_x, ps_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(eval_x, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 3] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc32ebd3ac0e6253, 0xbfa42c718ce308f7), (0xbbe1626e81e3c1bc, 0x3f482772320eab0e), ]; let ps_den = f_polyeval3( eval_x.hi, f64::from_bits(0xbee169811ef4f4a1), f64::from_bits(0x3e6ebdab5dbe02a5), f64::from_bits(0xbdeb1dbb29fec52a), ); let mut p_den = DoubleDouble::mul_f64_add(eval_x, ps_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add(eval_x, p_den, DoubleDouble::from_bit_pair(Q[0])); let p = DoubleDouble::div(p_num, p_den); let eval_sqr = DoubleDouble::quick_mult(eval_x, eval_x); let mut z = DoubleDouble::mul_f64_add_f64(eval_x, 0.5, 1.); z = DoubleDouble::mul_add(p, eval_sqr, z); let x_over_05 = DoubleDouble::from_exact_mult(x, 0.5); DoubleDouble::quick_mult(z, x_over_05) } /** Series for f(x) := BesselK(1, x) - Log(x)*BesselI(1, x) - 1/x Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k1_small(x: f64) -> f64 { let rcp = DoubleDouble::from_quick_recip(x); let x2 = DoubleDouble::from_exact_mult(x, x); const P: [(u64, u64); 6] = [ (0xbc7037c12b888927, 0xbfd3b5b6028a83d6), (0x3c39dba459d023e5, 0xbfb4bac288cfe0cd), (0x3be0575395050120, 0xbf6c4a1abe9061df), (0x3b755df8e375b3d4, 0xbf0c850679678599), (0xbb097e0ec926785f, 0xbe98c4a9b608ae1f), (0xbaa029f31c786e81, 0xbe104efe2246ee51), ]; let ps_num = f_polyeval3( x2.hi, f64::from_bits(0xbf0c850679678599), f64::from_bits(0xbe98c4a9b608ae1f), f64::from_bits(0xbe104efe2246ee51), ); let mut p_num = DoubleDouble::mul_f64_add(x2, ps_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(x2, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(x2, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 5] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c19f62e592f3e71, 0xbf8d3bd595449ca9), (0xbba8472b975a12d7, 0x3f194de71babe24a), (0xbb2eec4b611c19b5, 0xbe994a5dbec84e4d), (0x3a9bae2028402903, 0x3e0981ded64a954b), ]; let ps_den = f_fmla( x2.hi, f64::from_bits(0x3e0981ded64a954b), f64::from_bits(0xbe994a5dbec84e4d), ); let mut p_den = DoubleDouble::mul_f64_add(x2, ps_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(x2, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(x2, p_den, f64::from_bits(0x3ff0000000000000)); let p = DoubleDouble::div(p_num, p_den); let lg = fast_log_d_to_dd(x); let v_i = i1_fast(x); let z = DoubleDouble::mul_add(v_i, lg, rcp); let r = DoubleDouble::mul_f64_add(p, x, z); let err = f_fmla( r.hi, f64::from_bits(0x3c20000000000000), // 2^-61 f64::from_bits(0x3a80000000000000), // 2^-87 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } k1_small_hard(x) } /** Generated by SageMath: ```text euler_gamma = R(euler) lg = R(2).log() expr = (z**17 * (R(-6989) + R(2520) * euler_gamma - R(2520) * lg))/R('4832746593583104000') \ + (z**15 * (R(-1487)+R(560) * euler_gamma-R(560) *lg))/R('3728971137024000')\ +(z**13 * (R(-353)+R(140) * euler_gamma-R(140) * lg))/R('4161798144000')\ +(z**9 * (R(-131)+R(60) * euler_gamma-R(60) * lg))/R('88473600')\ +(z**11 * (R(-71)+R(30) * euler_gamma - R(30) *lg))/R('5308416000')+(z**7 * (R(-47)+R(24) * euler_gamma - R(24) * lg))/R(442368)\ +R(1/R(64)) * z**3 * (R(-5)+R(4) * euler_gamma-R(4) * lg)+ R(1/4) * z * (R(-1)+R(2) * euler_gamma-lg4)+(z**5 * (R(-5)+R(3) *euler_gamma-lg8))/R(1152)\ + (z**21 * (R(-82451)+R(27720) * euler_gamma-R(27720) * lg))/R('8420577664659200409600000')\ + (z**23 * (R(-42433)+R('13860') * euler_gamma-R('13860') * lg))/R('2223032503470028908134400000')\ + (z**25 * (R('-1132133')+R('360360') * euler_gamma-R('360360')* lg))/R('36066479336297749005572505600000')\ + (z**27 * (R('-1158863')+R('360360') * euler_gamma - R('360360') * lg))/R('26256396956824761276056784076800000')\ + (z**29 * (R('-236749')+R('72072') * euler_gamma-R('72072') * lg))/R('4411074688746559894377539724902400000')\ + (z**31 * (R('-4828073') + R('1441440') * euler_gamma - R('1441440') * lg))/R('84692634023933949972048762718126080000000') ``` **/ #[cold] #[inline(never)] fn k1_small_hard(x: f64) -> f64 { let rcp = DoubleDouble::from_quick_recip(x); let x2 = DoubleDouble::from_exact_mult(x, x); const P: [(u64, u64); 6] = [ (0xbc7037c12b888927, 0xbfd3b5b6028a83d6), (0x3c39dba459d023e5, 0xbfb4bac288cfe0cd), (0x3be0575395050120, 0xbf6c4a1abe9061df), (0x3b755df8e375b3d4, 0xbf0c850679678599), (0xbb097e0ec926785f, 0xbe98c4a9b608ae1f), (0xbaa029f31c786e81, 0xbe104efe2246ee51), ]; let mut p_num = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); p_num = DoubleDouble::mul_add(x2, p_num, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(x2, p_num, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(x2, p_num, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(x2, p_num, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 5] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c19f62e592f3e71, 0xbf8d3bd595449ca9), (0xbba8472b975a12d7, 0x3f194de71babe24a), (0xbb2eec4b611c19b5, 0xbe994a5dbec84e4d), (0x3a9bae2028402903, 0x3e0981ded64a954b), ]; let mut p_den = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(Q[4]), DoubleDouble::from_bit_pair(Q[3]), ); p_den = DoubleDouble::mul_add(x2, p_den, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(x2, p_den, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add(x2, p_den, DoubleDouble::from_bit_pair(Q[0])); let p = DoubleDouble::div(p_num, p_den); let lg = log_dd(x); let v_i = i1_fast(x); let z = DoubleDouble::mul_add(v_i, lg, rcp); let r = DoubleDouble::mul_f64_add(p, x, z); r.to_f64() } /** Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k1_asympt(x: f64) -> f64 { let recip = DoubleDouble::from_quick_recip(x); let e = i0_exp(x * 0.5); let r_sqrt = DoubleDouble::from_sqrt(x); const P: [(u64, u64); 12] = [ (0xbc9a6a0690becb3b, 0x3ff40d931ff62706), (0xbce573e1bbf2f0b7, 0x40402cebfab5721d), (0x3d11a739b7c11e7b, 0x4074f58abc0cfbf1), (0xbd2682a09ded0116, 0x409c8315f8facef2), (0xbd3a19e91a120168, 0x40b65f7a4caed8b9), (0x3d449c3d2b834543, 0x40c4fe41fdb4e7b8), (0xbd6bdd415ac7f7e1, 0x40c7aa402d035d03), (0x3d528412ff0d6b24, 0x40bf68faddd7d850), (0xbd48f4bb3f61dac6, 0x40a75f5650249952), (0xbd1dc534b275e309, 0x4081bddd259c0582), (0xbcce5103350bd226, 0x4046c7a049014484), (0x3c8935f8acd6c1d0, 0x3fef7524082b1859), ]; let x2 = DoubleDouble::quick_mult(recip, recip); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3cc0d2508437b3f4, 0x40396ff483adec14), (0xbd130a9c9f8a5338, 0x4070225588d8c15d), (0xbceceba8fa0e65a2, 0x4095481f6684e3bb), (0x3d4099f3c178fd2a, 0x40afedc8a778bf42), (0xbd3a7e6a6276a3e7, 0x40bc0c060112692e), (0x3d11538c155b16d8, 0x40bcb12bd1101782), (0xbd5f7b04cdea2c61, 0x40b07fa363202e10), (0xbce444ed035b66c6, 0x4093d6fe8f44f838), (0xbcf6f88fb942b610, 0x4065c99fa44030c3), (0xbcbd1d2aedee5bc9, 0x40207ffabeb00eea), (0xbc39a0c8091102c9, 0x3facff3d892cd57a), ]; let e0 = DoubleDouble::mul_add_f64( recip, DoubleDouble::from_bit_pair(Q[1]), f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_add( recip, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let z = DoubleDouble::div(p_num, p_den); let mut r_e = DoubleDouble::quick_mult(e, r_sqrt); r_e = DoubleDouble::from_exact_add(r_e.hi, r_e.lo); r_e = DoubleDouble::quick_mult(r_e, e); r_e = DoubleDouble::from_exact_add(r_e.hi, r_e.lo); let r = DoubleDouble::div(z, r_e); let err = r.hi * f64::from_bits(0x3c10000000000000); // 2^-61 let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub != lb { return k1_asympt_hard(x); } r.to_f64() } /** Generated by Wolfram Mathematica: ```text <70] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[cold] #[inline(never)] fn k1_asympt_hard(x: f64) -> f64 { static P: [DyadicFloat128; 15] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa06c98ff_b1382cb2_be5210ac_f26f25d1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -122, mantissa: 0xc5f546cb_659a39d0_fafbd188_36ca05b9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0xcd0b7cfa_de158d26_7084bbe9_f1bdb66d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xeac7be2f_957d1260_8849508a_2a5a8972_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -112, mantissa: 0xa4d14fec_fecc6444_4c7b0287_dad71a86_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -110, mantissa: 0x94e3180c_01df9932_ad2acd8b_bab59c05_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xb0de10f8_74918442_94a96368_8eaa4d0d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -108, mantissa: 0x8adfea76_d6dbe5d9_46bfaf83_9341f4b5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -108, mantissa: 0x8f0a4337_b69b602c_cf187222_f3a3379f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xbd4c3ebf_c2db0fad_1b425641_cc470043_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -110, mantissa: 0x9b14d29f_9b97e3c8_c1a7b9d0_787f0ddb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -112, mantissa: 0x93e670d2_07a553ef_a90d4895_cf1b5011_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0x93e0ee0a_cb4d8910_6b4d3e37_f4f9df49_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -120, mantissa: 0xff0ce10d_5585abd1_e8a53a12_65131ad4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0xf020536d_822cbe51_c8de095a_03367c83_u128, }, ]; static Q: [DyadicFloat128; 15] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -122, mantissa: 0x9c729dd5_4828a918_42807f58_d485a511_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -118, mantissa: 0x9ff6f631_0794001d_433ab0c5_d4c682a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xb3f81e8b_1e0e85a6_3928342e_c83088a1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -113, mantissa: 0xf6b1c203_a60d4294_239ad045_2c67c224_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0xd7a98b14_7a499762_abde5c38_3a5b40e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -110, mantissa: 0xf4eb8b77_a2cdc686_afd1273f_d464c8b7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xb4c1e12a_93ee86fc_930c6f94_cfa6ac3a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -109, mantissa: 0xaaeaab88_32b776b7_fdd76b0f_24349f41_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -110, mantissa: 0xc8ec9d61_5bf2ee9b_878b4962_4a5cee85_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -111, mantissa: 0x8b97bab0_3351673f_22f10d40_fd1c9ff3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -114, mantissa: 0xd31cb80a_bf8cbedc_b0dcf7e7_c599f79e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -117, mantissa: 0x96b354c8_69197193_ea4f608f_81943988_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -122, mantissa: 0x989af1bb_e48b5c44_7cd09746_f15e935a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb7b51326_23c29ed5_8d3dcf5a_79bd9a4f_u128, }, ]; let recip = DyadicFloat128::accurate_reciprocal(x); let e = rational128_exp(x); let r_sqrt = bessel_rsqrt_hard(x, recip); let mut p0 = P[14]; for i in (0..14).rev() { p0 = recip * p0 + P[i]; } let mut q0 = Q[14]; for i in (0..14).rev() { q0 = recip * q0 + Q[i]; } let v = p0 * q0.reciprocal(); let r = v * (e.reciprocal() * r_sqrt); r.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_k1() { assert_eq!(f_k1(0.643), 1.184534109892725); assert_eq!(f_k1(0.964), 0.6402280656771248); assert_eq!(f_k1(2.964), 0.04192888446074039); assert_eq!(f_k1(8.43), 9.824733212831289e-5); assert_eq!(f_k1(16.43), 2.3142404075259965e-8); assert_eq!(f_k1(423.43), 7.793648638470207e-186); assert_eq!(f_k1(0.), f64::INFINITY); assert_eq!(f_k1(-0.), f64::INFINITY); assert!(f_k1(-0.5).is_nan()); assert!(f_k1(f64::NEG_INFINITY).is_nan()); assert_eq!(f_k1(f64::INFINITY), 0.); } } pxfm-0.1.23/src/bessel/k1f.rs000064400000000000000000000163621046102023000137640ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::exponents::core_expf; use crate::logs::fast_logf; use crate::polyeval::{f_estrin_polyeval8, f_polyeval3, f_polyeval4}; /// Modified Bessel of the second kind order 1 /// /// Max ULP 0.5 pub fn f_k1f(x: f32) -> f32 { if x < 0. { return f32::NAN; } if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return f32::INFINITY; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f32::NAN }; } if x.is_nan() { return x + x; } } let xb = x.to_bits(); if xb >= 0x42cbc779u32 { // 101.889595 return 0.; } if xb <= 0x3f800000u32 { // 1.0 return k1f_small(x); } k1f_asympt(x) } /** Computes I1(x) = x/2 * (1 + 1 * (x/2)^2 + (x/2)^4 * P((x/2)^2)) Generated by Woflram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i1f_small(x: f32) -> f64 { let dx = x as f64; let x_over_two = dx * 0.5; let x_over_two_sqr = x_over_two * x_over_two; let x_over_two_p4 = x_over_two_sqr * x_over_two_sqr; let p_num = f_polyeval4( x_over_two_sqr, f64::from_bits(0x3fb5555555555355), f64::from_bits(0x3f6ebf07f0dbc49b), f64::from_bits(0x3f1fdc02bf28a8d9), f64::from_bits(0x3ebb5e7574c700a6), ); let p_den = f_polyeval3( x_over_two_sqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfa39b64b6135b5a), f64::from_bits(0x3f3fa729bbe951f9), ); let p = p_num / p_den; let p1 = f_fmla(0.5, x_over_two_sqr, 1.); let p2 = f_fmla(x_over_two_p4, p, p1); p2 * x_over_two } /** Series for f(x) := BesselK(1, x) - Log(x)*BesselI(1, x) - 1/x Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k1f_small(x: f32) -> f32 { let dx = x as f64; let rcp = 1. / dx; let x2 = dx * dx; let p_num = f_polyeval4( x2, f64::from_bits(0xbfd3b5b6028a83d6), f64::from_bits(0xbfb3fde2c83f7cca), f64::from_bits(0xbf662b2e5defbe8c), f64::from_bits(0xbefa2a63cc5c4feb), ); let p_den = f_polyeval4( x2, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbf9833197207a7c6), f64::from_bits(0x3f315663bc7330ef), f64::from_bits(0xbeb9211958f6b8c3), ); let p = p_num / p_den; let lg = fast_logf(x); let v_i = i1f_small(x); let z = f_fmla(lg, v_i, rcp); let z0 = f_fmla(p, dx, z); z0 as f32 } /** Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k1f_asympt(x: f32) -> f32 { let dx = x as f64; let recip = 1. / dx; let e = core_expf(x); let r_sqrt = dx.sqrt(); let p_num = f_estrin_polyeval8( recip, f64::from_bits(0x3ff40d931ff6270d), f64::from_bits(0x402d250670ed7a6c), f64::from_bits(0x404e517b9b494d38), f64::from_bits(0x405cb02b7433a838), f64::from_bits(0x405a03e606a1b871), f64::from_bits(0x4045c98d4308dbcd), f64::from_bits(0x401d115c4ce0540c), f64::from_bits(0x3fd4213e72b24b3a), ); let p_den = f_estrin_polyeval8( recip, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x402681096aa3a87d), f64::from_bits(0x404623ab8d72ceea), f64::from_bits(0x40530af06ea802b2), f64::from_bits(0x404d526906fb9cec), f64::from_bits(0x403281caca389f1b), f64::from_bits(0x3ffdb93996948bb4), f64::from_bits(0x3f9a009da07eb989), ); let v = p_num / p_den; let pp = v / (e * r_sqrt); pp as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_k1f() { assert_eq!(f_k1f(0.3), 3.055992); assert_eq!(f_k1f(1.89), 0.16180483); assert_eq!(f_k1f(5.89), 0.0015156545); assert_eq!(f_k1f(101.89), 0.); assert_eq!(f_k1f(0.), f32::INFINITY); assert_eq!(f_k1f(-0.), f32::INFINITY); assert!(f_k1f(-0.5).is_nan()); assert!(f_k1f(f32::NEG_INFINITY).is_nan()); assert_eq!(f_k1f(f32::INFINITY), 0.); } } pxfm-0.1.23/src/bessel/k2f.rs000064400000000000000000000216621046102023000137640ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::exponents::core_expf; use crate::logs::fast_logf; use crate::polyeval::{f_estrin_polyeval5, f_estrin_polyeval8, f_polyeval4, f_polyeval11}; /// Modified Bessel of the second kind of order 2 /// /// ulp 0.5 pub fn f_k2f(x: f32) -> f32 { if x < 0. { return f32::NAN; } let xb = x.to_bits(); if (xb & 0x0007_ffff) == 0 { if x == 0. { return f32::INFINITY; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f32::NAN }; } if x.is_nan() { return x + x; } } if xb >= 0x42cbceefu32 { // |x| >= 101.90417 return 0.; } if xb <= 0x34000000u32 { // x <= f32::EPSILON let dx = x as f64; let r = 2. / (dx * dx); return r as f32; } if xb <= 0x3f800000u32 { if xb <= 0x3e9eb852u32 { // x < 0.31 return k2f_tiny(x); } // x < 1.0 return k2f_small(x); } k2f_asympt(x) } #[inline] fn k2f_tiny(x: f32) -> f32 { // Power series at zero for K2 // 2.0000000000000000/x^2-0.50000000000000000-0.12500000000000000 (-0.86593151565841245+1.0000000000000000 Log[x]) x^2-0.010416666666666667 (-1.5325981823250791+1.0000000000000000 Log[x]) x^4-0.00032552083333333333 (-1.9075981823250791+1.0000000000000000 Log[x]) x^6-0.0000054253472222222222 (-2.1742648489917458+1.0000000000000000 Log[x]) x^8+O[x]^9 //-0.50000000000000000+2.0000000000000000/x^2 + a3 * x^8 + x^6 * a2 + x^4 * a1 + x^2 * a0 let dx = x as f64; let log_x = fast_logf(x); let a0 = f_fmla(-4.0000000000000000, log_x, 3.4637260626336498) * 0.031250000000000000; let a1 = f_fmla(-12.000000000000000, log_x, 18.391178187900949) * 0.00086805555555555556; let a2 = f_fmla(-24.000000000000000, log_x, 45.782356375801899) * 0.000013563368055555556; let a3 = (log_x - 2.1742648489917458) * (-0.0000054253472222222222); let dx_sqr = dx * dx; let two_over_dx = 2. / dx_sqr; let p = f_polyeval4(dx_sqr, a0, a1, a2, a3); let r = f_fmla(p, dx_sqr, two_over_dx) - 0.5; r as f32 } /** Computes I2(x) = x^2 * R(x^2) Generated by Wolfram Mathematica: ```text <75] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn i2f_small(x: f32) -> f64 { let dx = x as f64; let x_sqr = dx * dx; let p_num = f_estrin_polyeval5( x_sqr, f64::from_bits(0x3fc0000000000000), f64::from_bits(0x3f81520c0669099e), f64::from_bits(0x3f27310bf5c5e9b0), f64::from_bits(0x3eb8e2947e0a6098), f64::from_bits(0x3e336dfad46e2f35), ); let p_den = f_estrin_polyeval5( x_sqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbf900d253bb12edc), f64::from_bits(0x3f1ed3d9ab228297), f64::from_bits(0xbea14e6660c00303), f64::from_bits(0x3e13eb951a6cf38f), ); let p = p_num / p_den; p * x_sqr } /** Series for R(x^2) := (BesselK(2, x) - Log(x)*BesselI(2, x) - 2/x^2)/(1+x^2) Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k2f_small(x: f32) -> f32 { let dx = x as f64; let dx_sqr = dx * dx; let p_num = f_polyeval11( dx_sqr, f64::from_bits(0xbfdff794c9ee3b5c), f64::from_bits(0xc047d3276f18e5d2), f64::from_bits(0xc09200ed3702875a), f64::from_bits(0xc0c39f395c47be27), f64::from_bits(0xc0e0ec95bd1a3192), f64::from_bits(0xc0e5973cb871c8d0), f64::from_bits(0xc0cdaf528de00d53), f64::from_bits(0xc0afe6d3009de17c), f64::from_bits(0xc098417b22844112), f64::from_bits(0x4025c45260bb1b6a), f64::from_bits(0x402f2bf6b95ffe0c), ); let p_den = f_polyeval11( dx_sqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x405879a43b253224), f64::from_bits(0x40a3a501408a0198), f64::from_bits(0x40d8172abc4a8ccc), f64::from_bits(0x40f9fcb05e98bdbd), f64::from_bits(0x4109c45b54be586b), f64::from_bits(0x4106ad7023dd0b90), f64::from_bits(0x40ed7e988d2ba5a9), f64::from_bits(0x40966305e1c1123a), f64::from_bits(0xc090832b6a87317c), f64::from_bits(0x403b48eb703f4644), ); let p = p_num / p_den; let two_over_dx_sqr = 2. / dx_sqr; let lg = fast_logf(x); let v_i = i2f_small(x); let z = f_fmla(lg, v_i, two_over_dx_sqr); let z0 = f_fmla(p, f_fmla(dx, dx, 1.), z); z0 as f32 } /** Generated by Wolfram Mathematica: ```text <60] poly=Numerator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=Denominator[approx][[1]]; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ #[inline] fn k2f_asympt(x: f32) -> f32 { let dx = x as f64; let recip = 1. / dx; let e = core_expf(x); let r_sqrt = dx.sqrt(); let p_num = f_estrin_polyeval8( recip, f64::from_bits(0x3ff40d931ff626f2), f64::from_bits(0x402d954dceb445df), f64::from_bits(0x405084ea6680d028), f64::from_bits(0x406242344a8ea488), f64::from_bits(0x406594aa56f50fea), f64::from_bits(0x405aa04eb4f0af1c), f64::from_bits(0x403dd3e8e63849ef), f64::from_bits(0x4004e85453648d43), ); let p_den = f_estrin_polyeval8( recip, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4023da9f4e05358e), f64::from_bits(0x4040a4e4ceb523c9), f64::from_bits(0x404725c423c9f990), f64::from_bits(0x403a60c00deededc), f64::from_bits(0x40149975b84c3946), f64::from_bits(0x3fc69439846db871), f64::from_bits(0xbf6400819bac6f45), ); let v = p_num / p_den; let pp = v / (e * r_sqrt); pp as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_k2f() { assert!(f_k2f(-1.).is_nan()); assert!(f_k2f(f32::NAN).is_nan()); assert_eq!(f_k2f(0.), f32::INFINITY); assert_eq!(f_k2f(0.65), 4.3059196); assert_eq!(f_k2f(1.65), 0.44830766); } } pxfm-0.1.23/src/bessel/mod.rs000064400000000000000000000047621046102023000140630ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![deny(unreachable_pub)] mod alpha0; mod alpha1; mod beta0; mod beta1; mod i0; mod i0f; mod i1; mod i1f; mod i2; mod i2f; mod j0; mod j0_coeffs_remez; mod j0_coeffs_taylor; mod j0f; mod j0f_coeffs; mod j1; mod j1_coeffs; mod j1_coeffs_taylor; mod j1f; mod j1f_coeffs; mod jincpi; mod jincpif; mod k0; mod k0f; mod k1; mod k1f; mod k2f; mod y0; mod y0_coeffs; mod y0_coeffs_taylor; mod y0f; mod y0f_coeffs; mod y1; mod y1_coeffs; mod y1_coeffs_taylor; mod y1f; mod y1f_coeffs; pub use i0::f_i0; pub use i0f::f_i0f; pub use i1::f_i1; pub use i1f::f_i1f; pub use i2::f_i2; pub use i2f::f_i2f; pub use j0::f_j0; pub use j0f::f_j0f; pub use j1::f_j1; pub use j1f::f_j1f; pub use jincpi::f_jincpi; pub use jincpif::f_jincpif; pub use k0::f_k0; pub use k0f::f_k0f; pub use k1::f_k1; pub use k1f::f_k1f; pub use k2f::f_k2f; pub use y0::f_y0; pub use y0f::f_y0f; pub use y1::f_y1; pub use y1f::f_y1f; pxfm-0.1.23/src/bessel/y0.rs000064400000000000000000001071071046102023000136310ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::alpha0::{ bessel_0_asympt_alpha, bessel_0_asympt_alpha_fast, bessel_0_asympt_alpha_hard, }; use crate::bessel::beta0::{ bessel_0_asympt_beta, bessel_0_asympt_beta_fast, bessel_0_asympt_beta_hard, }; use crate::bessel::i0::bessel_rsqrt_hard; use crate::bessel::j0::j0_maclaurin_series; use crate::bessel::y0_coeffs::Y0_COEFFS; use crate::bessel::y0_coeffs_taylor::Y0_COEFFS_TAYLOR; use crate::bessel::y0f_coeffs::{Y0_ZEROS, Y0_ZEROS_VALUES}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log_dd_fast; use crate::polyeval::{f_polyeval12, f_polyeval13, f_polyeval15, f_polyeval22, f_polyeval24}; use crate::sin_helper::{sin_dd_small, sin_dd_small_fast, sin_f128_small}; use crate::sincos_reduce::{AngleReduced, rem2pi_any, rem2pi_f128}; /// Bessel of the second kind of order 0 (Y0) pub fn f_y0(x: f64) -> f64 { if x < 0. { return f64::NAN; } if !x.is_normal() { if x == 0. { return f64::NEG_INFINITY; } if x.is_nan() { return x + x; } if x.is_infinite() { if x.is_sign_negative() { return f64::NAN; } return 0.; } } let xb = x.to_bits(); if xb <= 0x3ff599999999999au64 { // 1.35 return y0_near_zero_fast(x); } // transient zone from 1.46 to 2 have bad behaviour for log poly already, // and not yet good to be easily covered, thus it use its own poly if xb <= 0x4000000000000000u64 { // 2 return y0_transient_area_fast(x); } if xb <= 0x4052d9999999999au64 { // 75.4 return y0_small_argument_fast(x); } y0_asympt_fast(x) } /** Generated by SageMath: Evaluates: Y0(x) = 2/pi*(euler_gamma + log(x/2))*J0(x) - sum((-1)^m*(x/2)^(2*m)/(m!)^2*sum(1+1/2 + ... 1/m)) expressed as: Y0(x)=log(x)*W0(x) - Z0(x) ```python from sage.all import * R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() N = 10 # Number of terms (adjust as needed) gamma = RealField(300)(euler_gamma) d2 = RealField(300)(2) pi = RealField(300).pi() # Define J0(x) Taylor expansion at x = 0 def j_series(n, x): return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)]) J0_series = j_series(0, x) def z_series(x): return sum([(-1)**m * (x/2)**(ZZ(2)*ZZ(m)) / ZZ(m).factorial()**ZZ(2) * sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) for m in range(1, N)]) W0 = (d2/pi) * J0_series Z0 = -gamma * (d2/pi) * J0_series + RealField(300)(2).log() * (d2/pi) * J0_series + (d2/pi) * z_series(x) # see the series print(W0) print(Z0) ``` **/ #[inline] fn y0_near_zero_fast(x: f64) -> f64 { const W: [(u64, u64); 15] = [ (0xbc86b01ec5417056, 0x3fe45f306dc9c883), (0x3c66b01ec5417056, 0xbfc45f306dc9c883), (0xbc26b01ec5417056, 0x3f845f306dc9c883), (0xbbd67fe4a5feb897, 0xbf321bb945252402), (0x3b767fe4a5feb897, 0x3ed21bb945252402), (0xbaf5c2495706f745, 0xbe672db9f21b0f5f), (0x3a90c8209874dfad, 0x3df49a6c656d62ff), (0x3a12921e91b07dd0, 0xbd7ae90af76a4d0f), (0xb992921e91b07dd0, 0x3cfae90af76a4d0f), (0x39089b0d8a9228ca, 0xbc754331c053fdad), (0x3878d321ddfd3c6e, 0x3beb3749ebf0a0dd), (0x37e77548130d809b, 0xbb5cca5ae46eae67), (0xb73a848e7ca1c943, 0x3ac9976d3cd4293f), (0xb6c884706195a054, 0xba336206ff1ce731), (0xb6387a7d2389630d, 0x39995103e9f1818f), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let w0 = f_polyeval12( x2.hi, f64::from_bits(W[3].1), f64::from_bits(W[4].1), f64::from_bits(W[5].1), f64::from_bits(W[6].1), f64::from_bits(W[7].1), f64::from_bits(W[8].1), f64::from_bits(W[9].1), f64::from_bits(W[10].1), f64::from_bits(W[11].1), f64::from_bits(W[12].1), f64::from_bits(W[13].1), f64::from_bits(W[14].1), ); let mut w = DoubleDouble::mul_f64_add(x2, w0, DoubleDouble::from_bit_pair(W[2])); w = DoubleDouble::mul_add(x2, w, DoubleDouble::from_bit_pair(W[1])); w = DoubleDouble::mul_add(x2, w, DoubleDouble::from_bit_pair(W[0])); const Z: [(u64, u64); 15] = [ (0xbc5ddfd831a70821, 0x3fb2e4d699cbd01f), (0xbc6d93e63489aea6, 0xbfc6bbcb41034286), (0xbc1b88525c2e130b, 0x3f9075b1bbf41364), (0x3be097334e26e578, 0xbf41a6206b7b973d), (0x3b51c64a34c78cda, 0x3ee3e99794203bbd), (0xbb1c407b0f5b2805, 0xbe7bce4a600d3ea4), (0xbaa57d1e1e88c9ca, 0x3e0a6ee796b871b6), (0x3a3b6e7030a77899, 0xbd92393d82c6b2e4), (0x397fcfedacb03781, 0x3d131085da82054c), (0xb8e45f51f6118e46, 0xbc8f4ed4b492ebcc), (0xb89bd46046c3c8de, 0x3c04b7ac8a1b15d0), (0x37d1a206fb205e32, 0xbb769201941d0d49), (0x3782f38acbf23993, 0x3ae4987e587ab039), (0x36b691bdabf5672b, 0xba4ff1953e0a7c5b), (0x3636e1c8cd260e18, 0x39b55031dc5e1967), ]; let z0 = f_polyeval12( x2.hi, f64::from_bits(Z[3].1), f64::from_bits(Z[4].1), f64::from_bits(Z[5].1), f64::from_bits(Z[6].1), f64::from_bits(Z[7].1), f64::from_bits(Z[8].1), f64::from_bits(Z[9].1), f64::from_bits(Z[10].1), f64::from_bits(Z[11].1), f64::from_bits(Z[12].1), f64::from_bits(Z[13].1), f64::from_bits(Z[14].1), ); let mut z = DoubleDouble::mul_f64_add(x2, z0, DoubleDouble::from_bit_pair(Z[2])); z = DoubleDouble::mul_add(x2, z, DoubleDouble::from_bit_pair(Z[1])); z = DoubleDouble::mul_add(x2, z, DoubleDouble::from_bit_pair(Z[0])); let w_log = log_dd_fast(x); let p = DoubleDouble::mul_add(w, w_log, -z); let err = f_fmla( p.hi, f64::from_bits(0x3c50000000000000), // 2^-58 f64::from_bits(0x3c30000000000000), // 2^-60 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y0_near_zero(x, w_log) } /** Generated by SageMath: Evaluates: Y0(x) = 2/pi*(euler_gamma + log(x/2))*J0(x) - sum((-1)^m*(x/2)^(2*m)/(m!)^2*sum(1+1/2 + ... 1/m)) expressed as: Y0(x)=log(x)*W0(x) - Z0(x) ```python from sage.all import * R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() N = 10 # Number of terms (adjust as needed) gamma = RealField(300)(euler_gamma) d2 = RealField(300)(2) pi = RealField(300).pi() # Define J0(x) Taylor expansion at x = 0 def j_series(n, x): return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)]) J0_series = j_series(0, x) def z_series(x): return sum([(-1)**m * (x/2)**(ZZ(2)*ZZ(m)) / ZZ(m).factorial()**ZZ(2) * sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) for m in range(1, N)]) W0 = (d2/pi) * J0_series Z0 = -gamma * (d2/pi) * J0_series + RealField(300)(2).log() * (d2/pi) * J0_series + (d2/pi) * z_series(x) # see the series print(W0) print(Z0) ``` **/ #[cold] #[inline(never)] fn y0_near_zero(x: f64, w_log: DoubleDouble) -> f64 { const W: [(u64, u64); 15] = [ (0xbc86b01ec5417056, 0x3fe45f306dc9c883), (0x3c66b01ec5417056, 0xbfc45f306dc9c883), (0xbc26b01ec5417056, 0x3f845f306dc9c883), (0xbbd67fe4a5feb897, 0xbf321bb945252402), (0x3b767fe4a5feb897, 0x3ed21bb945252402), (0xbaf5c2495706f745, 0xbe672db9f21b0f5f), (0x3a90c8209874dfad, 0x3df49a6c656d62ff), (0x3a12921e91b07dd0, 0xbd7ae90af76a4d0f), (0xb992921e91b07dd0, 0x3cfae90af76a4d0f), (0x39089b0d8a9228ca, 0xbc754331c053fdad), (0x3878d321ddfd3c6e, 0x3beb3749ebf0a0dd), (0x37e77548130d809b, 0xbb5cca5ae46eae67), (0xb73a848e7ca1c943, 0x3ac9976d3cd4293f), (0xb6c884706195a054, 0xba336206ff1ce731), (0xb6387a7d2389630d, 0x39995103e9f1818f), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let w = f_polyeval15( x2, DoubleDouble::from_bit_pair(W[0]), DoubleDouble::from_bit_pair(W[1]), DoubleDouble::from_bit_pair(W[2]), DoubleDouble::from_bit_pair(W[3]), DoubleDouble::from_bit_pair(W[4]), DoubleDouble::from_bit_pair(W[5]), DoubleDouble::from_bit_pair(W[6]), DoubleDouble::from_bit_pair(W[7]), DoubleDouble::from_bit_pair(W[8]), DoubleDouble::from_bit_pair(W[9]), DoubleDouble::from_bit_pair(W[10]), DoubleDouble::from_bit_pair(W[11]), DoubleDouble::from_bit_pair(W[12]), DoubleDouble::from_bit_pair(W[13]), DoubleDouble::from_bit_pair(W[14]), ); const Z: [(u64, u64); 15] = [ (0xbc5ddfd831a70821, 0x3fb2e4d699cbd01f), (0xbc6d93e63489aea6, 0xbfc6bbcb41034286), (0xbc1b88525c2e130b, 0x3f9075b1bbf41364), (0x3be097334e26e578, 0xbf41a6206b7b973d), (0x3b51c64a34c78cda, 0x3ee3e99794203bbd), (0xbb1c407b0f5b2805, 0xbe7bce4a600d3ea4), (0xbaa57d1e1e88c9ca, 0x3e0a6ee796b871b6), (0x3a3b6e7030a77899, 0xbd92393d82c6b2e4), (0x397fcfedacb03781, 0x3d131085da82054c), (0xb8e45f51f6118e46, 0xbc8f4ed4b492ebcc), (0xb89bd46046c3c8de, 0x3c04b7ac8a1b15d0), (0x37d1a206fb205e32, 0xbb769201941d0d49), (0x3782f38acbf23993, 0x3ae4987e587ab039), (0x36b691bdabf5672b, 0xba4ff1953e0a7c5b), (0x3636e1c8cd260e18, 0x39b55031dc5e1967), ]; let z = f_polyeval15( x2, DoubleDouble::from_bit_pair(Z[0]), DoubleDouble::from_bit_pair(Z[1]), DoubleDouble::from_bit_pair(Z[2]), DoubleDouble::from_bit_pair(Z[3]), DoubleDouble::from_bit_pair(Z[4]), DoubleDouble::from_bit_pair(Z[5]), DoubleDouble::from_bit_pair(Z[6]), DoubleDouble::from_bit_pair(Z[7]), DoubleDouble::from_bit_pair(Z[8]), DoubleDouble::from_bit_pair(Z[9]), DoubleDouble::from_bit_pair(Z[10]), DoubleDouble::from_bit_pair(Z[11]), DoubleDouble::from_bit_pair(Z[12]), DoubleDouble::from_bit_pair(Z[13]), DoubleDouble::from_bit_pair(Z[14]), ); DoubleDouble::mul_add(w, w_log, -z).to_f64() } /** Path for transient area between 1.35 to 2. **/ #[inline] pub(crate) fn y0_transient_area_fast(x: f64) -> f64 { /** Polynomial generated by Wolfram: ```text <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ const C: [(u64, u64); 28] = [ (0xbc689e111675434b, 0x3fe0aa48442f014b), (0x396ffb11562e8c70, 0x3cc1806f07aceb3c), (0xbc6156edff56513d, 0xbfd0aa48442f0030), (0xbc278dbff5ee7db4, 0x3fa439fac165db2d), (0x3c1f9463c2023663, 0x3f80d2af4ebc8fc4), (0xbbee09e5733a1236, 0x3f4f716488aebd9c), (0xbbf261a1f255ddf4, 0xbf5444bd2a7e6254), (0x3bd4f543544f1fe7, 0x3f384c300e8674d8), (0xbb96ef8d95fe049b, 0xbf217a0fc83af41e), (0x3ba2be82573ae98d, 0x3f0dbc664048e495), (0xbb942b15646c85f2, 0xbef8522f83e4a3e3), (0x3b7a127725ba4606, 0x3ee775c010ce4146), (0x3ae4a02f0b2a18e2, 0x3e7d1d7cf40f9697), (0x3b8fcf1a3d27236b, 0x3eea9c226c21712d), (0xbb70b3aa0a1e9ffb, 0x3ef8f237831ec74b), (0x3baa6c24261245f3, 0x3f08ebfea3ea469e), (0x3bb5fa1b8c4587c4, 0x3f1474022b90cbda), (0x3b69545db8d098d1, 0x3f1d153dc04c51c0), (0x3bc68eab6520d21b, 0x3f2198a4578cb6ca), (0xbbc255734bc49c8b, 0x3f2212febf7cecdd), (0x3bb8dd02722339f5, 0x3f1f314deec17049), (0x3bbb6ef8f04b26a2, 0x3f1657d051699088), (0x3b878233fbf501dc, 0x3f0a1a422dafcef6), (0xbb73730138d1dbc2, 0x3ef8423cd021f1dd), (0x3b7e2a0d7009d709, 0x3ee145cae37afe1b), (0x3b6af21aeaba4e57, 0x3ec1bc74380f6d7b), (0xbb3607fb9242657f, 0x3e977341fc10cdc8), (0xbac747923880f651, 0x3e5e30218bc1fee3), ]; const ZERO: DoubleDouble = DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243)); let r = DoubleDouble::full_add_f64(-ZERO, x); let p0 = f_polyeval24( r.to_f64(), f64::from_bits(C[4].1), f64::from_bits(C[5].1), f64::from_bits(C[6].1), f64::from_bits(C[7].1), f64::from_bits(C[8].1), f64::from_bits(C[9].1), f64::from_bits(C[10].1), f64::from_bits(C[11].1), f64::from_bits(C[12].1), f64::from_bits(C[13].1), f64::from_bits(C[14].1), f64::from_bits(C[15].1), f64::from_bits(C[16].1), f64::from_bits(C[17].1), f64::from_bits(C[18].1), f64::from_bits(C[19].1), f64::from_bits(C[20].1), f64::from_bits(C[21].1), f64::from_bits(C[22].1), f64::from_bits(C[23].1), f64::from_bits(C[24].1), f64::from_bits(C[25].1), f64::from_bits(C[26].1), f64::from_bits(C[27].1), ); let mut p = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::mul_add(p, r, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_add(p, r, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::mul_add(p, r, DoubleDouble::from_bit_pair(C[0])); let err = f_fmla( p.hi, f64::from_bits(0x3c50000000000000), // 2^-58 f64::from_bits(0x3b10000000000000), // 2^-78 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return y0_transient_area_moderate(x); } p.to_f64() } /** Path for transient area between 1.35 to 2. **/ fn y0_transient_area_moderate(x: f64) -> f64 { /** Polynomial generated by Wolfram: ```text <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` **/ const C: [(u64, u64); 28] = [ (0xbc689e111675434b, 0x3fe0aa48442f014b), (0x396ffb11562e8c70, 0x3cc1806f07aceb3c), (0xbc6156edff56513d, 0xbfd0aa48442f0030), (0xbc278dbff5ee7db4, 0x3fa439fac165db2d), (0x3c1f9463c2023663, 0x3f80d2af4ebc8fc4), (0xbbee09e5733a1236, 0x3f4f716488aebd9c), (0xbbf261a1f255ddf4, 0xbf5444bd2a7e6254), (0x3bd4f543544f1fe7, 0x3f384c300e8674d8), (0xbb96ef8d95fe049b, 0xbf217a0fc83af41e), (0x3ba2be82573ae98d, 0x3f0dbc664048e495), (0xbb942b15646c85f2, 0xbef8522f83e4a3e3), (0x3b7a127725ba4606, 0x3ee775c010ce4146), (0x3ae4a02f0b2a18e2, 0x3e7d1d7cf40f9697), (0x3b8fcf1a3d27236b, 0x3eea9c226c21712d), (0xbb70b3aa0a1e9ffb, 0x3ef8f237831ec74b), (0x3baa6c24261245f3, 0x3f08ebfea3ea469e), (0x3bb5fa1b8c4587c4, 0x3f1474022b90cbda), (0x3b69545db8d098d1, 0x3f1d153dc04c51c0), (0x3bc68eab6520d21b, 0x3f2198a4578cb6ca), (0xbbc255734bc49c8b, 0x3f2212febf7cecdd), (0x3bb8dd02722339f5, 0x3f1f314deec17049), (0x3bbb6ef8f04b26a2, 0x3f1657d051699088), (0x3b878233fbf501dc, 0x3f0a1a422dafcef6), (0xbb73730138d1dbc2, 0x3ef8423cd021f1dd), (0x3b7e2a0d7009d709, 0x3ee145cae37afe1b), (0x3b6af21aeaba4e57, 0x3ec1bc74380f6d7b), (0xbb3607fb9242657f, 0x3e977341fc10cdc8), (0xbac747923880f651, 0x3e5e30218bc1fee3), ]; const ZERO: DoubleDouble = DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243)); let mut r = DoubleDouble::full_add_f64(-ZERO, x); r = DoubleDouble::from_exact_add(r.hi, r.lo); let p0 = f_polyeval13( r.to_f64(), f64::from_bits(C[15].1), f64::from_bits(C[16].1), f64::from_bits(C[17].1), f64::from_bits(C[18].1), f64::from_bits(C[19].1), f64::from_bits(C[20].1), f64::from_bits(C[21].1), f64::from_bits(C[22].1), f64::from_bits(C[23].1), f64::from_bits(C[24].1), f64::from_bits(C[25].1), f64::from_bits(C[26].1), f64::from_bits(C[27].1), ); let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(C[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c10000000000000), // 2^-62 f64::from_bits(0x3a30000000000000), // 2^-91 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return y0_transient_area_hard(x); } p.to_f64() } #[cold] #[inline(never)] fn y0_transient_area_hard(x: f64) -> f64 { const ZERO: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0x8c9df6a6_ff921721_70d796f3_2017e155_u128, }; let r = DyadicFloat128::new_from_f64(x) - ZERO; /* Polynomial generated by Wolfram: ```text <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] ``` */ static C: [DyadicFloat128; 28] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x85524221_780a573b_0f774c55_e5a946dc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -178, mantissa: 0x8c03783d_6759e3ff_622ac5d1_8df27811_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x85524221_78018115_6edff565_13cf55ab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xa1cfd60b_2ed96743_9200508c_125cf3d8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x86957a75_e47e21f9_463c2023_663178df_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xfb8b2445_75ecdc3e_c35198bd_b9330775_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xa225e953_f312a24c_343e4abb_be73338f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xc2618074_33a6c29e_a86a89e3_fcde0075_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -140, mantissa: 0x8bd07e41_d7a0f05b_be3657f8_126b9715_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xede33202_4724aa57_d04ae75d_31ad69cd_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xc2917c1f_251f1a85_62ac8d90_be4550ff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xbbae0086_720a31a1_27725ba4_605e0479_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xe8ebe7a0_7cb4b852_80bc2ca8_63864ee0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xd4e11361_0b896bf9_e347a4e4_6d642f8e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc791bc18_f63a577a_62afaf0b_002753e2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xc75ff51f_5234f34d_8484c248_be6beef2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0xa3a0115c_865ed2bf_437188b0_f87883dc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0xe8a9ee02_628e0019_545db8d0_98d12eff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0x8cc522bc_65b652d1_d56ca41a_43537f6a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0x9097f5fb_e766e5b5_5196876c_6ea798ce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0xf98a6f76_0b824b1b_a04e4467_3ea487e1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0xb2be828b_4c84436d_df1e0964_d44f420f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xd0d2116d_7e77b0bc_119fdfa8_0ee2dfee_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc211e681_0f8ee764_67f63971_21f1a199_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0x8a2e571b_d7f0d9e2_a0d7009d_70969fa2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0x8de3a1c0_7b6bdb5e_435d5749_cadf3edd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -149, mantissa: 0xbb9a0fe0_866e3d3f_008db7b3_5029fe59_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -153, mantissa: 0xf1810c5e_0ff717a2_e1b71dfc_26babb9f_u128, }, ]; let mut z = C[27]; for i in (0..27).rev() { z = r * z + C[i]; } z.fast_as_f64() } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] pub(crate) fn y0_small_argument_fast(x: f64) -> f64 { let x_abs = x; // let avg_step = 74.607799 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6299609508652038; let fx = x_abs * INV_STEP; const Y0_ZEROS_COUNT: f64 = (Y0_ZEROS.len() - 1) as f64; let idx0 = fx.min(Y0_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(Y0_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(Y0_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(Y0_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return j0_maclaurin_series(x); } let is_too_close_to_zero = dist.abs() < 1e-3; let c = if is_too_close_to_zero { &Y0_COEFFS_TAYLOR[idx - 1] } else { &Y0_COEFFS[idx - 1] }; let r = DoubleDouble::full_add_f64(-found_zero, x); // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(Y0_ZEROS_VALUES[idx]); } let p = f_polyeval22( r.hi, f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), f64::from_bits(c[9].1), f64::from_bits(c[10].1), f64::from_bits(c[11].1), f64::from_bits(c[12].1), f64::from_bits(c[13].1), f64::from_bits(c[14].1), f64::from_bits(c[15].1), f64::from_bits(c[16].1), f64::from_bits(c[17].1), f64::from_bits(c[18].1), f64::from_bits(c[19].1), f64::from_bits(c[20].1), f64::from_bits(c[21].1), f64::from_bits(c[22].1), f64::from_bits(c[23].1), f64::from_bits(c[24].1), f64::from_bits(c[25].1), f64::from_bits(c[26].1), f64::from_bits(c[27].1), ); let mut z = DoubleDouble::mul_f64_add(r, p, DoubleDouble::from_bit_pair(c[5])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[4])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[3])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[2])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[1])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[0])); let p = z; let err = f_fmla( p.hi, f64::from_bits(0x3c60000000000000), // 2^-57 f64::from_bits(0x3c20000000000000), // 2^-61 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return y0_small_argument_moderate(r, c); } z.to_f64() } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. fn y0_small_argument_moderate(r: DoubleDouble, c: &[(u64, u64); 28]) -> f64 { let c0 = &c[15..]; let p0 = f_polyeval13( r.to_f64(), f64::from_bits(c0[0].1), f64::from_bits(c0[1].1), f64::from_bits(c0[2].1), f64::from_bits(c0[3].1), f64::from_bits(c0[4].1), f64::from_bits(c0[5].1), f64::from_bits(c0[6].1), f64::from_bits(c0[7].1), f64::from_bits(c0[8].1), f64::from_bits(c0[9].1), f64::from_bits(c0[10].1), f64::from_bits(c0[11].1), f64::from_bits(c0[12].1), ); let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(c[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c30000000000000), // 2^-60 f64::from_bits(0x3a30000000000000), // 2^-91 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub != lb { return y0_small_argument_hard(r, c); } p.to_f64() } #[cold] #[inline(never)] fn y0_small_argument_hard(r: DoubleDouble, c: &[(u64, u64); 28]) -> f64 { let mut p = DoubleDouble::from_bit_pair(c[27]); for i in (0..27).rev() { p = DoubleDouble::mul_add(r, p, DoubleDouble::from_bit_pair(c[i])); p = DoubleDouble::from_exact_add(p.hi, p.lo); } p.to_f64() } /* Evaluates: Y0 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) */ #[inline] pub(crate) fn y0_asympt_fast(x: f64) -> f64 { const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let recip = if x.to_bits() > 0x7fd000000000000u64 { DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_safe_div(4.0, x), 0.25) } else { DoubleDouble::from_recip(x) }; let alpha = bessel_0_asympt_alpha_fast(recip); let beta = bessel_0_asympt_beta_fast(recip); let AngleReduced { angle } = rem2pi_any(x); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_cos = sin_dd_small_fast(r0); let z0 = DoubleDouble::quick_mult(beta, m_cos); let r_sqrt = DoubleDouble::from_rsqrt_fast(x); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let r = DoubleDouble::quick_mult(scale, z0); let p = DoubleDouble::from_exact_add(r.hi, r.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3c10000000000000), // 2^-62 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y0_asympt(x, recip, r_sqrt, angle) } /* Evaluates: Y0 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) */ fn y0_asympt(x: f64, recip: DoubleDouble, r_sqrt: DoubleDouble, angle: DoubleDouble) -> f64 { const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let alpha = bessel_0_asympt_alpha(recip); let beta = bessel_0_asympt_beta(recip); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_cos = sin_dd_small(r0); let z0 = DoubleDouble::quick_mult(beta, m_cos); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let r = DoubleDouble::quick_mult(scale, z0); let p = DoubleDouble::from_exact_add(r.hi, r.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c30000000000000), // 2^-60 f64::from_bits(0x3a20000000000000), // 2^-93 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y0_asympt_hard(x) } /* Evaluates: Y0 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) */ #[cold] #[inline(never)] fn y0_asympt_hard(x: f64) -> f64 { const SQRT_2_OVER_PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcc42299e_a1b28468_7e59e280_5d5c7180_u128, }; const MPI_OVER_4: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let x_dyadic = DyadicFloat128::new_from_f64(x); let recip = DyadicFloat128::accurate_reciprocal(x); let alpha = bessel_0_asympt_alpha_hard(recip); let beta = bessel_0_asympt_beta_hard(recip); let angle = rem2pi_f128(x_dyadic); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_sin = sin_f128_small(r0); let z0 = beta * m_sin; let r_sqrt = bessel_rsqrt_hard(x, recip); let scale = SQRT_2_OVER_PI * r_sqrt; let p = scale * z0; p.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_y0() { //ULP should be less than 0.5, but it was 1017.1969361449036, on 3 result 0.37685001001284685, using f_y0 and MPFR 0.3768500100127904 assert_eq!(f_y0(3.), 0.3768500100127904); assert_eq!(f_y0(0.906009703874588), 0.01085796448629276); assert_eq!(f_y0(80.), -0.05562033908977); assert_eq!(f_y0(5.), -0.30851762524903376); assert_eq!( f_y0(f64::from_bits(0x3fec982eb8d417ea)), -0.000000000000000023389279284062102 ); assert!(f_y0(f64::NAN).is_nan()); assert_eq!(f_y0(f64::INFINITY), 0.); assert!(f_y0(f64::NEG_INFINITY).is_nan()); } #[test] fn test_y0_edge_values() { assert_eq!(f_y0(0.8900000000138676), -0.0031519646708080126); assert_eq!(f_y0(0.8900000000409116), -0.0031519646469294936); assert_eq!(f_y0(98.1760435789366), 0.0000000000000056889416242533015); assert_eq!( f_y0(91.8929453121571802176), -0.00000000000000007281665706677893 ); assert_eq!( f_y0(f64::from_bits(0x6e7c1d741dc52512u64)), f64::from_bits(0x2696f860815bc669) ); assert_eq!(f_y0(f64::from_bits(0x3e04cdee58a47edd)), -13.58605001628649); assert_eq!( f_y0(0.89357696627916749), -0.000000000000000023389279284062102 ); } } pxfm-0.1.23/src/bessel/y0_coeffs.rs000064400000000000000000002117041046102023000151550ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Y0 Remez poly coeffs at zeros and extremums Generated by SageMath: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = 1.35 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.03 - zeros[i] b = (zeros[i]) + 0.83 + 0.03 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.03 b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(y0_zeros) # print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 200; bessel_y0 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_y0(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RealField(500)(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return def print_remez_coeffs(poly): print("[") for i in range(len(poly)): coeff = poly[i] print_double_double("", coeff) print("],") degree = 27 print(f"pub(crate) static Y0_COEFFS: [[(u64, u64); {degree + 1}]; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print_remez_coeffs(coeffs) print("];") ``` **/ pub(crate) static Y0_COEFFS: [[(u64, u64); 28]; 47] = [ [ (0xbc7492c1ad707fcd, 0x3fe0aa48442f014b), (0x3889cbe7f6454fdf, 0x3becdccc60399188), (0x3c6201923a596bb0, 0xbfd0aa48442f014b), (0x3c24b04e2557df22, 0x3fa439fac16525f5), (0xbc059b63c3765131, 0x3f80d2af4e9323bc), (0xbbdcec718054f585, 0x3f4f71646bea8f8b), (0x3bf856364cecf8b8, 0xbf5444bda8b69d4e), (0x3bda1cb8be57cc8f, 0x3f384c2206701bfd), (0xbb8ae41d36dcce8d, 0xbf217ab4af8d0bf0), (0xbba9cb2ac1552425, 0x3f0dafb9b99a70f2), (0xbb951efcd9701bd5, 0xbef8bb9639d60207), (0x3b8a10d871292a77, 0x3ee48b6751827819), (0xbb709569bb189616, 0xbed1364cc5887f8d), (0x3b248bd9aba7d332, 0x3ebd06afc4e97689), (0x3b44874f3eb42a7d, 0xbea899b75531d45b), (0xbb036dc9313b0b72, 0x3e94f157466889b4), (0xbb15fb0fa7789259, 0xbe81e537d57e5872), (0xbae227bb9fde16a8, 0x3e6ebca03e74f872), (0x3ae23bb7c6812f3e, 0xbe5a95bfc7177df2), (0x3ae9256929650559, 0x3e46b9b8baa2a7e6), (0x3ac02e410dd7de2b, 0xbe32d4cd9df0cdc3), (0x3ac47f4d926b3967, 0x3e2169d04e3c7866), (0x3ab6f6c4b513d045, 0xbe12dac47ffdcb13), (0x3a6fa8ccc9968ba6, 0x3dfa16bd9d2454ff), (0xba171664de1838ee, 0xbda18f57d00cd0c8), (0x3a636003e2d9973c, 0x3dcac3134b14f54c), (0x3a5cb30d6a3e73d7, 0xbdd88bfc936d3a46), (0x3a600c3863532a47, 0x3dc074a2bfd935a7), ], [ (0xb6985ea12b68dbc6, 0xba0ce46bb97e3b37), (0xbc5a4026e448075b, 0xbfd9c34256a12a0c), (0xbc49ded6e42ffb00, 0x3faa09c9290367ef), (0xbc253b026c745733, 0x3fadf6d59bf50ebd), (0xbc18dbfc7b944e60, 0xbf7c116fdc598096), (0x3bf40cf995f4f110, 0xbf61e32bc4ef8a41), (0xbbcb82d9e30fbb8a, 0x3f29982765166254), (0xbb7a0c04b5d6f2fd, 0x3f0ab2c1fecdcfc4), (0x3b7cda0c15fabc6d, 0xbed486371e6a6640), (0xbb079525b0987a4e, 0xbe93b21684089b98), (0xbaf3ba730f1c40e9, 0xbe5777058741ab00), (0xbaf583debf7de8c9, 0x3e5452ea009488fe), (0x3ab98e298e66ceb6, 0xbe2f6938829aeacd), (0x3aa9d6dc6976f3c9, 0x3e0a5a1f3a03d35d), (0x3a7994a2d0f56a03, 0xbde994e7358cedf6), (0x3a5a354bba4fc371, 0x3dc88ae5d31af5c1), (0xba357cd4a8a94073, 0xbda75329787f3d8c), (0xba2d0839c51ea186, 0x3d8643c578f084cf), (0xba0526a2696c015c, 0xbd6554780d3aba1a), (0xb9ec9b6ca0c2368e, 0x3d447c69a36927e9), (0xb9b175a5c0e46062, 0xbd23b88e0a626f34), (0x3994f94bb00b0bd0, 0x3d02fdee82cca7a8), (0xb98eac61aa84bafd, 0xbce25983eb139aeb), (0xb9685d6dfdbe7bfb, 0x3cc2440cd8848b87), (0x3922fa28d497dc91, 0xbca164c6877c570d), (0xb917682fb55945f7, 0x3c78a082a7dc3992), (0xb90f407a50193eb2, 0xbc621ea0651d2198), (0xb8c56e242114685f, 0x3c523596b99eb3ff), ], [ (0x3c7b8d2a1c496808, 0xbfd5c7c556f0c19a), (0x36068b8c3a0eb972, 0x396e4544b8708e19), (0xbc6b8d2a1c496844, 0x3fc5c7c556f0c19a), (0xbc2b4d44aaaf080d, 0xbf8564d4b1ed0d7e), (0x3c2e4289c3ae4c4e, 0xbf8a15d92dfe3e27), (0xbbedbea922f2213b, 0x3f4b438430469ff7), (0x3bdc176048714c11, 0x3f37a8924cc2f914), (0xbb7021dbf4219b23, 0xbef5f69b4a8a3c05), (0xbb7729647a7cf1b3, 0xbed85b940eb607f9), (0x3b3d99d888f48f01, 0x3e955ac0f5c3162c), (0x3b0f25a287448fcc, 0x3e6d563e18b47eb8), (0x3ac452983ff83fe5, 0xbe23eac3a45e06f4), (0xbaa55a4be8b255ef, 0xbe0007671d55a8af), (0x3a6681c171d8b7ac, 0x3dc04e13e8d2d63b), (0xb9cb304019dc95a9, 0xbd46e2b306d18fe2), (0xb9e569987d3c61bc, 0x3d54d18f7c808f5a), (0xb9d65bf264af4caa, 0xbd349808958007f4), (0x39af1658e9591f8b, 0x3d0a5b43a3168022), (0xb98b94f19368caef, 0xbce1c9c4d5c7e2e7), (0xb91d94e29089b67f, 0x3cb933cacbb762ef), (0xb931aa0bcf9e385e, 0xbc91c66b5e59c10e), (0xb907d452cfe5d11e, 0x3c690530621ffb6d), (0x38e2fc94e9e2e560, 0xbc41a7142b188ece), (0x389fe83adc9ec098, 0x3c18ea69b49fa0ec), (0x386baf69f710f067, 0xbbf186b62773cb8b), (0xb830ab83fea718cc, 0x3bc97ee300661ddb), (0xb841e9ca9ef3f273, 0xbba4203d2c71dee3), (0x381487ed7b4c5c12, 0x3b7779cb668f4f30), ], [ (0x35f13ef25b4edb08, 0x3952841995e45c48), (0xbc78d4484b7cd2a7, 0x3fd334cca0697a5b), (0xbc341c66c86d3ee2, 0xbf95aef611fc4d57), (0xbc44929b43aab7e3, 0xbfa8969c64cbf452), (0x3bfab353487eb8be, 0x3f6b2f14a95527cb), (0x3c0aa67a62fa8841, 0x3f61d35e85fde2a3), (0xbbb270ba54528c94, 0xbf226dd71e391c8b), (0xbb61863ae7da7a16, 0xbf08177e4fe52324), (0x3b4949552d9354dc, 0x3ec6a9227352f96a), (0xbb44a5b99cf95459, 0x3ea34aa7573ef14e), (0xbb0698b7b84362ae, 0xbe60a2814d7ac448), (0xbad900bb94c56b91, 0xbe3442a3d3359ad9), (0x3a8ac6ca8212a487, 0x3defa6c509566c72), (0x3a56a6cae4d17a25, 0x3dbf14e5584823d7), (0xb9f7410034885564, 0xbd7714c292be3962), (0x39d1bcc695f4f231, 0xbd40679cd58549e2), (0x3997214169109d52, 0x3cf3365d5a792113), (0xb95497cd3660e90c, 0x3cc38cf06b3134d3), (0xb92ac63766c35618, 0xbc82bd5a84bf3644), (0x38dd10b30698d66a, 0x3c326e932d44d957), (0xb8bf280f5863dcdc, 0xbc1271150465312d), (0xb878f6f4bf335d0d, 0x3be8df3e61da29e5), (0x384a254e3a1a9970, 0xbbb9b1263c861574), (0x381db06e04e97e27, 0x3b8b3ef4b052ee69), (0xb7f2c3a3c46974ad, 0xbb5da7aeb72ad1b2), (0xb7c4810afcc72e8d, 0x3b2fdbbcc787affa), (0x37a36df7ebbbb4ed, 0xbb031287031f9ece), (0xb75db740f07d1867, 0x3ad85ce53417a3c0), ], [ (0x3c61dc672a53c590, 0x3fd15f993fceab5c), (0x35ea878b9ff55f5c, 0xb946a81d8aec1515), (0xbc51dc672a53c58f, 0xbfc15f993fceab5c), (0xbc0d1c390189caf7, 0x3f758ef6efbed797), (0xbc243ede64b782d9, 0x3f86395dfe49fcd4), (0xbbbb4484582c217c, 0xbf3fb15104a41c00), (0xbbd4410e752beb78, 0xbf35f88a11d5564f), (0xbb8b2d9b83a5b450, 0x3eef37d226a824b7), (0xbb61fb1782379734, 0x3ed6f7bab104f355), (0x3b2da2cb873ba95e, 0xbe8f0c45a3824d70), (0xbac11338801bec18, 0xbe6dfe11df12c715), (0xbac52938286abb6d, 0x3e2311adc2e753ee), (0xba9200612bccbf82, 0x3dfad34e18504e16), (0xba4c6eb5b9fade2d, 0xbdafdc8061ae8b15), (0xba251747464962f8, 0xbd819498ca6cef9b), (0x39d9f9efcc54f4de, 0x3d33a291d5991f6b), (0x39af3f93679996f3, 0x3d016f7ae80cadff), (0xb9422e176854fc2b, 0xbcb1f8d80decb659), (0xb8ef665f3b08f8e4, 0xbc7c27b5350d7ce7), (0x38af81adc69c8ae0, 0x3c2d08034e0e0d4c), (0xb88ed31bb5296f3b, 0x3befac201220d678), (0x37f6dcad77609354, 0xbb93e9257bbbec92), (0x37f2bad6f8609fad, 0xbb6dce086bd954ec), (0x37c3c466a462a963, 0x3b2c45f44eeac691), (0x377aca1c9e5ead22, 0xbaebf82d453f586e), (0x371d5ba887167511, 0x3abef01a452e6243), (0xb6e1a818be163885, 0xba8faba1ac8fc141), (0xb6f75474af743fde, 0x3a59bbaf9916fed8), ], [ (0x360f6f90e85783b8, 0x396e539ee4be998b), (0x3c61e8f568f8c6b6, 0xbfcff635cc72b9f1), (0x3c0fa6ebe8b754aa, 0x3f89036451ff57c5), (0x3c46345bcf3c5b81, 0x3fa4e667a71556af), (0x3c065e386829f088, 0xbf60325ee41e910c), (0x3bfde6b6846da9c7, 0xbf5fe23914fb9128), (0xbbb9c28522c54b49, 0x3f17f84d7c50e4c4), (0xbbaeab0290c997f1, 0x3f06afdd57be1e14), (0xbb2bbdfb6c40ca93, 0xbec04053abf4386a), (0x3b3787c4b69beaba, 0xbea2aea9ec48d8fd), (0xbaf17a36377f9c62, 0x3e593eb9f1ddb4e9), (0x3ad9f8321f3ce337, 0x3e3428a3a3e30a13), (0xba49c9c135d6bfa4, 0xbde99d8c42f7a020), (0xba59203ca37ccc7f, 0xbdbec9805045aa58), (0xba08ceab2aadd382, 0x3d72613659ce994f), (0xb9e8053d9b1a7b6c, 0x3d418f302bdba980), (0xb96ea7068003a9dc, 0xbcf3bc9ccb704250), (0xb93e32e516fbc8fc, 0xbcbf0dc4067be8fe), (0xb91a819a6b2cfdb1, 0x3c706e491f458177), (0xb8b2f6e0e017d3a4, 0x3c36013bac772fd5), (0xb88860e3b038bbbc, 0xbbe616b4d60c99dd), (0x38440765a3381ed6, 0xbba93fb6fc116a65), (0x37f070ddd36dbc13, 0x3b57963a3ba9df68), (0x37b30f1b7dcdc2ea, 0x3b1937f28596352a), (0x3760f019da1d4947, 0xbac837f92e435c71), (0xb6cfd07d0b99a723, 0xba80a4be8fbdea42), (0xb6b4329fac42bf24, 0x3a19c0ce24bac50d), (0xb69a16105af87cd5, 0x39ff46fe69318a2c), ], [ (0x3c54d14c77bc1691, 0xbfcdc14ea14e89f9), (0xb61ccfd68577b5e8, 0xb97a750db049a3bc), (0xbc44d14c77bc1688, 0x3fbdc14ea14e89f9), (0x3c00ff03f975831b, 0xbf6b037fe9cf2a52), (0xbc2f19a8f5b137a3, 0xbf8367d7d608e4ba), (0x3bdd892317f290f5, 0x3f34abef5636e4f7), (0x3bd5ba5b5b609686, 0x3f33d8a661229259), (0xbb700a3f0097a359, 0xbee5cfe92a1a2c45), (0xbb6087e84c57990c, 0xbed571814a1aa301), (0x3b22b6740db0f074, 0x3e87414e33c9bacd), (0x3afa4836a20e8280, 0x3e6ca7069e73d1d9), (0x3abe65fd39b0188a, 0xbe1e0b3a705ff247), (0x3a95774f6fa018cb, 0xbdfa15dd62cf9f10), (0xba399e86b7dd9f12, 0x3daa33948eada12c), (0x3a22398b28ff34ba, 0x3d81419b1fd428ef), (0x39c9ae1ea6c0045a, 0xbd30882f60b8a775), (0x39a31e54bbe9a33e, 0xbd015e5c0af749d4), (0x39454d020e06c1f7, 0x3cafb1e115e089b2), (0x3910a4f9eea95a23, 0x3c7b83826370860f), (0xb8c57c15f2ff0eb8, 0xbc27e5d539874c6c), (0xb87dc14618f0e43b, 0xbbf19dae391ff57d), (0xb82fe2e247291923, 0x3b9d2b7278390d46), (0x37f3825b1f8b77eb, 0x3b6298bb72cef60f), (0x37a7910d5f5dc998, 0xbb0d50bc222d50f5), (0x3776acb65e1367e0, 0xbad08ac20d33e370), (0x37062a8b170aa42b, 0x3a79154a0ab2b1c5), (0xb6d06d11501acdf8, 0x3a3884b2a5dd01b8), (0x36832f558f511cbf, 0xb9e1c3f19ed31df1), ], [ (0xb5d1f4401b5b78db, 0x396e44a7ff47853b), (0x3c41398cacaa32cb, 0x3fcbf32a27594007), (0x3bfe5ce4af72439b, 0xbf80bc2d84e65214), (0x3c4acd5148eb7ea0, 0xbfa26cab38a8b368), (0x3bfab9a1103e209b, 0x3f55f03e47165d72), (0xbbc4598141a3f87e, 0x3f5caaa76e34992d), (0xbbbb7ab55e886663, 0xbf10c5f18c46d030), (0xbb99f58bad5e7b5f, 0xbf04f0af7d46cd48), (0xbb3040f00afdd8ce, 0x3eb7d1e28094e21a), (0xbb3f12deda9fd086, 0x3ea1ad0731228479), (0xbae9fe69a18b2b74, 0xbe536021c8cb3c34), (0x3ad92bf3eabb82c3, 0xbe3371ae6c759181), (0x3a630cb928debacf, 0x3de46ce077a8bed7), (0xba5feb436591c0b8, 0x3dbe235d3564b639), (0xb9d711ddaf978bf4, 0xbd6e408e259c72fb), (0xb9c9d325620234dd, 0xbd415f07ac87e832), (0x399b66d31155b6c3, 0x3cf0a44f77f6a8ee), (0xb927de212062774e, 0x3cbefd8ab52f8ec1), (0x38daebbaa8d140b4, 0xbc6c54ebb5ad3567), (0xb8d1c883890c6817, 0xbc360b43cbb605a1), (0x38851f7136cf7e49, 0x3be33d74aac5c469), (0xb84c8ae944909141, 0x3ba99bfbb428a4d1), (0xb7f50f7d69247480, 0xbb555c095b9d3de2), (0xb78d195ad02b9a0b, 0xbb18c29d6b596412), (0x37588e53fd261c0a, 0x3ac3c05d45a0cec2), (0xb722c1c138d71c9e, 0x3a843feaf2fed511), (0xb6c263b564f34be6, 0xba2ec5c49e1d5e88), (0x36731f7cd8008380, 0xb9ec82a1b1f74089), ], [ (0x3c57ba12cd0fc91f, 0x3fca7022be084d99), (0xb5db8122d606073c, 0xb9614f36f1550bec), (0xbc47ba12cd0fc91d, 0xbfba7022be084d99), (0xbc0b3327197c9ced, 0x3f62ee079d020b12), (0x3c2d0f8f3671311f, 0x3f8163191c30aa62), (0xbbcc7f2dbb383293, 0xbf2d7806ea72fc76), (0x3bcf9ec581434d48, 0xbf320f95702b1d4e), (0x3b899e1a0f3c0abe, 0x3ee00610882294aa), (0x3b61505ce3b25d40, 0x3ed3e398cbc472ea), (0xbae050c778e973e5, 0xbe81bbe181c65162), (0xbb0c3fb832d7b54d, 0xbe6b0f89b7c61f3a), (0x3ab91b7cb5170340, 0x3e17c3f85882049b), (0xba976a7f60f10aab, 0x3df90236614c84dc), (0xba43abb3499d78c0, 0xbda564920d1387dc), (0x3a2b1f00d1e27499, 0xbd80be1811255cfe), (0x39b7396b68be0fd5, 0x3d2bb9712586bfac), (0x39a50316c82a22d1, 0x3d0101c31e1df222), (0xb93cd112332c006f, 0xbcab298cda76e792), (0x39181c12a03d0651, 0xbc7b22acc441d614), (0xb8cf36eb93d76394, 0x3c24dca37a331862), (0x387338c4943fcecc, 0x3bf176e94edd9a37), (0xb7ed97a80ea3375c, 0xbb99d4f0d7cf230e), (0x37c85bd213356682, 0xbb6287584fe1cda1), (0xb7957f660392a1e8, 0x3b0a5c024222d0c1), (0xb7798291e622cf2f, 0x3ad07cad512e27f5), (0xb712f27bce7fdd19, 0xba76918588d0c395), (0xb6d55b12c898a874, 0xba38d39ee7749b0b), (0xb680c165d28960ac, 0x39e0d21cd12bf761), ], [ (0x360f530de8a2298c, 0xb96ccd9d9aa9b157), (0xbc65b9c39e42719c, 0xbfc925c35988ee29), (0xbbdda9c0588bab35, 0x3f7862549367591e), (0x3c4a142ed6a5521c, 0x3fa0a4512039d6a2), (0x3be94ce533c65b81, 0xbf5013b38cfb9292), (0xbbea2a14cf0f61a4, 0xbf5a24a1215f6684), (0xbbae7b4c448b426e, 0x3f08f91421377fad), (0x3baf72fd0f5209e6, 0x3f035d17cec0172f), (0x3b3cd242e4f6fc44, 0xbeb2283a93114096), (0x3b259dda3f9805c1, 0xbea099e71392f54e), (0xbad6dce1c34353e2, 0x3e4e5de01e2e6566), (0xbab52eec6344539e, 0x3e32885854ea8b06), (0x3a6795d88d7a428b, 0xbde0730c2985fd22), (0x3a4e069c266df28e, 0xbdbd1743cbb2e11a), (0x3a0121929f450b8e, 0x3d68f8728745e1e6), (0x39de1722c384607b, 0x3d40f166cb29a7d1), (0xb98c9b7f51aa7e71, 0xbcec10e67c004e39), (0x39306913ae262394, 0xbcbe7aec1ba33e89), (0x38d8c6bf0ecbf421, 0x3c68543e12c9bcc0), (0x38d880f40d10394c, 0x3c35d3939f6d29f1), (0xb885e7f0bd8af4c8, 0xbbe0c7ba1192da1c), (0xb84abbb402955d93, 0xbba97d91773fae0d), (0xb7c3bf48e2c5ddfc, 0x3b52dfb951fe4ab6), (0xb7ac27c13775b2fb, 0x3b18c04f68a8baaf), (0xb751cb733bb217c3, 0xbac1a783b2905f0d), (0xb72e01e5e434cb26, 0xba844df5fac82b00), (0x36c6a6f050600220, 0x3a2bbf5dc58ec268), (0xb672c2ec04596698, 0x39ec99f34bc330e3), ], [ (0xbc63db68c567283b, 0xbfc80781c32422e7), (0xb60d9441230a8778, 0x397deb1fbbaf8566), (0x3c53db68c5672838, 0x3fb80781c32422e7), (0xbbfab5094c039945, 0xbf5c6923374d561f), (0xbc032419a9d405ca, 0xbf7fbe6df840847f), (0x3bc0f03bc2e75f5d, 0x3f264f4711a85f1a), (0x3bbd9972e6c197c9, 0x3f309ff42b0d7a68), (0xbb61aba5a7ce6e95, 0xbed8a60685a597d9), (0xbafdb153b11ed74e, 0xbed282d26a74c38e), (0xbb1d21d4a93dbe75, 0x3e7bdb57a889a4c1), (0xbb099a040b2ccf5b, 0x3e697d9c12a60cef), (0x3a35e0f484533648, 0xbe131aa8691738fb), (0x3a93c99c395b5c9a, 0xbdf7d486eee39a85), (0x3a223dad46ae9400, 0x3da197f258214b3d), (0xba1654ac01c16c13, 0x3d801dd7f92195ff), (0xb9cbde35eb70ebd4, 0xbd27480b9efaa860), (0x39a7bbce185d5c09, 0xbd00833ea1f83461), (0x393326656e27aad9, 0x3ca73bf7964edc39), (0x391e8e85dd3ba305, 0x3c7a891d704fed29), (0x38c6737263e77e58, 0xbc22222dcf097253), (0x3815c44bf33c3053, 0xbbf12db9d219b624), (0xb83a6ffdfedc9a0a, 0x3b96c4638eb6d0ab), (0xb7f870f3fdb66e9d, 0x3b624ff29cc34a5f), (0x3784f30eee231ab0, 0xbb0782fe0a2ed548), (0x376d3a1f2a7e18f9, 0xbad05b98a2d38bad), (0xb6fbbf0362b64b66, 0x3a745719daf0033a), (0xb6b5c16ada4dc5fa, 0x3a38b51735f94ad1), (0xb668156ec309831f, 0xb9de827eef669a9e), ], [ (0xb5d71d9a0e2250f8, 0x3932accf9d404efd), (0x3c64fef53f4893e5, 0x3fc70c4f66cab47f), (0xbc1e032768318e73, 0xbf72c6731071e936), (0x3c2f806b21bc9578, 0xbf9e924b85a17361), (0xbbe1434be87c634b, 0x3f48d6c364d92082), (0x3bf5cbe0638f4cee, 0x3f58247b02d6b0f6), (0xbbaade8b3660fd3f, 0xbf0376125938561d), (0x3bae81e47dd3839a, 0xbf0206da232a2b6a), (0x3b424b3c317353f9, 0x3eacaf84db871510), (0xbb022e3bac6444e5, 0x3e9f3671177306ca), (0x3a9f8b17e5f17584, 0xbe48654b001006cd), (0x3ad272b91e39e04f, 0xbe3199ec88b18766), (0x3a6b9a2ed7b2626d, 0x3ddaeb1a849305fb), (0x3a57caf104216cf2, 0x3dbbe67c197c48c0), (0xb9c6b55595b8d04e, 0xbd64cdfa0bd69898), (0xb9dbab7dec1030e5, 0xbd4064936f97922f), (0xb978bade7534a976, 0x3ce7c83b5186222e), (0xb95c7c9291c10511, 0x3cbdb73ad7fa8bcd), (0x38c3fe342ee888e5, 0xbc64eecbf0b91aab), (0xb8ddc5bba4aa2657, 0xbc356ab697c0b36f), (0xb85034aab887d3c4, 0x3bdd4506fe39afb4), (0x383d49e7992e0ac5, 0x3ba925d81aa2ac79), (0x37e1c2dbc1cbe029, 0xbb50a89d8a666333), (0xb7b31ae47aa79118, 0xbb18875d46ae8913), (0xb75fe255d6973d67, 0x3abf7e2c067e0a91), (0x37086207483b1723, 0x3a8432812904a786), (0x36a9a69e34c77135, 0xba28f9cef0d7c221), (0x366e1739129c6d8d, 0xb9ec7ae64440285f), ], [ (0xbc6d2f0105f3ce7c, 0x3fc62d94d97e859c), (0xb6196ae975958785, 0x3977cba836bb33ee), (0x3c5d2f0105f3ce79, 0xbfb62d94d97e859c), (0xbbf6c13bde837d51, 0x3f565481b55eaefb), (0x3c17013075a066fe, 0x3f7d5f857a2a6107), (0x3bc5f065aa633b82, 0xbf21a015a2ccb78f), (0xbbc12f349174f00d, 0xbf2eeb4eafd8614b), (0xbb53525d6141b63b, 0x3ed3a7b79e4d80fc), (0xbb662d899f08e930, 0x3ed154ed4598d2f0), (0xbb0444753ed61eee, 0xbe767f762ea293a1), (0xbafe11bb6d8cf182, 0xbe680ec1e042ee62), (0x3aa725a69e88f41a, 0x3e0f529652b9de0f), (0xba97b07721f181ff, 0x3df6ad7bd2247f55), (0x39e37ab8d29d6ed4, 0xbd9d4e582fb43553), (0x3a1f7027dbae57b9, 0xbd7eeb6efcbb6228), (0x39c89f73cf547041, 0x3d23b1eabb5c1c2c), (0x39960a6cdd6c228d, 0x3cffe92f0882b43f), (0xb94a0a88609a2efa, 0xbca3f20671568bda), (0xb917e7036f59109d, 0xbc79ce30ac166c3b), (0xb8b710f5a0405cb7, 0x3c1f8db6e94f5c58), (0x388042b39eb414de, 0x3bf0cc90c05bf217), (0xb83bf397bb30cb6c, 0xbb940c6bba534367), (0xb7f70d1d6ed27860, 0xbb61fe3820203226), (0xb77b9fa8fe59f5f1, 0x3b04ed91184b349c), (0x377e0b12ab59c923, 0x3ad023371cf7aa58), (0x370fad8a026e8d00, 0xba72475258dcb995), (0x36d50611a23601a2, 0xba3874f481897d45), (0xb67546ab95be8675, 0x39db9a35cb0268a5), ], [ (0xb6160b0c9b9ffd9f, 0xb97a3923dc9c072f), (0x3c5fe2103f7148c0, 0xbfc5664d37c37d7b), (0xbc0a0fbbe8bcf31e, 0x3f6e0ee8ec84659a), (0xbc383a77d074bd10, 0x3f9c6c415c971b4b), (0xbbb06fe5233f1827, 0xbf43ec49cb941f55), (0x3bfe14142e172805, 0xbf56853b2d047885), (0xbb98cea461592a31, 0x3eff632a9396fd4e), (0xbba049885559b284, 0x3f00e6afa01af561), (0x3b452a854998ce1f, 0xbea7541247acdf59), (0x3b3a7242d1d8f2ff, 0xbe9d735e8beb8fcc), (0xbae93d2eb5241282, 0x3e440e6a7cafc096), (0x3acae709b26c74f3, 0x3e30b9cfae2ab337), (0x3a72d6e49ffa1efb, 0xbdd668087e67279b), (0x3a5eab7f746fd96e, 0xbdbab498e6f69c73), (0x3a0c7eba82778adf, 0x3d618b5674894afb), (0xb9dabc635cef6b79, 0x3d3f99da023c7232), (0x396198c6e558139c, 0xbce450b8165c264b), (0xb9379aa14a14f4cc, 0xbcbcd387688c5092), (0xb8d00bf3298263f3, 0x3c621a103bd09ea7), (0x38c2b31b04643f75, 0x3c34e540faeea510), (0x387fbfca69c0c002, 0xbbd999b3cf8b9794), (0xb84578c966f9c437, 0xbba8a8f1c19ab5c8), (0xb7d1af3943438fb6, 0x3b4d71c31555dffa), (0xb797b6eaed91b502, 0x3b18289e061910a0), (0x371f92726b30b6ae, 0xbabc18185dc0f589), (0x372dd6314cb1a609, 0xba83f7bf0ecd3312), (0xb6b22addb7be68de, 0x3a2677b40b678a01), (0xb6852d3eb4bf8c8d, 0x39ec35403f3feccb), ], [ (0xbc5e9088e9ff2519, 0xbfc4b2a38f1ab9b4), (0xb5e56cdffbbb5799, 0xb95b36c3b9e47f10), (0x3c4e9088e9ff251a, 0x3fb4b2a38f1ab9b4), (0xbbfcc8083276a072, 0xbf5225a5c73f2233), (0x3c1525fe797e2125, 0xbf7b750d89a9b35f), (0xbbb08db59499cc78, 0x3f1cbdb4f1d5dbbd), (0x3bc35c23938c8103, 0x3f2cfe933fc6d0b8), (0x3b52d453a3ea1d43, 0xbed01ef10d839bbc), (0x3b71cffb5ca02d28, 0xbed05375a588a72b), (0xbb03f71b7795fb19, 0x3e729afe7ea7ba43), (0x3af336f1328c096c, 0x3e66c8fe015e6610), (0x3aa95a6cae05afad, 0xbe0a2a01e7af0241), (0xba78518ab4937cc9, 0xbdf59b33050d2092), (0xba24b06fe0fbe4ff, 0x3d98c0a50e7852d3), (0x3a16de13327f4ad6, 0x3d7da3426f355690), (0xb9cf30f26c9fd872, 0xbd20d3b48429ce84), (0x399b0cd9583574ed, 0xbcfec46e14cd5d9d), (0xb948a60ceb0a4c6f, 0x3ca13c3da7405df7), (0x39055845c840358d, 0x3c79043b4a0f0164), (0xb8a1906c502f6088, 0xbc1b902f4b27239f), (0x3883b1fc8ff5cfb3, 0xbbf05dbe7502cf7d), (0x3824e300158ee2c9, 0x3b91b0f5dc9eb0ab), (0x3803c301aa3c55ff, 0x3b619b550a0380e8), (0x37a48585c1f9fef8, 0xbb02a3e12dd3a21e), (0xb755a96cd7834eba, 0xbacfb47bc6c98397), (0x3705d5f51aa77044, 0x3a706b51c73e4699), (0x36cba3931d96b5c4, 0x3a381b0b33df04c5), (0x367c6c6e733152da, 0xb9d8f4cc5f2cd78e), ], [ (0xb6025bf8fd89fcf9, 0xb972fca96d67ab3c), (0x3c5f3474ffad3fda, 0x3fc40f8ffdf09a5f), (0x3c047810b9792fcf, 0xbf68c37a29c4586f), (0xbc348471cc77dfe6, 0xbf9aab099314b209), (0x3be6aa80fcd0444f, 0x3f406f735cc0f6a6), (0x3bebe02c39288577, 0x3f552d29a06802e0), (0x3b89fdf10253db0c, 0xbef9fc04c675c0ed), (0xbb62f9306dab6a7d, 0xbeffe48825ed3c8e), (0x3b4325167726e7d5, 0x3ea36bd2d58ff45b), (0xbb2af08b6d9e350f, 0x3e9be87e2cad2ce7), (0xbaec807c6aa50609, 0xbe40d1fdedc6cb17), (0xba7064ddbed15f1c, 0xbe2fdbeb107ddccf), (0x3a758934a4493d29, 0x3dd2f44d01321684), (0xba4232e1c56c35a5, 0x3db9921373ea0f26), (0xb9d9c42dee5eb68c, 0xbd5df6b83ac56981), (0x39db0125ce11e878, 0xbd3e6c005b62bffa), (0x3945c956b1073d49, 0x3ce1848c91de7161), (0xb95e0318e089dc41, 0x3cbbe5530d0fcf21), (0xb8fe3f75946d3513, 0xbc5f8540b8b05bd4), (0x38b0d6e492206c61, 0xbc3451eb9bf04528), (0xb875fecfd5f528a6, 0x3bd67f1edd3c6bd2), (0xb84a4a9a4b0746cb, 0x3ba8169212ae867e), (0xb7b418bb0baae011, 0xbb4a1a0ded4a699f), (0x378a8c57d3055718, 0xbb17b199d846adfb), (0xb72c6c0833446ef6, 0x3ab91bb0a0b6110c), (0xb701ddf674f848ee, 0x3a83a75f8b7df40d), (0xb6bc25ec9cd09377, 0xba243ac68cfbb83d), (0xb6618a00b084ab2f, 0xb9ebd3094ccdd46d), ], [ (0x3c4997782859a00d, 0x3fc37aaceac987b9), (0x360c6c83fa2a3645, 0xb97062679197f9db), (0xbc3997782859a008, 0xbfb37aaceac987b9), (0xbbd05a6eb7d72466, 0x3f4e3fdbfd65014a), (0x3c1d91e80a0529b4, 0x3f79de7a33bc3a97), (0xbbb56ef10c1ebcd7, 0xbf1801d911fbd06c), (0x3bcce92f388f20fc, 0xbf2b605a5ade3a80), (0xbb539bcd81dc9893, 0x3ecb0a2608144a3d), (0xbb6b367577014662, 0x3eceeceb341ad833), (0xbaf6cb1030890b1a, 0xbe6f623fc7be9f9f), (0xbb0412babf35582b, 0xbe65a9ca94a0d7dd), (0x3a9025c74264c26e, 0x3e0638ba2f5f5e6b), (0xba745be766d5eb9d, 0x3df4a1b4217ef864), (0xba32b2b63b552f66, 0xbd9530c712e738d4), (0xba0b3a7b1b9435f0, 0xbd7c6e5208e89146), (0x39aef5cdd93013e3, 0x3d1d0eb5303a804a), (0x3990081346d33170, 0x3cfda6ae03deea13), (0x39354c124a1478d1, 0xbc9e05ef8aaeac88), (0x3913481334a524ae, 0xbc783796c23b10d8), (0xb898c79983099259, 0x3c183703be1e37be), (0x386b3b99444e2d90, 0x3befd20ef0b0aee1), (0x381f9397cf40686a, 0xbb8f58105cfa40b0), (0xb8049a8a70075841, 0xbb612ee751921afc), (0xb7875e58d602839d, 0x3b00a4ae3e504c17), (0x376491233ef907eb, 0x3acf0d6bf9e21094), (0xb6870c562302f707, 0xba6d8997e250f98a), (0x36a578a2cb0b00eb, 0xba37af38523f4d8b), (0x3679f669a4d364ef, 0x39d69507180a7fc3), ], [ (0xb6079fabfeb11cd6, 0x39708ac287c0d455), (0xbc569479644686c3, 0xbfc2f206e49909c7), (0x3c0fab1b83d45c37, 0x3f64dbf6a9fb80d7), (0xbc32d9141794e6d9, 0x3f99336443318ed1), (0xbbd0d543bfdf046d, 0xbf3bb6aa3d4e9e78), (0x3bebe3f687043927, 0xbf540aaa5d94bd8d), (0x3b419d1c00b33367, 0x3ef5f61b666129a6), (0x3b7d88846cdeebc8, 0x3efe4158391f2c2b), (0x3b46369cf5ae0043, 0xbea07a7a0745f74a), (0xbaff9b3405275d12, 0xbe9a8ea97b670057), (0xbac6b3f282a770b3, 0x3e3cb10b3affeaff), (0x3a82ba290c76ba69, 0x3e2e6d78879f98a1), (0xba64a2f934330d70, 0xbdd044447904054e), (0xba47c3a2994a01a1, 0xbdb8850c99b76d50), (0x39f0a14b971e592d, 0x3d59e4fa8ff52f90), (0x39daa4eb91c06585, 0x3d3d4b2c1afd964f), (0x3939ae655dba1592, 0xbcde807e2b00279f), (0xb95a357647485d8d, 0xbcbaf942a59e1d56), (0x38d3683474a866fa, 0x3c5ba64c4108b1cf), (0x38d4c3ea257eaf58, 0x3c33ba614d4a472c), (0xb87c3f27ee7c8094, 0xbbd3e1ce58589614), (0xb8227a954e0b146b, 0xbba779ee6dc8cecf), (0x37e88af1866245a5, 0x3b473c7bb3ac4992), (0x37bd028f8f76417f, 0x3b172ca46f7c7bc4), (0x370731151b8a5503, 0xbab681c8b15fa806), (0xb7217a27a51bae97, 0xba83492f6b615d6b), (0xb6cf3fd3e1e70ee8, 0x3a22406d4c30a6aa), (0xb66fde7de35eca76, 0x39eb5d275267b9b5), ], [ (0x3c6b7326e3fbaa70, 0xbfc2740819f1caaa), (0xb60fcb36d157f3a9, 0xb974f95783b2a4e6), (0xbc5b7326e3fbaa6e, 0x3fb2740819f1caaa), (0xbbe4b7a0f7878877, 0xbf49b6f37d0a00f9), (0xbc011249d3675d9f, 0xbf78868d7401bf2e), (0x3bb6d7fdfc21db19, 0x3f1470a7cbcb436a), (0xbbc5a6b64d367c53, 0x3f29fe94ce3d3e83), (0xbb5352a68b135b7b, 0xbec71660e61f0f0c), (0xbb68d34686b6e2aa, 0xbecd6dfcdb026028), (0x3af006603a221bb1, 0x3e6ae79c35d01bca), (0xbb0ef1a3e0a6b3b6, 0x3e64ac50be6ca02e), (0x3a8def2f028aea7c, 0xbe03258409210f45), (0x3a9043d06a02be21, 0xbdf3c09685c05e25), (0x3a14118389ed7283, 0x3d925d85992670e2), (0x3a183ee519f14ba8, 0x3d7b509288f452b8), (0x39b2d75ecdbfec21, 0xbd19586d0c8690d8), (0x395ab270216fde7c, 0xbcfc973a175ffbb5), (0x3937848946c30fb7, 0x3c9a5d61717a7048), (0xb90bfd5527d43039, 0x3c776fa9ee1a4030), (0x38b4a933130a967e, 0xbc156907cfeb9559), (0xb880e1c36e1b1a90, 0xbbeee74de5f3fe9d), (0xb824cf2a1363166f, 0x3b8be6f4a0dc6589), (0x37e62c8c1385fd2e, 0x3b60be8c55ae96fd), (0x37612da67cbdd550, 0xbafdd3c1d9b37f13), (0xb755b91662c8fbb1, 0xbace5ad7a8b76af2), (0x37022a0cf4345b80, 0x3a6aa28d0971fd8b), (0xb6d5974c96417b09, 0x3a37382bb4104861), (0xb67d94e7b14fbe9b, 0xb9d478c454226508), ], [ (0x35ad2d12470026b7, 0xb961b6856d13f265), (0xbc6be2029a752b30, 0x3fc1ff5ebddd3c3a), (0xbc04bba52e05ed21, 0xbf61e2035324643c), (0xbc3a42d5bcad2050, 0xbf97f3506d4a1231), (0xbbd8ddfdbbecb4f0, 0x3f37c65c9302c53b), (0xbbff79e837d220e0, 0x3f53117816335151), (0x3b97f81238bbf14f, 0xbef2df9afa521294), (0xbb9270fec55a19f5, 0xbefcd5d4a9d78a14), (0xbb3a3cd8b565f901, 0x3e9c672d4d6f7766), (0xbb2736243a1ddf58, 0x3e995e4b102194f0), (0xbad74d875eae428a, 0xbe38d22636140e12), (0x3acf7d99ccb23385, 0xbe2d24fc9458bf7f), (0xba609b81368ae5f9, 0x3dcc462d9da63971), (0x3a5ec11516a5a336, 0x3db78eafb15964df), (0xb9d97eb9ab4c3802, 0xbd569f5d498b660b), (0x39c6683560d9facd, 0xbd3c3c4e5b0fab49), (0x39720c56827dbad1, 0x3cdaccaf11834f8b), (0x393a34dc5c675840, 0x3cba161c63abb183), (0x38da1df31f53fe59, 0xbc5870224af67b03), (0xb8dad0b4c075b658, 0xbc3324870c0ba14c), (0xb8797656c00d0ccf, 0x3bd1adca419ec564), (0x383d51df22546bde, 0x3ba6da83c474e675), (0x37e46d6d0e6bdfc9, 0xbb44c90643c60c0a), (0x37b79fc85a4600ba, 0xbb16a1256bbedf24), (0xb71139afc5c7d131, 0x3ab44023f1dfc483), (0x372a8761b55eada4, 0x3a82e31b2fbf1f0c), (0xb69918ba0175b2cd, 0xba208375ee71a5da), (0xb68573d1d2e5403d, 0xb9eadaddc4679dad), ], [ (0xbc4081c2a50ad27b, 0x3fc192f2627a74e3), (0xb602cbb028d0be5e, 0xb96f19a82d415934), (0x3c3081c2a50ad27f, 0xbfb192f2627a74e3), (0xbbed88bdcc1e72ee, 0x3f4635b38affe698), (0x3bfbe434e30d7a5a, 0x3f775eceaabf7f86), (0x3b9ca8671aa555b7, 0xbf11ac9e0164f7c1), (0x3bc6ba93b83783b1, 0xbf28cc464a35b0af), (0xbb6979a9d3cf3231, 0x3ec4014d9bf389c3), (0xbb64740ce7aaeb6b, 0x3ecc1f05a2d85165), (0x3b05322df741e1c6, 0xbe6761d18ebb04af), (0xbb0eb4591bc8e09e, 0xbe63cb9af103e0f5), (0x3aa091626e94e457, 0x3e00b3cb55bbe5d2), (0xba9e3e57a5ff1ba9, 0x3df2f5c763b33667), (0x3a315b0c770078e5, 0xbd9017771db5a5e9), (0xba14aef80f7b4c8d, 0xbd7a4a5e79f39fb9), (0x399f2119d96b7934, 0x3d165128cc4d99cc), (0xb99044f60a617a04, 0x3cfb991575a9dafe), (0xb926aff2cdbba534, 0xbc9756473a57c945), (0xb8eddecc5081ac54, 0xbc76b070fece7fc3), (0x38aa9bf0f1b7e51f, 0x3c130e1f9f15895b), (0x387bf52f2b971db4, 0x3bee01b29beac9db), (0xb82b5d175030a5d2, 0xbb88f8681f6cb14f), (0xb802f353c2babb03, 0xbb604e16aece260c), (0x3796062f77cde739, 0x3afad6e7811caa58), (0xb769dd7aa9c09187, 0x3acda3c957b84f57), (0xb69ebf7c2909d637, 0xba681861ce3144a5), (0x36d6353c4ed8910a, 0xba36bb1e8cb840f7), (0xb6713ccdbc67576a, 0x39d29b2e1989c79c), ], [ (0xb60827407277ec38, 0x3962a629f22fc940), (0xbc4e7aa4db2a788c, 0xbfc12dd55d4be2b3), (0xbbf6da5fa7c96d5a, 0x3f5f1aee31818d19), (0xbc319e43d5f0f1d3, 0x3f96de64242a8310), (0xbbd5e566736996f3, 0xbf34afdf89fca61a), (0x3bd951e5980d1ee4, 0xbf5238cfc13ac771), (0x3b9632bd2bd2da27, 0x3ef0719d13e00e52), (0x3b672b1f29067499, 0x3efb974781a526b4), (0xbb1d4aa2a14eec77, 0xbe98cc82a70d752f), (0xbb3bd18c494bed4b, 0xbe9850ae878c25bb), (0x3ad9b4f299f8cbdf, 0x3e35bba73e282ede), (0x3ac284476e69e80f, 0x3e2bfe1396e83644), (0x3a452a15bea62efd, 0xbdc8d7dbe4a241ab), (0xba562396ff096680, 0xbdb6adfbd773748d), (0x39fff36c9935638b, 0x3d53f51dcb398ad2), (0xb9d0c0a18775989a, 0x3d3b40d30be85f3d), (0xb968a32d9f779535, 0xbcd7bf544872d9cc), (0xb9300a2db3cd9c4c, 0xbcb93f163a09379e), (0xb8f5e58d33a695d3, 0x3c55c1ca7d35fae3), (0xb8cde16328522c93, 0x3c3293b43a786cbd), (0x3868b9d269703d27, 0xbbcfa1df021b9c1e), (0xb81fb6589e93977e, 0xbba63d0b33ef1315), (0xb7ebbf0e52f441d1, 0x3b42afdbaac319ef), (0x3763682a897a7957, 0x3b1614280111c2d3), (0x374088e1875cc18a, 0xbab24b9d3911b7e1), (0xb7203b62eacc40a5, 0xba82796c2afed41a), (0xb6bf609b433463fb, 0x3a1dfaf4709fa729), (0xb678488c980025d3, 0x39ea51c4a8e6f489), ], [ (0x3c60c06e2860e868, 0xbfc0cf3ee98f769b), (0xb5f9feaabed5f911, 0xb969e1daf76ea4e3), (0xbc50c06e2860e867, 0x3fb0cf3ee98f769b), (0xbbb4697a99d5d86c, 0xbf436f451f6e14fb), (0x3c194225ed089993, 0xbf765d05948a946a), (0x3b91ed6777d1a61a, 0x3f0ef55c5a0d16cd), (0x3bcf058a2a3a8b03, 0x3f27bfec9d15d038), (0x3b563856fcc3c4f3, 0xbec18c549f28e528), (0x3b59158b454353b0, 0xbecaf7544eeac766), (0x3af5145c85d21cb0, 0x3e648e81edf38b1d), (0x3afbd8241e556e27, 0x3e630341e78d1014), (0xba51c1fc73bfe02c, 0xbdfd73d2c942e970), (0xba8a049a511a826c, 0xbdf23ec2729d3a6d), (0x3a22971a921d0af9, 0x3d8c78e44cdec8b3), (0x39d9c56e9b4dce66, 0x3d795a6f6107b4e6), (0xb9bb8e56874267da, 0xbd13d1c77de8a03d), (0x3998a5b51d6fc50e, 0xbcfaace944141c60), (0xb93cff4a30c305b7, 0x3c94cfcb5e849650), (0xb8e907aca70c354e, 0x3c75fbc3b0ec933d), (0xb8a0d1de4a1de392, 0xbc11115c48c08b34), (0x38719338bd822266, 0xbbed24eb2fafa2dc), (0xb7d3634e9413e271, 0x3b8677909f205b32), (0x37fb57fb5bb117fe, 0x3b5fbfecf15f1ecd), (0xb7822bf0c08e088c, 0xbaf8423bd6a1b4d1), (0xb76a00917d57eda7, 0xbacced1ef16333df), (0x36eddbee5e40116d, 0x3a65e06ebbfe2e14), (0xb6cf548c275b3e70, 0x3a363be97f954678), (0x3646fc15979b90b0, 0xb9d0f619585e1af0), ], [ (0xb5eea501cb87ef99, 0x3972465ed4007bdd), (0xbc64353fd6c42f1e, 0x3fc0768257dad56a), (0x3bf3a4186dcff329, 0xbf5b602a7beaaa48), (0x3c16aaef36d826e2, 0xbf95ebc22efd092c), (0xbb76c80c9b064de4, 0x3f3236a604142e61), (0x3beddcf66c5978c8, 0x3f517a482faa8d85), (0x3b66ad649af92b73, 0xbeecfc00890787ae), (0x3b928f6dcddab559, 0xbefa7d7b128ac538), (0x3b25a6c98550b698, 0x3e95e419f1b57043), (0xbaf32b6c630a02f3, 0x3e97603cea235244), (0xbad9cee3035468eb, 0xbe333a0b436c8824), (0x3abe7890b1e58aeb, 0xbe2af46417845f40), (0x3a4f73757ba505ba, 0x3dc609ac8cd8177a), (0xba59cd5b34bda911, 0x3db5e11b87ad3903), (0x39f753770c6a00bd, 0xbd51c2756590391a), (0x39988f32e9922679, 0xbd3a586483dd891d), (0x3977131f1f9126e6, 0x3cd534d22c600962), (0x39500677438cdb27, 0x3cb8755ad322c506), (0xb8f45577511a2e70, 0xbc53809e528c5e70), (0x38d78081f89f0b4f, 0xbc3209a0a78d692e), (0xb8532441923d88b3, 0x3bcc77842d1425ee), (0x38002948000e0b89, 0x3ba5a4538094a38e), (0x37d2ec02968bd2b8, 0xbb40e2a860417e77), (0x37b26676c0acf6d9, 0xbb1588f3ef728c24), (0xb75b53bc7d88d00a, 0x3ab099700fe34bf3), (0x36e30a044384490d, 0x3a820f1c712673f5), (0xb6ab8f46c26e1b98, 0xba1b4fa75c261c78), (0x366effaba36280e2, 0xb9e9c5f163a1d50e), ], [ (0x3c61166b7995967a, 0x3fc0230ba90f2871), (0xb5c8e0d3f893a50f, 0xb944e3fd95304f5b), (0xbc51166b7995967a, 0xbfb0230ba90f2871), (0x3be85d0df08ff932, 0x3f413164a0864cde), (0x3c175b99fcae0fa4, 0x3f7579c1bdbcfc99), (0xbbaa847d3261afc4, 0xbf0b67e1913c668b), (0xbbbdc3b0bfb76e55, 0xbf26d26de4fd8c5d), (0x3b509cffcaa70410, 0x3ebf1b520b063853), (0x3b56e93d7c50e034, 0x3ec9f01e7c1909a0), (0x3aeb43dee887c41e, 0xbe624071b1796027), (0x3a99b4c11c97bb23, 0xbe624f8e939ce43c), (0xba9ac0bb48385d05, 0x3dfa35663595463f), (0xba62567920c13146, 0x3df199120d49d507), (0x3a1bdcb5b3b180ed, 0xbd896771e1b15e44), (0x3a1adae6ea9dcc28, 0xbd787ede134ed7a0), (0x39ac92871627b22c, 0x3d11bccdfbafa1fd), (0xb98c58fbb742d0bf, 0x3cf9d22a6dc5a57b), (0xb91dd27f9db4339f, 0xbc92b00e367301ce), (0x391afb7d91b7ccfc, 0xbc755236722b2dc7), (0x38ab20732a5e1932, 0x3c0ec2ce49a984e5), (0xb878a4f67789acc8, 0x3bec52d2fb40494f), (0xb82efb139c9eabfa, 0xbb84522e39f45c23), (0xb7e18df511f3aea9, 0xbb5eeb3ed3be49c9), (0x3790a89c14bccf9f, 0x3af606528674e24f), (0x3762e9176a7f8941, 0x3acc3a09b96f5019), (0xb6d1b63a61a018b7, 0xba63f00d5dec7881), (0xb6d89c276f90a3f7, 0xba35bd3ff3734b8b), (0xb63f6e7b2ed1bd35, 0x39cf0615ab9d7cb3), ], [ (0xb5d35e9581fc00c3, 0xb940bf81e7b6bf7f), (0x3c10417847765c1c, 0xbfbfa8b3f9ae4375), (0xbbcf334b36194e10, 0x3f5856073b7fa2cd), (0x3c3664c698368b18, 0x3f9514e652eb2e96), (0xbbb93b53ec8276c9, 0xbf3032298718ea1a), (0x3bfdfbf103edc8e4, 0xbf50d1153fde431b), (0x3b7c365adad42aa7, 0x3ee9cb455c29d6a7), (0xbb9fa9b04c310c1c, 0x3ef982167b1c52c3), (0x3b3466b70782cb7f, 0xbe938191ef68eab3), (0x3b31f4e70613c5d6, 0xbe968865345b3130), (0x3adaf50c9e003b40, 0x3e312960010da387), (0xbace36911be0e026, 0x3e2a0403679f6882), (0x3a41779eb4010bf6, 0xbdc3b67cc0b96c06), (0xba565f31bf6e70fc, 0xbdb526038b956efd), (0xb9d5ed9568f49fa3, 0x3d4fda06e840fa34), (0x39d1e175fdd2dad7, 0x3d3981de640d0e00), (0xb97d648a5890112c, 0xbcd311fc56c4b888), (0xb93dacd97e23c3ac, 0xbcb7b8f62899fc83), (0x38f158e1e7d5426e, 0x3c51977cb2740dc9), (0x38da9c4d3d78fa2e, 0x3c318706eb31dddd), (0x38690756a8b2b9b3, 0xbbc9c2ecf3513bc2), (0xb843d0ba97dc7b3a, 0xbba511e7341f19f5), (0xb7c70af900714fae, 0x3b3eaa18f0a1bc9d), (0xb7821dafb6b0a02f, 0x3b150190ffd95109), (0x372d7c9b2e2dbe3b, 0xbaae3fb72389f327), (0x372d26a5ec602bfe, 0xba81a629641ad013), (0xb6b095243f6598d9, 0x3a18f85627d46b37), (0xb679a0a342b383f9, 0x39e93a4bfaf23e38), ], [ (0x3c50db2c50623ec0, 0xbfbf13fb0c0e6fcd), (0x35fba9ea35ce88dd, 0x396fbca69a15def7), (0xbc40db2c50623ec1, 0x3faf13fb0c0e6fcd), (0xbbddaa71693254ea, 0xbf3eb3e6fcc47c00), (0xbc1a7c91ef9a7d9f, 0xbf74af74cbd77bef), (0xbb8ca4e36c0e1909, 0x3f087bb1ebeaec75), (0x3bc0dc1e11076c53, 0x3f25fe629203150e), (0xbb5990b5b3489011, 0xbebbd0f2a6555e6b), (0x3b6af9c37c820e57, 0xbec9040de830649e), (0x3ae759c4b2a6504b, 0x3e6057f7a76993d7), (0xbaf1d65072f86b24, 0x3e61ad6dd5105c3e), (0x3a9d40eb328040f7, 0xbdf782a6f5738cdb), (0x3a8bf5e5277cbb15, 0xbdf1027dc06d4453), (0xba28e3867173de2a, 0x3d86d65b13b16f65), (0xb9fcb2787109df88, 0x3d77b59e9ed7367d), (0x39ae1b468c4215d5, 0xbd0ff800f2a49a01), (0xb999ff66e26a3daf, 0xbcf907be43054aeb), (0xb926a66c1da18e82, 0x3c90e2e1d8f5ad75), (0xb91450507fc3a22f, 0x3c74b3a8b0fb5013), (0x38960772f0ae799d, 0xbc0be06d96b7165d), (0xb880df93b3817817, 0xbbeb8c22733ba4a9), (0xb800279bf5e0f4bd, 0x3b8278dcce924024), (0x37f6405c8f354677, 0x3b5e1fb516b57c41), (0x379e9caf5e3a0d68, 0xbaf4159150b0936f), (0xb7554adeee798af2, 0xbacb8c841ae83900), (0x36e38beff289f2bd, 0x3a623d5f11f3220d), (0x36c4bb8b7542c332, 0x3a3540f31271ca17), (0xb6641ee382a94dd9, 0xb9cc774f548476e1), ], [ (0xb5a8c0565f36d2df, 0x39138a74ee514d1c), (0x3c56a7c2ed8fa844, 0x3fbe8727c572a2c2), (0x3bfdee3ce04b3d12, 0xbf55d1ef092ab395), (0x3c206dda20eba87a, 0xbf9454e7a7395636), (0x3bb99eb39ffae527, 0x3f2d0cc3a7fa6d3d), (0xbbc9d1e5b54f9af7, 0x3f50398d2cbd02df), (0x3b8aa1f4bf33f006, 0xbee725b0909f9c66), (0xbb9b20d87a760073, 0xbef8a022f5fee447), (0xbb1fcb0c42b327cc, 0x3e9185b1ea97a54b), (0x3b3ea0aa1deb8165, 0x3e95c571167401ae), (0x3acd2759d32f612d, 0xbe2edff6514e1da9), (0x3ab2592f69cf47b5, 0xbe29298da3c4fa71), (0xba621593a3e29e00, 0x3dc1c34705eadfb1), (0xba424eda63e46424, 0x3db47ab8ec529c51), (0xb9e71b8905efe1df, 0xbd4cc24a2f007c3e), (0xb9c2a661b676a229, 0xbd38bbcc44e6c225), (0x396f64643e54c71a, 0x3cd1420df9bb4358), (0xb952c79ec699f349, 0x3cb7095f8b3266be), (0x38e9b99fa1cd4cdb, 0xbc4feb87e4e6508e), (0xb8d4b81d9d1d9436, 0xbc310c0caf4ba7ed), (0xb8635b1ba8939988, 0x3bc76f4ca2183df3), (0xb8470f94857758df, 0x3ba4868177e6a94b), (0xb7d51e8dd2ddba52, 0xbb3bf93dac9dd574), (0x37b66de2ce896857, 0xbb147f2c3ea4f41f), (0x37422b1ac15ef2d9, 0x3aabacb94681ac1b), (0x372b5172ed4e760e, 0x3a813fd96ffd162f), (0xb6bfc10cab672280, 0xba16e97ff088b7e8), (0x368ef32e3b7f65be, 0xb9e8b0d2637124f7), ], [ (0xbc3b9f1d130797af, 0x3fbe018dac1c17e3), (0xb5e141aefdec9b98, 0xb96cc7fef8ec3e0d), (0x3c2b9f1d130797b4, 0xbfae018dac1c17e3), (0xbbc5edf62333ab91, 0x3f3ba21bd15d02a4), (0x3c138b4f0d3a410f, 0x3f73f9e0db07e7ef), (0xbba6f23ddcae3185, 0xbf060b77c5e27622), (0x3ba86d4e04faa24d, 0xbf253f9b1a5d228c), (0xbb5fddc005e37ab4, 0x3eb910b38812c253), (0xbb40935ad5366a7f, 0x3ec82ee6dfdfedeb), (0x3afa8bf30766210f, 0xbe5d7cc2a9a602ee), (0x3b0b507850a97457, 0xbe611a57d8645358), (0x3a8673cba0bc56e8, 0x3df53d401519442d), (0xba8c0365adf75127, 0x3df07915ef87408d), (0x3a20221e3beb4ce4, 0xbd84aabcb6141c76), (0xba1d282fee2792c3, 0xbd76fcb8e2eada15), (0xb9a71c1e6871ca1b, 0x3d0cfcfdb2faeb02), (0xb99d6b8f41ec2a2a, 0x3cf84c5369d2e33d), (0x39204114eb9c2f69, 0xbc8eb11d7e6581d1), (0xb9191341e21aab61, 0xbc741f9ab4632bff), (0x38a996918c6850e8, 0x3c0965159407e959), (0xb88a5f0c11aeb57c, 0x3bead0e3ccfe39e7), (0x382f54e660147ef3, 0xbb80dee0e993354d), (0xb7f1c5f5adc77455, 0xbb5d5e03476b81b0), (0x37898d6415c2c8f8, 0x3af264535f4853fa), (0x376323c802fd85b0, 0x3acae5afea45a1d0), (0xb7064e5aaa6a944b, 0xba60bfa00dd729a9), (0x36cb04c64064bf04, 0xba34c82d1f8992b1), (0xb64e911d15e3dd3d, 0x39ca34d3a49f024e), ], [ (0x359edfac18b305f3, 0x39163cc00f5dbc0b), (0x3c555d27e18add4d, 0xbfbd82939ab62339), (0xbbe5f2055a671371, 0x3f53b5a54845670f), (0xbc331ee0af44ab91, 0x3f93a7ff1622def8), (0xbbb2001fd86915ca, 0xbf2a3ebc476a606d), (0xbbb7a5c728534a7e, 0xbf4f61adde3a8c61), (0xbb6721b027970cdc, 0x3ee4ec45da0478b0), (0x3b60295953d04e61, 0x3ef7d3b28159f23c), (0x3b21dd48381068cc, 0xbe8fb3f21bcd7fc4), (0x3b3047a478ead9ea, 0xbe95145a876d2273), (0xbac575cc2dd16f8c, 0x3e2bf64cdf7c0558), (0x3a9c7ea36a18f920, 0x3e2862204ac427d2), (0x3a25529af35b5dcf, 0xbdc01c0d48888811), (0x3a3766e366a3fc7a, 0xbdb3dd6cb1cbcd8f), (0x39e0fa707938a9eb, 0x3d4a2020c8b3c20d), (0x39bbbc58f9d26ec6, 0x3d3804a9d711292e), (0xb96e85f6cc946fb5, 0xbccf6a1ef9182e2a), (0x39591e00ef906d2f, 0xbcb665c82dfd3112), (0xb8eea5743e788fee, 0x3c4d1cbc474ae19a), (0x38c6e72f6eaa6ee4, 0x3c309883728ed044), (0xb85fe1b5b6914470, 0xbbc56bda19bbd907), (0xb83f2fa5959c5300, 0xbba4025c7e86cfc8), (0xb7d115ca11e0e05e, 0x3b39a17a25046119), (0xb7a514b6675a5e5f, 0x3b14026121051408), (0xb73ae1c02372f342, 0xbaa96b5d080744b6), (0xb6f3427ab8e0fc99, 0xba80dcf24b28c249), (0x36b101dd967ab100, 0x3a1519032b200dc8), (0x3675b89a8e98627b, 0x39e82ad2bc03a6a9), ], [ (0xbc56edd809f4ec43, 0xbfbd09b21e36c0bd), (0x35e5d21c4590e23a, 0xb963ad3554cdbdc3), (0x3c46edd809f4ec44, 0x3fad09b21e36c0bd), (0x3bd1da06fbc18d60, 0xbf390b0e6a475e45), (0xbc140975d5184af7, 0xbf7355b904fbf7ee), (0x3b9e3b983f1177c4, 0x3f03fc459d1e25a4), (0xbbb494c77a177888, 0x3f2492cc61d19dfe), (0x3b46367d4d2995c5, 0xbeb6bcf110a02ad1), (0x3b6b6ea46d6df357, 0xbec76d44f6a83523), (0x3a803005742b014c, 0x3e5ac61efcb3c36c), (0x3afeb84629addc98, 0x3e609436fcaa3965), (0xba99e294d7264bfe, 0xbdf34eb6095f969b), (0xba88db7c11c38cf9, 0xbdeff662945eb368), (0xba237b9cbf75a8c0, 0x3d82d05bf8ff5181), (0xb9d4ca3e6003606c, 0x3d76525fbb563fe0), (0xb9a93e3cfc188270, 0xbd0a6eb937c7f6c0), (0xb98026c04e791e1c, 0xbcf79e90468589aa), (0x39252d8dea0a8e75, 0x3c8c0998b46c2a84), (0xb9065519f44afceb, 0x3c73955fe5fb10db), (0x38ac6a20d09a8309, 0xbc073ec89759ba44), (0x3868ea900cd0acee, 0xbbea20bd7b455493), (0xb7fd0a1ee99e85f5, 0x3b7ef3962cbda037), (0x37ea27d0e101e8a6, 0x3b5ca6506245824f), (0xb773dd8f476a0af7, 0xbaf0e8cae31c27f5), (0xb75f5c680a514474, 0xbaca461c76aba331), (0x36c4607ce2cc9a56, 0x3a5ede6da0b05cf5), (0x36b52adf7a554ae1, 0x3a3453a0c69c3020), (0xb66d21d6c5df4ac2, 0xb9c8341f8ff89500), ], [ (0xb604e106c1a5d68b, 0x3960e1cf91ecbcd0), (0x3c4e1f19f10295a0, 0x3fbc96700031f601), (0x3bd8339df4a4988a, 0xbf51eb2a07d0f09e), (0xbc39bfe53ec12c89, 0xbf930b36eddaa234), (0xbbb206af4ba8cd76, 0x3f27dd2dde84b73c), (0xbbd1f3a6f0dd2e5a, 0x3f4e696553e0b8a5), (0x3b70bebcc672dde7, 0xbee3085aa35a1647), (0x3b964955e62a56d1, 0xbef7199f24bccae1), (0x3b29acbd06286b9c, 0x3e8cdbab6a766176), (0x3b336b635edd5e8a, 0x3e9472a7cffbf91e), (0xbaa919ffae68f01f, 0xbe2979f5211c4dae), (0xbacb3a83d6a4505a, 0xbe27ab4b01a902db), (0xba3d20efa9eb9b62, 0x3dbd63904e4c487c), (0x3a3a2266d5d6a8ef, 0x3db34c83fb1c2279), (0x39d10d542056a77f, 0xbd47dcfdf13e5ccc), (0x39b3859d37da710a, 0xbd375b01ddacf988), (0xb9565b371d7ee634, 0x3cccbd41ea6afd27), (0xb9581212fb798324, 0x3cb5cd46eaba1e98), (0x38e7f3fcdfe0798f, 0xbc4aaded22d1c26d), (0x38c46a63e955520e, 0xbc302c0feb2cc9ce), (0x385cf68aedadaeff, 0x3bc3ab0efb07293e), (0x384f8dd325a6cd09, 0x3ba38564ae72454e), (0xb7d09df47a273d60, 0xbb379494d9aa279b), (0x3794fe8c13f0d784, 0xbb138b6c661b3cba), (0xb7395294aeae0a19, 0x3aa76f5fd4aa472c), (0x3729b16a6763e36e, 0x3a807de116ccc64f), (0xb6b1c69123ace593, 0xba137e1e22a65820), (0x368881179d4440a6, 0xb9e7a919992ba54e), ], [ (0xbc5ca34ef67ceca5, 0x3fbc2861347b1b39), (0xb5d9566d846e8e8c, 0x396cceb50dfed9ea), (0x3c4ca34ef67ceca4, 0xbfac2861347b1b39), (0x3bbf201ae22fff02, 0x3f36d57bffb37fd5), (0xbc16b4ecac2fa1c1, 0x3f72c060ef553f18), (0xbb9df91b90d34532, 0xbf023a407b722d2e), (0xbbca3432d200d5d1, 0xbf23f55581ec683d), (0xbb5e04bafba5db02, 0x3eb4bfb4daa2ff62), (0xbb42a29e46400df9, 0x3ec6bc69099af2f7), (0xbafb52717e31e7c3, 0xbe5873340987d276), (0xbadb973833d824fb, 0xbe601951f02d2b37), (0x3a8c2da9623b39af, 0x3df1a6174fe55fbe), (0xba72657ffe3c0d22, 0x3def0eca5bc0284a), (0xba1b8e7e494f244b, 0xbd8137cb1fcc55a3), (0x39c37c1a924f4abf, 0xbd75b4f7f2bb19ed), (0x3999da79a9d54cda, 0x3d083934ed797abc), (0xb989eab29e540769, 0x3cf6fd29fcbcf38a), (0x3920c6c752968451, 0xbc89bbe4a386b212), (0xb91a160d6358c9f0, 0xbc73143b8f6fa78f), (0xb8a480a782f588c3, 0x3c055f1ef8c6530d), (0xb887a3802525f474, 0x3be97b209a79f9f3), (0x37f474a28bfc52ff, 0xbb7c822a3d9869c8), (0x37f5fabb96a9e9b8, 0xbb5bf86d95cc8f12), (0xb78a0516ef829f54, 0x3aef35917d0b3f76), (0x37622045f0e24361, 0x3ac9adf870fd0a7b), (0xb6e0bdb6d552746a, 0xba5c8b4b32991b65), (0xb6ca53a583f641f6, 0xba33e3ad6afab22c), (0x3644ed17a9579532, 0x39c66c8a74f2a901), ], [ (0x35d31fe5aa13389e, 0x39517eb126abaf87), (0xbc2986f8b543f27a, 0xbfbbbf246019c0d4), (0xbbf8243dc68fb135, 0x3f506224199140d8), (0xbc31c8ab4f070de8, 0x3f927c3416c09898), (0x3bc1400990dffef0, 0xbf25d279dc87cf69), (0xbba49f5dbb72a065, 0xbf4d86a5f5adbdac), (0x3b8c1a134d478c22, 0x3ee169041634c248), (0x3b908bd4df68b45a, 0x3ef66f5bd1bedae1), (0x3b2340bc492fa102, 0xbe8a69b2c717d54a), (0x3b2b327658083b81, 0xbe93de4eab456cbd), (0xba8a5251b6ada8e0, 0x3e2755eabbde6915), (0xbaceee9ff7faabed, 0x3e2702fe7ba9f8c3), (0xba380d3becf77482, 0xbdbaf2007eeae256), (0x3a5fcfcac159b57e, 0xbdb2c69746948e55), (0x39e98e02f368d7f4, 0x3d45e77ad9a9daf0), (0xb9d9fd1217de9157, 0x3d36bd7bc6045cd0), (0xb96832ead3387986, 0xbcca6a2a200a32c0), (0xb955d0d8052f28a5, 0xbcb53ef0001a8fc4), (0xb8bb1f311ea4c9b4, 0x3c488eb37fc1cfd3), (0x38cf9a896df080b1, 0x3c2f8c832f51b4aa), (0x37d4b18c2095b824, 0xbbc22200a0360453), (0xb829797fcaa4e047, 0xbba30f596dbfddae), (0x37a2d23a75e1c560, 0x3b35c6dd016030cd), (0xb734e085d594092d, 0x3b131a4ea769c7d3), (0x373bce3510c7cb6b, 0xbaa5ae7bd23b9081), (0x371fb7fbd6256541, 0xba8022d72980d3c8), (0xb6916a353736b148, 0x3a1211535635a157), (0xb68195f4662a5736, 0x39e72c1b69eda79f), ], [ (0x3c497d2b9281abc8, 0xbfbb5a622198a72c), (0xb5e793f1c68299a8, 0xb94513e9f11c844a), (0xbc397d2b9281abc8, 0x3fab5a622198a72c), (0x3bd29fd72f6919a6, 0xbf34ee71cf67c243), (0x3bef69e3e89e3763, 0xbf7237c02b462f6f), (0xbbaa32f85df10cac, 0x3f00b67b6fdfec62), (0xbbcb53a20d4b2f6c, 0x3f2365167d8bc330), (0xbb5df27a7ce0ec5b, 0xbeb3086b7a296e69), (0xbb64ce30c488b9c8, 0xbec61a141425c2a6), (0xbaf5a586400cf358, 0x3e56712b23991e80), (0x3afc0839ad44e9db, 0x3e5f50736839e481), (0x3a894d2884c96f7c, 0xbdf0366d02b91b84), (0xba3b7d3083bff34e, 0xbdee38f9bda5f6df), (0x3a0f47f210ca9110, 0x3d7faa3d1cb01e65), (0xba1e53d61aed5735, 0x3d752317a2a5b9a2), (0x39a61437236ae98e, 0xbd064cd06847bd1d), (0xb98a88cfd6fbb36d, 0xbcf666eebfeb573c), (0xb921559c51711009, 0x3c87b8b54f1785d0), (0xb906f3154f9ab684, 0x3c729b70ca32ed3d), (0xb8ae6effa325d36e, 0xbc03ba848f793a6f), (0xb8862efc7da56047, 0xbbe8df655223f804), (0xb7f4102cd3bf6abf, 0x3b7a5b9007f4f46f), (0x37fe605a6b4873f8, 0x3b5b53fa1a9d0aeb), (0xb7858edfd4fa5bb7, 0xbaece6fce7a8c528), (0xb763c9762154c0c5, 0xbac91d34853abb67), (0xb6f1321ee8b9d4f4, 0x3a5a7ad6f4ddf512), (0x36c7e2ebffed7e36, 0x3a3378793c3201e1), (0x363afde2a34531f7, 0xb9c4d6575c0bc39d), ], [ (0xb60d030c92133af6, 0x396cca2f2b0d4235), (0x3c56e5b3d654a3dd, 0x3fbaf9cb42cd08a7), (0x3bd4df22cc11675d, 0xbf4e1c66d7616e37), (0x3c32068ccdde2ecd, 0xbf91f90fd1013589), (0xbbb9426a5fb5b160, 0x3f240e3eb09b7d6d), (0x3bcf4131edb03e41, 0x3f4cb682ff471274), (0x3b8c9cd4cf70b12b, 0xbee0016819a61dd8), (0x3b8325d69b159807, 0xbef5d2d1c420646d), (0xbb157a8a155cbaaa, 0x3e884b0fe8a85355), (0x3b1d5bbe26d980b7, 0x3e93559d96bef598), (0x3ac3da55cd6ad83e, 0xbe257a0be74997ad), (0xbaac817776a96dfe, 0xbe26677c8f53b6a6), (0xba48a3c160c8aa22, 0x3db8d1ae21b756a1), (0xba55e41c05b333bc, 0x3db24a6e1ac65e87), (0x39d8b28dfb36d53c, 0xbd4432017034b94c), (0xb9b0c0b8d7240fb1, 0xbd362ae0447c7c88), (0xb96e042713d54739, 0x3cc86190e6a87083), (0xb940efa65c450767, 0x3cb4b9e1622f9586), (0x38cb94e9a0146b9b, 0xbc46b1f3e51e7332), (0x38c980a0b48ea2c9, 0xbc2ecd41315429fa), (0x386a6123111c55fe, 0x3bc0c7d6edd07b17), (0x3843ce4f1feb2ebc, 0x3ba29fe1dfade081), (0xb7b6d84618b5e516, 0xbb342eb57150f9e4), (0xb7a6474c8a6dcfb7, 0xbb12aee3771f508d), (0xb7333647a6c944af, 0x3aa4201b40c833df), (0xb71eb58df16b4736, 0x3a7f97bc8a144320), (0xb6aee477a8ff3709, 0xba10cc450b34befb), (0x368b6b8edb270aaf, 0xb9e6b4102ba6d220), ], [ (0x3c49a6abbfd839f8, 0x3fba9d183bc04545), (0xb5f15a143d9b75a9, 0x395a77273a2f7cb1), (0xbc39a6abbfd839f9, 0xbfaa9d183bc04545), (0x3b97025ee34cb468, 0x3f334779874010dc), (0xbc01fefbfc4e4e9b, 0x3f71ba2299ab88a8), (0xbb55c0e2a1925dd2, 0xbefecb19f5bdc649), (0xbbcce75d4325824c, 0xbf22e052707cc859), (0xbb5a63ba682d624b, 0x3eb18a5da77edd83), (0xbb6dd00d5413ce37, 0x3ec5846b622f592b), (0xbae5e872e9afa841, 0xbe54b17e97b5884a), (0x3ac6a221aaf909f2, 0xbe5e7f76674dfaab), (0xba84b34281199881, 0x3dedeb504ed353c6), (0x3a86775826683d8c, 0x3ded72e25f190409), (0xba00d222c75ec8a5, 0xbd7d3e076b0201d6), (0x39c62484e2aaf790, 0xbd749b825302af88), (0x39ad85f9e975e5bb, 0x3d049d35475fc5c4), (0xb99ca04c877af6e6, 0x3cf5dac9623f7b3a), (0x39280969190bc2ec, 0xbc85f3d5130dc427), (0x390c3038a68f53f8, 0xbc722a4aeb6975db), (0x38930f7db32e8831, 0x3c02479e3ad0904f), (0x386d535dbc6c1f3b, 0x3be84cdbd491db42), (0x381f7a28d6ae78be, 0xbb78745ed68ebb0a), (0xb7eb97e422517d33, 0xbb5ab87a4b0f3210), (0x378e41504a923c16, 0x3aeada8753b4f2fa), (0x375ded58316b4b3b, 0x3ac8939aed0eb956), (0x36d24ca9391ef811, 0xba58a3c50700bb64), (0xb6c8cff6f49b7cc7, 0xba331204a4a28f43), (0x366456ce1c2efeb7, 0x39c36abd94cda9ea), ], [ (0xb5d6aeec01447ebf, 0xb94fef3146f8bc8c), (0x3c5729f43724612e, 0xbfba4407dac72297), (0x3be5723d945cf783, 0x3f4bcba4dec1da44), (0xbc3fe775590d7dad, 0x3f91803c65cafdfb), (0x3bc90cfa57dbb4d4, 0xbf2283df2b3e4a6e), (0x3bc3e3e0391f1e1c, 0xbf4bf695e89259cd), (0x3b630f86ed6a9315, 0x3edd8f3759122d51), (0x3b9030fb5fd0d14f, 0x3ef54246c8e04218), (0xbb1b2983b9c2c402, 0xbe867111bc8e67a4), (0xbb3a3cef2b75d6f2, 0xbe92d72a1f62ec18), (0x3acbd165702624f6, 0x3e23d9ca3eb1e22f), (0xbacc01aeccf1babb, 0x3e25d74a6e225515), (0xba59e0b645683780, 0xbdb6f4b420b2f957), (0xba5cdfc243103d08, 0xbdb1d6f985dc3ec9), (0x39e7bf317b14f352, 0x3d42b1d81101dea8), (0xb9d83163c0057ca7, 0x3d35a2197089fbfb), (0x395c76bb39cce133, 0xbcc6974aff17c78e), (0x39598eb0a01efbec, 0xbcb43d4892ea1bcf), (0xb8ed15e01c0238c4, 0x3c450d21b45ff80d), (0xb84241f1dc4f6f34, 0x3c2e196b40872b31), (0x385c04a02280abca, 0xbbbf2abd4db5d9be), (0xb84959c23561aa48, 0xbba23699d666bfec), (0xb7d227fbae70ed91, 0x3b32c4313f19d90c), (0x37b6f63990f0594b, 0x3b1248f0a9284b37), (0x372ffeb55db91815, 0xbaa2bd11bf68d5b1), (0x371b75883a5be1b6, 0xba7ef1cd2cb739b8), (0xb6aa77e2877a5055, 0x3a0f531ca9868a0f), (0x368cea389ee72d20, 0x39e64106dd656961), ], [ (0x3c4f5da9526c15aa, 0xbfb9ee5eee1a97c6), (0xb5f1d3382c1276a4, 0xb96402f67a0b5834), (0xbc3f5da9526c15a9, 0x3fa9ee5eee1a97c6), (0xbbc331009164145e, 0xbf31d55d93e59bd7), (0xbbb6887e944cd005, 0xbf7146219394a99c), (0x3b8ca8e50931e16c, 0x3efc7d32bb646e2a), (0x3b459561844c17b3, 0x3f226599aed4f1ca), (0x3b2f06633c8a4cba, 0xbeb03ba58ec85c12), (0xbb602686ed9edd3e, 0xbec4f9e3961bb9dd), (0x3aeea9ee2c6a2043, 0x3e5328d4dc334079), (0xbaef3a53acd5c6d4, 0x3e5dbda7ac70ff93), (0x3a77a849dd25fe0f, 0xbdebb7c2f187144e), (0xba64d006a8eb9c0b, 0xbdecbac24c760567), (0x3a16ef76e61a4831, 0x3d7b1c35b65eca4e), (0xba1dac5564e87883, 0x3d741d23f93de7a0), (0x39a9abd11b46d7e7, 0xbd03208d806698c2), (0x399718ab551976b2, 0xbcf557c166250d9c), (0xb92d6295443bb3ec, 0x3c84637130a9d7f8), (0x3916194c75a97d3e, 0x3c71c021934a59f1), (0xb89fd63bcb1b75d7, 0xbc00fed119c972a1), (0xb88c541b145b8b02, 0xbbe7c2d6451d6c10), (0x381dbc09437e925e, 0x3b76c3357c9d7057), (0x37fb570ed16daac3, 0x3b5a25664a0ac691), (0xb74761fb4819cca1, 0xbae906c5b9661a95), (0xb76d18cd574324fb, 0xbac810df45f48012), (0x36ef5b739f6495ca, 0x3a56fe3f66728fcb), (0xb6d5974f41aa1f59, 0x3a32b0377532218e), (0xb660f1fa91a8fb3e, 0xb9c22493f39e943f), ], [ (0xb5e9353c25c13119, 0xb94016db9db1eb7c), (0x3c422d28ddb0663f, 0x3fb99be73fa3efcc), (0x3bc06623176e8b2d, 0xbf49c3248da75775), (0x3c24e67d5d6f01f7, 0xbf91107147eda800), (0xbbb9f85d6cd5a259, 0x3f212980be9d8520), (0xbbc6d7f4255305b5, 0x3f4b44e1221e6051), (0xbb75ffceb4091f98, 0xbedb67b78c1dd9c5), (0xbb952647474dbc63, 0xbef4bc49e9b5bcfd), (0xbb07d96f251b94dc, 0x3e84d02ffb8bcfd0), (0x3b3e32d27646b4d2, 0x3e9261c31456e43c), (0xbac761199eda3ccb, 0xbe226b400744def1), (0x3acd5778eedbc215, 0xbe2551251a2b4223), (0x3a46fe837cedeee3, 0x3db5500f9531112d), (0x3a083f723e083d02, 0x3db16b4e936f8a96), (0x39d95bf8d7caafb4, 0xbd415e70b28182e4), (0xb9d30dafff387703, 0xbd352230c03cb29f), (0x3945e77279062e4c, 0x3cc5019095879293), (0x395492014f9c999d, 0x3cb3c864dd8bd877), (0xb8c1fd1436671589, 0xbc4397af75e3218c), (0x38b351e168817cda, 0xbc2d701c9937c95b), (0xb855e93cc818d8e2, 0x3bbd0965d926054d), (0xb84897cb99dccaef, 0x3ba1d319c4fa1430), (0xb7dc0895bb1677aa, 0xbb3180c1e083f84d), (0x37be77bf0edd596f, 0xbb11e83053760c66), (0x374b4d74f0bce05a, 0x3aa17f5e91af9659), (0x371838fbe922ebee, 0x3a7e53a0935a1f43), (0x3684c2589850e2ae, 0xba0d4939983de020), (0x3684fdd4fb568c5f, 0xb9e5d2ed99505e47), ], [ (0xbc55bbc298d062cd, 0x3fb94c6f5898708b), (0xb5f666b728efc40e, 0x396f720ac4a0590b), (0x3c45bbc298d062cc, 0xbfa94c6f5898708b), (0xbbc91fb79f2262de, 0x3f308f4f1b8fb0dc), (0x3c11274d5c28ac62, 0x3f70da931c776c71), (0x3b468ef3cfeee3c5, 0xbefa7550d2940f2a), (0x3bbf74462dfd6413, 0xbf21f3b978a47cf4), (0xbb46a542136ebda6, 0x3eae28ea02472df4), (0xbb6c80d173cac31c, 0x3ec47930aec78cb8), (0x3adf057ade22322a, 0xbe51ce32c4f34e51), (0x3afb45adc8973d4f, 0xbe5d0950e99c8b39), (0xba7a6617d572dc1b, 0x3de9c5a1603e79e8), (0xba8e2eff860f1411, 0x3dec0f1778cf9887), (0xba168f093dfd4cd6, 0xbd7938fe13097690), (0xba1ecefa9c9a3a82, 0xbd73a70bdaedabef), (0x39aed81642403d1e, 0x3d01ceeed28a9bbc), (0x3997da4ad363efc9, 0x3cf4dcf95c5ca949), (0xb91477913a3a55c0, 0xbc82ff92717657c8), (0x3910bab9b4893246, 0xbc715c5a3e02442f), (0x389d817a2ccfa8fd, 0x3bffb3c968d17246), (0xb87cd010a2041864, 0x3be740ae3a8d3fe3), (0xb7e3b9850dbb1fd0, 0xbb754054fa60c54d), (0x37fb925f8ad7d3fb, 0xbb599a3322fec174), (0x3784fd568b6ae4b0, 0x3ae763dc0015bdca), (0xb76b4c77e261251c, 0x3ac794a91384b8c1), (0x36e8d58063ff5bb1, 0xba5583a75fd37094), (0xb69a2c623fdcd0ef, 0xba3252e98814e1a2), (0x3663e86d6d6cf480, 0x39c0feb0ea2eacb6), ], [ (0xb5e1d5aab91b0735, 0xb94d62f7652911ef), (0xbbb1d709b3e6a9e9, 0xbfb8ffc9b9a131f6), (0x3bdb4dd57b364903, 0x3f47f724314bb99d), (0xbc3086cbc396cba9, 0x3f90a89c5d1074ba), (0x3bb8da379d94d4d2, 0xbf1feeaeb33465e8), (0xbbef433944c1a759, 0xbf4a9fba36a7a08e), (0xbb7f256bdb98dce6, 0x3ed980034770f3b2), (0x3b91b4c8faeaae0e, 0x3ef43fa4bb8cba57), (0xbad948481030ddf3, 0xbe835f40f3a3902b), (0x3b3e2e9d940a676f, 0xbe91f465ba292c0d), (0xba98e1102f6772d7, 0x3e212688f74f8106), (0x3ac17030071395d4, 0x3e24d3f7e3fdde95), (0xba567e74d2a2034d, 0xbdb3daee9c38c74a), (0x3a51aeaf0688f02c, 0xbdb106a132ee69a7), (0x39ebe0f4bca30d89, 0x3d4030e7765d6c75), (0x39c14fc8399d63ea, 0x3d34aa4c24070ac4), (0x3933883151a4972a, 0xbcc3987402712b5f), (0xb942dee4f35f615b, 0xbcb35a87994f9f22), (0x38d71bf8bdfcbf64, 0x3c424aa138f72437), (0xb8ba56b686d5a4be, 0x3c2cd07eb7a4b5c9), (0xb8558c1bfdd348e3, 0xbbbb21f2d5bbbf78), (0xb83550a5585a2688, 0xbba174fb8120d7fa), (0x37b47b0dfc8fc083, 0x3b305ef4c6de1408), (0xb7bb881b76be83a0, 0x3b118c57455ac2ea), (0xb743465c91dd6734, 0xbaa061f86f5a1fc0), (0x3708e74190a8b10c, 0xba7dbce43544e4d4), (0xb68a21eaceaae3f4, 0x3a0b7321833d28bb), (0x36809484f141d2c7, 0x39e569a3e2d05d37), ], [ (0x3c5827414357db53, 0xbfb8b5ccb03d459b), (0x35f22b8b60cf7290, 0xb96f103383ea761f), (0xbc4827414357db52, 0x3fa8b5ccb03d459b), (0x3bc829bf4eaf9cff, 0xbf2edc98b92fedf3), (0x3c0a89c9aabf283f, 0xbf70767d524cea88), (0xbb9b6aea43cf84ab, 0x3ef8a85a847c89c3), (0x3b9126e1254c1bf9, 0x3f2189afaa2bffcc), (0xbb239c5c72e2b4cb, 0xbeac1d231a69bb02), (0x3b6e89e6ffd35f3d, 0xbec40139bdbc9d36), (0xbac6599803b1efd4, 0x3e509a6859c8e374), (0x3aded4460b047b6f, 0x3e5c60fc5f9b505f), (0xba80f4ba4649d3f0, 0xbde80ad391f7224c), (0xba8175d1cbd50fa3, 0xbdeb6e954dd6c922), (0xba13a4fa3d4d4a86, 0x3d778adc76ca1d1b), (0x39e0b384d483dfc2, 0x3d733867c824f37c), (0xb993f2721a70fbeb, 0xbd00a1ec5f4dca90), (0xb99e890379206b1f, 0xbcf469ac872b68fc), (0xb9207c6b7625a1c3, 0x3c81c1b6937f11f5), (0xb901775a0f7e0f63, 0x3c70fe687033cdc5), (0xb89ff8b30b7fba36, 0xbbfda774598edc97), (0x3875c8039f93b5dd, 0xbbe6c5c790b36d34), (0x380ece04cbe1e4a9, 0x3b73e54f8cfb2b46), (0xb7d83bd27bce64ed, 0x3b59165852609f70), (0x377e5472e34f528f, 0xbae5eb353d0d715e), (0x376ef3c901224023, 0xbac71e9aa439eb8d), (0x36e5bd48680a81b7, 0x3a542e64e00789ab), (0xb6d03ab3c0296c8d, 0x3a31f9ea0deead8a), (0x364a1b07722309cf, 0xb9bfea22321266c2), ], [ (0x35ef906f4164dc60, 0xb96927bfa8db52b2), (0x3c116404635b617f, 0x3fb86e51bb2ee24d), (0x3be40f7dbe05ef72, 0xbf465e3bad214eb8), (0xbc3502bddec37519, 0xbf9047d6ed159c31), (0xbbb68a41509da16e, 0x3f1dce4a381ce24e), (0x3be0a2f7a61834bd, 0x3f4a05b93842da9a), (0x3b384a0ade4543c9, 0xbed7ce3df60b0ea1), (0x3b8858267c36b09d, 0xbef3cb50138cce4b), (0x3b2cb60fbd506539, 0x3e8216e84a5dec74), (0x3b2d7337b289b637, 0x3e918e354c01533b), (0xbac53c3102b1edb8, 0xbe2005493039e5f0), (0x3ac1ef2cc0ca439b, 0xbe245ed4a3733e9d), (0xba3577e316826199, 0x3db28e2ed388f175), (0xba51361966067e0a, 0x3db0a83fb8aae5cc), (0x39d23d4aec4b7be8, 0xbd3e4745b1e410b2), (0xb9cc2b2efa2e5867, 0xbd3439aae872dae3), (0xb9550093ed38173e, 0x3cc2557a9d9a519f), (0xb95c225721c7ed22, 0x3cb2f313647cb524), (0xb8d9dd312bb7ea5b, 0xbc4120389f39a6c8), (0xb8cbc43aa5cd2092, 0xbc2c39cb315eea3a), (0xb84185a7cc406293, 0x3bb96c5a7748a20c), (0x38496ead43ea8719, 0x3ba11bdcff0ab3e8), (0xb7984affa3f0408a, 0xbb2eb47bf3d0d392), (0x37b23b859b45c934, 0xbb11351924a215f1), (0xb721ee8c0d2d3f36, 0x3a9ec1444b23676a), (0x371b235f8e2c7f49, 0x3a7d2d3b6879bb57), (0x36aa24c57ef1bc5e, 0xba09ca3fc26a353f), (0xb68eda4b8fd67c50, 0xb9e504fbf8d34ffc), ], [ (0xbc5aa58d824fcbf0, 0x3fb829356c2fb67c), (0xb5fd77431283aa4a, 0x3960ecbe354c0a2c), (0x3c4aa58d824fcbf0, 0xbfa829356c2fb67c), (0x3bc03ee1c336a8c1, 0x3f2cd964e5e4caa0), (0x3c0adae94b604803, 0x3f70190ce66b97c3), (0xbb6093ba87cf1908, 0xbef70d5fd8bad7b5), (0xbbae25e1759c4268, 0xbf2126a150469b05), (0x3b4f93e54fe01c25, 0x3eaa49ea85815004), (0xbb4a798f7842e742, 0x3ec3910f5c159f54), (0x3ab455b6ae464798, 0xbe4f0f4bdbe20c90), (0xbaf74c179ba876ae, 0xbe5bc3697829b270), (0x3a88354a18f986f7, 0x3de67f2959cd47c2), (0x3a6dc6f645f5de18, 0x3dead81c085abf1e), (0xb9f0a5000d22a9e2, 0xbd760a10ab0898ac), (0x3a0d6591c74acc66, 0xbd72d07fd9984920), (0xb99f00218c9ca6f1, 0x3cff2887ab34ba4c), (0xb988be1c4afb3efb, 0x3cf3fd2c46f43bf9), (0xb8eadfedf70fa7fe, 0xbc80a48214b2d829), (0x3909f66df0bcce8b, 0xbc70a5cd24e7ae0a), (0xb899f61798b66d98, 0x3bfbd0274fe475d9), (0xb86046afc74d497f, 0x3be6519199343e6f), (0xb812000c63615941, 0xbb72acc84cb991fe), (0xb7e378e992bff237, 0xbb589952fc8a6a0a), (0x378b39a8bc2ecbfa, 0x3ae49748fe385729), (0xb76b443078ea68f5, 0x3ac6ae557e486745), (0x36f8b6a88bc9e19b, 0xba52f9ba63bb636e), (0xb6a8a49f117ff2cd, 0xba31a503187756c4), (0x36578837435086f9, 0x39be08f63a02804b), ], [ (0xb5f43effe24b00dd, 0x3964e5a96d3cc648), (0xbc4ea89f3a432081, 0xbfb7e656ed57a0d1), (0x3bed3586339a9eb0, 0x3f44f0cfc62eb61c), (0x3c1736dd17549bf3, 0x3f8fdaba63e9c655), (0x3bb8a2f82c46dec6, 0xbf1be7bad1c50547), (0x3be9f603d64ca817, 0xbf4975ac0770c98d), (0xbb716dcdea217fca, 0x3ed64a6af83ba860), (0x3b95937b8720b7ef, 0x3ef35e6b41b6d77b), (0x3b1fd0d91a2464a1, 0xbe80f12d050df219), (0x3b0b801799b9f100, 0xbe912e744222ec5c), (0x3a882bc4d34bf5de, 0x3e1e04a8c0a89be6), (0x3ab7f6d69f6f7175, 0x3e23f0ed5e6a0d3b), (0x3a40221dd027ff69, 0xbdb163fd7157593b), (0x3a410e6fc017b151, 0xbdb04f8efe519654), (0xb9d61b861892425f, 0x3d3c6417f7a11d41), (0xb9df60b877c4e61e, 0x3d33cfa2affaf9e4), (0xb93fca12e22cd45c, 0xbcc1334e857adc92), (0xb940fcaa7e7a1f84, 0xbcb2917ae18b1995), (0x38d075a83e7685a6, 0x3c4013b4389ffbb8), (0x38b3ec31956d766e, 0x3c2bab4c1141e9b7), (0xb82612cb7e109475, 0xbbb7e1ea817e1f13), (0x3842297934775f91, 0xbba0c761c6922ab8), (0xb7a89c07cafc73fb, 0x3b2cdd9a9bd10cbd), (0xb7b8b565eb366f1b, 0x3b10e22afb97e007), (0xb73a476233fdd42f, 0xba9cef8ddac69711), (0xb716e797381cb799, 0xba7ca4454618f908), (0xb6a5522943296628, 0x3a0848f98ce0dc8b), (0x365472b048929931, 0x39e4a4c39def3d0d), ], [ (0xbc52d2ff041ff2f6, 0xbfb7a597eb76a5e3), (0xb5d66723cbc9de74, 0x3962eb71e7008809), (0x3c42d2ff041ff2f6, 0x3fa7a597eb76a5e3), (0x3bb9dc564fefd757, 0xbf2b0bd9eb615315), (0xbc03cbe9e9bac1aa, 0xbf6f831b9629acd2), (0xbb95cc1ecba38581, 0x3ef59d1c40c95ba7), (0x3bad7b9ad1a3693d, 0x3f20c9d35d4be191), (0xbb39533f4678ca4e, 0xbea8a711bec6920b), (0xbb4180f2a560b483, 0xbec327e42f39066e), (0x3adb23dbc7dc1492, 0x3e4d225aa8ded6cd), (0xbaea1e7c5ffe5f6a, 0x3e5b2f83a946aed5), (0x3a7207083f443397, 0xbde51bef06eb5d9f), (0xba7f450be91eb6e9, 0xbdea4ab19859cce7), (0xba0907e63b078849, 0x3d74b03ce339d83a), (0x3a00617d77666243, 0x3d726eb2bbaa63c7), (0x3998200aa70ed135, 0xbcfd433d6a1a8fc4), (0xb95c36471111f47b, 0xbcf396dd9428b7d7), (0x391cfade411a585e, 0x3c7f470853f5d974), (0xb9104560036c71a2, 0x3c705215ddbe6f8c), (0xb89e9dfcc8c7b005, 0xbbfa26d0528541cb), (0x3877907f8f994b48, 0xbbe5e38754f217db), (0xb7a00f2e50ac7581, 0x3b7192400028c4b5), (0x37d0b5957a7cceb4, 0x3b5822a7a7e2efa6), (0x378c09ba2822432c, 0xbae3636f4f21f020), (0x3762ceed74e3669d, 0xbac6437cc6062eef), (0xb6e668ce43677d5d, 0x3a51e56360c22f9c), (0x36a1ef54ef26b01a, 0x3a3153d505a39c09), (0x36443c33037016fa, 0xb9bfaca1a975c527), ], ]; pxfm-0.1.23/src/bessel/y0_coeffs_taylor.rs000064400000000000000000002066211046102023000165510ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated Y0 Taylor expansion at zero and extremums. Generated by SageMath: ```python mp.prec = 115 terms = 28 print(f"pub(crate) static Y0_COEFFS_TAYLOR: [[(u64, u64); {terms}]; {len(y0_zeros)}] = [") def get_constant_term(poly, y): for term in poly.operands(): if term.is_constant(): return term def print_taylor_coeffs(poly, n): print("[") for i in range(0, n): coeff = poly[i] print_double_double("", RealField(300)(coeff)) # print(f"{double_to_hex(coeff)},") print("],") prev_zero = 0 for i in range(0, len(y0_zeros)): k_range = y0_zeros[i] range_diff = k_range - prev_zero x0 = mp.mpf(k_range) from mpmath import mp, bessely, taylor, chebyfit poly = taylor(lambda val: bessely(0, val), x0, terms) print_taylor_coeffs(poly, terms) prev_zero = y0_zeros[i] print("];") ``` **/ pub(crate) static Y0_COEFFS_TAYLOR: [[(u64, u64); 28]; 47] = [ [ (0xbc749367c4c05aaa, 0x3fe0aa48442f014b), (0x0000000000000000, 0x0000000000000000), (0x3c649367c4c05aaa, 0xbfd0aa48442f014b), (0x3c4098c5b27f9542, 0x3fa439fac16525f6), (0xbc25adcf3e0230ee, 0x3f80d2af4e932386), (0xbbe4e773096516dd, 0x3f4f71646bea8111), (0x3bf3295907be08a9, 0xbf5444bda8b664a9), (0x3bcc92ed3e7dac0f, 0x3f384c220672ab82), (0xbbc2b56b5db9ac40, 0xbf217ab4afac0735), (0x3ba57929ce662323, 0x3f0dafb9b8983d86), (0xbb9a34080fad5051, 0xbef8bb962fa6c504), (0xbb70f97215a75a9f, 0x3ee48b6770c210bf), (0xbb6ac5099b6b7783, 0xbed1364ddbddf33b), (0x3b5c6a28d5d49339, 0x3ebd06aadd881cef), (0x3b360737a2bfac90, 0xbea8998eefe8caa1), (0x3b10ceb1fd02d154, 0x3e94f198aa7c73a8), (0x3b201bb903ea5d53, 0xbe81e742c1cf6acb), (0x3b0e3c97eb74692a, 0x3e6eb820636013a9), (0xbae9e5875024afeb, 0xbe5a709593e5d778), (0x3a9c3113327b82cf, 0x3e46d299b1a6ab0d), (0x3ad32a9aab166472, 0xbe33c08d3e0a3e4c), (0xbab2ec0cd7aefe76, 0x3e2122b2a831eedc), (0xba7fd1a1eaeba4e2, 0xbe0dcbb767b405d4), (0xba9f28de864d6d7d, 0x3df9f4d817711be0), (0xba84e5784f3ba466, 0xbde6a732ce7db295), (0x3a2ba83b1dceb593, 0x3dd3cdb1820544fc), (0x3a64cd3a569b8afb, 0xbdc156d9d7a9603b), (0xba4c3618e715b8ab, 0x3dae68388d1e7164), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc5a4026e436c4d3, 0xbfd9c34256a12a0c), (0xbc49ded6e8236fd3, 0x3faa09c9290367ef), (0xbc253b02d2a53d30, 0x3fadf6d59bf50ebd), (0xbc18dbf118b1a2cc, 0xbf7c116fdc598096), (0x3bf40db0aa3d7078, 0xbf61e32bc4ef8a41), (0xbbcbb6264c727077, 0x3f29982765166254), (0xbb86be82f4783a97, 0x3f0ab2c1fecdcfc4), (0x3b74540a4df5362c, 0xbed486371e6a663e), (0xbb38925afac5b2b8, 0xbe93b21684089b4c), (0x3af8953a9c0487f4, 0xbe5777058741bf97), (0xbad841f372dee964, 0x3e5452ea00945a70), (0x3aa79f6248f7f1b0, 0xbe2f6938829664f1), (0xba9880934623f972, 0x3e0a5a1f3a2a293e), (0xba74d07ce1ea2db9, 0xbde994e736de8ef8), (0x3a666975b24e41c6, 0x3dc88ae5c83467bc), (0x39e7564160acaf67, 0xbda75329361f19bb), (0x39f36d6ccdec6121, 0x3d8643c7a49b7f43), (0x39e06cdcecde2c8d, 0xbd655480c70f5929), (0xb9ee4b7548f46bdb, 0x3d447c1c44c1487e), (0x398be3f2b0a46b7a, 0xbd23b7d1fbf0fdd0), (0xb9aeefcda909f8cb, 0x3d0305531056d810), (0x398546902be387f3, 0xbce2626f5e5dfcac), (0x395bf1c6ad49bc60, 0x3cc1cd4c7460b8d8), (0xb91985693844d5c0, 0xbca1445851bfea5f), (0xb92b3bdde2175982, 0x3c80c63a86aa43b3), (0xb8ff7f8fe9d70fe2, 0xbc6051ca830eb872), (0xb8b0d0de6a7a8a72, 0x3c3fcc0fa90bfb3f), ], [ (0x3c7b8d2a1c496808, 0xbfd5c7c556f0c19a), (0x0000000000000000, 0x0000000000000000), (0xbc6b8d2a1c496808, 0x3fc5c7c556f0c19a), (0xbc2b4d44aaadbbec, 0xbf8564d4b1ed0d7e), (0x3c2e4289c3acba27, 0xbf8a15d92dfe3e27), (0xbbedbea927b719eb, 0x3f4b438430469ff7), (0x3bdc1760512f76cc, 0x3f37a8924cc2f914), (0xbb70219aa771d161, 0xbef5f69b4a8a3c05), (0xbb77299907aec5c4, 0xbed85b940eb607f9), (0x3b3d5ae26ad627b8, 0x3e955ac0f5c3162c), (0xbb0f58c09c1fabd1, 0x3e6d563e18b47eb9), (0x3a99750b0b40769a, 0xbe23eac3a45e06ef), (0x3a9e3d09f9f42f26, 0xbe0007671d55a8be), (0xba495377f5d84985, 0x3dc04e13e8d2ceb5), (0x3981b2ad63946aa5, 0xbd46e2b306cbb1f3), (0xb9fbadc4f0bb048c, 0x3d54d18f7c90e926), (0xb9c8225b40e694f7, 0xbd34980895b5067a), (0xb998c3893e3c0087, 0x3d0a5b439cef90cb), (0x3977814f4b07cebf, 0xbce1c9c4c0d530e1), (0x3952fcdfd498e788, 0x3cb933cc6493bf1c), (0x393ffe3660f335f2, 0xbc91c67122e8e134), (0x3904bb25b4c5ee57, 0x3c6904e906c46283), (0x38cd1dbe18c0ee49, 0xbc41a5ff5486c2fe), (0xb8a09b2fbba2c634, 0x3c18f24433ae1991), (0x3898e91198e4959c, 0xbbf1a84c8250ebd5), (0xb856349e52eccab3, 0x3bc90826d8cc3eff), (0xb848f5b7e7d4ec81, 0xbba1c456da51d36d), (0x37f66d77762bebcf, 0x3b7940bb04835b31), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc78d4484b7cd2a6, 0x3fd334cca0697a5b), (0xbc341c66c86d3ebd, 0xbf95aef611fc4d57), (0xbc44929b43aab7fb, 0xbfa8969c64cbf452), (0x3bfab353487eb36f, 0x3f6b2f14a95527cb), (0x3c0aa67a62fad710, 0x3f61d35e85fde2a3), (0xbbb270ba54459cab, 0xbf226dd71e391c8b), (0xbb61863b08bc5950, 0xbf08177e4fe52324), (0x3b494954a2d7de21, 0x3ec6a9227352f96a), (0xbb44a5b1e0c3c3e1, 0x3ea34aa7573ef14e), (0xbb06984676a524bc, 0xbe60a2814d7ac448), (0xbad9251769eb31a9, 0xbe3442a3d3359ad9), (0x3a86fc915b18c175, 0x3defa6c509566c72), (0xba3b534d6e1095ea, 0x3dbf14e5584823db), (0x3a16e8b19c361860, 0xbd7714c292be3936), (0x39e500ccc143989e, 0xbd40679cd5855172), (0xb998a55fa2ea549b, 0x3cf3365d5a786a7b), (0x395c00dd62ac7e1c, 0x3cc38cf06b47bc6e), (0x38f0c8bd8691968e, 0xbc82bd5a83b64d59), (0x38bddc7ea088ddcd, 0x3c326e92cf91d829), (0x38b27643db6c3b27, 0xbc127116123c3d66), (0x388c47f57a6d55b0, 0x3be8df4f1bd4a3f7), (0x3853b5c4a12853b5, 0xbbb9b0c7fab8762b), (0x381d1068b57233fd, 0x3b8b3b04447f58f8), (0x37f6b2b5793b64aa, 0xbb5dbd231117d61d), (0xb7d3a5abcdba22eb, 0x3b3035d90c22fa4e), (0xb786f2af60849004, 0xbb01a58ba966a549), (0x376712c78c816e41, 0x3ad33cc7a0e946ec), ], [ (0x3c61dc672a53c590, 0x3fd15f993fceab5c), (0x0000000000000000, 0x0000000000000000), (0xbc51dc672a53c590, 0xbfc15f993fceab5c), (0xbc0d1c390189cb30, 0x3f758ef6efbed797), (0xbc243ede64b782d9, 0x3f86395dfe49fcd4), (0xbbbb4484582c2699, 0xbf3fb15104a41c00), (0xbbd4410e752be535, 0xbf35f88a11d5564f), (0xbb8b2d9b83a11c89, 0x3eef37d226a824b7), (0xbb61fb17827843f5, 0x3ed6f7bab104f355), (0x3b2da2cb75d8087f, 0xbe8f0c45a3824d70), (0xbac1132bedbb6ebc, 0xbe6dfe11df12c715), (0xbac5290f391bbfe1, 0x3e2311adc2e753ee), (0xba92039061518817, 0x3dfad34e18504e16), (0xba4d6cd9e6f85fe9, 0xbdafdc8061ae8b15), (0xba189257c63f6446, 0xbd819498ca6cef9b), (0xb9c8f0f4bb78628c, 0x3d33a291d5991f74), (0x399127448ae5dbb8, 0x3d016f7ae80cad77), (0xb958d1b0f5eaa04b, 0xbcb1f8d80deccee6), (0x3910d158fa5b41a8, 0xbc7c27b5350a923c), (0x38c3559986f928ac, 0x3c2d08034e70dd4a), (0xb86c6bb218da7ccb, 0x3befac2006e277e3), (0x383c518f1fca847d, 0xbb93e926868daea2), (0x380ef79adc3898ef, 0xbb6dcdf980ddfdf4), (0x37cea115c120894b, 0x3b2c4665b1564c6a), (0xb783f5bf36c1dc64, 0xbaec0521ead39203), (0xb74144c7cd1de85b, 0x3abed64c1afbe47b), (0x3722cfb0d396394e, 0xba8e04ab2a193e84), (0xb6f088c0c22460a8, 0x3a5a77e09ed6a09d), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c61e8f568f8c6b9, 0xbfcff635cc72b9f1), (0x3c0fa6ebe8b75862, 0x3f89036451ff57c5), (0x3c46345bcf3c5b7d, 0x3fa4e667a71556af), (0x3c065e386829f03c, 0xbf60325ee41e910c), (0x3bfde6b6846da9d0, 0xbf5fe23914fb9128), (0xbbb9c28522c54ab2, 0x3f17f84d7c50e4c4), (0xbbaeab0290c99b85, 0x3f06afdd57be1e14), (0xbb2bbdfb6c4ce197, 0xbec04053abf4386a), (0x3b3787c4b6b6a0b6, 0xbea2aea9ec48d8fd), (0xbaf17a3632e2edc5, 0x3e593eb9f1ddb4e9), (0x3ad9f831e08fbb99, 0x3e3428a3a3e30a13), (0xba49cae682f11d51, 0xbde99d8c42f7a020), (0xba591eb785e59448, 0xbdbec9805045aa58), (0xba086b5bad70f23b, 0x3d72613659ce994f), (0xb9eb4013d9ba0032, 0x3d418f302bdba980), (0x38e42c05bf9582a5, 0xbcf3bc9ccb704253), (0x3952d598704c3b46, 0xbcbf0dc4067be8b2), (0x391246064faa45fa, 0x3c706e491f458956), (0xb88908e1a67ee56c, 0x3c36013bac769277), (0x388f595373e53a2e, 0xbbe616b4d62a47f6), (0x384c63a51904dc22, 0xbba93fb6fa556eab), (0xb7fb730412560441, 0x3b57963a88acf606), (0xb7aad1cf0b52dca3, 0x3b1937ef4e3db6a9), (0x37592af1b29a1e7c, 0xbac8387c0e875a84), (0xb6f7ae247b07d290, 0xba80a12689ec647c), (0x36beb9fdadfcf39a, 0x3a1bcc6e30896704), (0xb697aa9158bd1808, 0x39fd4db12fab6895), ], [ (0x3c54d14c77bc1691, 0xbfcdc14ea14e89f9), (0x0000000000000000, 0x0000000000000000), (0xbc44d14c77bc1691, 0x3fbdc14ea14e89f9), (0x3c00ff03f97580f3, 0xbf6b037fe9cf2a52), (0xbc2f19a8f5b1379e, 0xbf8367d7d608e4ba), (0x3bdd892317f291c8, 0x3f34abef5636e4f7), (0x3bd5ba5b5b609683, 0x3f33d8a661229259), (0xbb700a3f00979ee5, 0xbee5cfe92a1a2c45), (0xbb6087e84c57d2ad, 0xbed571814a1aa301), (0x3b22b6740da6456f, 0x3e87414e33c9bacd), (0x3afa4836a36f8841, 0x3e6ca7069e73d1d9), (0x3abe65fd6bda59de, 0xbe1e0b3a705ff247), (0x3a95774cb23eb7b8, 0xbdfa15dd62cf9f10), (0xba399fbe055cb8be, 0x3daa33948eada12c), (0x3a2240f402a7b379, 0x3d81419b1fd428ef), (0x39cc415e74e0cbc8, 0xbd30882f60b8a775), (0xb991c41d97727556, 0xbd015e5c0af749d4), (0x392937d5bb210372, 0x3cafb1e115e08994), (0x38f58b3c9e456997, 0x3c7b838263708865), (0x38c5cd0199e8f790, 0xbc27e5d539870f02), (0xb89a3dc2e116c3ad, 0xbbf19dae392457a1), (0x383bc230f8650284, 0x3b9d2b72778fe832), (0x37f13768b14c0c18, 0x3b6298bb7e2277f2), (0xb7aa1239c7070276, 0xbb0d50baf60db64c), (0xb773592299e9674f, 0xbad08ad53b850ab4), (0x3717cc8a5ae6e9ab, 0x3a79141842fa569d), (0xb6b9bec849ea1c6d, 0x3a38ab0a361907e6), (0xb67a764f692d7a9b, 0xb9e14491ed3e919d), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c41398cacaa32d4, 0x3fcbf32a27594007), (0x3bfe5ce4af724b17, 0xbf80bc2d84e65214), (0x3c4acd5148eb7e9d, 0xbfa26cab38a8b368), (0x3bfab9a1103e2000, 0x3f55f03e47165d72), (0xbbc4598141a3f849, 0x3f5caaa76e34992d), (0xbbbb7ab55e886623, 0xbf10c5f18c46d030), (0xbb99f58bad5e7aa5, 0xbf04f0af7d46cd48), (0xbb3040f00afca09c, 0x3eb7d1e28094e21a), (0xbb3f12dedaa2ba65, 0x3ea1ad0731228479), (0xbae9fe69a3662740, 0xbe536021c8cb3c34), (0x3ad92bf3f184780b, 0xbe3371ae6c759181), (0x3a630cc7c21c0cfc, 0x3de46ce077a8bed7), (0xba5feb6d0e335e60, 0x3dbe235d3564b639), (0xb9d7ae1d94bd92ac, 0xbd6e408e259c72fb), (0xb9c8768c2460ab80, 0xbd415f07ac87e832), (0xb91b6919f885a208, 0x3cf0a44f77f6a8ef), (0x393312b132a8d347, 0x3cbefd8ab52f8eb9), (0x38f1bfe622c31b37, 0xbc6c54ebb5ad3869), (0xb8a61a375002a1c0, 0xbc360b43cbb5f5e9), (0xb88cc62cec929222, 0x3be33d74aacb57e2), (0x3842ffe5c04b22b9, 0x3ba99bfbb3fe627d), (0x37e1d4df5722a5b0, 0xbb555c0969d70a77), (0x37b44cfc1475dce9, 0xbb18c29d2318e9b5), (0xb7682246c98d07a1, 0x3ac3c0750d221b4f), (0xb717ffcd427c1eee, 0x3a843fa688c2eb51), (0x369fc06d11ba5fce, 0xba2ef4ae2931c6ca), (0xb674d5d2266c5526, 0xb9ec57869d64feb9), ], [ (0x3c57ba12cd0fc91f, 0x3fca7022be084d99), (0x0000000000000000, 0x0000000000000000), (0xbc47ba12cd0fc91f, 0xbfba7022be084d99), (0xbc0b3327197c9da3, 0x3f62ee079d020b12), (0x3c2d0f8f36713120, 0x3f8163191c30aa62), (0xbbcc7f2dbb383204, 0xbf2d7806ea72fc76), (0x3bcf9ec581434d38, 0xbf320f95702b1d4e), (0x3b899e1a0f3c0857, 0x3ee00610882294aa), (0x3b61505ce3b29a78, 0x3ed3e398cbc472ea), (0xbae050c77864dd20, 0xbe81bbe181c65162), (0xbb0c3fb8339198a1, 0xbe6b0f89b7c61f3a), (0x3ab91b7c8e3c7c3c, 0x3e17c3f85882049b), (0xba976a7c841dba14, 0x3df90236614c84dc), (0xba43ab3b18e59a65, 0xbda564920d1387dc), (0x3a2b1754ca712321, 0xbd80be1811255cfe), (0x39b342bebee2071b, 0x3d2bb9712586bfac), (0xb99c92d876d25063, 0x3d0101c31e1df223), (0xb916e23fb5f67bb8, 0xbcab298cda76e77b), (0x3918a11b915d1274, 0xbc7b22acc441d872), (0x38cdcc71612b99d0, 0x3c24dca37a32e97c), (0x38855c0754c54ab3, 0x3bf176e94ee1fe21), (0x3836cf20a369d629, 0xbb99d4f0d74e9093), (0x3802940330562608, 0xbb6287585b150c7c), (0x37a0f4cbacc81873, 0x3b0a5c015f1f057c), (0x3779aaaf8d850193, 0x3ad07cc0082a44cf), (0xb70fd62f89ce46a9, 0xba76909f83007714), (0xb6d4e9d85e17b208, 0xba38f88423d4ad97), (0xb66d34e3378a5539, 0x39e072fc561ac2bd), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc65b9c39e42719e, 0xbfc925c35988ee29), (0xbbdda9c0588bc7cc, 0x3f7862549367591e), (0x3c4a142ed6a5521f, 0x3fa0a4512039d6a2), (0x3be94ce533c65cad, 0xbf5013b38cfb9292), (0xbbea2a14cf0f61af, 0xbf5a24a1215f6684), (0xbbae7b4c448b42eb, 0x3f08f91421377fad), (0x3baf72fd0f5209a4, 0x3f035d17cec0172f), (0x3b3cd242e4f5ce10, 0xbeb2283a93114096), (0x3b259dda3f9c3cd8, 0xbea099e71392f54e), (0xbad6dce1bfae1a53, 0x3e4e5de01e2e6566), (0xbab52eec76dd7e24, 0x3e32885854ea8b06), (0x3a6795ca81b0c1a2, 0xbde0730c2985fd22), (0x3a4e06d8277ffd55, 0xbdbd1743cbb2e11a), (0x3a013448997f1418, 0x3d68f8728745e1e6), (0x39dd9a182e4412f8, 0x3d40f166cb29a7d1), (0x398dd4bcf72e3139, 0xbcec10e67c004e3b), (0xb9542acf7b7def7d, 0xbcbe7aec1ba33e83), (0xb908d6ed91615a58, 0x3c68543e12c9bf9a), (0x38a13a9d572a9420, 0x3c35d3939f6d1ed2), (0x387a4284a63f1993, 0xbbe0c7ba11981a01), (0x38405b9a6bff4fca, 0xbba97d9177222a00), (0xb7f4c779b6c742c8, 0x3b52dfb95f4a8634), (0xb7aba81ffd3b5c41, 0x3b18c04f3759b6eb), (0x375fa028706c2252, 0xbac1a799c1562309), (0xb729c62dd7828d2a, 0xba844dc9c3e85489), (0xb6cf5aac2a393499, 0x3a2bea86b90f9faf), (0x36614b1df5aeed9d, 0x39ec85971210b79b), ], [ (0xbc63db68c567283b, 0xbfc80781c32422e7), (0x0000000000000000, 0x0000000000000000), (0x3c53db68c567283b, 0x3fb80781c32422e7), (0xbbfab5094c039454, 0xbf5c6923374d561f), (0xbc032419a9d405db, 0xbf7fbe6df840847f), (0x3bc0f03bc2e75d6b, 0x3f264f4711a85f1a), (0x3bbd9972e6c197fd, 0x3f309ff42b0d7a68), (0xbb61aba5a7ce6455, 0xbed8a60685a597d9), (0xbafdb153b13f2cf0, 0xbed282d26a74c38e), (0xbb1d21d4a94b9e91, 0x3e7bdb57a889a4c1), (0xbb099a040a6939c6, 0x3e697d9c12a60cef), (0x3a35e114fc2a1213, 0xbe131aa8691738fb), (0x3a93c999393c858b, 0xbdf7d486eee39a85), (0x3a223c1c4424f0db, 0x3da197f258214b3d), (0xba1644a8cbcb4af5, 0x3d801dd7f92195ff), (0xb9ca37ef1c0ef3fa, 0xbd27480b9efaa860), (0xb98847e4ec1195cf, 0xbd00833ea1f83461), (0xb928c4b1729bab7e, 0x3ca73bf7964edc26), (0x3913ebe30cf0771f, 0x3c7a891d704fef9b), (0x3881294f9e950341, 0xbc22222dcf094b80), (0xb898aeadae639677, 0xbbf12db9d21e37ed), (0x37ea537285a44833, 0x3b96c4638e4cc003), (0xb7f3ee61741a27e7, 0x3b624ff2a82fc9c9), (0xb7987ce466329a95, 0xbb0782fd4fc7cb7b), (0xb75dca0980ad8630, 0xbad05bab97dc88c3), (0x36f1b4cbf5a58e0a, 0x3a74565e5f91bb35), (0xb6d553555a830f19, 0x3a38da3118f887bc), (0x36758225c016dcfa, 0xb9ddea7aa8da61e4), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c64fef53f4893e5, 0x3fc70c4f66cab47f), (0xbc1e032768318e4d, 0xbf72c6731071e936), (0x3c2f806b21bc9577, 0xbf9e924b85a17361), (0xbbe1434be87c6363, 0x3f48d6c364d92082), (0x3bf5cbe0638f4cef, 0x3f58247b02d6b0f6), (0xbbaade8b3660fd4e, 0xbf0376125938561d), (0x3bae81e47dd383cf, 0xbf0206da232a2b6a), (0x3b424b3c3173e20f, 0x3eacaf84db871510), (0xbb022e3bac70bc67, 0x3e9f3671177306ca), (0x3a9f8b17b052db72, 0xbe48654b001006cd), (0x3ad272b921d7360d, 0xbe3199ec88b18766), (0x3a6b9a3bf5083c1d, 0x3ddaeb1a849305fb), (0x3a57cadaf3f1d693, 0x3dbbe67c197c48c0), (0xb9c7cc3d8d1e5e49, 0xbd64cdfa0bd69898), (0xb9db4ff4c3ee8f12, 0xbd4064936f97922f), (0xb9777557537dd027, 0x3ce7c83b5186222f), (0x395de8595a9345f0, 0x3cbdb73ad7fa8bc8), (0x38f6136241cc3637, 0xbc64eecbf0b91d4f), (0xb8d2eab985ecf43c, 0xbc356ab697c0ab6d), (0x387327e90134d3b9, 0x3bdd4506fe436113), (0xb837e66ef2a0608f, 0x3ba925d81a8dc397), (0xb7f15df323201ec3, 0xbb50a89d96a14715), (0xb7bfc8950449ed4b, 0xbb18875d24cf9582), (0xb754b1be99b10be3, 0x3abf7e546e402e74), (0x372718433d137dec, 0x3a84326527427bb9), (0xb68468a05b2cb0da, 0xba2921298884b92b), (0x367c4fc25beb34a3, 0xb9ec75a8ffac9550), ], [ (0xbc6d2f0105f3ce7c, 0x3fc62d94d97e859c), (0x0000000000000000, 0x0000000000000000), (0x3c5d2f0105f3ce7c, 0xbfb62d94d97e859c), (0xbbf6c13bde837960, 0x3f565481b55eaefb), (0x3c17013075a066f9, 0x3f7d5f857a2a6107), (0x3bc5f065aa6339f5, 0xbf21a015a2ccb78f), (0xbbc12f349174f010, 0xbf2eeb4eafd8614b), (0xbb53525d6141be28, 0x3ed3a7b79e4d80fc), (0xbb662d899f08a704, 0x3ed154ed4598d2f0), (0xbb0444753ebe791d, 0xbe767f762ea293a1), (0xbafe11bb6f1d4207, 0xbe680ec1e042ee62), (0x3aa725a667375b0d, 0x3e0f529652b9de0f), (0xba97b074118bab16, 0x3df6ad7bd2247f55), (0x39e3900c76e6a68e, 0xbd9d4e582fb43553), (0x3a1f5fd82381bd59, 0xbd7eeb6efcbb6228), (0x39c7389b8d7fe521, 0x3d23b1eabb5c1c2c), (0x3992974c386cdc2a, 0x3cffe92f0882b440), (0xb923c49452353597, 0xbca3f20671568bca), (0xb9002a4da3d3a816, 0xbc79ce30ac166eb5), (0x38b02f60dd891164, 0x3c1f8db6e94f1a96), (0x383459153c91e395, 0x3bf0cc90c0607e7d), (0x383003b333010a99, 0xbb940c6bb9f9a6c4), (0x37d6a317d4f5ae21, 0xbb61fe382b9ca927), (0xb76dfd62097696b0, 0x3b04ed907b4ff4b6), (0xb75abcbe1108a215, 0x3ad0234a19150d32), (0xb71105a3cea0d529, 0xba7246b54dbf759d), (0xb6cf812a75ac4069, 0xba3899f3eb5b7cf1), (0x36688dddcd012369, 0x39db1cda80386890), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c5fe2103f7148bb, 0xbfc5664d37c37d7b), (0xbc0a0fbbe8bcf9a6, 0x3f6e0ee8ec84659a), (0xbc383a77d074bd0a, 0x3f9c6c415c971b4b), (0xbbb06fe5233f06e8, 0xbf43ec49cb941f55), (0x3bfe14142e1727fe, 0xbf56853b2d047885), (0xbb98cea461592c41, 0x3eff632a9396fd4e), (0xbba049885559b2a5, 0x3f00e6afa01af561), (0x3b452a8549984c17, 0xbea7541247acdf59), (0x3b3a7242d1da1ee5, 0xbe9d735e8beb8fcc), (0xbae93d2eb398218a, 0x3e440e6a7cafc096), (0x3acae709ad00bd19, 0x3e30b9cfae2ab337), (0x3a72d6de94168a75, 0xbdd668087e67279b), (0x3a5eab8fef3b6421, 0xbdbab498e6f69c73), (0x3a0c8ec8094d97ed, 0x3d618b5674894afb), (0xb9db00611b51a32b, 0x3d3f99da023c7232), (0x3971efb1b8385b20, 0xbce450b8165c264c), (0xb934a2a8921ee27a, 0xbcbcd387688c508f), (0x390195709783e7c1, 0x3c621a103bd0a113), (0x38dbfdcea4f39167, 0x3c34e540faee9f3c), (0xb87ade2a66df50ab, 0xbbd999b3cf947860), (0x3847c3fb15ff4625, 0xbba8a8f1c18bd090), (0xb7c279575afc11de, 0x3b4d71c32bb0428b), (0x3797f3b19c608f42, 0x3b18289deefa7196), (0x3754153d9d2c7699, 0xbabc183d32d93a1f), (0x371c05c0e3242945, 0xba83f7ae467ae529), (0xb69ad19453e29618, 0x3a269b7adc6804ef), (0x367130005d91c163, 0x39ec3a580d0009a9), ], [ (0xbc5e9088e9ff2518, 0xbfc4b2a38f1ab9b4), (0x0000000000000000, 0x0000000000000000), (0x3c4e9088e9ff2519, 0x3fb4b2a38f1ab9b4), (0xbbfcc8083276a193, 0xbf5225a5c73f2233), (0x3c1525fe797e2126, 0xbf7b750d89a9b35f), (0xbbb08db59499cb94, 0x3f1cbdb4f1d5dbbd), (0x3bc35c23938c810e, 0x3f2cfe933fc6d0b8), (0x3b52d453a3ea26cd, 0xbed01ef10d839bbc), (0x3b71cffb5ca00bc2, 0xbed05375a588a72b), (0xbb03f71b77aa7082, 0x3e729afe7ea7ba43), (0x3af336f1341f6d84, 0x3e66c8fe015e6610), (0x3aa95a6cddd6ccb3, 0xbe0a2a01e7af0241), (0xba7851970a0eac4f, 0xbdf59b33050d2092), (0xba24b1969b00bcf7, 0x3d98c0a50e7852d3), (0x3a16ee76e659ed58, 0x3d7da3426f355690), (0xb9cdfb48abef1f45, 0xbd20d3b48429ce84), (0x399e510926654c46, 0xbcfec46e14cd5d9e), (0xb94d8b3c4e2a8910, 0x3ca13c3da7405de9), (0xb9199ffbceedc2fd, 0x3c79043b4a0f03df), (0xb8b7be40ca4f6a7f, 0xbc1b902f4b26eb03), (0x38971ae8f878f8af, 0xbbf05dbe75075aa3), (0xb834ec73bf06d543, 0x3b91b0f5dc51ac20), (0x37f5aae0017b0662, 0x3b619b551575f49b), (0xb799e67f64663319, 0xbb02a3e0a7397c83), (0x376711f24f4773dc, 0xbacfb4a185898d2d), (0x371e5adab87fe639, 0x3a706acbac6f6bd1), (0xb694af13fd9e3bbb, 0x3a383fb94408a8c0), (0x367e1f0c9bfb4eba, 0xb9d88b17eec4fb7c), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c5f3474ffad3fd7, 0x3fc40f8ffdf09a5f), (0x3c047810b9792b13, 0xbf68c37a29c4586f), (0xbc348471cc77dfe2, 0xbf9aab099314b209), (0x3be6aa80fcd045e0, 0x3f406f735cc0f6a6), (0x3bebe02c3928856d, 0x3f552d29a06802e0), (0x3b89fdf10253d75f, 0xbef9fc04c675c0ed), (0xbb62f9306dab684a, 0xbeffe48825ed3c8e), (0x3b43251677276142, 0x3ea36bd2d58ff45b), (0xbb2af08b6d9ffd1a, 0x3e9be87e2cad2ce7), (0xbaec807c6c103803, 0xbe40d1fdedc6cb17), (0xba7064dd3b6b5724, 0xbe2fdbeb107ddccf), (0x3a75893a2f37955a, 0x3dd2f44d01321684), (0xba4232fa9e2160b9, 0x3db9921373ea0f26), (0xb9da39ce7fd7d9d8, 0xbd5df6b83ac56981), (0x39db340c9865a7cd, 0xbd3e6c005b62bffa), (0xb9708387feb998a6, 0x3ce1848c91de7162), (0x39532ac00e2fa8ff, 0x3cbbe5530d0fcf1e), (0xb8f7971717114a0f, 0xbc5f8540b8b06042), (0xb8d7787ecd6e687d, 0xbc3451eb9bf040e8), (0xb8696fbf3607765c, 0x3bd67f1edd448664), (0xb84ad321b52d14f9, 0x3ba8169212a3f8c0), (0x37d9b42cb89199fa, 0xbb4a1a0e01aa07e3), (0x37a4d1d59a34de84, 0xbb17b199c8e398ae), (0x37565ae964dca96e, 0x3ab91bd224db8139), (0xb71f2cb70464cd53, 0x3a83a756c81f58e6), (0x36a634d3a7864fac, 0xba245b460d9907d1), (0xb68d4c3a3fc04b15, 0xb9ebdf60ca34bcd7), ], [ (0x3c4997782859a00d, 0x3fc37aaceac987b9), (0x0000000000000000, 0x0000000000000000), (0xbc3997782859a00d, 0xbfb37aaceac987b9), (0xbbd05a6eb7d72f47, 0x3f4e3fdbfd65014a), (0x3c1d91e80a0529b8, 0x3f79de7a33bc3a97), (0xbbb56ef10c1ebaad, 0xbf1801d911fbd06c), (0x3bcce92f388f20ea, 0xbf2b605a5ade3a80), (0xbb539bcd81dca55a, 0x3ecb0a2608144a3d), (0xbb6b3675770103a2, 0x3eceeceb341ad833), (0xbaf6cb1030653935, 0xbe6f623fc7be9f9f), (0xbb0412babffea489, 0xbe65a9ca94a0d7dd), (0x3a9025c6eebf2e96, 0x3e0638ba2f5f5e6b), (0xba745bdb1a5b34d9, 0x3df4a1b4217ef864), (0xba32b235688fed51, 0xbd9530c712e738d4), (0xba0b5b22087c168f, 0xbd7c6e5208e89146), (0x39aabbad8d2c58ef, 0x3d1d0eb5303a804a), (0x3988eb799dd68c33, 0x3cfda6ae03deea14), (0xb91737db06df4072, 0xbc9e05ef8aaeac6f), (0xb8ffe2eecdfe0f4b, 0xbc783796c23b134e), (0x38836225e752dac9, 0x3c183703be1e065f), (0xb87377273654d7a7, 0x3befd20ef0b9b32e), (0x381f98f1f5615157, 0xbb8f58105c7413a4), (0xb7f08f641ff4b998, 0xbb612ee75ce95b31), (0x37ac304030a2dba7, 0x3b00a4adc945e963), (0xb760c6584778a1df, 0x3acf0d914ecfdc7d), (0x36e07d1a751a4b9c, 0xba6d88af68997ed9), (0x36db1ad813072ac7, 0xba37d36ec5b8b8d2), (0x3672facc8520936e, 0x39d63a55dc5490c7), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc569479644686c1, 0xbfc2f206e49909c7), (0x3c0fab1b83d46057, 0x3f64dbf6a9fb80d7), (0xbc32d9141794e6dc, 0x3f99336443318ed1), (0xbbd0d543bfdf0729, 0xbf3bb6aa3d4e9e78), (0x3bebe3f68704392e, 0xbf540aaa5d94bd8d), (0x3b419d1c00b3671e, 0x3ef5f61b666129a6), (0x3b7d88846cdeeaef, 0x3efe4158391f2c2b), (0x3b46369cf5ad9126, 0xbea07a7a0745f74a), (0xbaff9b34051c76b6, 0xbe9a8ea97b670057), (0xbac6b3f27d760998, 0x3e3cb10b3affeaff), (0x3a82ba28da6d4ef2, 0x3e2e6d78879f98a1), (0xba64a30357ebbef6, 0xbdd044447904054e), (0xba47c38fca3d087e, 0xbdb8850c99b76d50), (0x39f0bc2d92a30cdc, 0x3d59e4fa8ff52f90), (0x39da7eb9dc7c3857, 0x3d3d4b2c1afd964f), (0x397e3e8ba2460cb7, 0xbcde807e2b0027a1), (0x394f139f76a41235, 0xbcbaf942a59e1d55), (0x38e1843405416d9e, 0x3c5ba64c4108b5da), (0x38d7063d60c6e606, 0x3c33ba614d4a4418), (0xb86c7ec67073bb42, 0xbbd3e1ce585ffa1f), (0x37e22b5fc552851b, 0xbba779ee6dc176e6), (0x37e956c614ab6059, 0x3b473c7bc63c3880), (0xb7b796c186b6db87, 0x3b172ca465caf995), (0x37588aab872e21fa, 0xbab681e73200f9aa), (0x37260574a8f5d812, 0xba83492c838e2b86), (0x36bb446923624df9, 0x3a225df78223620b), (0xb680e905ae135da7, 0x39eb6eaa1f93591f), ], [ (0x3c6b7326e3fbaa70, 0xbfc2740819f1caaa), (0x0000000000000000, 0x0000000000000000), (0xbc5b7326e3fbaa70, 0x3fb2740819f1caaa), (0xbbe4b7a0f7878f6f, 0xbf49b6f37d0a00f9), (0xbc011249d3675d98, 0xbf78868d7401bf2e), (0x3bb6d7fdfc21dddd, 0x3f1470a7cbcb436a), (0xbbc5a6b64d367c4b, 0x3f29fe94ce3d3e83), (0xbb5352a68b13573e, 0xbec71660e61f0f0c), (0xbb68d34686b724d9, 0xbecd6dfcdb026028), (0x3af006603a027d68, 0x3e6ae79c35d01bca), (0xbb0ef1a3dfdf0941, 0x3e64ac50be6ca02e), (0x3a8def2f9646d0a2, 0xbe03258409210f45), (0x3a9043cd5dc1ca57, 0xbdf3c09685c05e25), (0x3a140fbcac25067c, 0x3d925d85992670e2), (0x3a184f1121e2c362, 0x3d7b509288f452b8), (0x39b4b4c230260136, 0xbd19586d0c8690d8), (0x39776fb98c811c8b, 0xbcfc973a175ffbb6), (0xb9337afd9ae7c0eb, 0x3c9a5d61717a7033), (0x3907444e5980ecc1, 0x3c776fa9ee1a429f), (0x38bdaeb8edb9cbf2, 0xbc156907cfeb69d8), (0xb8705ec9beaf1eac, 0xbbeee74de5fce6e5), (0x382fdb3ba7577f93, 0x3b8be6f4a0664634), (0xb80c67b2a3f6b8fa, 0x3b60be8c60df72fe), (0xb7980c2fe23edbd8, 0xbafdd3c10be941a0), (0x376107929e229c71, 0xbace5afc740d98d1), (0xb6ffc39670c4b338, 0x3a6aa1c12cf8bc0c), (0x36bf0bd26da1ffcc, 0x3a375bd104e008ce), (0x3671519a4046ccc5, 0xb9d429e651c05e27), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc6be2029a752b31, 0x3fc1ff5ebddd3c3a), (0xbc04bba52e05ef56, 0xbf61e2035324643c), (0xbc3a42d5bcad204f, 0xbf97f3506d4a1231), (0xbbd8ddfdbbecb379, 0x3f37c65c9302c53b), (0xbbff79e837d220e1, 0x3f53117816335151), (0x3b97f81238bbf061, 0xbef2df9afa521294), (0xbb9270fec55a19ce, 0xbefcd5d4a9d78a14), (0xbb3a3cd8b5652e44, 0x3e9c672d4d6f7766), (0xbb2736243a1eeac9, 0x3e995e4b102194f0), (0xbad74d87610e5d51, 0xbe38d22636140e12), (0x3acf7d99cf14d15d, 0xbe2d24fc9458bf7f), (0xba609b77f08fc036, 0x3dcc462d9da63971), (0x3a5ec10df895da79, 0x3db78eafb15964df), (0xb9d9e108200b834c, 0xbd569f5d498b660b), (0x39c6a15cc2204e9d, 0xbd3c3c4e5b0fab49), (0xb9732871d1bbe384, 0x3cdaccaf11834f8d), (0xb93cb3c7ca476321, 0x3cba161c63abb182), (0xb8e7d3af6ae5f8f7, 0xbc5870224af67eb4), (0xb8dc947a17c950f7, 0xbc3324870c0b9f1a), (0x3835837498a32b18, 0x3bd1adca41a58439), (0x384e7a933bc23443, 0x3ba6da83c46ff8a1), (0xb7e2d9939a6b62de, 0xbb44c90654b3ecef), (0x37b4d48249a8211b, 0xbb16a125665039e4), (0x3751c4fab8892f89, 0x3ab4403fbdd7d32b), (0xb723bebaa05fe118, 0x3a82e31c9f4289aa), (0x36be4670338eb907, 0xba209e5b516e3eb9), (0x36636814b89df314, 0xb9eaf0173952c775), ], [ (0xbc4081c2a50ad27b, 0x3fc192f2627a74e3), (0x0000000000000000, 0x0000000000000000), (0x3c3081c2a50ad27b, 0xbfb192f2627a74e3), (0xbbed88bdcc1e7819, 0x3f4635b38affe698), (0x3bfbe434e30d7a64, 0x3f775eceaabf7f86), (0x3b9ca8671aa55df6, 0xbf11ac9e0164f7c1), (0x3bc6ba93b83783a0, 0xbf28cc464a35b0af), (0xbb6979a9d3cf377f, 0x3ec4014d9bf389c3), (0xbb64740ce7aaa9f5, 0x3ecc1f05a2d85165), (0x3b05322df74ff9fc, 0xbe6761d18ebb04af), (0xbb0eb4591c8e1e8d, 0xbe63cb9af103e0f5), (0x3aa091624db08269, 0x3e00b3cb55bbe5d2), (0xba9e3e54a390f0cd, 0x3df2f5c763b33667), (0x3a315b71b511ed17, 0xbd9017771db5a5e9), (0xba14beedd13cfb94, 0xbd7a4a5e79f39fb9), (0x39987da2b8e5b9fc, 0x3d165128cc4d99cc), (0xb995477d64dc86b2, 0x3cfb991575a9daff), (0x391a0c68aab7bf20, 0xbc9756473a57c932), (0x391f7919e47d81ac, 0xbc76b070fece822a), (0x38aea8dff65f4d33, 0x3c130e1f9f1562ad), (0xb885307e292801c8, 0x3bee01b29bf38fbe), (0x380c55e014e1fd44, 0xbb88f8681f03bf7f), (0xb7a97a5de24d257a, 0xbb604e16b9d18563), (0xb79be9ebe189653a, 0x3afad6e6ca7adff4), (0xb75781440aba92bc, 0x3acda3ed85696d1e), (0x36e87609f3833ad8, 0xba6817ad40ddad7a), (0xb6d43ee7c83c85cd, 0xba36de22ba99ddd2), (0x3644163dc4acb5e3, 0x39d255cee2696246), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc4e7aa4db2a788a, 0xbfc12dd55d4be2b3), (0xbbf6da5fa7c968b2, 0x3f5f1aee31818d19), (0xbc319e43d5f0f1d5, 0x3f96de64242a8310), (0xbbd5e5667369987f, 0xbf34afdf89fca61a), (0x3bd951e5980d1eeb, 0xbf5238cfc13ac771), (0x3b9632bd2bd2db1d, 0x3ef0719d13e00e52), (0x3b672b1f290673a0, 0x3efb974781a526b4), (0xbb1d4aa2a151d3bc, 0xbe98cc82a70d752f), (0xbb3bd18c494b86c6, 0xbe9850ae878c25bb), (0x3ad9b4f29c25b035, 0x3e35bba73e282ede), (0x3ac284476c98f69a, 0x3e2bfe1396e83644), (0x3a4529f3c858a5ed, 0xbdc8d7dbe4a241ab), (0xba562391a18ff729, 0xbdb6adfbd773748d), (0xb9fff61487742711, 0x3d53f51dcb398ad3), (0xb9d0d5d8e6a35200, 0x3d3b40d30be85f3d), (0xb97f65625ced3453, 0xbcd7bf544872d9cd), (0xb9476385a2a2b1f8, 0xbcb93f163a09379d), (0x38f06b1beee10cee, 0x3c55c1ca7d35fe43), (0x38b8eeb49079a75a, 0x3c3293b43a786b37), (0xb854b85c8c7227d3, 0xbbcfa1df0227f182), (0xb80a3744049cba08, 0xbba63d0b33ebfae1), (0xb7cca2e89550a07c, 0x3b42afdbba3b1d6f), (0xb799806c5d3ae5db, 0x3b161427fedb2614), (0x374631901a8ab5ef, 0xbab24bb69b617f29), (0x3706634bb0b1f240, 0xba827970d7fd5a93), (0x369d62ccd478840e, 0x3a1e2c0be398bf2f), (0xb676a35ad46d678c, 0x39ea69a77fc2c19d), ], [ (0x3c60c06e2860e868, 0xbfc0cf3ee98f769b), (0x0000000000000000, 0x0000000000000000), (0xbc50c06e2860e868, 0x3fb0cf3ee98f769b), (0xbbb4697a99d5fadb, 0xbf436f451f6e14fb), (0x3c194225ed089995, 0xbf765d05948a946a), (0x3b91ed6777d1acf2, 0x3f0ef55c5a0d16cd), (0x3bcf058a2a3a8b0d, 0x3f27bfec9d15d038), (0x3b563856fcc3c915, 0xbec18c549f28e528), (0x3b59158b4542d2c4, 0xbecaf7544eeac766), (0x3af5145c85b8d71b, 0x3e648e81edf38b1d), (0x3afbd8241fda0445, 0x3e630341e78d1014), (0xba51c1f8c39d84cc, 0xbdfd73d2c942e970), (0xba8a04a03e6e4b0a, 0xbdf23ec2729d3a6d), (0x3a229664fb891b84, 0x3d8c78e44cdec8b3), (0x39dac0cbab30eb59, 0x3d795a6f6107b4e6), (0xb9ba116bfc433ee0, 0xbd13d1c77de8a03d), (0x399e9b0cd3f3a20f, 0xbcfaace944141c61), (0x393126e2b3ac5379, 0x3c94cfcb5e84963e), (0x390ce3384ec723cf, 0x3c75fbc3b0ec9599), (0xb8a8a1431d96f0b6, 0xbc11115c48c0688d), (0x385d6ff29b2308fa, 0xbbed24eb2fb8425b), (0xb825e6a6df55bdde, 0x3b8677909ec26485), (0xb7c21d072a134e9c, 0x3b5fbfed070231f3), (0xb797829f30055e39, 0xbaf8423b3340403e), (0xb75751d2373f6e38, 0xbacced4275822f9a), (0x370ed561d6ebcce7, 0x3a65dfcd7ab2578d), (0x36cf53856f82b22b, 0x3a365e43730aa685), (0xb61c3bb3f92eb84f, 0xb9d0b87da5a9b4de), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc64353fd6c42f1d, 0x3fc0768257dad56a), (0x3bf3a4186dcffc49, 0xbf5b602a7beaaa48), (0x3c16aaef36d826d8, 0xbf95ebc22efd092c), (0xbb76c80c9b070fe3, 0x3f3236a604142e61), (0x3beddcf66c5978ce, 0x3f517a482faa8d85), (0x3b66ad649af93743, 0xbeecfc00890787ae), (0x3b928f6dcddab568, 0xbefa7d7b128ac538), (0x3b25a6c98552063d, 0x3e95e419f1b57043), (0xbaf32b6c630ee4fa, 0x3e97603cea235244), (0xbad9cee30553553d, 0xbe333a0b436c8824), (0x3abe7890b4a4106e, 0xbe2af46417845f40), (0x3a4f7394a3298f16, 0x3dc609ac8cd8177a), (0xba59cd5f345dc226, 0x3db5e11b87ad3903), (0x39f73ed5597f6f80, 0xbd51c2756590391a), (0x399986e8c9348fca, 0xbd3a586483dd891d), (0xb97cc034606fd4e1, 0x3cd534d22c600964), (0xb957a2d70318a209, 0x3cb8755ad322c506), (0x38e4680effc80bb4, 0xbc53809e528c6189), (0x38d5dd4c01f7d4c2, 0xbc3209a0a78d682e), (0xb8644847850e1cab, 0x3bcc77842d1f731c), (0x384c2f3bd9e41480, 0x3ba5a4538092f65b), (0x37efb4bb53ec98f4, 0xbb40e2a86e6cb3f9), (0x377521ae7e540c78, 0xbb1588f3efb4ad64), (0x375fdbdc3816089b, 0x3ab099874d761b53), (0x37298a0b16897a8b, 0x3a820f23922028f2), (0x36b4686e1a4ffa47, 0xba1b7c94063b4326), (0xb682cf52edcbf7b1, 0xb9e9dfbe640c7d02), ], [ (0x3c61166b7995967a, 0x3fc0230ba90f2871), (0x0000000000000000, 0x0000000000000000), (0xbc51166b7995967a, 0xbfb0230ba90f2871), (0x3be85d0df08ff853, 0x3f413164a0864cde), (0x3c175b99fcae0fa4, 0x3f7579c1bdbcfc99), (0xbbaa847d3261af11, 0xbf0b67e1913c668b), (0xbbbdc3b0bfb76e70, 0xbf26d26de4fd8c5d), (0x3b509cffcaa6fd75, 0x3ebf1b520b063853), (0x3b56e93d7c515f0c, 0x3ec9f01e7c1909a0), (0x3aeb43dee8b56e57, 0xbe624071b1796027), (0x3a99b4c0bd0ff4a5, 0xbe624f8e939ce43c), (0xba9ac0bb7d806efd, 0x3dfa35663595463f), (0xba625661d1f74770, 0x3df199120d49d507), (0x3a1bddfd9246953c, 0xbd896771e1b15e44), (0x3a1acb7638900b33, 0xbd787ede134ed7a0), (0x39a9e2e9004bba4f, 0x3d11bccdfbafa1fd), (0xb995262f16494ab9, 0x3cf9d22a6dc5a57c), (0x393e65a43ea6fde8, 0xbc92b00e367301bf), (0xb8e38ef38ce7f9e3, 0xbc755236722b3018), (0xb8a085f6fce94877, 0x3c0ec2ce49a94662), (0x38851022a9daf9df, 0x3bec52d2fb48c061), (0xb8260ec09f1c11bc, 0xbb84522e399fa43a), (0x37d6e8cbd63da93e, 0xbb5eeb3ee8f96a17), (0xb780414b4648c1d1, 0x3af60651f3414a8f), (0xb75a1e55435fe75b, 0x3acc3a2c8e72fa37), (0x37034c532c4c52e0, 0xba63ef7c46a9be7d), (0xb6d60fee2f339275, 0xba35deebe060dd5c), (0x366c4892cbf5f446, 0x39ce97bce469d7a5), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c10417847765c1a, 0xbfbfa8b3f9ae4375), (0xbbcf334b3619566d, 0x3f5856073b7fa2cd), (0x3c3664c698368b18, 0x3f9514e652eb2e96), (0xbbb93b53ec827565, 0xbf3032298718ea1a), (0x3bfdfbf103edc8e3, 0xbf50d1153fde431b), (0x3b7c365adad42a66, 0x3ee9cb455c29d6a7), (0xbb9fa9b04c310c2c, 0x3ef982167b1c52c3), (0x3b3466b707822fa7, 0xbe938191ef68eab3), (0x3b31f4e7061400c0, 0xbe968865345b3130), (0x3adaf50c9fd62c74, 0x3e312960010da387), (0xbace36911ce663a9, 0x3e2a0403679f6882), (0x3a4177820d3b2b22, 0xbdc3b67cc0b96c06), (0xba565f2ed3c28fcc, 0xbdb526038b956efd), (0xb9d5a1b33bcbb16b, 0x3d4fda06e840fa34), (0x39d1d67f1bd55539, 0x3d3981de640d0e00), (0x397c94419a95b1f3, 0xbcd311fc56c4b88a), (0x39532577b4bca3e2, 0xbcb7b8f62899fc83), (0xb8f552faebfd4704, 0x3c51977cb27410a2), (0x38d26b959afd2d20, 0x3c318706eb31dd46), (0x386ce90ca03d9538, 0xbbc9c2ecf35b9e14), (0x384b179344e2eb73, 0xbba511e7341e8837), (0xb7dba680290d429b, 0x3b3eaa190aa91ed0), (0xb7b49a491a85f98b, 0x3b1501910205c4a9), (0xb74ebc3f994c58ab, 0xbaae3fe1d152dac7), (0xb72316bcea29e953, 0xba81a632639f368e), (0xb698c03bf571184d, 0x3a192191e962f593), (0xb68c49d86016d888, 0x39e95576c2d368f1), ], [ (0x3c50db2c50623ec0, 0xbfbf13fb0c0e6fcd), (0x0000000000000000, 0x0000000000000000), (0xbc40db2c50623ec0, 0x3faf13fb0c0e6fcd), (0xbbddaa7169324a5a, 0xbf3eb3e6fcc47c00), (0xbc1a7c91ef9a7da1, 0xbf74af74cbd77bef), (0xbb8ca4e36c0e29e8, 0x3f087bb1ebeaec75), (0x3bc0dc1e11076c62, 0x3f25fe629203150e), (0xbb5990b5b348875c, 0xbebbd0f2a6555e6b), (0x3b6af9c37c81d002, 0xbec9040de830649e), (0x3ae759c4b27cdf74, 0x3e6057f7a76993d7), (0xbaf1d65071810a7a, 0x3e61ad6dd5105c3e), (0x3a9d40eb62d35800, 0xbdf782a6f5738cdb), (0x3a8bf5df6e6d389e, 0xbdf1027dc06d4453), (0xba28e41b1a5587d6, 0x3d86d65b13b16f65), (0xb9fc75d3c8772d41, 0x3d77b59e9ed7367d), (0xb9af754c04eface9, 0xbd0ff800f2a49a00), (0xb991f98cd4e6ac14, 0xbcf907be43054aec), (0xb933d033de8a73d1, 0x3c90e2e1d8f5ad67), (0x38eed8fb6a3c50a9, 0x3c74b3a8b0fb5259), (0x388913f9676a0ac9, 0xbc0be06d96b6ddb7), (0xb88ea864297f3fc7, 0xbbeb8c227343f289), (0xb82ff7b2b57b5685, 0x3b8278dcce458371), (0xb7f78beca367a3df, 0x3b5e1fb52b874a03), (0x379b7478eaac89e3, 0xbaf41590cb708f7e), (0xb752fe7b149fbb7c, 0xbacb8ca63f91e577), (0xb70548503aed227a, 0x3a623cdbe3c71609), (0x36c12f6cf019ff77, 0x3a3561f0d31660bb), (0x365d1dc388e61bc9, 0xb9cc13f7faffaf26), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c56a7c2ed8fa844, 0x3fbe8727c572a2c2), (0x3bfdee3ce04b3d39, 0xbf55d1ef092ab395), (0x3c206dda20eba87a, 0xbf9454e7a7395636), (0x3bb99eb39ffae4f4, 0x3f2d0cc3a7fa6d3d), (0xbbc9d1e5b54f9af7, 0x3f50398d2cbd02df), (0x3b8aa1f4bf33efdb, 0xbee725b0909f9c66), (0xbb9b20d87a760067, 0xbef8a022f5fee447), (0xbb1fcb0c42b0e854, 0x3e9185b1ea97a54b), (0x3b3ea0aa1deb55ca, 0x3e95c571167401ae), (0x3acd2759cfccc15b, 0xbe2edff6514e1da9), (0x3ab2592f6b4b9153, 0xbe29298da3c4fa71), (0xba62158d0945cb91, 0x3dc1c34705eadfb1), (0xba424ede84d84b4b, 0x3db47ab8ec529c51), (0xb9e73e83248604d7, 0xbd4cc24a2f007c3e), (0xb9c2979e3d03632b, 0xbd38bbcc44e6c225), (0x39703e1bd29b296c, 0x3cd1420df9bb4359), (0x395d047d716a7a8d, 0x3cb7095f8b3266bd), (0xb8cd11469be08694, 0xbc4feb87e4e655cc), (0x38be1dd0526935fa, 0xbc310c0caf4ba7a9), (0x385a60dd5e84c9c5, 0x3bc76f4ca221cf39), (0xb83ecbabc0dd7d07, 0x3ba4868177e6f5ef), (0x37b8847e584a462d, 0xbb3bf93dc497bf28), (0xb7bb4e77466271a4, 0xbb147f2c424e92f5), (0x374a584169fadea4, 0x3aabace093fa5e7e), (0x370af91e2a607b95, 0x3a813fe3dbef7300), (0x36a10a818d4db7be, 0xba170f75c4345a45), (0xb6269b19813edb68, 0xb9e8ccf104c5a0ca), ], [ (0xbc3b9f1d130797af, 0x3fbe018dac1c17e3), (0x0000000000000000, 0x0000000000000000), (0x3c2b9f1d130797af, 0xbfae018dac1c17e3), (0xbbc5edf62333beba, 0x3f3ba21bd15d02a4), (0x3c138b4f0d3a4110, 0x3f73f9e0db07e7ef), (0xbba6f23ddcae2db1, 0xbf060b77c5e27622), (0x3ba86d4e04faa212, 0xbf253f9b1a5d228c), (0xbb5fddc005e382a4, 0x3eb910b38812c253), (0xbb40935ad53575b8, 0x3ec82ee6dfdfedeb), (0x3afa8bf307790c80, 0xbe5d7cc2a9a602ee), (0x3b0b50784ff133f1, 0xbe611a57d8645358), (0x3a8673cb487ec434, 0x3df53d401519442d), (0xba8c03600ffb7a70, 0x3df07915ef87408d), (0x3a2022a5f15014b6, 0xbd84aabcb6141c76), (0xba1d37109cce2377, 0xbd76fcb8e2eada15), (0xb9a95525555a3484, 0x3d0cfcfdb2faeb02), (0x39997fd3cf0000fa, 0x3cf84c5369d2e33d), (0x38f88b42ac1a9330, 0xbc8eb11d7e6581b7), (0x39181a3f66a29421, 0xbc741f9ab4632e3b), (0xb8abf00ddaa40351, 0x3c0965159407b5ab), (0x3885289d8a9dc178, 0x3bead0e3cd065e84), (0xb8220f36807a6153, 0xbb80dee0e94d3838), (0xb7e15def3c2d10d9, 0xbb5d5e035bd44cab), (0x379e09d7e4e2053c, 0x3af26452e5cf7372), (0x375c2b8feb4af0ba, 0x3acae5d15fef7e8f), (0x370c46b7285b4063, 0xba60bf2894ab39b9), (0x36bc8ff0c23e41b6, 0xba34e87ee39a6f39), (0x366a289544183384, 0x39c9daa655367c6d), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c555d27e18add4d, 0xbfbd82939ab62339), (0xbbe5f2055a671318, 0x3f53b5a54845670f), (0xbc331ee0af44ab91, 0x3f93a7ff1622def8), (0xbbb2001fd8691606, 0xbf2a3ebc476a606d), (0xbbb7a5c728534a7d, 0xbf4f61adde3a8c61), (0xbb6721b027970bc9, 0x3ee4ec45da0478b0), (0x3b60295953d04e19, 0x3ef7d3b28159f23c), (0x3b21dd48380f5e9a, 0xbe8fb3f21bcd7fc4), (0x3b3047a478eaf94e, 0xbe95145a876d2273), (0xbac575cc2ab01d93, 0x3e2bf64cdf7c0558), (0x3a9c7ea365ef1c0c, 0x3e2862204ac427d2), (0x3a25523941e42ede, 0xbdc01c0d48888811), (0x3a3766e8ee24e58a, 0xbdb3dd6cb1cbcd8f), (0x39e11ac6552bc64c, 0x3d4a2020c8b3c20d), (0x39bbaa3793fd39c4, 0x3d3804a9d711292e), (0xb965d9ecddfcbd4d, 0xbccf6a1ef9182e2c), (0xb95ee6d1970be0a7, 0xbcb665c82dfd3111), (0x38e2ccf8afc7f5eb, 0x3c4d1cbc474ae672), (0x38baa3fe632e7af8, 0x3c309883728ed041), (0x386cc2812a2e5111, 0xbbc56bda19c4b049), (0x3825988783a1ff06, 0xbba4025c7e87cb33), (0x3798e8afd688bd54, 0x3b39a17a3b2afb39), (0x37b0dd0e73f34a5f, 0x3b14026125d71009), (0xb73504f75a230f17, 0xbaa96b8155611361), (0x36fcaf6a0d9e7292, 0xba80dcfdcb67c11b), (0x363354ed9306d4a3, 0x3a153c10e4500766), (0xb6880389022204ec, 0x39e84794b22bad24), ], [ (0xbc56edd809f4ec43, 0xbfbd09b21e36c0bd), (0x0000000000000000, 0x0000000000000000), (0x3c46edd809f4ec43, 0x3fad09b21e36c0bd), (0x3bd1da06fbc186d3, 0xbf390b0e6a475e45), (0xbc140975d5184af6, 0xbf7355b904fbf7ee), (0x3b9e3b983f117cfc, 0x3f03fc459d1e25a4), (0xbbb494c77a177873, 0x3f2492cc61d19dfe), (0x3b46367d4d299b08, 0xbeb6bcf110a02ad1), (0x3b6b6ea46d6db74f, 0xbec76d44f6a83523), (0x3a8030056b81d3a7, 0x3e5ac61efcb3c36c), (0x3afeb8462b17799c, 0x3e609436fcaa3965), (0xba99e294aeb8cd7b, 0xbdf34eb6095f969b), (0xba88db8194acb808, 0xbdeff662945eb368), (0xba237c1915fc9c0d, 0x3d82d05bf8ff5181), (0xb9d3e0b801e8758e, 0x3d76525fbb563fe0), (0xb9a734f42937bddb, 0xbd0a6eb937c7f6c0), (0x396073f8f8b180ec, 0xbcf79e90468589ab), (0xb922e469e5eb93e5, 0x3c8c0998b46c2a6d), (0x38badc48095c4e55, 0x3c73955fe5fb130b), (0xb8949ebb69e71ffd, 0xbc073ec897598aef), (0xb88f7564544e1430, 0xbbea20bd7b4d506a), (0xb7fb326fec2fdde6, 0x3b7ef3962c3d7988), (0x37e82dd0be2c1482, 0x3b5ca6507646e165), (0xb7879646e68dbcf8, 0xbaf0e8ca73f2d68d), (0xb74018d4e9ae2637, 0xbaca463d4098cc93), (0x36f61d9992deaded, 0x3a5edd93261617c3), (0xb6dbe7fd3fa3deaf, 0x3a34734a62443d4b), (0x3623d3bbf119c872, 0xb9c7e1ec2479954a), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c4e1f19f10295a1, 0x3fbc96700031f601), (0x3bd8339df4a4a968, 0xbf51eb2a07d0f09e), (0xbc39bfe53ec12c8a, 0xbf930b36eddaa234), (0xbbb206af4ba8d313, 0x3f27dd2dde84b73c), (0xbbd1f3a6f0dd2e56, 0x3f4e696553e0b8a5), (0x3b70bebcc672e081, 0xbee3085aa35a1647), (0x3b964955e62a56d5, 0xbef7199f24bccae1), (0x3b29acbd0629609d, 0x3e8cdbab6a766176), (0x3b336b635edd4912, 0x3e9472a7cffbf91e), (0xbaa919ffba04358e, 0xbe2979f5211c4dae), (0xbacb3a83d64d312f, 0xbe27ab4b01a902db), (0xba3d20c26289bb46, 0x3dbd63904e4c487c), (0x3a3a2263834e8f85, 0x3db34c83fb1c2279), (0x39d0d1629893175f, 0xbd47dcfdf13e5ccc), (0x39b38e8b7b2086d0, 0xbd375b01ddacf988), (0xb96c94f8a51700d8, 0x3cccbd41ea6afd29), (0xb9596f4635f2eb43, 0x3cb5cd46eaba1e98), (0xb8ef331fa6111e01, 0xbc4aaded22d1c6ea), (0xb8c316503d17378d, 0xbc302c0feb2cc9ff), (0xb86b0bb9dacdd402, 0x3bc3ab0efb0f5a6a), (0xb83c8dfa9ab81f86, 0x3ba38564ae73cbd4), (0xb7ce2bd40d6dd04f, 0xbb379494ee2fe052), (0xb7a9f50c26ffe35d, 0xbb138b6c6bd628fc), (0xb704cc1a22fd0a79, 0x3aa76f817567d54d), (0xb72b4eeb7ce6fd0f, 0x3a807ded69c2252a), (0x36b142adaa59897c, 0xba139e9549f763d8), (0xb6561aae4c08fc78, 0xb9e7c644065d040a), ], [ (0xbc5ca34ef67ceca5, 0x3fbc2861347b1b39), (0x0000000000000000, 0x0000000000000000), (0x3c4ca34ef67ceca5, 0xbfac2861347b1b39), (0x3bbf201ae2302561, 0x3f36d57bffb37fd5), (0xbc16b4ecac2fa1c2, 0x3f72c060ef553f18), (0xbb9df91b90d34cd8, 0xbf023a407b722d2e), (0xbbca3432d200d5db, 0xbf23f55581ec683d), (0xbb5e04bafba5dc5a, 0x3eb4bfb4daa2ff62), (0xbb42a29e463f2261, 0x3ec6bc69099af2f7), (0xbafb52717e21f4f1, 0xbe5873340987d276), (0xbadb9738396340d1, 0xbe601951f02d2b37), (0x3a8c2da917c5d2d4, 0x3df1a6174fe55fbe), (0xba7265752e07ea23, 0x3def0eca5bc0284a), (0xba1b8d994d0c183a, 0xbd8137cb1fcc55a3), (0x39c1b1fb4f7e04be, 0xbd75b4f7f2bb19ed), (0x39961a8be6115ecd, 0x3d083934ed797abc), (0xb998209f68cee7a8, 0x3cf6fd29fcbcf38b), (0x38da8f6db73066be, 0xbc89bbe4a386b1fc), (0x39119e7a973ba60e, 0xbc73143b8f6fa9b5), (0xb8a42d280d3b7044, 0x3c055f1ef8c6277c), (0xb8741bc4d5b892a4, 0x3be97b209a81cdd1), (0x381f56010f66d563, 0xbb7c822a3d227a0b), (0xb7d326c5dc6baa73, 0xbb5bf86da968d5d8), (0x37685ec534d88737, 0x3aef3590b082abca), (0x376f5328f688841e, 0x3ac9ae18938ed4dc), (0x369b410a6e56968b, 0xba5c8a82558390d1), (0xb6c5a55f28288a0c, 0xba3402b3aeae6a78), (0x365785f4c242b76d, 0x39c621268afb8484), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc2986f8b543f277, 0xbfbbbf246019c0d4), (0xbbf8243dc68faf05, 0x3f506224199140d8), (0xbc31c8ab4f070de9, 0x3f927c3416c09898), (0x3bc1400990dffd7c, 0xbf25d279dc87cf69), (0xbba49f5dbb72a054, 0xbf4d86a5f5adbdac), (0x3b8c1a134d478d15, 0x3ee169041634c248), (0x3b908bd4df68b455, 0x3ef66f5bd1bedae1), (0x3b2340bc492ebacd, 0xbe8a69b2c717d54a), (0x3b2b327658085637, 0xbe93de4eab456cbd), (0xba8a52518b85c3bb, 0x3e2755eabbde6915), (0xbaceee9ff82c0693, 0x3e2702fe7ba9f8c3), (0xba380d66035d4ef3, 0xbdbaf2007eeae256), (0x3a5fcfcb227b90a8, 0xbdb2c69746948e55), (0x39e9a9de8d952335, 0x3d45e77ad9a9daf0), (0xb9d9fd6d3c1b2712, 0x3d36bd7bc6045cd0), (0x392032afd924a7d3, 0xbcca6a2a200a32c2), (0xb959d59bb0713bcd, 0xbcb53ef0001a8fc4), (0xb8ed4be5f4212c88, 0x3c488eb37fc1d400), (0xb89d39eabce00ec1, 0x3c2f8c832f51b562), (0x3840e097e8a92261, 0xbbc22200a03da113), (0x384c3af44c4ec552, 0xbba30f596dc1d400), (0xb7dc9bccb090c4a1, 0x3b35c6dd14718296), (0xb7bce5b1aace9f68, 0x3b131a4eaddd4e23), (0x3744f32babed55e0, 0xbaa5ae9b0fa87ab5), (0x372de16b15f9f82a, 0xba8022e41d997f41), (0x36b5867aa0456426, 0x3a122f7b20539f5a), (0x368433fa75fa367b, 0x39e74982e085fb06), ], [ (0x3c497d2b9281abc8, 0xbfbb5a622198a72c), (0x0000000000000000, 0x0000000000000000), (0xbc397d2b9281abc8, 0x3fab5a622198a72c), (0x3bd29fd72f6917e5, 0xbf34ee71cf67c243), (0x3bef69e3e89e3765, 0xbf7237c02b462f6f), (0xbbaa32f85df10bfa, 0x3f00b67b6fdfec62), (0xbbcb53a20d4b2f61, 0x3f2365167d8bc330), (0xbb5df27a7ce0e8f5, 0xbeb3086b7a296e69), (0xbb64ce30c488f398, 0xbec61a141425c2a6), (0xbaf5a586401bb54e, 0x3e56712b23991e80), (0x3afc0839aea10c7b, 0x3e5f50736839e481), (0x3a894d28c9a59269, 0xbdf0366d02b91b84), (0xba3b7dda45b64dc6, 0xbdee38f9bda5f6df), (0x3a0f464a8fd7c7bf, 0x3d7faa3d1cb01e65), (0xba1e45ca78c915d9, 0x3d752317a2a5b9a2), (0x39a7d004a800c3b5, 0xbd064cd06847bd1d), (0xb95179a5ef0f66b7, 0xbcf666eebfeb573d), (0xb9285e2b929e1519, 0x3c87b8b54f1785bc), (0xb919589128d0188e, 0x3c729b70ca32ef58), (0xb8a46a9746bfb343, 0xbc03ba848f791229), (0x386730f56682d5be, 0xbbe8df65522ba529), (0x37f2ab030e344d2f, 0x3b7a5b900787f393), (0xb7bb11ca75f0fcdb, 0x3b5b53fa2dd77bb4), (0x378eb255c1629783, 0xbaece6fc2aac5380), (0xb729982419793a6f, 0xbac91d5406064eb8), (0xb6ebe671ea8254cb, 0x3a5a7a1d77627f77), (0xb6cf1004e96b1aa1, 0x3a3396e1ce8aa477), (0xb62a0c13a37cd740, 0xb9c490dcdeea0de1), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c56e5b3d654a3de, 0x3fbaf9cb42cd08a7), (0x3bd4df22cc118423, 0xbf4e1c66d7616e37), (0x3c32068ccdde2ecb, 0xbf91f90fd1013589), (0xbbb9426a5fb5baf4, 0x3f240e3eb09b7d6d), (0x3bcf4131edb03e4e, 0x3f4cb682ff471274), (0x3b8c9cd4cf70b38d, 0xbee0016819a61dd8), (0x3b8325d69b159805, 0xbef5d2d1c420646d), (0xbb157a8a155b14f1, 0x3e884b0fe8a85355), (0x3b1d5bbe26d9661b, 0x3e93559d96bef598), (0x3ac3da55cae73bf1, 0xbe257a0be74997ad), (0xbaac817776602a6c, 0xbe26677c8f53b6a6), (0xba48a3adc3758fa2, 0x3db8d1ae21b756a1), (0xba55e41c080dae7e, 0x3db24a6e1ac65e87), (0x39d87ea029a22f95, 0xbd4432017034b94c), (0xb9b0c571c0172220, 0xbd362ae0447c7c88), (0x392c7ada7dc7ba07, 0x3cc86190e6a87084), (0xb8cce5846ffd630a, 0x3cb4b9e1622f9586), (0x38e2a29910f701c9, 0xbc46b1f3e51e7716), (0x389f461c8b8d14fd, 0xbc2ecd4131542af6), (0xb865a2f5fd7d4f74, 0x3bc0c7d6edd792f0), (0xb84d80cbe9f82337, 0x3ba29fe1dfb030da), (0xb7be1d7b0beadd6d, 0xbb342eb58314dd57), (0xb7bd13d73eb584cb, 0xbb12aee37e25148e), (0x3706be9737507cbd, 0x3aa420385af46d51), (0x37178c7e05bb4a09, 0x3a7f97d766899d96), (0x36b40aa8f19fb9a4, 0xba10e85b8b8bab6c), (0xb68622de5eece514, 0xb9e6d19365680b1c), ], [ (0x3c49a6abbfd839f8, 0x3fba9d183bc04545), (0x0000000000000000, 0x0000000000000000), (0xbc39a6abbfd839f8, 0xbfaa9d183bc04545), (0x3b97025ee34cfaec, 0x3f334779874010dc), (0xbc01fefbfc4e4e9c, 0x3f71ba2299ab88a8), (0xbb55c0e2a19295ff, 0xbefecb19f5bdc649), (0xbbcce75d43258257, 0xbf22e052707cc859), (0xbb5a63ba682d6499, 0x3eb18a5da77edd83), (0xbb6dd00d54139579, 0x3ec5846b622f592b), (0xbae5e872e9945332, 0xbe54b17e97b5884a), (0x3ac6a221a04b77f7, 0xbe5e7f76674dfaab), (0xba84b342c0e05e8d, 0x3dedeb504ed353c6), (0x3a86775d5b3d25ee, 0x3ded72e25f190409), (0xba00d09a917a59f6, 0xbd7d3e076b0201d6), (0x39c46b750b88e7f8, 0xbd749b825302af88), (0x39abeb00dd42cc76, 0x3d049d35475fc5c4), (0x399639c0b0dc546c, 0x3cf5dac9623f7b3a), (0xb8c1489d884eb85a, 0xbc85f3d5130dc414), (0xb91861dc55985f01, 0xbc722a4aeb6977eb), (0x3890153f6d844191, 0x3c02479e3ad06b06), (0x3880093480726623, 0x3be84cdbd4996301), (0xb80c8f94083b0211, 0xbb78745ed629d641), (0x37e3f2458bb649a6, 0xbb5ab87a5deb4183), (0xb788f6fa139ccbd7, 0x3aeada86a4d62add), (0x3756d41ddc1f8d52, 0x3ac893b9d1f77835), (0xb6ee50fc22fbfa2f, 0xba58a3198036b128), (0x36c2de5121e2e61a, 0xba332fd57127bac6), (0xb63875952298668b, 0x39c32aa4779bf0be), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c5729f43724612e, 0xbfba4407dac72297), (0x3be5723d945cf385, 0x3f4bcba4dec1da44), (0xbc3fe775590d7dac, 0x3f91803c65cafdfb), (0x3bc90cfa57dbb628, 0xbf2283df2b3e4a6e), (0x3bc3e3e0391f1e19, 0xbf4bf695e89259cd), (0x3b630f86ed6a90e0, 0x3edd8f3759122d51), (0x3b9030fb5fd0d14f, 0x3ef54246c8e04218), (0xbb1b2983b9c451c8, 0xbe867111bc8e67a4), (0xbb3a3cef2b75d5c2, 0xbe92d72a1f62ec18), (0x3acbd165727f6821, 0x3e23d9ca3eb1e22f), (0xbacc01aecceaa6e4, 0x3e25d74a6e225515), (0xba59e0bf6ede94ee, 0xbdb6f4b420b2f957), (0xba5cdfc28e1823b4, 0xbdb1d6f985dc3ec9), (0x39e7d772f8fce3e1, 0x3d42b1d81101dea8), (0xb9d82ef548b3e361, 0x3d35a2197089fbfb), (0xb956841fa8612f5c, 0xbcc6974aff17c78f), (0x394b2b4bcdaabf0e, 0xbcb43d4892ea1bcf), (0xb8dd3073293bb4a5, 0x3c450d21b45ffbaf), (0xb8b6f6e75ed53665, 0x3c2e196b40872c65), (0x384e654070aa0a0c, 0xbbbf2abd4dc31a0d), (0x3847ef0270966133, 0xbba23699d6695800), (0xb7d774e0a1072a6c, 0x3b32c4314fb1b042), (0x3798dfd4a7af4ecb, 0x3b1248f0b0a01e5c), (0x374feaa8039e5d21, 0xbaa2bd2ced8351bd), (0x37162b8b059830f3, 0xba7ef1e8bc571d77), (0x36a5be76c75f587a, 0x3a0f87929eae0a41), (0x367e0d8209c727ce, 0x39e65e8aae87b358), ], [ (0x3c4f5da9526c15aa, 0xbfb9ee5eee1a97c6), (0x0000000000000000, 0x0000000000000000), (0xbc3f5da9526c15aa, 0x3fa9ee5eee1a97c6), (0xbbc33100916421b3, 0xbf31d55d93e59bd7), (0xbbb6887e944ccfcf, 0xbf7146219394a99c), (0x3b8ca8e50931ec0e, 0x3efc7d32bb646e2a), (0x3b459561844c2171, 0x3f226599aed4f1ca), (0x3b2f06633c8a57af, 0xbeb03ba58ec85c12), (0xbb602686ed9f14f1, 0xbec4f9e3961bb9dd), (0x3aeea9ee2c50aae8, 0x3e5328d4dc334079), (0xbaef3a53aa36f2d4, 0x3e5dbda7ac70ff93), (0x3a77a84a53fa4382, 0xbdebb7c2f187144e), (0xba64d01b19ecf2c5, 0xbdecbac24c760567), (0x3a16eec036aa6895, 0x3d7b1c35b65eca4e), (0xba1d9ece3561eb27, 0x3d741d23f93de7a0), (0x39ab2aa54e1d2f75, 0xbd03208d806698c2), (0xb99acf6d8899800a, 0xbcf557c166250d9c), (0x391934ffa520f9d8, 0x3c84637130a9d7e6), (0x38f36ddde127bd83, 0x3c71c021934a5bf8), (0xb89d68e84d698c21, 0xbc00fed119c94fe7), (0x388e25551faa0fb9, 0xbbe7c2d64524cfa1), (0x381e8f2946a1a0bb, 0x3b76c3357c3f7adf), (0x37f7b13ebe2df289, 0x3b5a25665c8bb28a), (0xb78e1214cb5a34de, 0xbae906c5169421c4), (0x376f2d89008c8e68, 0xbac810fd94a57b7b), (0x36d90aeea93b07c4, 0x3a56fd9fc0a89c82), (0xb6dc9ebd96e6e684, 0x3a32cd7652121959), (0xb61332c9199d4380, 0xb9c1e8fff9203895), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c422d28ddb0663f, 0x3fb99be73fa3efcc), (0x3bc06623176e8323, 0xbf49c3248da75775), (0x3c24e67d5d6f01f8, 0xbf91107147eda800), (0xbbb9f85d6cd5a102, 0x3f212980be9d8520), (0xbbc6d7f4255305b6, 0x3f4b44e1221e6051), (0xbb75ffceb4092099, 0xbedb67b78c1dd9c5), (0xbb952647474dbc63, 0xbef4bc49e9b5bcfd), (0xbb07d96f2518a716, 0x3e84d02ffb8bcfd0), (0x3b3e32d27646b835, 0x3e9261c31456e43c), (0xbac76119a10d67c2, 0xbe226b400744def1), (0x3acd5778eebf7e73, 0xbe2551251a2b4223), (0x3a46fe94a695c8b2, 0x3db5500f9531112d), (0x3a083f83ad3b6fcc, 0x3db16b4e936f8a96), (0x39d92e892227b268, 0xbd415e70b28182e4), (0xb9d311286e6202d4, 0xbd352230c03cb29f), (0x39694a35e842f6b5, 0x3cc5019095879294), (0xb95c82d35e7d0a85, 0x3cb3c864dd8bd878), (0xb8e021ec04623c9c, 0xbc4397af75e324f3), (0xb8c1d4036b77bcc2, 0xbc2d701c9937cabc), (0x385d6fca0674878d, 0x3bbd0965d9326e17), (0xb84fa05c3c3c3a3f, 0x3ba1d319c4fce696), (0xb77cd5e86688f3b8, 0xbb3180c1f00da609), (0xb7ba86637aa4bf02, 0xbb11e8305b488b70), (0x3736c6f17e2a0301, 0x3aa17f7804b40b24), (0xb7084fe04399b71a, 0x3a7e53bca7936259), (0x369739312d3bebf0, 0xba0d7a5725978bd4), (0x3689e9b194e5ecb2, 0xb9e5f05f8d349ae8), ], [ (0xbc55bbc298d062cd, 0x3fb94c6f5898708b), (0x0000000000000000, 0x0000000000000000), (0x3c45bbc298d062cd, 0xbfa94c6f5898708b), (0xbbc91fb79f224deb, 0x3f308f4f1b8fb0dc), (0x3c11274d5c28ac61, 0x3f70da931c776c71), (0x3b468ef3cfedd83e, 0xbefa7550d2940f2a), (0x3bbf74462dfd6402, 0xbf21f3b978a47cf4), (0xbb46a542136ebd9e, 0x3eae28ea02472df4), (0xbb6c80d173ca8c69, 0x3ec47930aec78cb8), (0x3adf057ade51b16d, 0xbe51ce32c4f34e51), (0x3afb45adc74dd76d, 0xbe5d0950e99c8b39), (0xba7a6618445563ec, 0x3de9c5a1603e79e8), (0xba8e2efa815aa6df, 0x3dec0f1778cf9887), (0xba168e5ec792cc80, 0xbd7938fe13097690), (0xba1edc43381b3d99, 0xbd73a70bdaedabef), (0x39ad72e528e9a77a, 0x3d01ceeed28a9bbc), (0x3981b5050358ac3a, 0x3cf4dcf95c5ca94a), (0x38e5c074caf95ef8, 0xbc82ff92717657b8), (0xb8c1517cb6203642, 0xbc715c5a3e02462c), (0x38848ac21ce9d63b, 0x3bffb3c968d1317c), (0xb868eaf9f67497e9, 0x3be740ae3a9480c4), (0xb7e7ce53355d1e7c, 0xbb754054fa0921f1), (0xb7db46466a3c45dd, 0xbb599a3335285172), (0x376a7830f0710c1c, 0x3ae763db68405483), (0x37496d5dfac38e6e, 0x3ac794c6d23aefa1), (0xb6d0259444fde6bc, 0xba5583129058029b), (0xb6b49a7445a09fb2, 0xba326f9c89204c85), (0x3648f301c94c285c, 0x39c0c73ede23db3f), ], [ (0x0000000000000000, 0x0000000000000000), (0xbbb1d709b3e6aac3, 0xbfb8ffc9b9a131f6), (0x3bdb4dd57b3641ab, 0x3f47f724314bb99d), (0xbc3086cbc396cba9, 0x3f90a89c5d1074ba), (0x3bb8da379d94d744, 0xbf1feeaeb33465e8), (0xbbef433944c1a75a, 0xbf4a9fba36a7a08e), (0xbb7f256bdb98dded, 0x3ed980034770f3b2), (0x3b91b4c8faeaae10, 0x3ef43fa4bb8cba57), (0xbad948481046b8ce, 0xbe835f40f3a3902b), (0x3b3e2e9d940a603b, 0xbe91f465ba292c0d), (0xba98e1101ee20622, 0x3e212688f74f8106), (0x3ac17030074177fa, 0x3e24d3f7e3fdde95), (0xba567e7ce0ee9db6, 0xbdb3daee9c38c74a), (0x3a51aeae4597f6fa, 0xbdb106a132ee69a7), (0x39ebf6485dd79da8, 0x3d4030e7765d6c75), (0x39c15870eda63050, 0x3d34aa4c24070ac4), (0xb958792c38458a32, 0xbcc3987402712b60), (0xb95ac711e3d7df47, 0xbcb35a87994f9f22), (0xb8b987c84af86497, 0x3c424aa138f72769), (0x38cd1d7e8860d6ea, 0x3c2cd07eb7a4b74f), (0xb85adedac22a5607, 0xbbbb21f2d5c76559), (0xb8403dbefd803008, 0xbba174fb8123d957), (0xb7decb7c15886751, 0x3b305ef4d5737c95), (0xb78dcfe2c3d73d6b, 0x3b118c574d742d02), (0x3746542ad0f810ba, 0xbaa0621051dc9615), (0x371434d10d672431, 0xba7dbd00a70ea7c3), (0x36a3d2f4625f489c, 0x3a0ba13931894290), (0x367d34b5778ce244, 0x39e586f4fb44eb1c), ], [ (0x3c5827414357db53, 0xbfb8b5ccb03d459b), (0x0000000000000000, 0x0000000000000000), (0xbc4827414357db53, 0x3fa8b5ccb03d459b), (0x3bc829bf4eaf884d, 0xbf2edc98b92fedf3), (0x3c0a89c9aabf2841, 0xbf70767d524cea88), (0xbb9b6aea43cf7c69, 0x3ef8a85a847c89c3), (0x3b9126e1254c1c3f, 0x3f2189afaa2bffcc), (0xbb239c5c72e2b643, 0xbeac1d231a69bb02), (0x3b6e89e6ffd32981, 0xbec40139bdbc9d36), (0xbac65998040abd88, 0x3e509a6859c8e374), (0x3aded4461012c62e, 0x3e5c60fc5f9b505f), (0xba80f4ba127543b5, 0xbde80ad391f7224c), (0xba8175d6b9c314bd, 0xbdeb6e954dd6c922), (0xba13a59996f17ca1, 0x3d778adc76ca1d1b), (0x39e11be5ff01d8f8, 0x3d733867c824f37c), (0xb99156aaeb019d3d, 0xbd00a1ec5f4dca90), (0xb98d52e6f6ab31a5, 0xbcf469ac872b68fd), (0xb92873e76419e2d3, 0x3c81c1b6937f11e6), (0x38ccce25f4bbd867, 0x3c70fe687033cfb9), (0x3891a388623b4d18, 0xbbfda774598ea00a), (0xb869e8b9411b1044, 0xbbe6c5c790ba8cb1), (0x38166a66767c0cb3, 0x3b73e54f8ca945a2), (0xb7f10320398ad824, 0x3b5916586436314c), (0x37824e29afdee9e2, 0xbae5eb34af321144), (0x376cca34b6192949, 0xbac71eb7d8b137e6), (0xb6e44bfb5b2e06d0, 0x3a542dd9e755ef71), (0x36d5af611735126d, 0x3a321616f456ec2b), (0xb6303bf3b5725f15, 0xb9bf82bf12709cef), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c116404635b6173, 0x3fb86e51bb2ee24d), (0x3be40f7dbe05e2df, 0xbf465e3bad214eb8), (0xbc3502bddec37518, 0xbf9047d6ed159c31), (0xbbb68a41509d990f, 0x3f1dce4a381ce24e), (0x3be0a2f7a61834bb, 0x3f4a05b93842da9a), (0x3b384a0ade44f859, 0xbed7ce3df60b0ea1), (0x3b8858267c36b09d, 0xbef3cb50138cce4b), (0x3b2cb60fbd510cee, 0x3e8216e84a5dec74), (0x3b2d7337b289cb04, 0x3e918e354c01533b), (0xbac53c3104a34351, 0xbe2005493039e5f0), (0x3ac1ef2cc08d8fcc, 0xbe245ed4a3733e9d), (0xba3577c4c664c7a0, 0x3db28e2ed388f175), (0xba513618783b7d45, 0x3db0a83fb8aae5cc), (0x39d2152affe981ca, 0xbd3e4745b1e410b2), (0xb9cc35474710f93a, 0xbd3439aae872dae3), (0xb90f376af336ee4d, 0x3cc2557a9d9a51a0), (0xb9418e01d92d0d8b, 0x3cb2f313647cb524), (0xb8ee555d5c581be4, 0xbc4120389f39a9c9), (0x38bceac00481a0f5, 0xbc2c39cb315eebe0), (0x38543f94ec753f1e, 0x3bb96c5a77539703), (0xb7f664a9d463aaf9, 0x3ba11bdcff0ddb62), (0xb7909879d65e235f, 0xbb2eb47c0f406536), (0x37b323a3eb4616f4, 0xbb1135192cf31d4c), (0x36df969385034399, 0x3a9ec17139b4fa1e), (0xb712728ddaed35bd, 0x3a7d2d581a06903c), (0xb68322eeb5683b7f, 0xba09f599e9b3fcee), (0xb6584681390e9457, 0xb9e522216f24e570), ], [ (0xbc5aa58d824fcbf0, 0x3fb829356c2fb67c), (0x0000000000000000, 0x0000000000000000), (0x3c4aa58d824fcbf0, 0xbfa829356c2fb67c), (0x3bc03ee1c336b408, 0x3f2cd964e5e4caa0), (0x3c0adae94b604802, 0x3f70190ce66b97c3), (0xbb6093ba87cf3d05, 0xbef70d5fd8bad7b5), (0xbbae25e1759c428e, 0xbf2126a150469b05), (0x3b4f93e54fe01a02, 0x3eaa49ea85815004), (0xbb4a798f784213ff, 0x3ec3910f5c159f54), (0x3ab455b6aeed4cdd, 0xbe4f0f4bdbe20c90), (0xbaf74c179ce6757b, 0xbe5bc3697829b270), (0x3a883549e84165fc, 0x3de67f2959cd47c2), (0x3a6dc709a66c6637, 0x3dead81c085abf1e), (0xb9f0a2a8eed90e0b, 0xbd760a10ab0898ac), (0x3a0d4bed5455a7cd, 0xbd72d07fd9984920), (0x399e8c3991730925, 0x3cff2887ab34ba4b), (0xb99d15049de98d82, 0x3cf3fd2c46f43bfa), (0x3918217b1630091e, 0xbc80a48214b2d81b), (0xb90aebeb32b2ec56, 0xbc70a5cd24e7aff5), (0x387f8e2a60b26930, 0x3bfbd0274fe43cf0), (0xb87decdf6830646f, 0x3be65191993b3def), (0xb8169726f5849485, 0xbb72acc84c6c9c30), (0xb7ecea63d3d7881a, 0xbb5899530e0f85dd), (0x3783523fe1e47394, 0x3ae4974878ee147d), (0xb75b7329483fca7c, 0x3ac6ae722e577e49), (0x36f5f5ad175e3a10, 0xba52f937d6c2c894), (0x36da45ec2b162935, 0xba31c0af96ec39d1), (0xb63b5886d2aae802, 0x39bda7e9893ee0e5), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc4ea89f3a43207f, 0xbfb7e656ed57a0d1), (0x3bed3586339aa922, 0x3f44f0cfc62eb61c), (0x3c1736dd17549bef, 0x3f8fdaba63e9c655), (0x3bb8a2f82c46d7d1, 0xbf1be7bad1c50547), (0x3be9f603d64ca819, 0xbf4975ac0770c98d), (0xbb716dcdea217bd7, 0x3ed64a6af83ba860), (0x3b95937b8720b7f0, 0x3ef35e6b41b6d77b), (0x3b1fd0d91a2328f8, 0xbe80f12d050df219), (0x3b0b801799b9887e, 0xbe912e744222ec5c), (0x3a882bc4f09a4762, 0x3e1e04a8c0a89be6), (0x3ab7f6d6a00158e7, 0x3e23f0ed5e6a0d3b), (0x3a40220f85fad9d6, 0xbdb163fd7157593b), (0x3a410e6d9a99af97, 0xbdb04f8efe519654), (0xb9d5f5b1b377833f, 0x3d3c6417f7a11d41), (0xb9df5b1599ff1601, 0x3d33cfa2affaf9e4), (0xb953811266af2ff0, 0xbcc1334e857adc93), (0xb95d7d93dd11d118, 0xbcb2917ae18b1995), (0x38e71d9f8e4fabac, 0x3c4013b4389ffe8d), (0x38b8b37790d4d1d0, 0x3c2bab4c1141eb75), (0x3858ea4627e8efee, 0xbbb7e1ea8188735c), (0x381cd9d4b13e954d, 0xbba0c761c695703d), (0xb7c2ccb36474c65d, 0x3b2cdd9ab5adf543), (0xb7ad59a9bff1b6e1, 0x3b10e22b0412a059), (0x37298e06ba0a7eff, 0xba9cefb8354e799e), (0x371ce2c8c6a65fa1, 0xba7ca4621c89c3ea), (0x369bfbcde055522b, 0x3a0871d638e71562), (0x36702a74cab2e18d, 0x39e4c1b3f6f3c4fc), ], [ (0xbc52d2ff041ff2f6, 0xbfb7a597eb76a5e3), (0x0000000000000000, 0x0000000000000000), (0x3c42d2ff041ff2f6, 0x3fa7a597eb76a5e3), (0x3bb9dc564feff08d, 0xbf2b0bd9eb615315), (0xbc03cbe9e9bac1ac, 0xbf6f831b9629acd2), (0xbb95cc1ecba38a9d, 0x3ef59d1c40c95ba7), (0x3bad7b9ad1a36974, 0x3f20c9d35d4be191), (0xbb39533f46784cb0, 0xbea8a711bec6920b), (0xbb4180f2a561ac4b, 0xbec327e42f39066e), (0x3adb23dbc633fe86, 0x3e4d225aa8ded6cd), (0xbaea1e7c5d2c24a0, 0x3e5b2f83a946aed5), (0x3a72070bf439257d, 0xbde51bef06eb5d9f), (0xba7f45169aef013e, 0xbdea4ab19859cce7), (0xba0912db1823cb9f, 0x3d74b03ce339d83a), (0x3a007d1a27a09f97, 0x3d726eb2bbaa63c7), (0xb991c095fa32b480, 0xbcfd433d6a1a8fc3), (0x3988ca74e8a71011, 0xbcf396dd9428b7d8), (0xb91f2420c8969cf6, 0x3c7f470853f5d87d), (0x39129d5b5b244d63, 0x3c705215ddbe7188), (0xb89ad8ca1c6e4ad7, 0xbbfa26d052836024), (0xb86057f50da94b85, 0xbbe5e38754f9398d), (0x381cce919f096c57, 0x3b71923ffdac92d4), (0x37f2bbe0806d82ac, 0x3b5822a7b984366d), (0x377a0e974a7e67bc, 0xbae3636b0de0af87), (0x376c2d3712cd37ea, 0xbac6439959854a9a), (0xb6f5653a15338763, 0x3a51e12428cdc675), (0x36bd7966e734f9d4, 0x3a316f2e8a6d63cb), (0xb64936e1f9cb0f09, 0xb9bbf81db6228424), ], ]; pxfm-0.1.23/src/bessel/y0f.rs000064400000000000000000000243571046102023000140040ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j0f::{j0f_asympt_alpha, j0f_asympt_beta, j1f_rsqrt}; use crate::bessel::y0f_coeffs::{Y0_ZEROS, Y0_ZEROS_VALUES, Y0F_COEFFS}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::fast_logf; use crate::polyeval::{f_polyeval10, f_polyeval18}; use crate::sin_helper::sin_small; use crate::sincos_reduce::rem2pif_any; /// Bessel of the second kind of order 0 (Y0) /// /// Max ULP 0.5 pub fn f_y0f(x: f32) -> f32 { if x < 0. { return f32::NAN; } if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return f32::NEG_INFINITY; } if x.is_nan() { return x + x; } if x.is_infinite() { if x.is_sign_negative() { return f32::NAN; } return 0.; } } let xb = x.to_bits(); if xb <= 0x3faccccdu32 { // 1.35 return y0f_near_zero(f32::from_bits(xb)); } // transient zone from 1.35 to 2 have bad behaviour for log poly already, // and not yet good to be easily covered, thus it use its own poly if xb <= 0x40000000u32 { // 2 return y0_transient_area(x); } if xb <= 0x4296999au32 { // 75.3 return y0f_small_argument_path(f32::from_bits(xb)); } // Exceptions: let xb = x.to_bits(); if xb == 0x5023e87f { return f32::from_bits(0x28085b2d); } else if xb == 0x48171521 { return f32::from_bits(0x2bd244ba); } else if xb == 0x4398c299 { return f32::from_bits(0x32c730db); } else if xb == 0x7f0e5a38 { return f32::from_bits(0x131f680b); } else if xb == 0x6ef9be45 { return f32::from_bits(0x987d8a8f); } y0f_asympt(x) } /** Generated by SageMath: Evaluates: Y0(x) = 2/pi*(euler_gamma + log(x/2))*J0(x) - sum((-1)^m*(x/2)^(2*m)/(m!)^2*sum(1+1/2 + ... 1/m)) expressed as: Y0(x)=log(x)*W0(x) - Z0(x) ```python from sage.all import * R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() N = 10 # Number of terms (adjust as needed) gamma = RealField(300)(euler_gamma) d2 = RealField(300)(2) pi = RealField(300).pi() # Define J0(x) Taylor expansion at x = 0 def j_series(n, x): return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)]) J0_series = j_series(0, x) def z_series(x): return sum([(-1)**m * (x/2)**(ZZ(2)*ZZ(m)) / ZZ(m).factorial()**ZZ(2) * sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) for m in range(1, N)]) W0 = (d2/pi) * J0_series Z0 = -gamma * (d2/pi) * J0_series + RealField(300)(2).log() * (d2/pi) * J0_series + (d2/pi) * z_series(x) # see the series print(W0) print(Z0) ``` **/ #[inline] fn y0f_near_zero(x: f32) -> f32 { const W: [u64; 10] = [ 0x3fe45f306dc9c883, 0xbfc45f306dc9c883, 0x3f845f306dc9c883, 0xbf321bb945252402, 0x3ed21bb945252402, 0xbe672db9f21b0f5f, 0x3df49a6c656d62ff, 0xbd7ae90af76a4d0f, 0x3cfae90af76a4d0f, 0xbc754331c053fdad, ]; let dx = x as f64; let x2 = dx * dx; let w0 = f_polyeval10( x2, f64::from_bits(W[0]), f64::from_bits(W[1]), f64::from_bits(W[2]), f64::from_bits(W[3]), f64::from_bits(W[4]), f64::from_bits(W[5]), f64::from_bits(W[6]), f64::from_bits(W[7]), f64::from_bits(W[8]), f64::from_bits(W[9]), ); const Z: [u64; 10] = [ 0x3fb2e4d699cbd01f, 0xbfc6bbcb41034286, 0x3f9075b1bbf41364, 0xbf41a6206b7b973d, 0x3ee3e99794203bbd, 0xbe7bce4a600d3ea4, 0x3e0a6ee796b871b6, 0xbd92393d82c6b2e4, 0x3d131085da82054c, 0xbc8f4ed4b492ebcc, ]; let z0 = f_polyeval10( x2, f64::from_bits(Z[0]), f64::from_bits(Z[1]), f64::from_bits(Z[2]), f64::from_bits(Z[3]), f64::from_bits(Z[4]), f64::from_bits(Z[5]), f64::from_bits(Z[6]), f64::from_bits(Z[7]), f64::from_bits(Z[8]), f64::from_bits(Z[9]), ); let w_log = fast_logf(x); f_fmla(w0, w_log, -z0) as f32 } #[inline] fn y0_transient_area(x: f32) -> f32 { let dx = x as f64; // first Y0 bessel zero const ZERO: DoubleDouble = DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243)); let r = (dx - ZERO.hi) - ZERO.lo; /* Poly generated by Wolfram Matematica: <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] */ let p = f_polyeval18( r, f64::from_bits(0x3fe0aa48442f8375), f64::from_bits(0x3de601d3b959b8d8), f64::from_bits(0xbfd0aa4840bb8529), f64::from_bits(0x3fa439fc16d4835e), f64::from_bits(0x3f80d2dcd97d2b4f), f64::from_bits(0x3f4f833368f9f047), f64::from_bits(0xbf541a702ee92277), f64::from_bits(0x3f3abc113cf0f4da), f64::from_bits(0xbefac1ded6f17ba8), f64::from_bits(0x3f33ef372e24df82), f64::from_bits(0x3f3bf8b42322df40), f64::from_bits(0x3f4582f9daec9ca7), f64::from_bits(0x3f479fc07175494e), f64::from_bits(0x3f4477a5e32b723a), f64::from_bits(0x3f39fbfd6a6d6f0c), f64::from_bits(0x3f2760a66816527b), f64::from_bits(0x3f0a68fdeeba224f), f64::from_bits(0x3edd78c6c87089e1), ); p as f32 } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] fn y0f_small_argument_path(x: f32) -> f32 { let x_abs = x as f64; // let avg_step = 74.607799 / 47.0; // let inv_step = 1.0 / avg_step; const INV_STEP: f64 = 0.6299609508652038; let fx = x_abs * INV_STEP; const Y0_ZEROS_COUNT: f64 = (Y0_ZEROS.len() - 1) as f64; let idx0 = fx.min(Y0_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(Y0_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(Y0_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(Y0_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { // Really should not happen here, but if it is then to log expansion return y0f_near_zero(x); } // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(Y0_ZEROS_VALUES[idx]) as f32; } let c = &Y0F_COEFFS[idx - 1]; let r = (x_abs - found_zero.hi) - found_zero.lo; let p = f_polyeval18( r, f64::from_bits(c[0]), f64::from_bits(c[1]), f64::from_bits(c[2]), f64::from_bits(c[3]), f64::from_bits(c[4]), f64::from_bits(c[5]), f64::from_bits(c[6]), f64::from_bits(c[7]), f64::from_bits(c[8]), f64::from_bits(c[9]), f64::from_bits(c[10]), f64::from_bits(c[11]), f64::from_bits(c[12]), f64::from_bits(c[13]), f64::from_bits(c[14]), f64::from_bits(c[15]), f64::from_bits(c[16]), f64::from_bits(c[17]), ); p as f32 } /* Evaluates: Y0 = sqrt(2/(PI*x)) * beta(x) * sin(x - PI/4 - alpha(x)) */ #[inline] fn y0f_asympt(x: f32) -> f32 { let dx = x as f64; let alpha = j0f_asympt_alpha(dx); let beta = j0f_asympt_beta(dx); let angle = rem2pif_any(x); const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651); const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_cos = sin_small(r0); let z0 = beta * m_cos; let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx); (scale * z0) as f32 } #[cfg(test)] mod tests { use crate::f_y0f; #[test] fn test_y0f() { assert_eq!(f_y0f(90.5), 0.08254846); assert_eq!(f_y0f(77.5), 0.087678276); assert_eq!(f_y0f(1.5), 0.3824489); assert_eq!(f_y0f(0.5), -0.44451874); assert!(f_y0f(-1.).is_nan()); assert_eq!(f_y0f(0.), f32::NEG_INFINITY); assert_eq!(f_y0f(f32::INFINITY), 0.); assert!(f_y0f(f32::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/bessel/y0f_coeffs.rs000064400000000000000000001020541046102023000153200ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Y0 zeros and extremums. Generated by SageMath: ```python R120 = RealField(120) zeros = [] mp.prec = 150 step = mpf("0.1") epsilon = mpf("1e-35") x = mpf("1.25") previous_zero = R120(0) y0_zeros = [] while x < mpf("76.0"): f1 = bessely(0, x) f2 = bessely(0, x + step) if f1 * f2 < 0: zero = findroot(lambda t: bessely(0, t), (x, x + step), solver='secant', tol=mp.mpf("1e-41")) previous_zero = zero y0_zeros.append(zero) if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon: zeros.append(previous_zero) x += step y0_extrema = [] x = mpf("1.25") while x < mpf("76.0"): d1 = mp.diff(lambda t: bessely(0, t), x) d2 = mp.diff(lambda t: bessely(0, t), x + step) if d1 * d2 < 0: extremum = findroot(lambda t: mp.diff(lambda u: bessely(0, u), t), (x, x + step), solver='secant', tol=mp.mpf("1e-41")) y0_extrema.append(extremum) x += step # Print results for i, z in enumerate(j0_zeros): print(f"Zero {i+1}: x ≈ {z}") print("Extrema (peaks/valleys) of Y0(x):") for e in y0_extrema: print(f"nExtrema: {e}") y0_zeros.extend(y0_extrema) y0_zeros = sorted(y0_zeros) # Print results for i, z in enumerate(y0_zeros): print(f"Peak or zero {i+1}: x ≈ {z}") print("") print("pub(crate) static Y0_ZEROS: [(u64, u64); 48] = [") print(f"(0x0, 0x0),") for z in y0_zeros: k = split_double_double(z) hi = double_to_hex(k[1]) lo = double_to_hex(k[0]) print(f"({lo}, {hi}),") print("];") ``` **/ pub(crate) static Y0_ZEROS: [(u64, u64); 48] = [ (0x0, 0x0), // not really used, just a stab to avoid messing with indices (0xbc8bd1e50d219bfd, 0x400193bed4dff243), (0xbc9f06ae7804384e, 0x400fa9534d98569c), (0x3cbdfe7bac228e8c, 0x4015b7fe4e87b02e), (0xbc99774a495f56cf, 0x401c581dc4e72103), (0x3cb479cc068d9046, 0x40213127ae6169b4), (0xbcccb49ff791c495, 0x402471d735a47d58), (0x3c80fc786ce06080, 0x40277f9138d43206), (0xbcc7df81de86f24d, 0x402ab8e1c4a1e74a), (0xbcc5e091a50f8e05, 0x402dcb7d88de848b), (0x3cd25a237d12159b, 0x4030803c74003214), (0xbcda1ee4c5487ede, 0x40320b1c695f1e3b), (0xbcd8bf92d51fbaeb, 0x4033a42cdf5febd7), (0x3cd391b14410528f, 0x40353025492188cd), (0x3cdca75080cf53a8, 0x4036c832fd77ac07), (0x3cb52f75f025b205, 0x403854fa303820ca), (0xbcb03e052bd9c0af, 0x4039ec46f3e80146), (0xbcbcf130fbea3b24, 0x403b79acee8cfb7d), (0x3cd0aab17eca74b9, 0x403d106449616c4f), (0xbc9e7a77047d6166, 0x403e9e480605283c), (0x3ced2f18aa8a8f2f, 0x40401a4420e4abee), (0xbce96beabef7ecf4, 0x4040e16907f8fb56), (0xbca9dd1578036d11, 0x4041ac588c944279), (0x3cd2481e87adfe57, 0x404273a7b35a7aff), (0xbce9c3dd43e59158, 0x40433e6ecf5cb221), (0x3cda8ffacaac8461, 0x404405e18393afb5), (0xbce753b7fcd5250c, 0x4044d0867ec213f3), (0x3cbfe463face2c1c, 0x4045981787d668db), (0x3cec2eb6ee3e4c70, 0x4046629f4e1e0321), (0xbce26390f25f01cb, 0x40472a4a85cc317e), (0xbcaafdee84ced526, 0x4047f4b904dc9a53), (0xbcdcc667e557a177, 0x4048bc7b10ed3960), (0x3cebbca9a96dc1aa, 0x404986d378522b70), (0x3cb377717d2f36f7, 0x404a4ea9997b5eaa), (0xbcedf185c89a4066, 0x404b18ee87b4e700), (0xbcc68a841a2af000, 0x404be0d6766d13de), (0x3ced8a878e90eda4, 0x404cab0a1968b221), (0x3cddcc8dd083c434, 0x404d7301ec2bf16e), (0xbceb5c58b22794af, 0x404e3d2619226875), (0xbce5919b54336657, 0x404f052c3146d1da), (0xbc87b54cc765fd11, 0x404fcf4276983013), (0xbcf389f975d9dfa2, 0x40504baab8e42f8f), (0xbce195534d06b08a, 0x4050b0af92483bf5), (0xbcd4e0ffa0b9d2e9, 0x405114bee8d0f4bd), (0xbcf1c076cb371565, 0x405179be0c18f0e1), (0x3cf5d0de43102daa, 0x4051ddd2b7398636), (0xbce8a4f19e47d0be, 0x405242cca44048f8), (0x3ceb379dbe48b8f5, 0x4052a6e6306f1d08), ]; /** Zeros and extremums solved values for Y0 Generated by MPFR: ```text let mut arr = vec![]; for zeros in Y0_ZEROS.iter() { if zeros.1 == 0 { arr.push(0); } else { let mpfr = Float::with_val(107, f64::from_bits(zeros.1)).y0(); arr.push(mpfr.to_f64().to_bits()); } } println!( "arr: [{}]", arr.iter() .map(|x| format!("0x{:016x}", x)) .collect::>() .join(", ") ); ``` **/ pub(crate) static Y0_ZEROS_VALUES: [u64; 48] = [ 0x0000000000000000, 0x3fe0aa48442f014b, 0xbc88fa8956b4b481, 0xbfd5c7c556f0c19a, 0x3c7e91b198d39ce2, 0x3fd15f993fceab5c, 0xbcacabd7c823bf21, 0xbfcdc14ea14e89f9, 0x3ca4d9fe48a91cef, 0x3fca7022be084d99, 0x3cacd827f6c074a2, 0xbfc80781c32422e7, 0x3cb1d336c8b0a153, 0x3fc62d94d97e859c, 0x3cb3296749aaf800, 0xbfc4b2a38f1ab9b4, 0x3c845d52c7c075b2, 0x3fc37aaceac987b9, 0x3ca3bc249963d4c1, 0xbfc2740819f1caaa, 0xbcc069eacea8ff0b, 0x3fc192f2627a74e3, 0xbc7bc4fd81e2b2c5, 0xbfc0cf3ee98f769b, 0x3cba82b3a8997d82, 0x3fc0230ba90f2871, 0xbcb71414f52d813b, 0xbfbf13fb0c0e6fcd, 0xbcbae2d399eafcc6, 0x3fbe018dac1c17e3, 0xbc78e44442565953, 0xbfbd09b21e36c0bd, 0xbcb8c779e4075b10, 0x3fbc2861347b1b39, 0xbcb9f6a4816aab2e, 0xbfbb5a622198a72c, 0xbcb8e727b71a083d, 0x3fba9d183bc04545, 0xbcb67533047d83fb, 0xbfb9ee5eee1a97c6, 0x3c52f9257b962770, 0x3fb94c6f5898708b, 0xbcab7916830bd3b8, 0xbfb8b5ccb03d459b, 0x3cbb1b180f8e9062, 0x3fb829356c2fb67c, 0xbcb267f22477b55d, 0xbfb7a597eb76a5e3, ]; /** Taylor series at different zeros and extremums for Y0 Generated by SageMath: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = 2 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i]) + 0.83 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05 b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(y0_zeros) print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 500; bessel_y0 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_y0(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RR(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return degree = 17 print(f"pub(crate) static Y0F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print("[") for c in coeffs: print(double_to_hex(c) + ",") print("],") print("];") ``` **/ pub(crate) static Y0F_COEFFS: [[u64; 18]; 47] = [ [ 0x3fe0aa48442f014b, 0xbc009e915c2e5f95, 0xbfd0aa48442f0143, 0x3fa439fac165257c, 0x3f80d2af4e929791, 0x3f4f71646c0dc646, 0xbf5444bda7f2ee4c, 0x3f384c21f1d0de42, 0xbf217ab4d69ab0db, 0x3f0dafc989c8ea40, 0xbef8bbefbac0d893, 0x3ee48ac7a622784f, 0xbed1245593770ad0, 0x3ebc28878607b687, 0xbea585c089718cc9, 0x3e8b7ad75bd333d8, 0xbe68a20d8d3d57a5, 0x3e362c70b36d12a4, ], [ 0x3bf75cf88f1b7237, 0xbfd9c34256a12a0c, 0x3faa09c9290367ec, 0x3fadf6d59bf50e4b, 0xbf7c116fdc597e2f, 0xbf61e32bc4eef0b0, 0x3f29982765136b27, 0x3f0ab2c1fd5871c0, 0xbed486371d6e71eb, 0xbe93b212b9208b3e, 0xbe577700c20e01fd, 0x3e545234fb052f6a, 0xbe2f6a5f736d8c82, 0x3e0a8134a3ddd47f, 0xbde9666a74f1504a, 0x3dc63b75b90c0da3, 0xbdaa991122c61028, 0x3d930f1a31e30006, ], [ 0xbfd5c7c556f0c19a, 0xbbc44b457ab6a440, 0x3fc5c7c556f0c19a, 0xbf8564d4b1ed0d7e, 0xbf8a15d92dfe3e28, 0x3f4b438430469f6e, 0x3f37a8924cc2fcab, 0xbef5f69b4a89930d, 0xbed85b940ebd0c07, 0x3e955ac0f4e7f8ab, 0x3e6d563e284b0072, 0xbe23eac267e6cf3c, 0xbe00077161c32b55, 0x3dc04d965b688847, 0xbd45e4f4886f7d51, 0x3d5501605dba787a, 0xbd363e6119f047ec, 0x3d096861e7e8004b, ], [ 0xbb236a0ad5bec7c3, 0x3fd334cca0697a5b, 0xbf95aef611fc4d57, 0xbfa8969c64cbf452, 0x3f6b2f14a95527cb, 0x3f61d35e85fde2a4, 0xbf226dd71e391c65, 0xbf08177e4fe524db, 0x3ec6a9227352b13b, 0x3ea34aa757412911, 0xbe60a2814d2e238a, 0xbe3442a3d67717ae, 0x3defa6c448c9759c, 0x3dbf14eacd6e3a21, 0xbd771434b676ae83, 0xbd406a106470261f, 0x3cf2c5324aed291b, 0x3cc47f208256e17f, ], [ 0x3fd15f993fceab5c, 0xbb597aaa5d4472ea, 0xbfc15f993fceab5c, 0x3f758ef6efbed797, 0x3f86395dfe49fcd4, 0xbf3fb15104a41c03, 0xbf35f88a11d55641, 0x3eef37d226a827fd, 0x3ed6f7bab104d878, 0xbe8f0c45a3868f32, 0xbe6dfe11ded99f62, 0x3e2311adc6046d1a, 0x3dfad34dd085ee0f, 0xbdafdc85833041dc, 0xbd819463fb6a5c22, 0x3d33a4c369438250, 0x3d014560b8776112, 0xbcb2ae15d3a41e47, ], [ 0x3b12ba7db6ce5807, 0xbfcff635cc72b9f1, 0x3f89036451ff57c5, 0x3fa4e667a71556af, 0xbf60325ee41e910c, 0xbf5fe23914fb9128, 0x3f17f84d7c50e49e, 0x3f06afdd57be1e75, 0xbec04053abf415e2, 0xbea2aea9ec4954d7, 0x3e593eb9f19579b5, 0x3e3428a3a4917f21, 0xbde99d8be9e4cd5a, 0xbdbec9815ee61f19, 0x3d7260f619cb637c, 0x3d418f963ce687db, 0xbcf38a6e7195daa0, 0xbcbf332d386dfb1b, ], [ 0xbfcdc14ea14e89f9, 0x3b52ef4e10970973, 0x3fbdc14ea14e89f9, 0xbf6b037fe9cf2a52, 0xbf8367d7d608e4ba, 0x3f34abef5636e4f9, 0x3f33d8a66122924a, 0xbee5cfe92a1a2ead, 0xbed571814a1a8669, 0x3e87414e33ccd6d7, 0x3e6ca7069e37c5b4, 0xbe1e0b3a74e3f35e, 0xbdfa15dd188a976e, 0x3daa33983e3b34b5, 0x3d8141656fbf9e02, 0xbd3089bd5153b08a, 0xbd01345e91fc8d5c, 0x3cb05566655c2807, ], [ 0xbb10bed1f7905ee9, 0x3fcbf32a27594007, 0xbf80bc2d84e65214, 0xbfa26cab38a8b368, 0x3f55f03e47165d72, 0x3f5caaa76e34992d, 0xbf10c5f18c46d00f, 0xbf04f0af7d46cd82, 0x3eb7d1e28094a46b, 0x3ea1ad073122cd33, 0xbe536021c88affe4, 0xbe3371ae6cd96849, 0x3de46ce028e7c109, 0x3dbe235dc856ef66, 0xbd6e401d592ca47a, 0xbd415f37788a98a4, 0x3cf078a1b34fa822, 0x3cbefbc3ca8cda9f, ], [ 0x3fca7022be084d99, 0xbb4ddca3665cb95a, 0xbfba7022be084d99, 0x3f62ee079d020b12, 0x3f8163191c30aa62, 0xbf2d7806ea72fc7a, 0xbf320f95702b1d3e, 0x3ee006108822968d, 0x3ed3e398cbc455aa, 0xbe81bbe181c8bfbe, 0xbe6b0f89b78908bf, 0x3e17c3f85c062f0a, 0x3df902361639d835, 0xbda56494e7b59641, 0xbd80bde23236fbba, 0x3d2bbbd3bb25cf30, 0x3d00d7f96ac5af92, 0xbcabe3861f527a48, ], [ 0x3b0d39acdbc38af2, 0xbfc925c35988ee29, 0x3f7862549367591e, 0x3fa0a4512039d6a2, 0xbf5013b38cfb9292, 0xbf5a24a1215f6684, 0x3f08f91421377f72, 0x3f035d17cec01753, 0xbeb2283a93110ac0, 0xbea099e713932038, 0x3e4e5de01dbe7d10, 0x3e3288585522eec4, 0xbde0730be51a22c7, 0xbdbd174416e1daeb, 0x3d68f810d9b70d7c, 0x3d40f177553ea68b, 0xbcebc58c79d9f1a6, 0xbcbe6305e9d630f0, ], [ 0xbfc80781c32422e7, 0x3b483f69e003254a, 0x3fb80781c32422e7, 0xbf5c6923374d561f, 0xbf7fbe6df840847f, 0x3f264f4711a85f1d, 0x3f309ff42b0d7a58, 0xbed8a60685a59ae7, 0xbed282d26a74a669, 0x3e7bdb57a88d9298, 0x3e697d9c12695952, 0xbe131aa86bece7b9, 0xbdf7d486a4891297, 0x3da197f4a31bb9d7, 0x3d801da2d1e74508, 0xbd2749f32e6b29e4, 0xbd005a3044bf379a, 0x3ca7cdb1346a2761, ], [ 0xbb095b0f9cce8be6, 0x3fc70c4f66cab47f, 0xbf72c6731071e936, 0xbf9e924b85a17361, 0x3f48d6c364d92082, 0x3f58247b02d6b0f6, 0xbf037612593855eb, 0xbf0206da232a2b7e, 0x3eacaf84db86b79e, 0x3e9f367117733794, 0xbe48654affaeff8a, 0xbe3199ec88cf0125, 0x3ddaeb1a0e170f3e, 0x3dbbe67c38767c0a, 0xbd64cda59f058a2d, 0xbd406490f1401c35, 0x3ce7873ddbd2ecb8, 0x3cbd9254c745332c, ], [ 0x3fc62d94d97e859c, 0xbb4423d84fd9daf1, 0xbfb62d94d97e859c, 0x3f565481b55eaefb, 0x3f7d5f857a2a6107, 0xbf21a015a2ccb791, 0xbf2eeb4eafd8612c, 0x3ed3a7b79e4d8384, 0x3ed154ed4598b648, 0xbe767f762ea5d48d, 0xbe680ec1e0075865, 0x3e0f52965769de53, 0x3df6ad7b894b88a3, 0xbd9d4e5bf81e66fd, 0xbd7eeb07104d446e, 0x3d23b37b411dc13d, 0x3cff991c92fdc4d8, 0xbca4681dcbe602f7, ], [ 0x3b0608e1eb7299ca, 0xbfc5664d37c37d7b, 0x3f6e0ee8ec84659a, 0x3f9c6c415c971b4b, 0xbf43ec49cb941f55, 0xbf56853b2d047885, 0x3eff632a9396fcf6, 0x3f00e6afa01af56c, 0xbea7541247ac8e20, 0xbe9d735e8beba89d, 0x3e440e6a7c5b76f7, 0x3e30b9cfae36d52a, 0xbdd66808178f0472, 0xbdbab498e9ad024c, 0x3d618b0d40031fb2, 0x3d3f99bd1527877f, 0xbce4186fe1076e16, 0xbcbca6e4a9f85609, ], [ 0xbfc4b2a38f1ab9b4, 0x3b4106370f2ef866, 0x3fb4b2a38f1ab9b4, 0xbf5225a5c73f2233, 0xbf7b750d89a9b35f, 0x3f1cbdb4f1d5dbc0, 0x3f2cfe933fc6d09a, 0xbed01ef10d839ddf, 0xbed05375a5888b31, 0x3e729afe7eaa78e7, 0x3e66c8fe01244a3c, 0xbe0a2a01eba23e6a, 0xbdf59b32be188f85, 0x3d98c0a83d3ee202, 0x3d7da2dd5a1ff0d5, 0xbd20d5047e87a8a0, 0xbcfe76ab94a96cf5, 0x3ca19e4f3f768bb8, ], [ 0xbb033ddc20ef994b, 0x3fc40f8ffdf09a5f, 0xbf68c37a29c4586f, 0xbf9aab099314b209, 0x3f406f735cc0f6a6, 0x3f552d29a06802e0, 0xbef9fc04c675c0a0, 0xbeffe48825ed3c99, 0x3ea36bd2d58fad6c, 0x3e9be87e2cad35c1, 0xbe40d1fded7d33ea, 0xbe2fdbeb107f2787, 0x3dd2f44ca7722117, 0x3db992136419242c, 0xbd5df6388aabd242, 0xbd3e6bd4176ef817, 0x3ce15380b88a0004, 0x3cbbb4210e2ade39, ], [ 0x3fc37aaceac987b9, 0xbb3d355a175fbb67, 0xbfb37aaceac987b9, 0x3f4e3fdbfd65014a, 0x3f79de7a33bc3a97, 0xbf1801d911fbd06f, 0xbf2b605a5ade3a62, 0x3ecb0a2608144de7, 0x3eceeceb341aa1c8, 0xbe6f623fc7c35376, 0xbe65a9ca94685dee, 0x3e0638ba32c100f7, 0x3df4a1b3dc97031d, 0xbd9530c9cb91ec68, 0xbd7c6deff6c29a1e, 0x3d1d10f27ed0d91c, 0x3cfd5b5110a971f2, 0xbc9eac069b193638, ], [ 0x3b00e83df01ac491, 0xbfc2f206e49909c7, 0x3f64dbf6a9fb80d7, 0x3f99336443318ed1, 0xbf3bb6aa3d4e9e78, 0xbf540aaa5d94bd8d, 0x3ef5f61b66612962, 0x3efe4158391f2c2d, 0xbea07a7a0745b8f1, 0xbe9a8ea97b66fe4d, 0x3e3cb10b3a7e93b8, 0x3e2e6d788791546c, 0xbdd044442a2af39d, 0xbdb8850c7d8525ad, 0x3d59e48a6e2fcf83, 0x3d3d4af5e70dabe3, 0xbcde2a65241d7e39, 0xbcbac578a90cdb0d, ], [ 0xbfc2740819f1caaa, 0x3b395de3b03fa760, 0x3fb2740819f1caaa, 0xbf49b6f37d0a00f9, 0xbf78868d7401bf2e, 0x3f1470a7cbcb436d, 0x3f29fe94ce3d3e66, 0xbec71660e61f123b, 0xbecd6dfcdb022b53, 0x3e6ae79c35d4303c, 0x3e64ac50be35d108, 0xbe0325840c0fab26, 0xbdf3c09642eaf47d, 0x3d925d87f4bac822, 0x3d7b50337a12ad98, 0xbd195a5cf071931d, 0xbcfc4e3bdd8deb9e, 0x3c9aec36c7cd8057, ], [ 0xbafde3378387cd4f, 0x3fc1ff5ebddd3c3a, 0xbf61e2035324643c, 0xbf97f3506d4a1231, 0x3f37c65c9302c53a, 0x3f53117816335151, 0xbef2df9afa521258, 0xbefcd5d4a9d78a10, 0x3e9c672d4d6f090d, 0x3e995e4b10218b56, 0xbe38d22635a19a7c, 0xbe2d24fc943fc6e5, 0x3dcc462d12216cc2, 0x3db78eaf8cc86453, 0xbd569efa1b265a8d, 0xbd3c3c11b66258b3, 0x3cda808e4f387067, 0x3cb9e0f8deb75911, ], [ 0x3fc192f2627a74e3, 0xbb3645a3987074b0, 0xbfb192f2627a74e3, 0x3f4635b38affe698, 0x3f775eceaabf7f86, 0xbf11ac9e0164f7c3, 0xbf28cc464a35b093, 0x3ec4014d9bf38c8d, 0x3ecc1f05a2d81e1e, 0xbe6761d18ebe9900, 0xbe63cb9af0ceb4cf, 0x3e00b3cb584e2702, 0x3df2f5c722e3bf8d, 0xbd9017792eaec1aa, 0xbd7a4a02574df6fb, 0x3d1652dad940d7a4, 0x3cfb525fce2f20bd, 0xbc97d2bda2bb98bd, ], [ 0x3afa988afe4c49f9, 0xbfc12dd55d4be2b3, 0x3f5f1aee31818d19, 0x3f96de64242a8310, 0xbf34afdf89fca61a, 0xbf5238cfc13ac771, 0x3ef0719d13e00e1d, 0x3efb974781a526ac, 0xbe98cc82a70d12de, 0xbe9850ae878c16d4, 0x3e35bba73dc2363a, 0x3e2bfe1396c7d24f, 0xbdc8d7db68570364, 0xbdb6adfbad375234, 0x3d53f4c573239e3d, 0x3d3b40924b9cec60, 0xbcd77b88ddf3cd06, 0xbcb909671eb81963, ], [ 0xbfc0cf3ee98f769b, 0x3b33bcff5c943527, 0x3fb0cf3ee98f769b, 0xbf436f451f6e14fb, 0xbf765d05948a946a, 0x3f0ef55c5a0d16d1, 0x3f27bfec9d15d01e, 0xbec18c549f28e7a1, 0xbecaf7544eea95a1, 0x3e648e81edf6b6c0, 0x3e630341e759775f, 0xbdfd73d2cdd0aab5, 0xbdf23ec233be72a4, 0x3d8c78e7f536eeff, 0x3d795a1608a24a32, 0xbd13d34748616c7a, 0xbcfa685ede39fb91, 0x3c953d75ba0ff04b, ], [ 0xbaf7d336e374344e, 0x3fc0768257dad56a, 0xbf5b602a7beaaa48, 0xbf95ebc22efd092c, 0x3f3236a604142e61, 0x3f517a482faa8d85, 0xbeecfc008907874e, 0xbefa7d7b128ac52d, 0x3e95e419f1b51819, 0x3e97603cea233f99, 0xbe333a0b43111627, 0xbe2af464175ecac5, 0x3dc609ac1d6253eb, 0x3db5e11b59984046, 0xbd51c2262e85ed55, 0xbd3a58213539aed8, 0x3cd4f80a679b93ee, 0x3cb83fa375444bd0, ], [ 0x3fc0230ba90f2871, 0xbb31a4207958473d, 0xbfb0230ba90f2871, 0x3f413164a0864cde, 0x3f7579c1bdbcfc99, 0xbf0b67e1913c668f, 0xbf26d26de4fd8c43, 0x3ebf1b520b063cbf, 0x3ec9f01e7c18d94a, 0xbe624071b17c353c, 0xbe624f8e936aca3d, 0x3dfa356639a676b4, 0x3df19911d0412ad5, 0xbd89677525aa079f, 0xbd787e875d392b57, 0x3d11be245f9c21d5, 0x3cf98faabb17d8d4, 0xbc93119ed524d1f5, ], [ 0x3af57b2a92bacca4, 0xbfbfa8b3f9ae4375, 0x3f5856073b7fa2cd, 0x3f9514e652eb2e96, 0xbf3032298718ea1a, 0xbf50d1153fde431b, 0x3ee9cb455c29d651, 0x3ef982167b1c52b5, 0xbe938191ef689b27, 0xbe968865345b1bd6, 0x3e31296000bb210d, 0x3e2a0403677632fc, 0xbdc3b67c5c27ec16, 0xbdb526035aeb726c, 0x3d4fd977f75a677c, 0x3d398199969ac0ac, 0xbcd2db2724a8c540, 0xbcb7838b8a136198, ], [ 0xbfbf13fb0c0e6fcd, 0x3b2fb8a657120d32, 0x3faf13fb0c0e6fcd, 0xbf3eb3e6fcc47c00, 0xbf74af74cbd77bef, 0x3f087bb1ebeaec78, 0x3f25fe62920314f5, 0xbebbd0f2a6556264, 0xbec9040de83035a2, 0x3e6057f7a76c1f7c, 0x3e61ad6dd4dfaab9, 0xbdf782a6f91b13a7, 0xbdf1027d851ec0eb, 0x3d86d65e028f8e8e, 0x3d77b54a61df8d64, 0xbd0ffa6793d8746b, 0xbcf8c72862ef4d7d, 0x3c913a3849824cc1, ], [ 0xbaf37825e4b1711a, 0x3fbe8727c572a2c2, 0xbf55d1ef092ab395, 0xbf9454e7a7395636, 0x3f2d0cc3a7fa6d3d, 0x3f50398d2cbd02df, 0xbee725b0909f9c17, 0xbef8a022f5fee439, 0x3e9185b1ea975d21, 0x3e95c5711673ea6a, 0xbe2edff650b86504, 0xbe29298da3993db9, 0x3dc1c346aaab062e, 0x3db47ab8b9f6e94a, 0xbd4cc1c87cd4af9d, 0xbd38bb86b43ec34d, 0x3cd1104df3fa9e99, 0x3cb6d47888429c17, ], [ 0x3fbe018dac1c17e3, 0xbb2cbf68b5ed7271, 0xbfae018dac1c17e3, 0x3f3ba21bd15d02a4, 0x3f73f9e0db07e7ef, 0xbf060b77c5e27625, 0xbf253f9b1a5d2273, 0x3eb910b38812c5ec, 0x3ec82ee6dfdfc034, 0xbe5d7cc2a9aa9fae, 0xbe611a57d834f490, 0x3df53d401868b2b6, 0x3df07915b5d7b1b9, 0xbd84aabf5e11aa97, 0xbd76fc66f73ce419, 0x3d0cff2a096a9861, 0x3cf80d87c580ea09, 0xbc8f4ef03ad4ec66, ], [ 0x3af1bbdf10c72747, 0xbfbd82939ab62339, 0x3f53b5a54845670f, 0x3f93a7ff1622def8, 0xbf2a3ebc476a606d, 0xbf4f61adde3a8c61, 0x3ee4ec45da047869, 0x3ef7d3b28159f22c, 0xbe8fb3f21bccfc28, 0xbe95145a876d09d8, 0x3e2bf64cdef37a7c, 0x3e2862204a96b8ac, 0xbdc01c0cf54f6b8d, 0xbdb3dd6c7e6818d8, 0x3d4a1faa7e189d99, 0x3d3804640c4d999d, 0xbccf0f5eda690a07, 0xbcb63189b3dc27d0, ], [ 0xbfbd09b21e36c0bd, 0x3b2a335791a61ca6, 0x3fad09b21e36c0bd, 0xbf390b0e6a475e45, 0xbf7355b904fbf7ee, 0x3f03fc459d1e25a7, 0x3f2492cc61d19de6, 0xbeb6bcf110a02e19, 0xbec76d44f6a8089e, 0x3e5ac61efcb7f75f, 0x3e609436fc7c1966, 0xbdf34eb60c63b887, 0xbdeff662240b32ed, 0x3d82d05e647447d5, 0x3d76520ffbea05d6, 0xbd0a70b3d6b77e3f, 0xbcf7617161d2567e, 0x3c8c991bfcf38c32, ], [ 0xbaf03b145709e9fb, 0x3fbc96700031f601, 0xbf51eb2a07d0f09e, 0xbf930b36eddaa234, 0x3f27dd2dde84b73c, 0x3f4e696553e0b8a5, 0xbee3085aa35a1606, 0xbef7199f24bccad0, 0x3e8cdbab6a75e8e1, 0x3e9472a7cffbdf8d, 0xbe2979f5209f2f88, 0xbe27ab4b017a68c3, 0x3dbd638fb5c45254, 0x3db34c83c71aa648, 0xbd47dc91892a3240, 0xbd375abc2b119f77, 0x3ccc6a16f48d942f, 0x3cb599c2db65d50c, ], [ 0x3fbc2861347b1b39, 0xbb27f93aa95d7811, 0xbfac2861347b1b39, 0x3f36d57bffb37fd5, 0x3f72c060ef553f18, 0xbf023a407b722d31, 0xbf23f55581ec6826, 0x3eb4bfb4daa30262, 0x3ec6bc69099ac792, 0xbe587334098baabf, 0xbe601951f000356a, 0x3df1a61752a7a337, 0x3def0ec9ee45cf6f, 0xbd8137cd564b9118, 0xbd75b4aa3b6c601b, 0x3d083b040a6d9f05, 0x3cf6c19bd64bc967, 0xbc8a3eded96f75bf, ], [ 0x3aedd70a3afed493, 0xbfbbbf246019c0d4, 0x3f506224199140d8, 0x3f927c3416c09898, 0xbf25d279dc87cf68, 0xbf4d86a5f5adbdac, 0x3ee169041634c20c, 0x3ef66f5bd1bedad0, 0xbe8a69b2c7176656, 0xbe93de4eab455284, 0x3e2755eabb6b4563, 0x3e2702fe7b7aa32d, 0xbdbaf1fff2894365, 0xbdb2c697124bdb4b, 0x3d45e717125b6112, 0x3d36bd366d374341, 0xbcca1d9ce8759323, 0xbcb50c32fba6f689, ], [ 0xbfbb5a622198a72c, 0x3b261140492792be, 0x3fab5a622198a72c, 0xbf34ee71cf67c243, 0xbf7237c02b462f6f, 0x3f00b67b6fdfec64, 0x3f2365167d8bc319, 0xbeb3086b7a29712d, 0xbec61a141425984e, 0x3e56712b239ca861, 0x3e5f507367e2287b, 0xbdf0366d05430f3b, 0xbdee38f952d755dd, 0x3d7faa412f355ab7, 0x3d7522cbd2af359c, 0xbd064e7a6cf56505, 0xbcf62cd7c73270a1, 0x3c883112ff8933cd, ], [ 0xbaeb8a30d224cee7, 0x3fbaf9cb42cd08a7, 0xbf4e1c66d7616e37, 0xbf91f90fd1013589, 0x3f240e3eb09b7d6d, 0x3f4cb682ff471274, 0xbee0016819a61da0, 0xbef5d2d1c420645b, 0x3e884b0fe8a7ecd7, 0x3e93559d96bedaf4, 0xbe257a0be6df375d, 0xbe26677c8f23f9e7, 0x3db8d1ada000f3d8, 0x3db24a6de676e9f8, 0xbd4431a53c25281e, 0xbd362a9b74747797, 0x3cc81ad277664852, 0x3cb487f213f494c1, ], [ 0x3fba9d183bc04545, 0xbb24612b590e8e50, 0xbfaa9d183bc04545, 0x3f334779874010dc, 0x3f71ba2299ab88a8, 0xbefecb19f5bdc64d, 0xbf22e052707cc843, 0x3eb18a5da77ee010, 0x3ec5846b622f2fd0, 0xbe54b17e97b8ccc9, 0xbe5e7f7666f84ced, 0x3dedeb50538393d5, 0x3ded72e1f6ccd5a2, 0xbd7d3e0b2d7b598f, 0xbd749b384c86d390, 0x3d049ebe7a682354, 0x3cf5a2123b57dec6, 0xbc8662ce26072b62, ], [ 0x3ae97c92b0497970, 0xbfba4407dac72297, 0x3f4bcba4dec1da44, 0x3f91803c65cafdfb, 0xbf2283df2b3e4a6d, 0xbf4bf695e89259cd, 0x3edd8f3759122cea, 0x3ef54246c8e04206, 0xbe867111bc8e08a2, 0xbe92d72a1f62d131, 0x3e23d9ca3e4f40f9, 0x3e25d74a6df26826, 0xbdb6f4b3a86a00b8, 0xbdb1d6f951aed310, 0x3d42b1828de6ffa0, 0x3d35a1d54468858d, 0xbcc655ad620318bd, 0xbcb40c27591e7a1a, ], [ 0xbfb9ee5eee1a97c6, 0x3b22e5c966133b1c, 0x3fa9ee5eee1a97c6, 0xbf31d55d93e59bd7, 0xbf7146219394a99c, 0x3efc7d32bb646e2e, 0x3f226599aed4f1b4, 0xbeb03ba58ec85e6f, 0xbec4f9e3961b9170, 0x3e5328d4dc364807, 0x3e5dbda7ac1d3f8b, 0xbdebb7c2f5dfce50, 0xbdecbac1e6849bc9, 0x3d7b1c39328db702, 0x3d741cdba002ff38, 0xbd0321f9e5a1aec7, 0xbcf520545c68186a, 0x3c84ca30f2d8fe34, ], [ 0xbae7aaec85700fa6, 0x3fb99be73fa3efcc, 0xbf49c3248da75775, 0xbf91107147eda800, 0x3f212980be9d8520, 0x3f4b44e1221e6051, 0xbedb67b78c1dd966, 0xbef4bc49e9b5bceb, 0x3e84d02ffb8b7772, 0x3e9261c31456c932, 0xbe226b4006e91d9d, 0xbe25512519fb5144, 0x3db5500f2545f2d3, 0x3db16b4e5f84ad48, 0xbd415e211f9e7a0f, 0xbd3521ed4cbd2b27, 0x3cc4c4800c50a30c, 0x3cb39810921b4be9, ], [ 0x3fb94c6f5898708b, 0xbb219499b2c197ca, 0xbfa94c6f5898708b, 0x3f308f4f1b8fb0dc, 0x3f70da931c776c71, 0xbefa7550d2940f2e, 0xbf21f3b978a47cde, 0x3eae28ea0247325a, 0x3ec47930aec7652a, 0xbe51ce32c4f61fb7, 0xbe5d0950e94a9be9, 0x3de9c5a164496f38, 0x3dec0f17151563cb, 0xbd79390150c5d3eb, 0xbd73a6c5157c0de8, 0x3d01d041a270134c, 0x3cf4a6c2b9e9b4e9, 0xbc835f05ebdf3e12, ], [ 0x3ae60bdc6a36e0e5, 0xbfb8ffc9b9a131f6, 0x3f47f724314bb99d, 0x3f90a89c5d1074ba, 0xbf1feeaeb33465e7, 0xbf4a9fba36a7a08e, 0x3ed980034770f358, 0x3ef43fa4bb8cba45, 0xbe835f40f3a33db9, 0xbe91f465ba2910f8, 0x3e212688f6f9e1b4, 0x3e24d3f7e3ce0c1a, 0xbdb3daee33c4651d, 0xbdb106a0ff5e7529, 0x3d40309d2f92ac42, 0x3d34aa09772c258a, 0xbcc35f72aaef208c, 0xbcb32afd4e360d62, ], [ 0xbfb8b5ccb03d459b, 0x3b206ac337f71f68, 0x3fa8b5ccb03d459b, 0xbf2edc98b92fedf3, 0xbf70767d524cea88, 0x3ef8a85a847c89c6, 0x3f2189afaa2bffb7, 0xbeac1d231a69bf1e, 0xbec40139bdbc767b, 0x3e509a6859cb8509, 0x3e5c60fc5f4b173c, 0xbde80ad395bd719c, 0xbdeb6e94ec333a76, 0x3d778adf7d6d4ffb, 0x3d7338227f2ea5d9, 0xbd00a328a2899a4a, 0xbcf4349a4535eb0d, 0x3c821ac1fe027675, ], [ 0xbae4990a795d52df, 0x3fb86e51bb2ee24d, 0xbf465e3bad214eb8, 0xbf9047d6ed159c31, 0x3f1dce4a381ce24d, 0x3f4a05b93842da9a, 0xbed7ce3df60b0e4e, 0xbef3cb50138cce39, 0x3e8216e84a5d9f52, 0x3e918e354c013832, 0xbe2005492fe9c63e, 0xbe245ed4a343a749, 0x3db28e2e71c56d3c, 0x3db0a83f8589bb9d, 0xbd3e46baa33f452c, 0xbd3439690ccae646, 0x3cc2201c8a30e9e6, 0x3cb2c44f88828341, ], [ 0x3fb829356c2fb67c, 0xbb1ebe6fec859455, 0xbfa829356c2fb67c, 0x3f2cd964e5e4caa0, 0x3f70190ce66b97c3, 0xbef70d5fd8bad7b8, 0xbf2126a150469af1, 0x3eaa49ea858153dd, 0x3ec3910f5c157962, 0xbe4f0f4bdbe6f9e5, 0xbe5bc36977db17fb, 0x3de67f295d55fdea, 0x3dead81ba8b0c52f, 0xbd760a13803ef42a, 0xbd72d03bf820c54e, 0x3cff2ad7c1434050, 0x3cf3c92e07a03306, 0xbc80f7d055471199, ], [ 0x3ae34bfa6ed120b4, 0xbfb7e656ed57a0d1, 0x3f44f0cfc62eb61c, 0x3f8fdaba63e9c655, 0xbf1be7bad1c50546, 0xbf4975ac0770c98d, 0x3ed64a6af83ba812, 0x3ef35e6b41b6d769, 0xbe80f12d050da9bf, 0xbe912e744222d16c, 0x3e1e04a8c0124324, 0x3e23f0ed5e3ac1ab, 0xbdb163fd1599c398, 0xbdb04f8ecba977f7, 0x3d3c639575076eb9, 0x3d33cf61a84aa254, 0xbcc101368b088743, 0xbcb26377b4c35c24, ], [ 0xbfb7a597eb76a5e3, 0x3b53aefe167f1294, 0x3fa7a597eb76a5e3, 0xbf2b0bd9eb615315, 0xbf6f831b9629acd2, 0x3ef59d1c40c95bc4, 0x3f20c9d35d4be179, 0xbea8a711bec6b4b0, 0xbec327e42f38db9e, 0x3e4d225aa909ad2f, 0x3e5b2f83a8f0f85c, 0xbde51bef24cad6b5, 0xbdea4ab13337518e, 0x3d74b0547a699854, 0x3d726e6cf385d626, 0xbcfd56db39ddf26a, 0xbcf362be01af446b, 0x3c82edb1a6e2242c, ], ]; pxfm-0.1.23/src/bessel/y1.rs000064400000000000000000001164531046102023000136360ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::alpha1::{ bessel_1_asympt_alpha, bessel_1_asympt_alpha_fast, bessel_1_asympt_alpha_hard, }; use crate::bessel::beta1::{ bessel_1_asympt_beta, bessel_1_asympt_beta_fast, bessel_1_asympt_beta_hard, }; use crate::bessel::i0::bessel_rsqrt_hard; use crate::bessel::y1_coeffs::Y1_COEFFS_REMEZ; use crate::bessel::y1_coeffs_taylor::Y1_COEFFS; use crate::bessel::y1f_coeffs::{Y1_ZEROS, Y1_ZEROS_VALUES}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log_dd_fast; use crate::polyeval::{f_polyeval12, f_polyeval13, f_polyeval15, f_polyeval22, f_polyeval24}; use crate::sin_helper::{cos_dd_small, cos_dd_small_fast, cos_f128_small}; use crate::sincos_reduce::{AngleReduced, rem2pi_any, rem2pi_f128}; /// Bessel of the second kind order one ( Y1 ) pub fn f_y1(x: f64) -> f64 { if x < 0. { return f64::NAN; } if !x.is_normal() { if x == 0. { return f64::NEG_INFINITY; } if x.is_nan() { return x + x; } if x.is_infinite() { if x.is_sign_negative() { return f64::NAN; } return 0.; } } let xb = x.to_bits(); if xb <= 0x3ff75c28f5c28f5cu64 { // 1.46 return y1_near_zero_fast(x); } // transient zone from 1.46 to 2 have bad behaviour for log poly already, // and not yet good to be easily covered, thus it use its own poly if xb <= 0x4000000000000000u64 { // 2 return y1_transient_zone_fast(x); } if xb <= 0x4049c00000000000u64 { // 51.5 return y1_small_argument_fast(x); } y1_asympt_fast(x) } /** Generated by SageMath: Evaluates: y2 = -J1(x)*log(x) + 1/x * (1 - sum((-1)^m*(H(m)+H(m-1))/(2^m*m!*(m-1)!)*x^(2*m)) Y1(x) = 2/pi*(-y2(x)+(euler_gamma - log(2))*J1(x)) expressed as: Y1(x)=log(x)*W1(x) - Z1(x) - 2/(pi*x) ```python from sage.all import * R = LaurentSeriesRing(RealField(300), 'x', default_prec=300) x = R.gen() N = 16 # Number of terms (adjust as needed) gamma = RealField(300)(euler_gamma) d2 = RealField(300)(2) pi = RealField(300).pi() log2 = RealField(300)(2).log() def j_series(n, x): return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)]) J1_series = j_series(1, x) def harmony(m): return sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) def z_series(x): return sum([(-1)**m * (x)**(ZZ(2)*ZZ(m)) / (ZZ(2)**(2*m) * ZZ(m).factorial() * (ZZ(m) - ZZ(1)).factorial()) * (harmony(m) + harmony(m - 1)) for m in range(1, N)]) W1 = d2/pi * J1_series Z1 = -(d2/(x*pi) * z_series(x) + d2/pi * gamma * J1_series(x) - d2/pi * log2 * J1_series(x)) def y1_full(x): return d2/pi * (J1_series(x) * x.log() - 1/x * ( 1 - z_series(x)) + (gamma - log2) * J1_series(x)) # see the series print(W0) print(Z0) ``` See ./notes/bessel_y1_taylor.ipynb for generation **/ #[inline] fn y1_near_zero_fast(x: f64) -> f64 { const W: [(u64, u64); 15] = [ (0xbc76b01ec5417056, 0x3fd45f306dc9c883), (0x3c46b01ec5417056, 0xbfa45f306dc9c883), (0xbbfe40290701eb1e, 0x3f5b2995e7b7b604), (0xbba67fe4a5feb897, 0xbf021bb945252402), (0xbb0334914cdd2ba9, 0x3e9cf9286ea1d337), (0x3aab4f3c6d42c1f4, 0xbe2ee7a29824147f), (0xba407fb57ef4dc2c, 0x3db78be9987d036d), (0x39d2921e91b07dd0, 0xbd3ae90af76a4d0f), (0x395a28c8620dc90e, 0x3cb7eb97f85e7d62), (0xb8cf83f52abe45c5, 0xbc31028e3376648a), (0xb8441050c68ca435, 0x3ba3cb1e7d0c17e7), (0xb7ab072548a1aa43, 0xbb133191ed9f1eef), (0xb6f05192c2d9b6ee, 0x3a7f7f4b5e8ef7b0), (0x367ad65afe306d57, 0xb9e626e36cb3515d), (0xb5ea1c4136f8f230, 0x394b01153dce6810), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let w0 = f_polyeval12( x2.hi, f64::from_bits(W[3].1), f64::from_bits(W[4].1), f64::from_bits(W[5].1), f64::from_bits(W[6].1), f64::from_bits(W[7].1), f64::from_bits(W[8].1), f64::from_bits(W[9].1), f64::from_bits(W[10].1), f64::from_bits(W[11].1), f64::from_bits(W[12].1), f64::from_bits(W[13].1), f64::from_bits(W[14].1), ); let mut w = DoubleDouble::mul_f64_add(x2, w0, DoubleDouble::from_bit_pair(W[2])); w = DoubleDouble::mul_add(x2, w, DoubleDouble::from_bit_pair(W[1])); w = DoubleDouble::mul_add(x2, w, DoubleDouble::from_bit_pair(W[0])); w = DoubleDouble::quick_mult_f64(w, x); const Z: [(u64, u64); 15] = [ (0x3c61d7eb2e54cda1, 0x3fc91866143cbc8a), (0xbc2f9f7a0ce54a40, 0xbfabd3975c75b4a7), (0xbbf7659313f45e8c, 0x3f6835b97894be5b), (0x3b9cbcd40f1be7b9, 0xbf12c7dbffcde97d), (0xbb495d78778645b4, 0x3eb0a780ac776eac), (0xbae15be86455c1ab, 0xbe432e5a4ddeea30), (0xba5ad966c12f1e3c, 0x3dcf0ce34d2066a6), (0x39e9717155dc7521, 0xbd52a4e1aea45c18), (0x394f447fe5de1290, 0x3cd1474ade9154ac), (0xb8e1699d9009a7fc, 0xbc4978ba84f218c0), (0xb8505502096ead17, 0x3bbe9598c016378b), (0x37942b6c36b2c5f1, 0xbb2e7e5fcfc4b7b1), (0x37210853b78bd08a, 0x3a99a6c1266c116d), (0xb686c9639c9d976e, 0xba02738998fe7337), (0xb603b739ee04b9fe, 0x3966f58cd41b6d08), ]; let z0 = f_polyeval12( x2.hi, f64::from_bits(Z[3].1), f64::from_bits(Z[4].1), f64::from_bits(Z[5].1), f64::from_bits(Z[6].1), f64::from_bits(Z[7].1), f64::from_bits(Z[8].1), f64::from_bits(Z[9].1), f64::from_bits(Z[10].1), f64::from_bits(Z[11].1), f64::from_bits(Z[12].1), f64::from_bits(Z[13].1), f64::from_bits(Z[14].1), ); let mut z = DoubleDouble::mul_f64_add(x2, z0, DoubleDouble::from_bit_pair(Z[2])); z = DoubleDouble::mul_add(x2, z, DoubleDouble::from_bit_pair(Z[1])); z = DoubleDouble::mul_add(x2, z, DoubleDouble::from_bit_pair(Z[0])); z = DoubleDouble::quick_mult_f64(z, x); let w_log = log_dd_fast(x); const MINUS_TWO_OVER_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3c86b01ec5417056, 0xbfe45f306dc9c883)); let m_two_over_pi_div_x: DoubleDouble; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { m_two_over_pi_div_x = DoubleDouble::div_dd_f64(MINUS_TWO_OVER_PI, x) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::two_product_compatible; m_two_over_pi_div_x = if two_product_compatible(x) { DoubleDouble::div_dd_f64(MINUS_TWO_OVER_PI, x) } else { DoubleDouble::div_safe_dd_f64(MINUS_TWO_OVER_PI, x) }; } if m_two_over_pi_div_x.hi.is_infinite() { return f64::NEG_INFINITY; } let zvp = DoubleDouble::mul_add(w, w_log, -z); let p = DoubleDouble::add(m_two_over_pi_div_x, zvp); let err = f_fmla( p.hi, f64::from_bits(0x3c30000000000000), // 2^-60 f64::from_bits(0x3be0000000000000), // 2^-65 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y1_near_zero(x, w_log) } /** Generated by SageMath: Evaluates: y2 = -J1(x)*log(x) + 1/x * (1 - sum((-1)^m*(H(m)+H(m-1))/(2^m*m!*(m-1)!)*x^(2*m)) Y1(x) = 2/pi*(-y2(x)+(euler_gamma - log(2))*J1(x)) expressed as: Y1(x)=log(x)*W1(x) - Z1(x) - 2/(pi*x) ```python from sage.all import * R = LaurentSeriesRing(RealField(300), 'x', default_prec=300) x = R.gen() N = 16 # Number of terms (adjust as needed) gamma = RealField(300)(euler_gamma) d2 = RealField(300)(2) pi = RealField(300).pi() log2 = RealField(300)(2).log() def j_series(n, x): return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)]) J1_series = j_series(1, x) def harmony(m): return sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) def z_series(x): return sum([(-1)**m * (x)**(ZZ(2)*ZZ(m)) / (ZZ(2)**(2*m) * ZZ(m).factorial() * (ZZ(m) - ZZ(1)).factorial()) * (harmony(m) + harmony(m - 1)) for m in range(1, N)]) W1 = d2/pi * J1_series Z1 = -(d2/(x*pi) * z_series(x) + d2/pi * gamma * J1_series(x) - d2/pi * log2 * J1_series(x)) def y1_full(x): return d2/pi * (J1_series(x) * x.log() - 1/x * ( 1 - z_series(x)) + (gamma - log2) * J1_series(x)) # see the series print(W0) print(Z0) ``` See ./notes/bessel_y1_taylor.ipynb for generation **/ #[cold] #[inline(never)] fn y1_near_zero(x: f64, w_log: DoubleDouble) -> f64 { const W: [(u64, u64); 15] = [ (0xbc76b01ec5417056, 0x3fd45f306dc9c883), (0x3c46b01ec5417056, 0xbfa45f306dc9c883), (0xbbfe40290701eb1e, 0x3f5b2995e7b7b604), (0xbba67fe4a5feb897, 0xbf021bb945252402), (0xbb0334914cdd2ba9, 0x3e9cf9286ea1d337), (0x3aab4f3c6d42c1f4, 0xbe2ee7a29824147f), (0xba407fb57ef4dc2c, 0x3db78be9987d036d), (0x39d2921e91b07dd0, 0xbd3ae90af76a4d0f), (0x395a28c8620dc90e, 0x3cb7eb97f85e7d62), (0xb8cf83f52abe45c5, 0xbc31028e3376648a), (0xb8441050c68ca435, 0x3ba3cb1e7d0c17e7), (0xb7ab072548a1aa43, 0xbb133191ed9f1eef), (0xb6f05192c2d9b6ee, 0x3a7f7f4b5e8ef7b0), (0x367ad65afe306d57, 0xb9e626e36cb3515d), (0xb5ea1c4136f8f230, 0x394b01153dce6810), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut w = f_polyeval15( x2, DoubleDouble::from_bit_pair(W[0]), DoubleDouble::from_bit_pair(W[1]), DoubleDouble::from_bit_pair(W[2]), DoubleDouble::from_bit_pair(W[3]), DoubleDouble::from_bit_pair(W[4]), DoubleDouble::from_bit_pair(W[5]), DoubleDouble::from_bit_pair(W[6]), DoubleDouble::from_bit_pair(W[7]), DoubleDouble::from_bit_pair(W[8]), DoubleDouble::from_bit_pair(W[9]), DoubleDouble::from_bit_pair(W[10]), DoubleDouble::from_bit_pair(W[11]), DoubleDouble::from_bit_pair(W[12]), DoubleDouble::from_bit_pair(W[13]), DoubleDouble::from_bit_pair(W[14]), ); w = DoubleDouble::quick_mult_f64(w, x); const Z: [(u64, u64); 15] = [ (0x3c61d7eb2e54cda1, 0x3fc91866143cbc8a), (0xbc2f9f7a0ce54a40, 0xbfabd3975c75b4a7), (0xbbf7659313f45e8c, 0x3f6835b97894be5b), (0x3b9cbcd40f1be7b9, 0xbf12c7dbffcde97d), (0xbb495d78778645b4, 0x3eb0a780ac776eac), (0xbae15be86455c1ab, 0xbe432e5a4ddeea30), (0xba5ad966c12f1e3c, 0x3dcf0ce34d2066a6), (0x39e9717155dc7521, 0xbd52a4e1aea45c18), (0x394f447fe5de1290, 0x3cd1474ade9154ac), (0xb8e1699d9009a7fc, 0xbc4978ba84f218c0), (0xb8505502096ead17, 0x3bbe9598c016378b), (0x37942b6c36b2c5f1, 0xbb2e7e5fcfc4b7b1), (0x37210853b78bd08a, 0x3a99a6c1266c116d), (0xb686c9639c9d976e, 0xba02738998fe7337), (0xb603b739ee04b9fe, 0x3966f58cd41b6d08), ]; let mut z = f_polyeval15( x2, DoubleDouble::from_bit_pair(Z[0]), DoubleDouble::from_bit_pair(Z[1]), DoubleDouble::from_bit_pair(Z[2]), DoubleDouble::from_bit_pair(Z[3]), DoubleDouble::from_bit_pair(Z[4]), DoubleDouble::from_bit_pair(Z[5]), DoubleDouble::from_bit_pair(Z[6]), DoubleDouble::from_bit_pair(Z[7]), DoubleDouble::from_bit_pair(Z[8]), DoubleDouble::from_bit_pair(Z[9]), DoubleDouble::from_bit_pair(Z[10]), DoubleDouble::from_bit_pair(Z[11]), DoubleDouble::from_bit_pair(Z[12]), DoubleDouble::from_bit_pair(Z[13]), DoubleDouble::from_bit_pair(Z[14]), ); z = DoubleDouble::quick_mult_f64(z, x); const MINUS_TWO_OVER_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3c86b01ec5417056, 0xbfe45f306dc9c883)); let m_two_over_pi_div_x: DoubleDouble; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { m_two_over_pi_div_x = DoubleDouble::div_dd_f64(MINUS_TWO_OVER_PI, x) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::two_product_compatible; m_two_over_pi_div_x = if two_product_compatible(x) { DoubleDouble::div_dd_f64(MINUS_TWO_OVER_PI, x) } else { DoubleDouble::div_safe_dd_f64(MINUS_TWO_OVER_PI, x) }; } if m_two_over_pi_div_x.hi.is_infinite() { return f64::NEG_INFINITY; } let zvp = DoubleDouble::mul_add(w, w_log, -z); DoubleDouble::full_dd_add(m_two_over_pi_div_x, zvp).to_f64() } #[inline] fn y1_transient_zone_fast(x: f64) -> f64 { /* <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] */ const C: [(u64, u64); 28] = [ (0x38d23216c8eac2ee, 0x3c631de77e55e9b0), (0x3c77f3a6718f8e03, 0x3fe0aa48442f0150), (0xbc52b77d09be8679, 0xbfbe56f82217b33a), (0x3c237af39fc9d759, 0xbfa0d2af4e922afe), (0xbc08241e95389bc3, 0xbf73a6dec2f9f739), (0x3c18eac6a35acd63, 0x3f7e671c82a1c956), (0x3be0a0f3c8908083, 0xbf65429d5dbc3bb0), (0x3be217fa58861600, 0x3f517abad71c26c0), (0x3bebc327d6c65514, 0xbf40b28b4ef33a56), (0xbbcb597d6bdd5992, 0x3f2ef0d150ec9934), (0x3bb1a480de696e07, 0xbf1c0758a86844be), (0xbb9c6ea6352ab84e, 0x3f0b7c88b58d9ef3), (0x3b7dbb78dfd868a9, 0xbee97ef9519bdcfd), (0xbb8d4519030f499d, 0x3f04815f08e7ad5e), (0x3bbbd70e1480e260, 0x3f10f348483b57bc), (0x3b7117cf4d2b6f3c, 0x3f231914389bb1bb), (0x3b8ca48beaf6a58d, 0x3f30b29e838345b4), (0x3bccfac65ce17cf9, 0x3f39a69e98f61897), (0xbbeae7e3065b09c9, 0x3f40b9511666fcf0), (0xbbe5cbddf691e7e6, 0x3f428cd8388e634b), (0xbbd91372412d1e1b, 0x3f414ba048d9e1d5), (0xbbb0781a70c6f715, 0x3f3acdcf66f1de95), (0xbba3ae83fd425494, 0x3f30f44ae6620bba), (0x3bc001d75da77b74, 0x3f21154a0a1f2161), (0xbb91c9afb1a1b874, 0x3f0a687b664cbac6), (0x3b8e0a06b9444963, 0x3eed7c3cbb4ba5d8), (0x3b4f0e9dfc915934, 0x3ec53ca23fdd0999), (0xbb0409258f8ffca8, 0x3e8de620acb51b2d), ]; // this poly relative to first zero const ZERO: DoubleDouble = DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243)); let mut r = DoubleDouble::full_add_f64(-ZERO, x); r = DoubleDouble::from_exact_add(r.hi, r.lo); let p0 = f_polyeval24( r.to_f64(), f64::from_bits(C[4].1), f64::from_bits(C[5].1), f64::from_bits(C[6].1), f64::from_bits(C[7].1), f64::from_bits(C[8].1), f64::from_bits(C[9].1), f64::from_bits(C[10].1), f64::from_bits(C[11].1), f64::from_bits(C[12].1), f64::from_bits(C[13].1), f64::from_bits(C[14].1), f64::from_bits(C[15].1), f64::from_bits(C[16].1), f64::from_bits(C[17].1), f64::from_bits(C[18].1), f64::from_bits(C[19].1), f64::from_bits(C[20].1), f64::from_bits(C[21].1), f64::from_bits(C[22].1), f64::from_bits(C[23].1), f64::from_bits(C[24].1), f64::from_bits(C[25].1), f64::from_bits(C[26].1), f64::from_bits(C[27].1), ); let mut p = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::mul_add(p, r, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_add(p, r, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::mul_add(p, r, DoubleDouble::from_bit_pair(C[0])); let err = f_fmla( p.hi, f64::from_bits(0x3c50000000000000), // 2^-58 f64::from_bits(0x3b90000000000000), // 2^-70 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y1_transient_zone(x) } fn y1_transient_zone(x: f64) -> f64 { /* <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] */ const C: [(u64, u64); 28] = [ (0x38d23216c8eac2ee, 0x3c631de77e55e9b0), (0x3c77f3a6718f8e03, 0x3fe0aa48442f0150), (0xbc52b77d09be8679, 0xbfbe56f82217b33a), (0x3c237af39fc9d759, 0xbfa0d2af4e922afe), (0xbc08241e95389bc3, 0xbf73a6dec2f9f739), (0x3c18eac6a35acd63, 0x3f7e671c82a1c956), (0x3be0a0f3c8908083, 0xbf65429d5dbc3bb0), (0x3be217fa58861600, 0x3f517abad71c26c0), (0x3bebc327d6c65514, 0xbf40b28b4ef33a56), (0xbbcb597d6bdd5992, 0x3f2ef0d150ec9934), (0x3bb1a480de696e07, 0xbf1c0758a86844be), (0xbb9c6ea6352ab84e, 0x3f0b7c88b58d9ef3), (0x3b7dbb78dfd868a9, 0xbee97ef9519bdcfd), (0xbb8d4519030f499d, 0x3f04815f08e7ad5e), (0x3bbbd70e1480e260, 0x3f10f348483b57bc), (0x3b7117cf4d2b6f3c, 0x3f231914389bb1bb), (0x3b8ca48beaf6a58d, 0x3f30b29e838345b4), (0x3bccfac65ce17cf9, 0x3f39a69e98f61897), (0xbbeae7e3065b09c9, 0x3f40b9511666fcf0), (0xbbe5cbddf691e7e6, 0x3f428cd8388e634b), (0xbbd91372412d1e1b, 0x3f414ba048d9e1d5), (0xbbb0781a70c6f715, 0x3f3acdcf66f1de95), (0xbba3ae83fd425494, 0x3f30f44ae6620bba), (0x3bc001d75da77b74, 0x3f21154a0a1f2161), (0xbb91c9afb1a1b874, 0x3f0a687b664cbac6), (0x3b8e0a06b9444963, 0x3eed7c3cbb4ba5d8), (0x3b4f0e9dfc915934, 0x3ec53ca23fdd0999), (0xbb0409258f8ffca8, 0x3e8de620acb51b2d), ]; // this poly relative to first zero const ZERO: DoubleDouble = DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243)); let r = DoubleDouble::full_add_f64(-ZERO, x); let p0 = f_polyeval13( r.to_f64(), f64::from_bits(C[15].1), f64::from_bits(C[16].1), f64::from_bits(C[17].1), f64::from_bits(C[18].1), f64::from_bits(C[19].1), f64::from_bits(C[20].1), f64::from_bits(C[21].1), f64::from_bits(C[22].1), f64::from_bits(C[23].1), f64::from_bits(C[24].1), f64::from_bits(C[25].1), f64::from_bits(C[26].1), f64::from_bits(C[27].1), ); let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(C[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(C[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c20000000000000), // 2^-61 f64::from_bits(0x3a90000000000000), // 2^-86 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y1_transient_hard(x) } #[cold] #[inline(never)] fn y1_transient_hard(x: f64) -> f64 { /* <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] */ pub(crate) static C: [DyadicFloat128; 28] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -184, mantissa: 0x98ef3bf2_af4d8048_c85b23ab_0bb72488_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x85524221_780a817f_3a6718f8_e03513ec_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xf2b7c110_bd99d256_efa137d0_cf1f7988_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0x86957a74_9157ef64_286301b1_453792e2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x9d36f617_cfb9c982_41e95389_bc32e8c2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf338e415_0e4ab31d_58d46b59_ac6792eb_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xaa14eaed_e1dd7f7a_f861bb7b_fbe6acb5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x8bd5d6b8_e1360121_7fa58861_5ff9b614_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0x85945a77_99d2ac87_9b052735_5d7f5f59_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0xf7868a87_64c99c94_d0528454_cdccd44c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -141, mantissa: 0xe03ac543_4225edcb_6fe432d2_3f11a8b0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xdbe445ac_6cf79639_159cad54_7b1eda7c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xcbf7ca8c_dee7e624_48720279_75757a17_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xa40af847_3d6aef15_d737e785_b3163322_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0x879a4241_dabde37a_e1c2901c_4c06b1dc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0x98c8a1c4_dd8dd811_17cf4d2b_6f3c3910_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0x8594f41c_1a2da01c_a48beaf6_a58cef9f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xcd34f4c7_b0c4b9cf_ac65ce17_cf940c9c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x85ca88b3_37e77ca3_039f349e_c6ddb06d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x9466c1c4_731a5546_84412dc3_033a8ee7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x8a5d0246_cf0ea66e_c8dbed2e_1e50b14f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xd66e7b37_8ef4a77c_3f2c79c8_4757a40d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0x87a25733_105dcfb1_45f00af6_adb11b5f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0x88aa5050_f90b0a00_3aebb4ef_6e7e9ce1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xd343db32_65d62ee3_6504e5e4_78c55965_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xebe1e5da_5d2ec3c1_40d72889_2c57e483_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0xa9e511fe_e84cc8f8_74efe48a_c9a09ebc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xef310565_a8d9675f_b6d38380_1abf92a6_u128, }, ]; const ZERO: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0x8c9df6a6_ff921721_70d796f3_2017e155_u128, }; let r = DyadicFloat128::new_from_f64(x) - ZERO; let mut p = C[27]; for i in (0..27).rev() { p = r * p + C[i]; } p.fast_as_f64() } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] pub(crate) fn y1_small_argument_fast(x: f64) -> f64 { // let avg_step = 51.03 / 33.0; // let inv_step = 1.0 / avg_step; // // println!("inv_step {}", inv_step); const INV_STEP: f64 = 0.6466784244562023; let fx = x * INV_STEP; const Y1_ZEROS_COUNT: f64 = (Y1_ZEROS.len() - 1) as f64; let idx0 = fx.min(Y1_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(Y1_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(Y1_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(Y1_ZEROS[idx1]); let dist0 = (found_zero0.hi - x).abs(); let dist1 = (found_zero1.hi - x).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { return y1_near_zero_fast(x); } let close_to_zero = dist.abs() < 1e-3; let c = if close_to_zero { &Y1_COEFFS[idx - 1] } else { &Y1_COEFFS_REMEZ[idx - 1] }; let r = DoubleDouble::full_add_f64(-found_zero, x); // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(Y1_ZEROS_VALUES[idx]); } let p = f_polyeval22( r.hi, f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), f64::from_bits(c[9].1), f64::from_bits(c[10].1), f64::from_bits(c[11].1), f64::from_bits(c[12].1), f64::from_bits(c[13].1), f64::from_bits(c[14].1), f64::from_bits(c[15].1), f64::from_bits(c[16].1), f64::from_bits(c[17].1), f64::from_bits(c[18].1), f64::from_bits(c[19].1), f64::from_bits(c[20].1), f64::from_bits(c[21].1), f64::from_bits(c[22].1), f64::from_bits(c[23].1), f64::from_bits(c[24].1), f64::from_bits(c[25].1), f64::from_bits(c[26].1), f64::from_bits(c[27].1), ); let mut z = DoubleDouble::mul_f64_add(r, p, DoubleDouble::from_bit_pair(c[5])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[4])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[3])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[2])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[1])); z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[0])); let p = z; let err = f_fmla( p.hi, f64::from_bits(0x3c60000000000000), // 2^-57 f64::from_bits(0x3c20000000000000), // 2^-61 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y0_small_argument_moderate(r, c) } fn y0_small_argument_moderate(r: DoubleDouble, c0: &[(u64, u64); 28]) -> f64 { let c = &c0[15..]; let p0 = f_polyeval13( r.to_f64(), f64::from_bits(c[0].1), f64::from_bits(c[1].1), f64::from_bits(c[2].1), f64::from_bits(c[3].1), f64::from_bits(c[4].1), f64::from_bits(c[5].1), f64::from_bits(c[6].1), f64::from_bits(c[7].1), f64::from_bits(c[8].1), f64::from_bits(c[9].1), f64::from_bits(c[10].1), f64::from_bits(c[11].1), f64::from_bits(c[12].1), ); let c = c0; let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(c[14])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[13])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[12])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[11])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[10])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[9])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[8])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[7])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[6])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[5])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[4])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[3])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[2])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[1])); p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[0])); let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c30000000000000), // 2^-60 f64::from_bits(0x3bf0000000000000), // 2^-64 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y1_small_argument_hard(r, c) } #[cold] #[inline(never)] fn y1_small_argument_hard(r: DoubleDouble, c: &[(u64, u64); 28]) -> f64 { // if we're too close to zero taylor will converge faster and more accurate, // since remez, minimax and other almost cannot polynomial optimize near zero let mut p = DoubleDouble::from_bit_pair(c[27]); for i in (0..27).rev() { p = DoubleDouble::mul_add(r, p, DoubleDouble::from_bit_pair(c[i])); p = DoubleDouble::from_exact_add(p.hi, p.lo); } p.to_f64() } /* Evaluates: Y1 = sqrt(2/(PI*x)) * beta(x) * sin(x - 3*PI/4 - alpha(x)) Discarding 1/2*PI gives: Y1 = sqrt(2/(PI*x)) * beta(x) * (-cos(x - PI/4 - alpha(x))) */ #[inline] pub(crate) fn y1_asympt_fast(x: f64) -> f64 { const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let recip = if x.to_bits() > 0x7fd000000000000u64 { DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_safe_div(4.0, x), 0.25) } else { DoubleDouble::from_recip(x) }; let alpha = bessel_1_asympt_alpha_fast(recip); let beta = bessel_1_asympt_beta_fast(recip); let AngleReduced { angle } = rem2pi_any(x); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_cos = -cos_dd_small_fast(r0); let z0 = DoubleDouble::quick_mult(beta, m_cos); let r_sqrt = DoubleDouble::from_rsqrt_fast(x); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let r = DoubleDouble::quick_mult(scale, z0); let p = DoubleDouble::from_exact_add(r.hi, r.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c40000000000000), // 2^-60 f64::from_bits(0x3bf0000000000000), // 2^-87 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y1_asympt(x, recip, r_sqrt, angle) } /* Evaluates: Y1 = sqrt(2/(PI*x)) * beta(x) * sin(x - 3*PI/4 - alpha(x)) Discarding 1/2*PI gives: Y1 = sqrt(2/(PI*x)) * beta(x) * (-cos(x - PI/4 - alpha(x))) */ fn y1_asympt(x: f64, recip: DoubleDouble, r_sqrt: DoubleDouble, angle: DoubleDouble) -> f64 { const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8cbc0d30ebfd15), f64::from_bits(0x3fe9884533d43651), ); const MPI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc81a62633145c07), f64::from_bits(0xbfe921fb54442d18), ); let alpha = bessel_1_asympt_alpha(recip); let beta = bessel_1_asympt_beta(recip); // Without full subtraction cancellation happens sometimes let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha); let r0 = DoubleDouble::full_dd_add(angle, x0pi34); let m_cos = -cos_dd_small(r0); let z0 = DoubleDouble::quick_mult(beta, m_cos); let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt); let r = DoubleDouble::quick_mult(scale, z0); let p = DoubleDouble::from_exact_add(r.hi, r.lo); let err = f_fmla( p.hi, f64::from_bits(0x3c30000000000000), // 2^-60 f64::from_bits(0x3a80000000000000), // 2^-87 ); let ub = p.hi + (p.lo + err); let lb = p.hi + (p.lo - err); if ub == lb { return p.to_f64(); } y1_asympt_hard(x) } /* Evaluates: Y1 = sqrt(2/(PI*x)) * beta(x) * sin(x - 3*PI/4 - alpha(x)) Discarding 1/2*PI gives: Y1 = sqrt(2/(PI*x)) * beta(x) * (-cos(x - PI/4 - alpha(x))) */ #[cold] #[inline(never)] fn y1_asympt_hard(x: f64) -> f64 { const SQRT_2_OVER_PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcc42299e_a1b28468_7e59e280_5d5c7180_u128, }; const MPI_OVER_4: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let x_dyadic = DyadicFloat128::new_from_f64(x); let recip = DyadicFloat128::accurate_reciprocal(x); let alpha = bessel_1_asympt_alpha_hard(recip); let beta = bessel_1_asympt_beta_hard(recip); let angle = rem2pi_f128(x_dyadic); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_cos = cos_f128_small(r0).negated(); let z0 = beta * m_cos; let r_sqrt = bessel_rsqrt_hard(x, recip); let scale = SQRT_2_OVER_PI * r_sqrt; let p = scale * z0; p.fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_y1() { // ULP should be less than 0.500001, but it was 0.5089558379720955, on 2.1957931471395398 result -0.0007023285780874727, using f_y1 and MPFR -0.0007023285780874729 assert_eq!(f_y1(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007291282546733975), -873124540555277200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!(f_y1(2.1957931471395398), -0.0007023285780874727); assert_eq!( f_y1(f64::from_bits(0x571a31ffe2ff7e9fu64)), f64::from_bits(0x32e58532f95056ffu64) ); assert_eq!( f_y1(f64::from_bits(0x400193bed4dff243)), 0.00000000000000002513306678922122 ); assert_eq!( f_y1(f64::from_bits(0x3ffc513c569fe78e)), -0.24189760895998239 ); assert_eq!( f_y1(f64::from_bits(0x4192391e4c8faa60)), -0.000000000000000002572292246748134 ); assert_eq!( f_y1(f64::from_bits(0x403e9e480605283c)), -0.00000000000000001524456280251315 ); assert_eq!( f_y1(f64::from_bits(0x40277f9138d43206)), 0.000000000000000006849807120770496 ); assert_eq!(f_y1(f64::INFINITY), 0.); assert!(f_y1(f64::NEG_INFINITY).is_nan()); assert!(f_y1(f64::NAN).is_nan()); } #[test] fn test_y1_edge_cases() { assert_eq!(f_y1(2.1904620854463985), -0.0034837351616785234); assert_eq!(f_y1(2.197142201034536), 4.5568985277260593e-7); assert_eq!(f_y1(1.4000000000000004), -0.4791469742327998); assert_eq!(f_y1(2.0002288794493848), -0.1069033735586767); } } pxfm-0.1.23/src/bessel/y1_coeffs.rs000064400000000000000000001404341046102023000151570ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Remez poly at point for Y1 Generated by SageMath and Sollya: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = 1.4 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.03 - zeros[i] b = (zeros[i]) + 0.83 + 0.03 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.03 b = (zeros[i] + zeros[i + 1]) / 2 + 0.03 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(y1_zeros) print(intervals) def build_sollya_script(a, b, zero, deg): return f""" prec = 200; bessel_y1 = library("/Users/radzivon/RustroverProjects/pxfm/notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_y1(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RealField(500)(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return def print_remez_coeffs(poly): print("[") for i in range(len(poly)): coeff = poly[i] print_double_double("", coeff) print("],") degree = 27 print(f"pub(crate) static Y1_COEFFS: [[(u64, u64); {degree + 1}]; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print_remez_coeffs(coeffs) print("];") ``` **/ pub(crate) static Y1_COEFFS_REMEZ: [[(u64, u64); 28]; 32] = [ [ (0xb839eddec375bf6c, 0x3b9d10948a169574), (0xbc74a40e665752d5, 0x3fe0aa48442f014b), (0xbc5d63ac05d1c2a6, 0xbfbe56f82217b8f1), (0x3c1a86d2f484de78, 0xbfa0d2af4e932384), (0xbc18399f4b2b50aa, 0xbf73a6dec3729034), (0x3c0746a596f9ad9c, 0x3f7e671c7d1193a4), (0x3bf3d92bfdba1d2f, 0xbf65429dc5a47c3d), (0xbbf4b8971a16b469, 0x3f517ab4afad8d4c), (0x3b652513f456a41f, 0xbf40b2d877c8c1c4), (0xbbcc3336d312aa0f, 0x3f2eea7bbac80106), (0xbbaf716735bf35cc, 0xbf1c3fae403eeb85), (0xbbad1a66b3876cc3, 0x3f09d174ea03d698), (0x3b8d9b871bbf32f3, 0xbef7956a25d2646a), (0xbb773ed35ee47138, 0x3ee58659a1776ea8), (0xbb62769d658c2265, 0xbed3a28e8e3dbde3), (0xbb552085e0470bd4, 0x3ec1e78375f4f94a), (0xbb08d21567003010, 0xbeb050ddfe36a8d4), (0x3ad34a82d3857504, 0x3e9db7fda6f15f12), (0x3b2eab75515a5387, 0xbe8b2f16073b5272), (0x3b154bf5b63c1a3c, 0x3e78ee8a3e626df9), (0xbae94fc562d9a8af, 0xbe65dbfe34a22d4b), (0xbafe6d5418c52ec0, 0x3e52ed2e77b64c13), (0xbae2e47cbd9517fb, 0xbe45f153b0798574), (0x3ad48498c8542ad5, 0x3e37beb356ba6efd), (0xba9b754aa573c033, 0xbe026b71e3609cb5), (0xba952f344bc0c1b0, 0xbdf0ee25335de707), (0xba9d8998731da058, 0xbe10333960f701ed), (0x3aa4fd188b620a2f, 0x3e02f1394b2fc331), ], [ (0x3c3c696f3e8f595c, 0x3fdaabb4011ed330), (0x37349e0b66c92237, 0x3aa5d4664eb6a104), (0xbc682b7fdbcd42e2, 0xbfc8b45babe797ba), (0x3bf25562940422c5, 0x3f8e147099a6f0ea), (0xbbfea4fe1c2176f7, 0x3f88c5af1eeb2d6b), (0xbbc92561b6f1afd0, 0xbf4133fa47da52e2), (0xbbd2318dbab67c78, 0xbf3bf8af93ff0b8c), (0x3b8367aefe821e18, 0x3f021d64be62ccf7), (0xbb5ba2bd39c31481, 0x3eb44d2ce67b2ce0), (0x3b33f47634278a41, 0x3eb14c3ab2ad7c72), (0xbb35600f33967647, 0xbe9b8eee52e1c5c0), (0x3b1e72487b134917, 0x3e7a85f1a876eaac), (0x3af57616cb55d15e, 0xbe5bf86b3c8c3956), (0xbacc84ceaea79fcd, 0x3e3f01920ab67df5), (0xbacf7e9704007b68, 0xbe20fac5449162d1), (0xba8a696b60bf9429, 0x3e0281882dcdc5b5), (0xba74ae0431042976, 0xbde42b5ce9ff90d4), (0x3a4ccb47728927b2, 0x3dc5f94ad54c0b9a), (0x3a2998fdce097e66, 0xbda7ed4bc62e5bfe), (0x3a25b8d3d29e6d16, 0x3d8a0a9970b12e30), (0xb9fd16bf93867f52, 0xbd6c55bc3e323959), (0xb9be0d077b14dc04, 0x3d4eddb2bc728a6f), (0x39bef3623a05f15f, 0xbd30ceb720a28712), (0xb9af97a81acfc768, 0x3d11f5e51ac3427a), (0x3990a840895512d8, 0xbcf30a29d26fe9e8), (0xb97f8b7789198fa8, 0x3cd774949aecc05b), (0x3930f32d60ee9695, 0xbcbee41d171d95d6), (0xb92bb8694cebdcf4, 0x3c96d81ef4f30d1d), ], [ (0xb5bd273adffce0f7, 0xb95d4023dff47874), (0x3c7b8d2a1c4966d1, 0xbfd5c7c556f0c19a), (0xbc370c18fffaa71b, 0x3fa00b9f8571ca1f), (0xbc4e4289c3a5bb03, 0x3faa15d92dfe3e27), (0xbbf5a35920e4110a, 0xbf710a329e2c23fa), (0xbc05118854f257ec, 0xbf61be6db9923acf), (0x3bcb875e5c6cb75b, 0x3f2337c7e138f484), (0x3ba72a340f9a98f1, 0x3f085b940eb607f9), (0xbb21a52945306bc3, 0xbec80619147b78f2), (0xbb469f0f1be4d82d, 0xbea255e6cf70cf33), (0x3ae6cf00d3f14236, 0x3e5b62cd0201498a), (0x3ad09fb089acb5d5, 0x3e380b1aac007d45), (0x3a846c00973acf35, 0xbdfa7ee05a569284), (0xba2f88c51e1b4b4a, 0x3d84065ca5ea7a77), (0x3a12f4d97219bd18, 0xbd93847684c52488), (0xba07e0dcba44e25e, 0x3d74980895f648d3), (0x39efb8f4f34b685f, 0xbd4c00f7d7a2505b), (0xb9b0c1aa67b8ed6e, 0x3d2402fd40ed4b9e), (0x3993d56fd395d2c5, 0xbcfded828c8c4b93), (0xb95fd48828b69170, 0x3cd6381399866139), (0xb953bf2573b4d2c9, 0xbcb06b3a2379b696), (0xb92dc38af391a21b, 0x3c884327396947d2), (0xb90f7aa26b6f4550, 0xbc61ee8868358f55), (0xb8db41373ba1af43, 0x3c3a9d108cee5321), (0x38b6c01210cd7020, 0xbc1373d3a1131d7c), (0x387b749adc7b48d6, 0x3bea94db4c089199), (0xb86a113c4f1a075b, 0xbbc7ddb04ee5e8fa), (0x38478b50ffaa017a, 0x3ba9bccbc209b225), ], [ (0xbc583acf6511df31, 0xbfd36732d4b96094), (0x35bb32394e3544b3, 0xb9504d29c8d39de2), (0xbc5b435291c33435, 0x3fc3001c8002caf8), (0x3c085153ba2c8a0d, 0xbf7bf5a03bab4999), (0x3c28d66c54022151, 0xbf8751ea028c1953), (0x3be6d2f42909876b, 0x3f423874cd8d0401), (0xbbb4d7b925e5e573, 0x3f364f6610d64939), (0xbb9920eb8c3a22f7, 0xbef02978de3838b9), (0x3b66c8e6bd84e120, 0xbed72f0766d0d591), (0x3b20b7ba8289b800, 0x3e8f2081874c7e33), (0xbafe9312e3e2eb2a, 0x3e6defd5dce00666), (0x3ab45c8d50dfdf07, 0xbe2205c6fe8f26fd), (0x3a63094c526b5e53, 0xbdfb6432e005a435), (0x3a5f030235b03180, 0x3db0289fce476893), (0x3a06336d9bbe36cd, 0x3d80778a2d37fd6e), (0x39ca74bc4d2363cc, 0xbd29723fe568d2cc), (0xb9a9854b8c15ca93, 0xbd082f3f7062fec4), (0xb960225f10f6c2a9, 0x3cc7a09f41509f4d), (0x38e482bb3a554a6f, 0xbc85319ecc467384), (0x390dda9bdc9a0a0c, 0x3c62d63451822c2b), (0xb8c73bb6bf497904, 0xbc38c3eac5e357dd), (0xb8814c483642d1a7, 0x3c0ba16f9ef7d844), (0x3871b7e296e61522, 0xbbdf92d4713ff54f), (0xb84e39cdf13f5f7c, 0x3bb25448a2561236), (0x37fdcd7885723648, 0xbb85269652dc40ed), (0x37e69c4b0a60ddd9, 0x3b58bb2c31aabdf7), (0x37cd1cbdeb5d68ef, 0xbb2f0558fc9fc6be), (0xb77691ca0957001c, 0x3aff85ebcabb7e09), ], [ (0xb5d0a191002f7d89, 0x3946a82e829b73d0), (0x3c61dc672a53c58f, 0x3fd15f993fceab5c), (0xbc1455aa7db14f8f, 0xbf902b3933cf21b1), (0x3c443ede64b782da, 0xbfa6395dfe49fcd4), (0x3be10ad2b71b989e, 0x3f63ced2a2e69180), (0x3c0f30cad7e0eac9, 0x3f607a678d6000bb), (0x3baf8fd02659436b, 0xbf1b50d7e1d32020), (0x3b91fb17828700ad, 0xbf06f7bab104f355), (0xbb60ab92716b77c6, 0x3ec176e72bf94b8f), (0x3b31557f37d0bc88, 0x3ea2becb2b6bbc6d), (0x3aea30df2d48cbea, 0xbe5a384eebfe1367), (0xbad27cd4c55aaf05, 0xbe341e7a923c3a90), (0x3a8bfdf2814022d5, 0x3de9e3284f5dd101), (0xba5d8b8089251a1e, 0x3dbec40b623ea350), (0xba1f7c34ccfe84c2, 0xbd726868b83f8d7d), (0x39eff9c315ea063c, 0xbd416f7ae80cad5e), (0x3901c0bf665fc134, 0x3cf318658ecb9f66), (0xb95a3e748f544b78, 0x3cbfacabdbab4e26), (0xb9045493a1f3354c, 0xbc713cc1f69cc0fc), (0xb8b0df6f123cf21e, 0xbc33cb940319e5c9), (0x3863c569980a714d, 0x3bda2202db83e3df), (0xb85ff8178cbd6f47, 0x3bb47d99d87a6c81), (0x381b27b5c35fabff, 0xbb7452b1dfb57b43), (0x37dfa437b73973d9, 0x3b350569c6b6e6ea), (0xb7ade85c8a408aba, 0xbb080cb19b69b6d0), (0xb7663e78d5cbec8e, 0x3ad82b8c2a256a02), (0xb732862a69eab24c, 0xbaa7b1cc7eec05b9), (0x371988acfb374395, 0x3a78a467c1568a16), ], [ (0xbc64f19a2762f5ae, 0x3fd00ef3745e0e3c), (0xb5f8d8215e0ae323, 0x39749943012b8dfc), (0xbc2a5ca3437ac1e3, 0xbfbfcdacdda138f2), (0x3c19a8e604f9385e, 0x3f706cc34cd829fa), (0x3c01d3813b5701b6, 0x3f84641bb10c16cb), (0x3bbd08ac252b4bd1, 0xbf37fac943e2a16d), (0xbbd98c55ed55e628, 0xbf34769ed32e14a2), (0xbb8b665d8b88d4a7, 0x3ee80608ecda1520), (0xbb7d207258853e42, 0x3ed5cc8242d77e79), (0x3b2f5c5f13a6d47c, 0xbe888c8f253923cc), (0xbb0d50fa940eb605, 0xbe6ce5908c1f1376), (0x3abc197e72c6469e, 0x3e1ed1625825eeeb), (0x3a969b2f19a7ed88, 0x3dfa30d624f10edf), (0x3a41771a6391a818, 0xbdaa50765ef82dbe), (0x39eb336c0c56cc4b, 0xbd814cd364ef8287), (0xb9d42fa2e0b554e2, 0x3d306199db2399a2), (0x39a86abea2a826ff, 0x3d0164150f087364), (0xb910d2f6ebf5241d, 0xbcaefb1085d3b487), (0x390479f708f87e53, 0xbc7ba1419f5a8512), (0xb8cf5a4e3ac59e65, 0x3c27638ccf278b3d), (0xb89307e1a0fbb15c, 0x3bf18a62dcf6ad4f), (0x3829bd1dae700b20, 0xbb9b54a49cff984a), (0x37fef0a051abf082, 0xbb6359324a5430fd), (0x379ca525de290a07, 0x3b10367cab8a544a), (0x376e61614232382c, 0x3aca894799ef9e96), (0xb6d099267c5285fc, 0xba44a99194b99bec), (0xb6cac95a848fd4ed, 0xba4e189da839ed62), (0xb6a1589b016c9eb3, 0x3a0eb3a19cff56d9), ], [ (0xb6157dc0fbaeeffe, 0x397a750db1884eed), (0x3c54d14c77bc1688, 0xbfcdc14ea14e89f9), (0x3c2340bd04e7ddab, 0x3f84429fef5b5fbd), (0x3c4f19a8f5b137a3, 0x3fa367d7d608e4ba), (0xbbf4eb6bddef3531, 0xbf59d6eb2bc49e35), (0xbba2f121221c3a28, 0xbf5dc4f991b3db86), (0x3bbf047b904254ec, 0x3f1315ec04d6e6bc), (0x3b9087e84c57d400, 0x3f0571814a1aa301), (0x3b2795eb852a844d, 0xbeba2977fa42f227), (0x3b3f92ddd9d5b409, 0xbea1e86423086328), (0x3aff19e1c4bddb87, 0x3e54a7b82d41f690), (0xbad019797b0c36e0, 0x3e3390660a1bb74c), (0x3a8a68e98c9b9a08, 0xbde549e8b3ed12f4), (0x3a500e13e664d35d, 0xbdbe32cf77b347a3), (0xb9d4a45373f28834, 0x3d6eff58d55a39fb), (0x39d2d3ed13f5fe2d, 0x3d415e5c0af749d4), (0x39116a2ef1b4cefb, 0xbcf0d67f939f4916), (0xb907e51a357adff3, 0xbcbef3f2afde997e), (0xb8ba32737d1e38e3, 0x3c6c60ed34505e3e), (0x38db347adfaf8e1c, 0x3c360519c76d8628), (0x387aa159aedf8fee, 0xbbe324831e6fcd1d), (0x38366083503c9cb5, 0xbba99201cdb23c66), (0x37de183660131013, 0x3b5512064fe60126), (0x37b1a5631a9356cb, 0x3b18d0404e2355af), (0x37401bfae4d1c1bd, 0xbac3979694373619), (0x36fc444a6f9d50fd, 0xba840b6d6d5adfae), (0xb6bab8d9fe8decf4, 0x3a2cebab05fc8474), (0xb6643dfbc2e7b96e, 0x39ee6703cd7c47ef), ], [ (0xbc5a8046704071bd, 0xbfcc075da85beb4f), (0x360798e196eec32e, 0xb971c7c4d6d8ab9e), (0xbc53b0c30f3f6ea8, 0x3fbbdeb6ff9f55e1), (0x3bef54869c181889, 0xbf661eefb74da882), (0xbc20492140a086de, 0xbf8229ea914b846e), (0xbbc9a664ae9a2d3a, 0x3f30cbcc6778fd37), (0xbbd8078d46437191, 0x3f32aa59f5091f7b), (0xbb7b81f3aff076e3, 0xbee1c15d5251ae6a), (0x3b707e9f1d7b9d80, 0xbed4583f15abd692), (0xbb2cc9b93fea46bb, 0x3e831d151a1284aa), (0x3b0aa58bde012b8a, 0x3e6b74e57c226d3c), (0x3abe0f5313d3a3df, 0xbe19044f1378d3e4), (0xba92c7e5b316fd24, 0xbdf93b1ec7cafe33), (0x3a314f797aa7c27a, 0x3da61a4e89bf8438), (0x3a2985182535db57, 0x3d80d430f7e78fff), (0xb9c88dfe73b74d4c, 0xbd2c3b0a8f7a7b0e), (0x39abe65ee3cc9c8d, 0xbd010e773677ab43), (0x391b33dc1a20b3ea, 0x3cab59410f7e6f2b), (0xb913e4b69baed354, 0x3c7b2e693f06a59f), (0x38b855eec84bd050, 0xbc24d1b6b5dc1362), (0x3895dc4ab685c9a0, 0xbbf17c6418e3a01d), (0xb833fe3056697f69, 0x3b999a3de53bc586), (0x37f8f01faf48a793, 0x3b628ca7df1c74e1), (0xb77f3f6f64fd7c97, 0xbb09f8ce2cdbd2b7), (0xb762fd5da648ce9c, 0xbad083f17385f58f), (0x3716906b313f0c25, 0x3a7628fa950b5817), (0xb6c02a526d5ba00c, 0x3a38dadf7e4128f1), (0xb68876e851c5781b, 0xb9e0755c2cf04c01), ], [ (0xb60b222179696176, 0x39614f36ef623dbe), (0x3c57ba12cd0fc91d, 0x3fca7022be084d99), (0xbc17334559c5149d, 0xbf7c650b6b83109a), (0xbc4d0f8f3671311f, 0xbfa163191c30aa62), (0x3bbcf7c95031f9af, 0x3f526b045287ddca), (0xbbf7b71420f279ed, 0x3f5b17602840abf5), (0xbb99a95b35521dab, 0xbf0c0a9cee3c842a), (0xbb91505ce3b29b1b, 0xbf03e398cbc472ea), (0x3b5125ae0676cb8e, 0x3eb3f35db1ff1b8e), (0xbb4e582cdfc3c4cd, 0x3ea0e9b612dbd385), (0x3ae57a34be37e069, 0xbe5056babcd9632b), (0x3ad18fdd5d5f696f, 0xbe32c1a8c8f963a5), (0xb9e38df4d597ab98, 0x3de161b6aa9fde63), (0xba4ed163038669b8, 0x3dbd4caa1e0162bc), (0xba08f4a604b97cee, 0xbd69fdda132e53b1), (0x39dc01e3b41a02ab, 0xbd4101c31e1df223), (0xb986207f93b27521, 0x3cecdc25a81e55f2), (0x3954737eca211d08, 0x3cbe87025cca1386), (0xb90b81b0f636ed32, 0xbc68c602211c726f), (0xb8c8869ba08d8915, 0xbc35d4a3a29a8a84), (0x3873a38e72663f1d, 0x3be0f3be0d4659ff), (0x384c0a8ef8364a36, 0x3ba97a197d5f15ec), (0x37d74edace719127, 0xbb52f220ef308891), (0xb7a8963ecee526ab, 0xbb18bb20459441c5), (0xb76b806269e7e9d0, 0x3ac1a0e6c4af5773), (0xb6e3b3a0df8cf60e, 0x3a844a1fb6f8097f), (0x36cfc680cfe3679a, 0xba2b974aca95015c), (0xb616726934bf9753, 0xb9ec9d1d06dc3c83), ], [ (0x3c518b0303bbe2f5, 0x3fc931a5a0ae5aa0), (0x36121d64a54c4faf, 0x397d0e55f98c2988), (0x3c348c3f5f957879, 0xbfb919c8a3f203fa), (0xbc0ef6b166c80d4c, 0x3f602a38da6262a9), (0xbc207165718dd6e1, 0x3f807ced48910819), (0x3bc68f5ae1c266f9, 0xbf2900f33a00690a), (0xbbc8c05ccff0a4b5, 0xbf31278d46fd153c), (0xbb6f62aece58d8e5, 0x3edb2595529cf1c7), (0xbb731bd584077786, 0x3ed2f7c2d608e0eb), (0xbb1f324b3544fc75, 0xbe7e212d2378b576), (0xbb005c49aacfd364, 0xbe69f3fcf3638b5a), (0xbab2a5d20b39cff5, 0x3e144fbf0377cdfa), (0xba636fe0444316b4, 0x3df82268e83f4ed0), (0x3a40f4d52865b8bd, 0xbda26cc2b02dc737), (0x3a2cea5ea61316c8, 0xbd80418bae8bbc48), (0x39b62f3557be1ae9, 0x3d2812815e643e0a), (0xb995174e2d5d5173, 0x3d009b2ac849ff66), (0xb94bf84e1c96b290, 0xbca7c55d0a6d073d), (0xb91bee74f41f6ceb, 0xbc7aa167b939dcf6), (0xb894276de305638b, 0x3c2264568716791b), (0x389d8028e4fa69b9, 0x3bf137648ca28b1b), (0x383829bd6501c349, 0xbb96ed64da9d1ba3), (0x37d8257b2a34401a, 0xbb62564f7e37977f), (0x37a8ba671e5c18cd, 0x3b0789c67b0265e0), (0x377cd4a2067dca1a, 0x3ad05f6c5196ec96), (0xb719395c6f8dc2fc, 0xba7443a74dff8e34), (0xb6d72ed3f4c7738e, 0xba38b9f499af8cbf), (0x366f755619b61063, 0x39de5a75c31562e5), ], [ (0x3613f88ad2184341, 0xb97deb1fbadd35dc), (0xbc63db68c5672838, 0xbfc80781c32422e7), (0xbc1bf83906fd4d0d, 0x3f754eda697a0098), (0x3c232419a9d405ca, 0x3f9fbe6df840847f), (0x3bd5a76a98bd919a, 0xbf4be318d61276e1), (0xbbe633162d1131ea, 0xbf58efee4094379c), (0xbb4139e1a56cbd35, 0x3f059145b4f0e4de), (0x3b2db153b13f607a, 0x3f0282d26a74c38e), (0x3b48c60f3e75a12e, 0xbeaf56c29d9ad959), (0xbb2ffef5e5fc81af, 0xbe9fdd03174f902a), (0x3acf87aa05cc99f1, 0x3e4a44a7907fee59), (0xbaded732e6cb4b4d, 0x3e31df65332ab3e4), (0xba6ed0c9b89ddac3, 0xbddc96e9cf361a43), (0x3a2bdfd4155ccb1c, 0xbdbc3439f3fac67e), (0x3a0882dd9c8f8976, 0x3d65d38ae50afdda), (0x39c918a46e201723, 0x3d40833ea1f83461), (0xb9805ea372f2e760, 0xbce8afb70fb3c9e7), (0xb9589e6fcbbece80, 0xbcbdda411e59ed93), (0xb8fe64047a8b5cb6, 0x3c65889665db0701), (0x38cc032f117d0608, 0x3c35792846a5cf0c), (0x3877212a63ae9eee, 0xbbdde1c2aabb0157), (0x38433a64e3a464ef, 0xbba92deda759a7ee), (0x37f57ed77143c7c0, 0x3b50e62605143db4), (0x37bcf9184fd6279b, 0x3b1889818af5b2f7), (0x37585a8626052c83, 0xbabfc6cafa7cab59), (0x371544bf1179e875, 0xba8431694dabf284), (0xb6c8663570999d11, 0x3a291671421e9a9a), (0x366d87c073318aaf, 0x39ec7c2e9f5155fa), ], [ (0x3c559364e26d93ec, 0xbfc713fc51664c74), (0x35fb44d96564e55b, 0x395783f5327e6c23), (0xbc488077fd102b68, 0x3fb7049760cde490), (0xbbff945ad33190e5, 0xbf58ef5f1cbe4874), (0x3c0b034f6fcde56c, 0xbf7e5f53caf3bead), (0x3bcb16596420529e, 0x3f237b0b62ddadd1), (0xbb74114140670232, 0x3f2fd3bac08286da), (0xbb66bf25df781814, 0xbed5789803de3afe), (0xbb30f115b8c5264b, 0xbed1c0faa89993b9), (0xbb1173613a405c7a, 0x3e7845b49b0674ba), (0x3ada42fc27fec004, 0x3e6886872801396c), (0x3a9cf2618301d0ff, 0xbe10b036779ac071), (0xba8ed0ec9b47defb, 0xbdf7049d18354c88), (0x3a3b54899e1cad3f, 0x3d9edd9d0fb2ebd2), (0x3a01a5a29ccc845b, 0x3d7f44600957fa58), (0xb9ca58ef04ecc85d, 0xbd2486b1d6a91df8), (0xb9990a9ead891a51, 0xbd0016025abd20b3), (0x38e7c870470babf1, 0x3ca498b3d1754fe9), (0x38f03447a5f61ea1, 0x3c79f47baf518c44), (0x38ceb6119f0d50ac, 0xbc2029b685b74cd7), (0x38512b942de2f7a8, 0xbbf0ddbdab3fefe6), (0x3827e51f6a1999e3, 0x3b94667d2d99941b), (0x380b6b9ec305a50e, 0x3b620a8a16336d5f), (0xb7951f2acc7ec6bd, 0xbb052c2d5a568fd7), (0x377c8c53cd7e3c8e, 0xbad02a6eef6c4f74), (0xb70808e163129b9f, 0x3a7266d35702aef4), (0x36b4acbcd065af62, 0x3a387c082ca923a1), (0x362c2b7e6c7f80f3, 0xb9dbb92bd7a2a5fb), ], [ (0xb5fce01036202a2f, 0xb977cba8376f75ad), (0xbc6d2f0105f3ce79, 0x3fc62d94d97e859c), (0x3bd10ece6e29dfc9, 0xbf70bf614807033c), (0xbc37013075a066ff, 0xbf9d5f857a2a6107), (0x3be49380eb03f59c, 0x3f46081b0b7fe572), (0x3bfce3676d17b413, 0x3f57307b03e248f8), (0xbbabc5fb92b99d48, 0xbf0132c0aa83d0dc), (0x3b962d899f08a69c, 0xbf0154ed4598d2f0), (0x3b436681f34a9d12, 0x3ea94f64f476e615), (0xbb2a69d5b518c645, 0x3e9e12725853a9fb), (0x3aec161d9a9d14fb, 0xbe4588c758dfc8ab), (0xbade3ba8f5e7da28, 0xbe31021cdd9b5f7f), (0x3a7b80d1898736a0, 0x3dd7cfa7a6c26b53), (0xba5b73ca7f2fd400, 0x3dbb0e011d23f5e3), (0x3a0a4b395e402c3a, 0xbd6276cc0fa65a6a), (0xb9d2e425ec7c0961, 0xbd3fe92f0882b440), (0xb97dfb208f190c67, 0x3ce53126d86bf486), (0x39466ab6083aa181, 0x3cbd07f6c1993c8f), (0xb8fc1c6cc0e8c2a3, 0xbc62bc249a86f555), (0xb8dace7e8fe0ba98, 0xbc34ffb4f078a4b9), (0x38784b88dbeaf757, 0x3bda504d640eb072), (0xb84627e1aa462991, 0x3ba8bd8d3c086d8d), (0xb7acd97ac1b07880, 0xbb4e157f9aadb1fb), (0xb770a16ecb1b132a, 0xbb1834ef40762499), (0xb6fcba2044990927, 0x3abc8e561ba674cf), (0xb7113212416c8ac8, 0x3a83fd2ac64e50dc), (0x36c9bcf42c5735bb, 0xba26bc42552c47ab), (0xb68c57d3f3c335cf, 0xb9ec3b9a1d42e3e6), ], [ (0xbc5b858aeca267e1, 0x3fc56b97f8091ac5), (0xb5db386c16851988, 0xb958742bfa32f6c1), (0xbc21d2a41bfc4c19, 0xbfb560fcc8c08469), (0xbbe6529450b1fd05, 0x3f53fafa39618883), (0xbc1ad54776e42e71, 0x3f7c49141623372f), (0x3bb39ecd4785a5a4, 0xbf1f69980694fd17), (0x3bcc2a33b89df083, 0xbf2dc5f848aa9d34), (0xbb7ed412867be351, 0x3ed178fc979b77bd), (0x3b73a93300f08ebf, 0x3ed0b494a4bafcc7), (0xbb1a1471efdf1226, 0xbe73fc3884c2743a), (0x3b0b5eabaae144fe, 0xbe673afb9fb4d844), (0xbaa47c72bb33286a, 0x3e0bd90346a3e0ed), (0xba99f0845cc41fa4, 0x3df5f3bafb215b44), (0x3a2ab1757b26fafb, 0xbd9a1c27c37569c8), (0xba09d78a09cb2510, 0xbd7e0455dbf9cc4f), (0xb9cc60b0fda73c5a, 0x3d2199b19fcacda0), (0x398ae18bb5a4d6cb, 0x3cff1334609dc3bc), (0xb93dfbfdb03c0541, 0xbca1e37265d5ce13), (0xb9124b9c1211f5ba, 0xbc79353f1aee07d2), (0x38b6ddd071a04833, 0x3c1c68e4abc15d44), (0xb89af51247543220, 0x3bf075c5531fabc6), (0xb83bd38f05e57450, 0xbb921f6f50975ff8), (0xb8036a56ab0cdb14, 0xbb61ae48288fd913), (0x375b9f05da83eefa, 0x3b02fdf3cf9be443), (0x37523bbd552356c6, 0x3acfccedcdaa6c1c), (0x370a91e99171a293, 0xba70a685da70f4ee), (0x36b74aa0dfffb869, 0xba38280b96abaf7a), (0x36763d2c62a700f6, 0x39d93cfbd5a050e0), ], [ (0x35ff76e3d2dd1a44, 0x395b36c3bc5679d2), (0xbc5e9088e9ff251a, 0xbfc4b2a38f1ab9b4), (0x3bf658189763e156, 0x3f6b3878aadeb34d), (0xbc3525fe797e2125, 0x3f9b750d89a9b35f), (0x3bb2c48be700fe5e, 0xbf41f6911725a956), (0xbbed0a355d52c199, 0xbf55beee6fd51c8a), (0xbb8079c92f6ce382, 0x3efc3625d7a65089), (0xbba1cffb5ca00b9e, 0x3f005375a588a72b), (0xbb398a01195f4a0d, 0xbea4ee5e4e7cb18b), (0xbb2804ad81294950, 0xbe9c7b3d81b5ff94), (0x3aea91d5260903d9, 0x3e41fce14f48518c), (0xbadb70b3abcec291, 0x3e30346643c9d86e), (0xba7397d52845348b, 0xbdd41c861bc1c34b), (0xba5410b5ffe22406, 0xbdb9eeda214eabbe), (0x39f8192b2b15935c, 0x3d5f8cf277ce6338), (0xb9de17c1ee8e15dd, 0x3d3ec46e14cd5d9e), (0xb97a6de668e3d04f, 0xbce2500181b463c6), (0x392d839824b54192, 0xbcbc24c2b350e45d), (0x38e6e5769440b209, 0x3c605d9c149f1949), (0xb8d2d7cef4612fe4, 0x3c34752e1249361d), (0xb85cc90966d8e53e, 0xbbd73842b122f4e9), (0xb84a80ace8d16161, 0xbba83594fd8e48aa), (0x37e69bb04bf99132, 0x3b4acb92dbb1222f), (0xb76f84be471103d9, 0x3b17c779363e533d), (0x375bd738b69b7baf, 0xbab9a6bc39977c62), (0xb72709f09b9c49c1, 0xba83b3d20f9f7463), (0xb68fc77a615eb219, 0x3a2494670cd27cf5), (0xb6826334c4bccfb0, 0x39ebe0ddc5ab4300), ], [ (0xbc4d00ae4313eed0, 0xbfc413644356a52b), (0x361469f16306ea73, 0xb97886d88ac06c23), (0x3c2e7840863e7c12, 0x3fb40bb88c6f2b85), (0x3bd5631193c7bbe6, 0xbf5078d13cfc400e), (0x3c1a406bffcdbe30, 0xbf7a9191262ab9d5), (0x3bbe2809cb4317d4, 0x3f1a005297618f35), (0x3bc92fd90e2b1391, 0x3f2c0cbad847a60e), (0x3b6faeaea4946c57, 0xbecd1a72e7c35fd8), (0x3b6a2e571e687616, 0xbecf9a2654099c40), (0x3b14a1a09cdfd73c, 0x3e70c6b06e20fcbe), (0xbb08c15da7f48d8f, 0x3e66136d6425ea74), (0xbaa9c15de165ee39, 0xbe07977677c6badc), (0x3a91f269e34226c9, 0xbdf4f77b3143a31f), (0xba2add845990ae24, 0x3d965720b0a36de3), (0x3a0614d5e1fc171d, 0x3d7cd126dc5db8d4), (0x39acdeda9cc1b993, 0xbd1e6d575a54f608), (0x3998efad7cccf4f0, 0xbcfdfb4d0beacd2e), (0xb93dd45bf2db34c1, 0x3c9f3cccbe3a6b23), (0xb90d9046de649745, 0x3c786f5c7a82a7c3), (0x38bcc387ac92fa4e, 0xbc190b8ec99c1761), (0xb897fa896ae9170b, 0xbbf0061c155efe6d), (0xb80e81b9d7fb3a38, 0x3b901f2cce805aa0), (0xb7e9b68e9f1a61ca, 0x3b61476b1f425669), (0xb7a17936a7b35d36, 0xbb0109964cb5ee15), (0xb71070e07280a9b5, 0xbacf2f6936a50cd9), (0xb704566a8e45b2c1, 0x3a6e1ae6370795ee), (0xb6c4223bfe21f7a6, 0x3a37c2c229a343d5), (0xb6672d858cefe400, 0xb9d6f33f958fa10d), ], [ (0x3611a27c9ec03a6f, 0x39706267910ea7d6), (0x3c4997782859a008, 0x3fc37aaceac987b9), (0xbc09de167b0f525a, 0xbf66afe4fe0bc0f7), (0xbc3d91e80a0529b5, 0xbf99de7a33bc3a97), (0x3bdacaad4f266c0b, 0x3f3e024f567ac487), (0xbbf5aee36a6b58b3, 0x3f548843c426abe0), (0xbb8ed7ac2e5ef1cf, 0xbef7a8e14711c0f5), (0x3b9b367577010374, 0xbefeeceb341ad833), (0xbb4d96e37263f84b, 0x3ea1a743e05b39ca), (0xbb36e8969000eefe, 0x3e9b143d39c90dd5), (0xbad319f8c17a1d1b, 0xbe3e8e00012321d3), (0x3aae89c89982dfa2, 0xbe2ef28e323e7496), (0x3a7f30c6340427ad, 0x3dd137a1bf5bde2c), (0x3a5bf7e9721f9c44, 0x3db8e087c7cb7f1d), (0x39fb9386784ae3b7, 0xbd5b3dc9dd36d846), (0xb9c9416eb664afb4, 0xbd3da6ae03deea14), (0x397c9f46130e8018, 0x3cdfe64e83599734), (0xb94f05115daba819, 0x3cbb3e899a8275ba), (0x38c31d3c51684ee2, 0xbc5cc15471c3a370), (0x38dff660cb4ed828, 0xbc33e3495674137f), (0x386b19ea37ea8387, 0x3bd491cabca4a282), (0xb7fee9491d40343c, 0x3ba7a07e1fc95f06), (0x37e4a41a5994c845, 0xbb47ecb9be67f4a7), (0x3786f1c46d712a3a, 0xbb174a2d06d7d6cc), (0x37594e2ff6a6309a, 0x3ab712a9f6839c0d), (0xb7147e96a2d3fad0, 0x3a835bcefeaed781), (0xb6c430af3e496108, 0xba22a3254eb3d159), (0xb683689f2fc779f3, 0xb9eb727d700d89b6), ], [ (0x3c4f123683cf20a8, 0x3fc2f4e70d6c7e01), (0x361f442aef336146, 0xb97591bf30ddf0c2), (0xbc5702b97938a87d, 0xbfb2ef24d6f7526a), (0x3be17c9efd992fc9, 0x3f4bc33c9dc6ec82), (0xbc153a673a682d1e, 0x3f7920414ee2acbe), (0xbba8c8602e55078d, 0xbf15f9173916a219), (0xbbbd01332ea23729, 0xbf2a94fdbdcec471), (0xbb6340ead67ee22f, 0x3ec8b309990f950c), (0x3b62bfaf2a2b92bf, 0x3ece087ff4517c02), (0x3b05bdd16ba2b30c, 0xbe6ca22ab12cb4b7), (0x3ad498149d36365c, 0xbe650d1f28635cda), (0x3aac3cc8c5cf9b92, 0x3e04441552e259a7), (0xba95d08f72147a49, 0x3df411b8a8258957), (0xb9f001851befe105, 0xbd9354e914c31b45), (0x3a1141eaf70efbe6, 0xbd7bb16f111ebae7), (0x39b1abb08be1dbdb, 0x3d1a888536e27439), (0xb992bb2516838f25, 0x3cfced726c1026c8), (0x392858a15531d1cd, 0xbc9b745d75ff638e), (0xb8f68dca35d3026e, 0xbc77aaea63220979), (0x38ba5598d094c6db, 0x3c162ef6548b3d48), (0x3868e319c4957108, 0x3bef27eac43efa6e), (0xb823d9360fee46a7, 0xbb8cc635a6cfb635), (0xb801a40c068e9744, 0xbb60db1d947bfc05), (0x37881141d0dd48d0, 0x3afea05195871c93), (0x3766e70475fe3f97, 0x3ace8489e5ad7b34), (0x36ff2a338fa956ef, 0xba6b3d80597f37cb), (0xb681333c765d8ec9, 0xba375182dac04c91), (0x367a4126c3cf44ba, 0x39d4e0f3b5cdb046), ], [ (0x361be200b4a5908e, 0x3974f957842c3586), (0x3c6b7326e3fbaa6e, 0xbfc2740819f1caaa), (0xbbad91d1969669a0, 0x3f6349369dc780bb), (0x3c211249d3675d9f, 0x3f98868d7401bf2e), (0x3bab901426ad7111, 0xbf398cd1bebe1445), (0x3b8e845cf46e9a08, 0xbf537eef9aadeee2), (0xbb978bd723278bd2, 0x3ef43394c95b2d2b), (0x3b98d34686b7250a, 0x3efd6dfcdb026028), (0xbb39039620a09507, 0xbe9e448fbc8a1f43), (0x3b1ab8335f58d6d9, 0xbe99d764ee07c839), (0xbad24a385e18b9fd, 0x3e3a53958c8d74ff), (0x3aae692fd829adc7, 0x3e2da0e1c8a08d37), (0xba68265b22821350, 0xbdcdd7f918de776f), (0xba554536fed50ee3, 0xbdb7e68037d5c861), (0x39e8fab1857f8e79, 0x3d57c2e63bbe27ca), (0xb9b6eea6ea65f06f, 0x3d3c973a175ffbb6), (0xb97a4e6705d4e73d, 0xbcdc033788921734), (0xb95d7517b81f587e, 0xbcba5d9f2bdd8af4), (0x38fc5fbb6c45e1de, 0x3c596cb946e789e8), (0x38c497a6d69d23c5, 0x3c335090afbe12d6), (0x38799c64a296461a, 0xbbd24f90893c37df), (0xb7fbecdd04e88b2a, 0xbba706010539124a), (0xb7eafe8f4b0c9808, 0x3b457032af41d7a4), (0xb7bc178a723aab4c, 0x3b16c43d5e0cacac), (0x37373a6759c668d6, 0xbab4ce42861296d9), (0x3714ea53a56cccdf, 0xba82fa99ffa503c9), (0x36a6206269dd287a, 0x3a20e7e4d182d7e6), (0xb64ef30807ed040a, 0x39eaf6aa0936f5c1), ], [ (0x3c34f78a7cfd8a8a, 0xbfc20198200b699d), (0x360565ac287f5dbb, 0x3964862986ce6868), (0x3c1ede75d6e0c0a5, 0x3fb1fd242a74e630), (0x3be31a446a06705c, 0xbf47cf261dfbf19a), (0xbc0b11e38b0823ed, 0xbf77e4820ec1dde4), (0xbbbbba7e6db236bb, 0x3f12e1bd281dfcbb), (0x3bc48aed48d0a238, 0x3f2950bb06c6fdf9), (0x3b5f50566d2c1e7b, 0xbec54a38ab6af546), (0xbb69fdc0d6c239ec, 0xbecca94f38024fdc), (0xbaf76dde5126de40, 0x3e68c7e75971c85c), (0xbb0678751bf4f650, 0x3e6423fc7e251ca9), (0x3aab4294dcf0c897, 0xbe019fe1d8e51b96), (0xba976b8065979a15, 0xbdf34198c795142c), (0x3a1b7155c351ab8b, 0x3d90e78cdab26dd9), (0xba1a3a4b53edd6ed, 0x3d7aa74cb5ba4b0e), (0xb9a9e4993f6f7c4a, 0xbd1756ee8369797d), (0xb992ea1492b57e10, 0xbcfbee3ccbac62a3), (0xb9058529ec2e805b, 0x3c984c93627c1378), (0xb90c3b9cf073d667, 0x3c76ecd2977e72a5), (0x38be2449e2bf487c, 0xbc13c1ad21981036), (0x3883f6d9af30b491, 0xbbee45c90965f9de), (0xb7f83349481ced2f, 0x3b89c8e8d181a236), (0x380803a9275b7f65, 0x3b606d491b5da420), (0x3798109188279175, 0xbafb9c064d80a138), (0x376013fe3b9f77b2, 0xbacdd315dbfb672b), (0x36fc9d61cb3c3abf, 0x3a68b2de73775fa8), (0xb6ce777cbee59127, 0x3a36d90ef88dab95), (0xb67862ced9ec7588, 0xb9d305b1d99a3c61), ], [ (0xb5fb86fee5ebbcf6, 0x396f19a82c6866ac), (0xbc4081c2a50ad27f, 0x3fc192f2627a74e3), (0x3c06268e5916d632, 0xbf60a846a83fecf2), (0xbc1be434e30d7a5a, 0xbf975eceaabf7f86), (0x3bbc2d7f1eb154d6, 0x3f3617c581be35b1), (0xbbb0beeca29a2baa, 0x3f529934b7a84483), (0xbb91b58b66aab0a7, 0xbef18123e875188a), (0x3b94740ce7aaa9dc, 0xbefc1f05a2d85165), (0xbb3fd873b63ab5e9, 0x3e9a4e0bc0926545), (0xbb233d21389bce0f, 0x3e98be81ad44d933), (0xbabb1f9ca258cce3, 0xbe36f73795e25c01), (0x3ababafde69f161c, 0xbe2c70ab158cd19a), (0x3a5796bd01bf9720, 0x3dca262190472d9a), (0x3a444e2c448f52df, 0x3db70112aab52bc2), (0xb9f5a65a43d3cb6e, 0xbd54ec163f88c02f), (0x39d52f72c43ac9e8, 0xbd3b991575a9daff), (0xb9742584b2344dbc, 0x3cd8cbabadfd45c4), (0xb952f19a04e89b00, 0x3cb9867f1ea85270), (0xb8f407ccf94d1457, 0xbc56a0c58ce961b7), (0xb8d0795ea11bd36d, 0xbc32c10fa1783b9d), (0xb85c7f401bf9086f, 0x3bd0630454542422), (0x3831adbad02f8547, 0x3ba66b5f3f83dfb5), (0xb7c18a605d4d2201, 0xbb434a75d1b13844), (0x37a6e2dd153188df, 0xbb163af22779791d), (0xb75d10a8ae54e7d5, 0x3ab2d2655ffc3033), (0xb72fe47a60aa5d90, 0x3a829478c1a243e5), (0xb69af79b5351dbd0, 0xba1ebe95a9db6af0), (0xb68a3c131c1f2df8, 0xb9ea729d3347c622), ], [ (0x3c68f71f103b6bf8, 0x3fc12f9870d68e18), (0x35eedd0c814b660b, 0x39584c0de5cb23f9), (0xbc5fd0d25668ad6b, 0xbfb12c11811945f9), (0x3bebc70ffc015992, 0x3f44b638f21f0f76), (0x3c1bc10a4e0506fd, 0x3f76d2a897d58353), (0x3ba5de76c7b42d7a, 0xbf10732e5458ba20), (0x3bcfca03362738fd, 0xbf2835929300df3f), (0x3b4992f62f114659, 0x3ec297283816a83b), (0xbb50d6dea52a7094, 0x3ecb73adedf11a43), (0xbb0dce80931dc602, 0xbe65b455b903f09c), (0x3b0295728813e0af, 0xbe6353f0797a6699), (0xba8bf23e761207b9, 0x3dfefc9ac17b1eeb), (0xba878c04e9d38305, 0x3df28535463ce067), (0xba096e621beb197b, 0xbd8dd894cbbee3f9), (0xba0f45ad9ade804f, 0xbd79b288cc392b5b), (0x39916204abd42d65, 0x3d14b2ec9ace070c), (0xb9936d340e28fba5, 0x3cfaff72f6057831), (0x393a603e53eacc06, 0xbc95a7bfada0275b), (0xb901b469e17f5bb3, 0xbc7637b7b45acfc3), (0xb8820547fceb973f, 0x3c11b216f1fbcae9), (0x38886047cf777ac4, 0x3bed6a4aa2540e36), (0xb7deebf62d61db26, 0xbb87366125ff8ead), (0xb7f352b13b569959, 0xbb6000a238ddbac3), (0x378f208cf7576478, 0x3af8faebb4eb88ac), (0xb7338292ec57b7e3, 0x3acd201e6cbbf759), (0xb70a1ecbbc05a2ed, 0xba6674d821ccdd7a), (0x36c727a7e3d4fb6c, 0xba365d344fa9d6d7), (0x365f47ff2787d3f1, 0x39d15e5b7cf8fc11), ], [ (0x360bdb5b805e25b0, 0x3969e1daf83188a7), (0x3c60c06e2860e867, 0xbfc0cf3ee98f769b), (0xbbfc2c390327e76c, 0x3f5d26e7af251f79), (0xbc394225ed089993, 0x3f965d05948a946a), (0xbbcb3460aae307ce, 0xbf335959b8482e40), (0xbbf744279fabe84c, 0xbf51cff175d05c2a), (0xbb83714c1d2b527e, 0x3eeeb59416879106), (0xbb89158b4542d28b, 0x3efaf7544eeac766), (0x3b284917e9916dd8, 0xbe9720522bb1fc81), (0xbb31671693e89a81, 0xbe97c41261705419), (0x3a886ab5cb454f45, 0x3e343fa0ea5e007d), (0xbab8f90f9f428048, 0x3e2b5e23abebd7a4), (0x3a64e5d5f577d2d2, 0xbdc722397e750312), (0xba51768fabb7fdb1, 0xbdb62f2174e6be49), (0xb9fba4dd6a628798, 0x3d5294ab060a163a), (0xb9de8957f248872f, 0x3d3aace944141c61), (0x394ff7327b4ba565, 0xbcd61cc8146cdfa1), (0xb9394e82e72782f6, 0xbcb8bb3c270a284d), (0x38f4722936097c3e, 0x3c54449d966478fa), (0x385797f171c71fea, 0x3c323712fdd32aac), (0xb85151bbb56468ad, 0xbbcd7cedd0538c51), (0x3800563232817820, 0xbba5d3f2f4d3b9e1), (0xb7d9661fbc11e8a2, 0x3b416f9a7e4f8d43), (0xb7b5912190425469, 0x3b15b1f1d8d05a13), (0x375dae4cd5158605, 0xbab116c0b74e863e), (0xb72f2d5922ef51d5, 0xba822c909d7ff79e), (0x3686e084ffb6066d, 0x3a1c0950bfbf78de), (0x36899d263bfc66cf, 0x39e9ea82b7b42ba3), ], [ (0xbc6742aa46ea9b31, 0xbfc077eede4a0d89), (0xb5d51339f008438b, 0xb93d0e3fbdb78328), (0x3c3cabc5883fc763, 0x3fb0751548b2924d), (0x3bd8c3b817f5be4f, 0xbf423b5d46a73864), (0x3c1e7b0b0210cbce, 0xbf75e2467c8fb832), (0xbb9abdc39961759f, 0x3f0cfe5c189d6e4d), (0xbbcf4c0c63a83958, 0x3f273bbd8c7aef2d), (0x3b6d9272577eb3fa, 0xbec06974d3d04287), (0xbb56fb637948d35e, 0xbeca6081d36e6a2b), (0xbaee9b9b2585b7c5, 0x3e6334a83cf6092b), (0xbb0e3539c25f29f0, 0x3e6299571cb4e1fb), (0xba80b2cd9f616718, 0xbdfb7f5bc0aada50), (0xba818316569b1592, 0xbdf1da63b4d6f878), (0xba03f4308aff6abe, 0x3d8a9288ceccd9f2), (0x3a16f5c0a511bfb0, 0x3d78d1d74c88ee4c), (0x39a16735a5eb7383, 0xbd127eed3a482d7f), (0xb9883ce9962db86a, 0xbcfa2143706ccb78), (0xb933e39af0b0a816, 0x3c936d1464c4bf22), (0x390afef7e49ce49a, 0x3c758cc3ad07d84d), (0xb8ae01cde6f904a8, 0xbc0fe0c8ce96de05), (0x387fd4921dadf9fd, 0xbbec97f7854a0777), (0x37f77fd4b81374ba, 0x3b84fee62588d5e1), (0xb7f6a3ad2cef6d22, 0x3b5f2dcbb8b70749), (0x379518518eb791db, 0xbaf6b09656bd01ca), (0x3755aca529972d2e, 0xbacc6f2f1ddb116e), (0xb70b72b0eec38d9d, 0x3a647b8c438cfbcc), (0x36cc4b3943e41f19, 0x3a35e0cb3264bc18), (0x36290f8597bf8fe9, 0xb9cfcd0aefeb1cbe), ], [ (0x35d2722913fb4c63, 0x3944e3fd926f8fb1), (0x3c61166b7995967a, 0x3fc0230ba90f2871), (0x3bfb746b17280a35, 0xbf59ca16f0c9734e), (0xbc375b99fcae0fa4, 0xbf9579c1bdbcfc99), (0x3bc1259c7efa1bb2, 0x3f3120ecfac5c017), (0xbbd35a76e06cda5a, 0x3f511dd26bbe2946), (0x3b72ed405d5bc408, 0xbeeb37e7c9a57149), (0xbb86e93d7c515f2f, 0xbef9f01e7c1909a0), (0xbb2f562d62e74ecf, 0x3e94887fe7a88c2c), (0xbad010f8761951e4, 0x3e96e37238841d4b), (0xba99b7f17d43bc36, 0xbe3204b644d6a04b), (0xbacc8fcda9cad56e, 0xbe2a659b13eebf8a), (0x3a42b7267c5e128a, 0x3dc4a40c87601c97), (0xba57720418c52447, 0x3db56f0250e4fcac), (0xb9f80ede07f2b143, 0xbd50a1011bf4a7dd), (0x39d51971dde44362, 0xbd39d22a6dc5a57c), (0x3973c4be23c7c005, 0x3cd3db0f19da31d9), (0xb95d91267d6c60a3, 0x3cb7fc7d4070961c), (0xb8e43885990b2b03, 0xbc5243aa7bbc7ede), (0x38d02229cd94d6a5, 0xbc31b3c3dd0d78fd), (0xb83af6a3d8823899, 0x3bcaabdcab96df5c), (0x384894bf3b4da9f0, 0x3ba541bb402c78ac), (0xb7dda9ab25eaff8c, 0xbb3fa915b2fa47b8), (0x379cbdf7cf876dad, 0xbb152ba169685593), (0x3733162e8c1ee94b, 0x3aaf26066ae9706e), (0x36f9819114677bb3, 0x3a81c51763321aee), (0x36a446eca6c003a9, 0xba19a5c3984013f5), (0xb68b1567ca85f2fe, 0xb9e96168a239b1d9), ], [ (0xbc446154ab44acb3, 0x3fbfab0b166d23d8), (0x35dbf46a8ed0ff76, 0x393d7c0296d587f1), (0x3c4290cc8b89531c, 0xbfafa65c1ce7ebd6), (0x3be9bdd7d19e6706, 0x3f4035bf503ffc1f), (0x3be801473cc85f34, 0x3f750d1b04713c41), (0x3babe22a416a834b, 0xbf09cd14a92842a2), (0x3bca868e6f4e4834, 0xbf265d504af5d8fe), (0x3b5814b5b96336a9, 0x3ebd3feeb33d9cee), (0xbb4c05f6b4f495e3, 0x3ec96a257062f76e), (0x3b0b04fde267ccf6, 0xbe61254f302b36b2), (0x3ad771b2683ddadc, 0xbe61f11585e04fca), (0x3a8b3d53dc0784a1, 0x3df89a7674dd98cd), (0x3a7b6da4a2d7c8b5, 0x3df13f0ba48c1692), (0x3a248eb19153b909, 0xbd87d67b47fd268e), (0x3a0aa35dfad0cb5d, 0xbd780381812ad9b0), (0xb97e8eabaacf7749, 0x3d10a41213b1209a), (0xb9694e4f19ae8248, 0x3cf9530714f8af89), (0xb935bd4a759fcd07, 0xbc918884a9ff47a4), (0x390c5a7313603d8b, 0xbc74ec3ce9f28ddc), (0x3891396752d2f4be, 0x3c0cde4ce08c9c88), (0xb88f3ed08df90975, 0x3bebd00bdad9a3b4), (0xb82845f2323731b8, 0xbb831454d10def31), (0x37f8ae176f7e036c, 0xbb5e62383fd8bdbf), (0xb7891c6860574ef2, 0x3af4b117f31a9f40), (0xb76e1cfee2b9a0d7, 0x3acbc29e8f1ce304), (0xb6d4fcd41e5c1c66, 0xba62bec668d1d14b), (0xb69b898b21726f67, 0xba3565d792f0e519), (0xb667b0601d949d31, 0x39cd328695f5c7be), ], [ (0xb5856985dc45fea1, 0xb96fbca69975e716), (0x3c50db2c50623ec1, 0xbfbf13fb0c0e6fcd), (0x3bf63fd50ee5bfaf, 0x3f5706ed3d935d00), (0x3c3a7c91ef9a7d9f, 0x3f94af74cbd77bef), (0xbbac31e3b8ee60ac, 0xbf2e9a9e66e5a792), (0x3bf35ae9733a6eb9, 0xbf507ec9ed824fcb), (0xbb4a161032086ff0, 0x3ee856d4518ab29e), (0xbb9af9c37c81cff9, 0x3ef9040de830649e), (0x3af6ec0adcd73b17, 0xbe9262f69c56c652), (0xbb34da0db90f8b57, 0xbe9618c94a54734d), (0x3acfc6bc54a1c19e, 0x3e3029d2c8bf70d6), (0x3ab60f30dc12e39e, 0x3e2983bca0a3e67c), (0x3a60395cd0053820, 0xbdc28e2a00002a82), (0xba51c63c15e96dac, 0xbdb4beeacafc4fad), (0x39ed5a030c6605c2, 0x3d4df880e37a5060), (0x39d2026270de9105, 0x3d3907be43054aec), (0xb952832db501353a, 0xbcd1f10ff685083c), (0x395f463c7798955d, 0xbcb74a1dc71abca5), (0x38e7d8e5ae99ce88, 0x3c508d41117c90f3), (0xb8d552c759edc37c, 0x3c313795880a77fc), (0x386b16755d17fac8, 0xbbc83ea1ceb16a07), (0xb848188a8a68517f, 0xbba4b5cc8ded0fc2), (0xb7d762214edd8666, 0x3b3cdf000bd6f203), (0xb789ca564a28d131, 0x3b14a97cac9def65), (0xb74e5064a15a2c78, 0xbaac7eef42820297), (0x371d86a43d3d4298, 0xba815f89d5c7d990), (0xb6ba98e94c93cb57, 0x3a1789ebfe3c8e8c), (0xb68a2c469d8fa268, 0x39e8d984b79cb9e9), ], [ (0xbc5bf01bf61d8ed3, 0xbfbe891b327da16d), (0xb5cc3c81dba6f81d, 0x3953aec892af6d03), (0xbc3636379e4f582f, 0x3fae8533ce07bdb8), (0x3bc53b9dd0e1816e, 0xbf3d1253218e31b0), (0xbc1eae521e3467c6, 0xbf744e6826476498), (0xbb6864ec60e7922a, 0x3f07271a9b5e3cb4), (0x3bace83941ef46b5, 0x3f2595b697c8ec04), (0xbb5f57ab9661648d, 0xbeba46b03ecb38cc), (0xbb4dc38fda907530, 0xbec88c173e07621e), (0x3add237c79f6db0f, 0x3e5ed9b1754fbd3c), (0xbb0d6748bb472b61, 0x3e615891ef314e18), (0x3a8caec9a3fbb1e1, 0xbdf62ca352cf904e), (0x3a7916cf164a75f3, 0xbdf0b14767c2b010), (0x3a2595ab6e7a4beb, 0x3d85879bb4a2a8ac), (0xb9f9a36051cbdc81, 0x3d7745bbca5b0e82), (0xb9a0856355ee0f2f, 0xbd0e21736ab8469f), (0x3985ce3b693f20e7, 0xbcf893b256068d4d), (0x3920359c32c5de22, 0x3c8fd42c80d03657), (0xb9029a5c2c268edd, 0x3c7455e80611a14d), (0xb8a84439970d2016, 0xbc0a4682da82870e), (0x3879596804aa9b9c, 0xbbeb12f0bb307616), (0xb815b3814c55d4ca, 0x3b816a7f58b7a414), (0xb7f11e258570c30d, 0x3b5d9fa088a0baf3), (0xb78f1b32689b744c, 0xbaf2f1ad94886e01), (0x376c31c2ebc43a82, 0xbacb1bde877c7dfa), (0x36f7154043b459d4, 0x3a6136b97f99fb4d), (0x3693894e8fe8da2f, 0x3a34edb643b11559), (0x36486be2c3a76600, 0xb9cae2d7b5d6550c), ], [ (0xb5e117018bd0a4d7, 0x396cc7fef85a11ce), (0xbc3b9f1d130797b4, 0x3fbe018dac1c17e3), (0x3be072789a66c0ad, 0xbf54b994dd05c1fb), (0xbc338b4f0d3a410f, 0xbf93f9e0db07e7ef), (0xbb9a8995613210dd, 0x3f2b8e55b75b13ab), (0xbbd251fa83bbf995, 0x3f4fdf68a78bb3d2), (0xbb783beff5b1e008, 0xbee5ee9d17106a08), (0x3b70935ad535759f, 0xbef82ee6dfdfedeb), (0xbb36eeb8b4349e83, 0x3e90962d7f6d61a6), (0x3b3ddb699c12a377, 0x3e9560edce7d682d), (0xbaadbe6efa7bc4c2, 0xbe2d34381d02bdbe), (0xbab5faefe93fce4d, 0xbe28b5a0e74ae0d3), (0xba651c2d1b2cfd90, 0x3dc0cab953f05720), (0xba4cdf9f9b970a3b, 0x3db41d21c68d7ed3), (0x39efe10ea47be16f, 0xbd4b2d2dd7cb3c52), (0xb9d985842dbfa533, 0xbd384c5369d2e33d), (0x396e2573c81613c3, 0x3cd04e17ab25ece8), (0x3940629f2b3df4a6, 0x3cb6a38e0aef9402), (0xb8e1d69808a03084, 0xbc4e28099fc922c0), (0xb8c82332ebaf3236, 0xbc30c28e6023fb30), (0x386b9c9fc0c05d07, 0x3bc62487322c4643), (0xb84bcacb7b5c3520, 0x3ba430a24f213ff8), (0xb7c5039f9a7e3931, 0xbb3a7037139e97ed), (0x379c58e611949e56, 0xbb142c5d039a4a70), (0x3727db4e84bd36dc, 0x3aaa2a8a29e14a1d), (0x36cc215ba322ceb2, 0x3a80fcdc0bece4f5), (0xb6b57109b2328425, 0xba15ac88c96a9a92), (0x3661fe5c16d66355, 0xb9e854529bb11eca), ], [ (0xbc4d7a7b8d722118, 0x3fbd84391bb2748d), (0xb5f89e9b40c23cab, 0x39715c553323e555), (0x3c4b439a88ed803b, 0xbfad80edb3c4ea05), (0xbbd902d343596722, 0x3f3a431f5421f7ef), (0xbc13a66c5c4dc379, 0x3f73a282fe7b63a8), (0x3bacf6f60b035a27, 0xbf04ed653e607bdd), (0xbbb378680e9561b7, 0xbf24e15832bda3c4), (0xbb5464c53ca4420f, 0x3eb7c5832dd1374f), (0x3b40f0848ee6fe3d, 0x3ec7c2b80da8df98), (0xbadb963cfcbd4c8f, 0xbe5bf160ccd35445), (0xbac9dbc6af458996, 0xbe60cda2141b2a1e), (0x3a876693420f17fa, 0x3df41d31d2a419e4), (0xba820602dcfc6a1c, 0x3df02f6ca850168a), (0xba125360d2345a18, 0xbd83901f61054085), (0xba17df49fb76cb0e, 0xbd7696ce2b748d02), (0x39af2c4622bc54e9, 0x3d0b6e82997a390e), (0x399ac81facf7b5ab, 0x3cf7e214796bec18), (0x3927c686b63cfcd2, 0xbc8d0a3822eede5d), (0xb9116570c5a93cb1, 0xbc73c944a2b7a866), (0xb8a7e7acb8f1f32c, 0x3c080748c2fd703d), (0xb87cb3127b6df48b, 0x3bea608ebfae056a), (0xb81b4f7b9cda848d, 0xbb7fee483d8cb2bd), (0xb7fcfe24d11f96d0, 0xbb5ce67574b83792), (0x3757b86fe74315fe, 0x3af168f6128b62f7), (0xb76886b34e3ecd6f, 0x3aca7bbe8016f1c0), (0x36d81a3f26ccf62a, 0xba5fb8acc96dbd9b), (0xb6dd8ec78e1a519f, 0xba347945efb0e5b5), (0xb650c6a09f8b3be4, 0x39c8d517ce0975bd), ], [ (0xb5f1cdfb0cbbbf9b, 0x3963ad355553c663), (0xbc56edd809f4ec44, 0xbfbd09b21e36c0bd), (0xbbfd63853cd12a08, 0x3f52c84acfb586b4), (0x3c340975d5184af7, 0x3f9355b904fbf7ee), (0xbbc2e53f276aead9, 0xbf28fb570465af0d), (0x3bdedf2b372334a8, 0xbf4edc3292ba6cfd), (0xbb81b7d6d1c235c3, 0x3ee3e552ee8c2577), (0xbb9b6ea46d6db745, 0x3ef76d44f6a83523), (0x3b2fdb93f3cf1ba4, 0xbe8e1ee2dc4a3bda), (0x3b3cccd425113a57, 0xbe94b944bbd4c7bf), (0xbac4687392bdbcfe, 0x3e2a8c3a4ce36f16), (0x3ac2a4a12febf7d8, 0x3e27f8c9ef47068e), (0xba40ac973313c53b, 0xbdbe9295749ee471), (0x3a116490085933e1, 0xbdb38813c3eb77e4), (0x39e5a2d8c5b27290, 0x3d48c7cda44b7754), (0xb9a05a73d2dc3c66, 0x3d379e90468589ab), (0x3961ad36dfeb19e3, 0xbccdca323fb2ed12), (0xb95c95ee628cae05, 0xbcb6080be2ba756c), (0x38e14a5e61e5df84, 0x3c4b9a8e33ba505f), (0x38869b43fbbf40af, 0x3c3054766d105227), (0x3869a58ba74326c8, 0xbbc44fda8cffeefb), (0xb80e3c951291e0af, 0xbba3b257514f6e67), (0x37d7232bb9cc06e3, 0x3b384ea2f19dc085), (0xb7b20d806734b932, 0x3b13b4adeb19bbff), (0x37470ea8b4edb81d, 0xbaa81cf876394534), (0x372493d295b38feb, 0xba809da078876581), (0xb6b9d7d8c4984442, 0x3a14055384d957ac), (0xb68f3f22c46d785d, 0x39e7d2d65aaf6d5b), ], [ (0xbc579e384ae35818, 0xbfbc97d79918527d), (0x35eb9172f9b7276c, 0x395ce1b629f3b194), (0x3c415f3ee939a0c0, 0x3fac95081ab2b511), (0x3bd3c58af0675aab, 0xbf37e0b14f7d7c3f), (0x3c167e93b7727b22, 0xbf730688f6836a76), (0xbb9eaad91947069e, 0x3f030941f6e78e36), (0x3bb70db1e3b30ff6, 0x3f243d5898657a6f), (0xbb39f80469778551, 0xbeb5a39a94f2ad54), (0xbb5db472078111de, 0xbec70b18406146f7), (0x3af60534ae337487, 0x3e597607f9532274), (0xbad7032885ed6fc7, 0x3e604e788f4f63b9), (0xba876faf3495b1f5, 0xbdf2598919473e7e), (0xba64011e20bbe632, 0xbdef70154273be01), (0xba12fbde85806234, 0x3d81df5c1ca3869c), (0x3a11557ac79b4968, 0x3d75f5256665e918), (0xb96dc72056cbaf44, 0xbd091a176f7295bc), (0xb99ab0535f46bdf0, 0xbcf73cf989310b2c), (0x392f229ecb648d6b, 0x3c8a9f0a04e76a3b), (0x38dd6e9f2d0c2bf9, 0x3c7345b205781b7b), (0x38a22edb9f6d2f0c, 0xbc0611e4c0bc23e9), (0xb888702d77aa4448, 0xbbe9b88423f59f05), (0xb7df03c936a4e4a6, 0x3b7d637385b6b500), (0xb7f31f276ec1d4a1, 0x3b5c36bdc90c0d20), (0x37908786cc7f97a2, 0xbaf00eeea5fbf4a4), (0xb7521f3b34bd9065, 0xbac9e29e4e7fe131), (0xb6d9c8943eaa0627, 0x3a5d56f0d36bcfd3), (0x36cd064c8625bd4e, 0x3a3408faa535443a), (0xb66864ee592be672, 0xb9c8d8880a8fa4ae), ], ]; pxfm-0.1.23/src/bessel/y1_coeffs_taylor.rs000064400000000000000000001352711046102023000165540ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Taylor series for Y1 in extremums and zeros. Generated by SageMath: ```python mp.prec = 115 terms = 28 print(f"pub(crate) static Y1_COEFFS: [[(u64, u64); {terms}]; {len(y1_zeros)}] = [") def get_constant_term(poly, y): for term in poly.operands(): if term.is_constant(): return term def print_taylor_coeffs(poly, n): print("[") for i in range(0, n): coeff = poly[i] print_double_double("", RealField(115)(coeff)) # print(f"{double_to_hex(coeff)},") print("],") prev_zero = 0 for i in range(0, len(y1_zeros)): k_range = y1_zeros[i] range_diff = k_range - prev_zero x0 = mp.mpf(k_range) from mpmath import mp, bessely, taylor poly = taylor(lambda val: bessely(1, val), x0, terms) # print(poly) print_taylor_coeffs(poly, terms) prev_zero = y1_zeros[i] print("];") ``` */ pub(crate) static Y1_COEFFS: [[(u64, u64); 28]; 32] = [ [ (0x0000000000000000, 0x0000000000000000), (0xbc749367c4c05aaa, 0x3fe0aa48442f014b), (0xbc58e5288bbf5fe3, 0xbfbe56f82217b8f1), (0x3c45adcf3e0230ee, 0xbfa0d2af4e932386), (0xbc1aef581a20d1b6, 0xbf73a6dec37290aa), (0x3bea0fd3a3179817, 0x3f7e671c7d1196fd), (0x3bdbfdc1a54825cd, 0xbf65429dc5a45612), (0x3bf2b56b5db9ac40, 0x3f517ab4afac0735), (0x3bebebd87be68c3c, 0xbf40b2d877d5a29c), (0xbbcf3ef5ec675b9a, 0x3f2eea7bbb907646), (0xbbbc5481911cf1b3, 0xbf1c3fae3b0ad706), (0xbb97d87196deccbb, 0x3f09d174c9ccecd9), (0x3b9ce9bed2434862, 0xbef7956ad3fe9783), (0xbb81a3285733db7f, 0x3ee5865d11ebb14d), (0x3b7c0f8e48b356f0, 0xbed3a27f1fd4ac6e), (0xbb601bb903ea5d53, 0x3ec1e742c1cf6acb), (0xbb208185a8aebef4, 0xbeb051d134cb0a72), (0x3b2d22383a2945e9, 0x3e9dbea846629267), (0xbb2d0bd2365f955b, 0xbe8b1a1682f5eb1f), (0xbb17f54155dbfd8e, 0x3e78b0b08d8ccddf), (0x3b0c6ae86d8ad6fe, 0xbe667d8a7cc18981), (0xbaea87f82b9f7fa9, 0x3e547c0e174bc402), (0x3ae6655ff087a6b2, 0xbe42a7fb50d94c09), (0xba74f97124d12cda, 0x3e30fd661ade45f0), (0x3aad4c923a16d045, 0xbe1ef1655b283bca), (0x3aa6328133433e29, 0x3e0c2d21fe733c5f), (0xba292d7e82d617f2, 0xbdf9a7efb711afac), (0xba60d9e2266f470a, 0x3de75c3fc5194fe2), ], [ (0x3c3c696f3eb0ae77, 0x3fdaabb4011ed330), (0x0000000000000000, 0x0000000000000000), (0xbc682b7fe4dd90ef, 0xbfc8b45babe797ba), (0x3bf255e280edf040, 0x3f8e147099a6f0ea), (0xbbfea368c6887e7f, 0x3f88c5af1eeb2d6b), (0xbbca04ffe9904e56, 0xbf4133fa47da52e2), (0xbbd3086cde21e2cb, 0xbf3bf8af93ff0b8c), (0xbbafa9018f253e3c, 0x3f021d64be62ccf9), (0x3b3a4d52bc5a61e1, 0x3eb44d2ce67b2d18), (0xbb48016de8c47acb, 0x3eb14c3ab2ad79cc), (0x3b28724eeca6e146, 0xbe9b8eee52e1ce01), (0xbb184699c450d4ac, 0x3e7a85f1a878746a), (0xbaf5fb00f2f338b7, 0xbe5bf86b3c89849b), (0x3adf14ae65986334, 0x3e3f01920a1ecb6b), (0xbac5a8492238e17f, 0xbe20fac544c5a674), (0x3a972f86dd69da9b, 0x3e02818841d3a289), (0xba686f565d0da109, 0xbde42b5ceddd3872), (0x3a540c6129af60a6, 0x3dc5f9472a38633d), (0xba4276328d0b688c, 0xbda7ed484e6442ee), (0xba23ab0f9748db4a, 0x3d8a0b10351f65a6), (0x39d5b91f2ce320af, 0xbd6c567ba5000a2c), (0x39e0b587d390388d, 0x3d4ed39e06bafa8a), (0xb9ca4dd40bbdfa57, 0xbd30c36f7f68d190), (0xb9ae9f2d1d6c950e, 0x3d123a81488a8c60), (0x39796d1b53f4c705, 0xbcf3d198a043957c), (0xb97e66e460933260, 0x3cd58b80d1da3cb2), (0xb95de7856c390662, 0xbcb76b414bca83a9), (0x3923face03bca6a1, 0x3c99742311b12a8a), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c7b8d2a1c496808, 0xbfd5c7c556f0c19a), (0xbc370c18fffb661e, 0x3fa00b9f8571ca1f), (0xbc4e4289c3acba27, 0x3faa15d92dfe3e27), (0xbbf5a3591cb63f33, 0xbf710a329e2c23fa), (0xbc0511883ce39919, 0xbf61be6db9923acf), (0x3bcb8759d4a0e5cd, 0x3f2337c7e138f484), (0x3ba7299907aec5c4, 0x3f085b940eb607f9), (0xbb2063eb830ecaea, 0xbec80619147b78f2), (0xbb4468879e6c349e, 0xbea255e6cf70cf33), (0xbafc601de5ef1462, 0x3e5b62cd02014989), (0xbad6adc77b77235d, 0x3e380b1aac007d1d), (0x3a624f45defeeef1, 0xbdfa7ee05a568fe6), (0xba283df15edc8775, 0x3d84065ca5f23bb5), (0xba2c1a2ebca15779, 0xbd93847684c7da93), (0x3a08225b40e694f7, 0x3d74980895b5067a), (0xb9eed81f16f01fb8, 0xbd4c00f7d6be89d7), (0xb9a4e2f268d1912d, 0x3d2402fd58efd6fd), (0x399973b6338a6d0f, 0xbcfded82b76f72f2), (0x3978023c06cffc92, 0x3cd6380d6ba31980), (0xb94735a17d43c8d2, 0xbcb06b38ec70e0a6), (0x3907f71a9df6b85b, 0x3c88443f14394c1d), (0xb8f01075b123018b, 0xbc61ee2105252260), (0xb8b57669955b81a8, 0x3c3a7c72c37961bf), (0xb8954dc89e6e0348, 0xbc138e5e595f9137), (0xb87ee16a4e8bff5b, 0x3becdf0d22c4f792), (0xb86abb1732ed43be, 0xbbc54e9dcbced4f1), (0xb82e4e62e1a676d6, 0x3b9f718438e6ba2f), ], [ (0xbc583acf6511df31, 0xbfd36732d4b96094), (0x0000000000000000, 0x0000000000000000), (0xbc5b435291c33433, 0x3fc3001c8002caf8), (0x3c085153ba2c907f, 0xbf7bf5a03bab4999), (0x3c28d66c540219c4, 0xbf8751ea028c1953), (0x3be6d2f429037cfc, 0x3f423874cd8d0401), (0xbbb4d7b925522373, 0x3f364f6610d64939), (0xbb9920eb782e7608, 0xbef02978de3838b9), (0x3b66c8e5402ae5c0, 0xbed72f0766d0d591), (0x3b20b724f28fabb4, 0x3e8f2081874c7e33), (0xbafe89c3eab7b761, 0x3e6defd5dce00666), (0x3ab712e9adc751d5, 0xbe2205c6fe8f26fd), (0xba90a1fcff20092c, 0xbdfb6432e005a435), (0xba40d93a2f6bee54, 0x3db0289fce476883), (0xba2c7d1344d3ff23, 0x3d80778a2d37fe43), (0x39a7b4208bcbde0d, 0xbd29723fe5684800), (0xb9a84df62153f4f5, 0xbd082f3f70663f33), (0xb91998f4a32b0e4b, 0x3cc7a09f40ec7306), (0x39256931314bf68c, 0xbc85319ec342127c), (0x38fd4eda573e2499, 0x3c62d63483483be2), (0xb8a4a42a37750699, 0xbc38c3ecf9381019), (0x3893811d88a13751, 0x3c0ba15f09ca6382), (0xb8653a606cd73ccb, 0xbbdf92174ea83693), (0x385bcb6c1b8ec617, 0x3bb25604c3a40365), (0xb82168dd0f69d5f1, 0xbb853b55eb1a54fe), (0xb7e96fc33c8ede98, 0x3b5889d72e8200c6), (0xb7b3762a6112ab36, 0xbb2c5b6e1cc194ec), (0xb78614198a535866, 0x3b0061d24b95ed7a), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c61dc672a53c590, 0x3fd15f993fceab5c), (0xbc1455aa7db14f38, 0xbf902b3933cf21b1), (0x3c443ede64b782d9, 0xbfa6395dfe49fcd4), (0x3be10ad2b71b9820, 0x3f63ced2a2e69180), (0x3c0f30cad7e0ebe8, 0x3f607a678d6000bb), (0x3baf8fd02659f1ef, 0xbf1b50d7e1d32020), (0x3b91fb17827843f5, 0xbf06f7bab104f355), (0xbb60ab92724984c7, 0x3ec176e72bf94b8f), (0x3b31557f6e92a4a7, 0x3ea2becb2b6bbc6d), (0x3aea30e9dd0c4fab, 0xbe5a384eebfe1367), (0xbad27d53b702d9ee, 0xbe341e7a923c3a90), (0x3a8be8710ba9cded, 0x3de9e3284f5dd101), (0xba5a7ff332888842, 0x3dbec40b623ea350), (0x3a1bb0f2b7e06e32, 0xbd726868b83f8d7d), (0xb9d127448ae5dbb8, 0xbd416f7ae80cad77), (0xb98b4267f56d6b60, 0x3cf318658ecb9bd5), (0x394a28f7ccb2ac45, 0x3cbfacabdbabe483), (0xb8fdeb4ca08fc098, 0xbc713cc1f6930364), (0x38c8e1a7a7c446ff, 0xbc33cb94044d8aee), (0x3846a7a1323190de, 0x3bda22029099f534), (0x385ab5c5889916dc, 0x3bb47d9b88989e97), (0x381dfc385d309d52, 0xbb745299177606ed), (0x37def84f6911654b, 0x3b3503d9701ead82), (0x3757dbc183f5d86f, 0xbb08176b7514ca80), (0x3726e80a82be2e11, 0x3ad863cb123482cb), (0xb7400c9d5c314e72, 0xbaa6552586051784), (0xb6ed950d76fdf6bc, 0x3a74afbafce97c21), ], [ (0xbc64f19a2762f5ae, 0x3fd00ef3745e0e3c), (0x0000000000000000, 0x0000000000000000), (0xbc2a5ca3437ac1c3, 0xbfbfcdacdda138f2), (0x3c19a8e604f93931, 0x3f706cc34cd829fa), (0x3c01d3813b5701a3, 0x3f84641bb10c16cb), (0x3bbd08ac252b4932, 0xbf37fac943e2a16d), (0xbbd98c55ed55e5ec, 0xbf34769ed32e14a2), (0xbb8b665d8b88b73b, 0x3ee80608ecda1520), (0xbb7d207258864fea, 0x3ed5cc8242d77e79), (0x3b2f5c5f133a954a, 0xbe888c8f253923cc), (0xbb0d50fa8d8c7a72, 0xbe6ce5908c1f1376), (0x3abc19806933366e, 0x3e1ed1625825eeeb), (0x3a969b1553c1a884, 0x3dfa30d624f10edf), (0x3a41711a2b894301, 0xbdaa50765ef82dbe), (0x39ef8b9861fc6da9, 0xbd814cd364ef8287), (0xb9bec99ce5124af1, 0x3d306199db2399a2), (0x39a24cb0ca5a627f, 0x3d0164150f087360), (0xb90883d74ed9e2a1, 0xbcaefb1085d3b5a6), (0x390110bd90901ca7, 0xbc7ba1419f5a6f40), (0x389f7ac7f08169b1, 0x3c27638ccf29c1b0), (0xb89f51222b4b42bb, 0x3bf18a62dccdca9d), (0xb83b3be96059d0b4, 0xbb9b54a4a2d7343a), (0x38017f10a44ce3ed, 0xbb635931e0eacdee), (0x37be3118e01854ca, 0x3b1036817e50e3af), (0xb7657afa36f3f4a9, 0x3aca87e3e3debd9e), (0x36c384606510e7f7, 0xba44ec6558f8bb31), (0x36c308ed950cf583, 0xba4d684c0820785d), (0xb6acfa02e081161c, 0x3a0f0d58bca1c41b), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c54d14c77bc1691, 0xbfcdc14ea14e89f9), (0x3c2340bd04e7df4a, 0x3f84429fef5b5fbd), (0x3c4f19a8f5b1379e, 0x3fa367d7d608e4ba), (0xbbf4eb6bddef363a, 0xbf59d6eb2bc49e35), (0xbba2f121221c388c, 0xbf5dc4f991b3db86), (0x3bbf047b90425584, 0x3f1315ec04d6e6bc), (0x3b9087e84c57d2ad, 0x3f0571814a1aa301), (0x3b2795eb85278f1d, 0xbeba2977fa42f227), (0x3b3f92ddd9da4ad7, 0xbea1e86423086328), (0x3aff19e1c5d9e237, 0x3e54a7b82d41f690), (0xbad0197985af09ca, 0x3e3390660a1bb74c), (0x3a8a68e5322dab0d, 0xbde549e8b3ed12f4), (0x3a500e54fb5a85ec, 0xbdbe32cf77b347a3), (0xb9d3ea446c95f85a, 0x3d6eff58d55a39fb), (0x39d1c41d97727556, 0x3d415e5c0af749d4), (0x3994a6959d259d8b, 0xbcf0d67f939f4917), (0x3951f0d6f37c7a4e, 0xbcbef3f2afde9972), (0xb8ce371e6c4a5fb7, 0x3c6c60ed345061d2), (0xb8ce6598cd4716cf, 0x3c360519c76d6d8a), (0xb868ddc08c092699, 0xbbe324831e767061), (0x3820a7a0186edebf, 0xbba99201cd6f64ed), (0xb7d50b99e3cbd8ed, 0x3b55120660d9db07), (0x37bd05b3e6de1af6, 0x3b18d03fd947900e), (0x373b419f47dccb93, 0xbac397b2f45393ab), (0x371a75815e071b8c, 0xba840af84bf4566b), (0x36c253d300be5f73, 0x3a2d23b6405995b9), (0x365d14598eec4332, 0x39ee07cb3c4c18f5), ], [ (0xbc5a8046704071bd, 0xbfcc075da85beb4f), (0x0000000000000000, 0x0000000000000000), (0xbc53b0c30f3f6eaa, 0x3fbbdeb6ff9f55e1), (0x3bef54869c1812be, 0xbf661eefb74da882), (0xbc20492140a086db, 0xbf8229ea914b846e), (0xbbc9a664ae9a2c1e, 0x3f30cbcc6778fd37), (0xbbd8078d46437190, 0x3f32aa59f5091f7b), (0xbb7b81f3aff07289, 0xbee1c15d5251ae6a), (0x3b707e9f1d7b7e6a, 0xbed4583f15abd692), (0xbb2cc9b93ff3f6ce, 0x3e831d151a1284aa), (0x3b0aa58bdebda7d1, 0x3e6b74e57c226d3c), (0x3abe0f534111cac9, 0xbe19044f1378d3e4), (0xba92c7e898648f68, 0xbdf93b1ec7cafe33), (0x3a314e62ad0639ef, 0x3da61a4e89bf8438), (0x3a298cd71751f9aa, 0x3d80d430f7e78fff), (0xb9c643be1c5347dd, 0xbd2c3b0a8f7a7b0e), (0xb9608e40ab9aafb9, 0xbd010e773677ab43), (0x3946ed856edf6b25, 0x3cab59410f7e6f10), (0xb8e86e49965ef8df, 0x3c7b2e693f06a801), (0xb8bd6df9232d394a, 0xbc24d1b6b5dbdd8a), (0x389d45bfc9e28c95, 0xbbf17c6418e80b27), (0x38330cb81415d134, 0x3b999a3de4a881f9), (0x38014861b029a2c1, 0x3b628ca7ea60d3ed), (0x3763e7968eedb33e, 0xbb09f8cd292fbd53), (0xb772e1ee82abca63, 0xbad0840446d9db33), (0x36eac14fda382bcb, 0x3a7627f31e8af8f1), (0x36d03dd271f85894, 0x3a38fffe9d4c8a9c), (0x368992b4a1b37e32, 0xb9e006ef0777e888), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c57ba12cd0fc91f, 0x3fca7022be084d99), (0xbc17334559c5138c, 0xbf7c650b6b83109a), (0xbc4d0f8f36713120, 0xbfa163191c30aa62), (0x3bbcf7c95031f425, 0x3f526b045287ddca), (0xbbf7b71420f279ea, 0x3f5b17602840abf5), (0xbb99a95b35521d32, 0xbf0c0a9cee3c842a), (0xbb91505ce3b29a78, 0xbf03e398cbc472ea), (0x3b5125ae0677178c, 0x3eb3f35db1ff1b8e), (0xbb4e582cdfc5009b, 0x3ea0e9b612dbd385), (0x3ae57a34bc6cd52d, 0xbe5056babcd9632b), (0x3ad18fdd63164b8f, 0xbe32c1a8c8f963a5), (0xb9e37fef15ca364c, 0x3de161b6aa9fde63), (0xba4ed1a8c48bfaf3, 0x3dbd4caa1e0162bc), (0xba0907496979f354, 0xbd69fdda132e53b1), (0x39dc92d876d25063, 0xbd4101c31e1df223), (0xb980f5f389d54392, 0x3cecdc25a81e55f3), (0xb9476a7e07116985, 0x3cbe87025cca1380), (0x38f93a72b93872b3, 0xbc68c602211c7544), (0xb8dd598494fb4eb0, 0xbc35d4a3a29a7da9), (0x387e1025298516ea, 0x3be0f3be0d4b8ee0), (0x3829d1ee76262ed4, 0x3ba97a197d3cf12a), (0xb7f42ff2642fd193, 0xbb52f220fc5e4bf1), (0xb79a001d511e0971, 0xbb18bb200c3f6737), (0xb75720aadc56d8cc, 0x3ac1a0fc9e585d08), (0xb6f810019c65facf, 0x3a8449eb5d1ccd0b), (0x36c0524fdb6e5bf4, 0xba2bc209d14d289f), (0xb663781b8b017ac7, 0xb9ec816d53cd34ad), ], [ (0x3c518b0303bbe2f5, 0x3fc931a5a0ae5aa0), (0x0000000000000000, 0x0000000000000000), (0x3c348c3f5f957887, 0xbfb919c8a3f203fa), (0xbc0ef6b166c80aea, 0x3f602a38da6262a9), (0xbc207165718dd6e6, 0x3f807ced48910819), (0x3bc68f5ae1c2651e, 0xbf2900f33a00690a), (0xbbc8c05ccff0a4b4, 0xbf31278d46fd153c), (0xbb6f62aece58de7b, 0x3edb2595529cf1c7), (0xbb731bd5840756d7, 0x3ed2f7c2d608e0eb), (0xbb1f324b35355b3a, 0xbe7e212d2378b576), (0xbb005c49ab958b73, 0xbe69f3fcf3638b5a), (0xbab2a5d22fb87422, 0x3e144fbf0377cdfa), (0xba636fc80c961f59, 0x3df82268e83f4ed0), (0x3a40f5458ba7db6a, 0xbda26cc2b02dc737), (0x3a2ce24e6964787f, 0xbd80418bae8bbc48), (0x39b27ec279e7b798, 0x3d2812815e643e0a), (0x39a36cf3023b50ff, 0x3d009b2ac849ff66), (0x39133d4af08ad917, 0xbca7c55d0a6d0728), (0x38de47b036357356, 0xbc7aa167b939df6b), (0x3886507c635a91ef, 0x3c22645687164ddf), (0xb88b93b25f237a68, 0x3bf137648ca710a0), (0xb8159c0acc3fb928, 0xbb96ed64da2728ee), (0x37e7e2b02a3ea356, 0xbb62564f89aafafd), (0xb7a8f4b2647af4ab, 0x3b0789c5abd21586), (0xb7722d480745c160, 0x3ad05f7f4ebd3555), (0x37185f3d16f70670, 0xba7442d6813292c4), (0xb6d2d55a451fd98e, 0xba38df199441f62a), (0xb65428bef2d53556, 0x39ddaedad9d103ec), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc63db68c567283b, 0xbfc80781c32422e7), (0xbc1bf83906fd50c1, 0x3f754eda697a0098), (0x3c232419a9d405db, 0x3f9fbe6df840847f), (0x3bd5a76a98bd9674, 0xbf4be318d61276e1), (0xbbe633162d1131fe, 0xbf58efee4094379c), (0xbb4139e1a56d06b2, 0x3f059145b4f0e4de), (0x3b2db153b13f2cee, 0x3f0282d26a74c38e), (0x3b48c60f3e751263, 0xbeaf56c29d9ad959), (0xbb2ffef5e5f8ef91, 0xbe9fdd03174f902a), (0x3acf87aa0c95189d, 0x3e4a44a7907fee59), (0xbaded732eaed6428, 0x3e31df65332ab3e4), (0xba6ed0d6f75e03b2, 0xbddc96e9cf361a43), (0x3a2be09d928f0cb2, 0xbdbc3439f3fac67e), (0x3a0894702a4e04ba, 0x3d65d38ae50afdda), (0x39c847e4ec1195d0, 0x3d40833ea1f83461), (0xb9816bc0dd8ea673, 0xbce8afb70fb3c9e8), (0x395196a0917179fd, 0xbcbdda411e59ed8f), (0xb8c4610e8c50f3dd, 0x3c65889665db09a8), (0xb8d125a6e60383eb, 0x3c35792846a5c5e9), (0x38475c9e6c26184f, 0xbbdde1c2aac4bc04), (0xb834983a005c0922, 0xbba92deda741b574), (0xb7fd331deb45d073, 0x3b50e62611579a41), (0xb7b4d43c6fbeedae, 0x3b18898163cacd25), (0x37345581502d5210, 0xbabfc6f37553b483), (0xb72eac4aa67583bb, 0xba843147e449ee48), (0x36a768c097b2d633, 0x3a293dd77e784298), (0xb667f8f81d88a65c, 0x39ec7209a4872362), ], [ (0x3c559364e26d93ec, 0xbfc713fc51664c74), (0x0000000000000000, 0x0000000000000000), (0xbc488077fd102b67, 0x3fb7049760cde490), (0xbbff945ad3318fed, 0xbf58ef5f1cbe4874), (0x3c0b034f6fcde568, 0xbf7e5f53caf3bead), (0x3bcb16596420523c, 0x3f237b0b62ddadd1), (0xbb7411414067003c, 0x3f2fd3bac08286da), (0xbb66bf25df78108f, 0xbed5789803de3afe), (0xbb30f115b8c73e8d, 0xbed1c0faa89993b9), (0xbb1173613a4d69f6, 0x3e7845b49b0674ba), (0x3ada42fc2e50738e, 0x3e6886872801396c), (0x3a9cf261fcd9b5e3, 0xbe10b036779ac071), (0xba8ed0f2c9abc118, 0xbdf7049d18354c88), (0x3a3b53ce13beae6c, 0x3d9edd9d0fb2ebd2), (0x3a01c67e454c422c, 0x3d7f44600957fa58), (0xb9c8cf2dd5194971, 0xbd2486b1d6a91df8), (0x39a50688f914608c, 0xbd0016025abd20b4), (0x392da82dcfc4875f, 0x3ca498b3d1754fd7), (0xb9082f62c6ce39c5, 0x3c79f47baf518ec1), (0x38a6105821b4975c, 0xbc2029b685b728de), (0x389216a765538354, 0xbbf0ddbdab448097), (0x3830ae5354e24a65, 0x3b94667d2d37a045), (0x38016f3b498e4738, 0x3b620a8a21b80dcb), (0xb78daf501176b370, 0xbb052c2caec48eea), (0x377fe5ca7bc39984, 0xbad02a81f53376b9), (0xb714e540400d2a70, 0x3a7266275dfcd434), (0xb6a1501fbef1dde4, 0x3a38a1141391318a), (0x3672180bf6683e02, 0xb9db2e3c29487cd8), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc6d2f0105f3ce7c, 0x3fc62d94d97e859c), (0x3bd10ece6e29b084, 0xbf70bf614807033c), (0xbc37013075a066f9, 0xbf9d5f857a2a6107), (0x3be49380eb03f78d, 0x3f46081b0b7fe572), (0x3bfce3676d17b40c, 0x3f57307b03e248f8), (0xbbabc5fb92b99e67, 0xbf0132c0aa83d0dc), (0x3b962d899f08a704, 0xbf0154ed4598d2f0), (0x3b436681f34b2420, 0x3ea94f64f476e615), (0xbb2a69d5b51b6d77, 0x3e9e12725853a9fb), (0x3aec161d9909f167, 0xbe4588c758dfc8ab), (0xbade3ba8f2d73fb0, 0xbe31021cdd9b5f7f), (0x3a7b80d7aefb24c5, 0x3dd7cfa7a6c26b53), (0xba5b73dd1f1185ae, 0x3dbb0e011d23f5e3), (0x3a0a3aee2b581931, 0xbd6276cc0fa65a6a), (0xb9d2974c386cdc2a, 0xbd3fe92f0882b440), (0xb982bfc89a29ddc4, 0x3ce53126d86bf487), (0xb94dd068a7b1e2e7, 0x3cbd07f6c1993c8c), (0xb8fb38430712c4a6, 0xbc62bc249a86f7c9), (0xb8d065bd6a2ed972, 0xbc34ffb4f0789e1c), (0xb854136ccbc577a4, 0x3bda504d6417aae1), (0xb84be408189a39ee, 0x3ba8bd8d3bf76896), (0x37eab1c3ced9a78a, 0xbb4e157fb142efc6), (0x37a40d8e8cc67990, 0xbb1834ef259f93cb), (0xb75167300d24b2f1, 0x3abc8e7b497b27c6), (0x36d98f27f9bf4556, 0x3a83fd162f3a5584), (0x36c5a4266d838510, 0xba26e0585c2f983a), (0x366678ba75bc0bf4, 0xb9ec3d3ba73f49c5), ], [ (0xbc5b858aeca267e1, 0x3fc56b97f8091ac5), (0x0000000000000000, 0x0000000000000000), (0xbc21d2a41bfc4c1d, 0xbfb560fcc8c08469), (0xbbe6529450b1ff0b, 0x3f53fafa39618883), (0xbc1ad54776e42e6f, 0x3f7c49141623372f), (0x3bb39ecd4785a672, 0xbf1f69980694fd17), (0x3bcc2a33b89df073, 0xbf2dc5f848aa9d34), (0xbb7ed412867be695, 0x3ed178fc979b77bd), (0x3b73a93300f0b087, 0x3ed0b494a4bafcc7), (0xbb1a1471efd3f084, 0xbe73fc3884c2743a), (0x3b0b5eabaa159e81, 0xbe673afb9fb4d844), (0xbaa47c72ef2556f3, 0x3e0bd90346a3e0ed), (0xba99f08140c074ed, 0x3df5f3bafb215b44), (0x3a2ab2b535dc2fdf, 0xbd9a1c27c37569c8), (0xba09f88e2bb9d462, 0xbd7e0455dbf9cc4f), (0xb9cdb0302c98b2dd, 0x3d2199b19fcacda0), (0x39851865cfbaca3e, 0x3cff1334609dc3bd), (0xb8c2cd00a5fcb440, 0xbca1e37265d5ce04), (0x38c8d0340828b4e4, 0xbc79353f1aee0a50), (0xb897b28613de5d51, 0x3c1c68e4abc12011), (0x388b3ab1625e378c, 0x3bf075c553243bdb), (0xb82923cf876dbeab, 0xbb921f6f50442923), (0xb80ef47dee3f5afd, 0xbb61ae48340c53aa), (0x37a8614c654ed794, 0x3b02fdf33e2b9584), (0x376126c601c703f9, 0x3acfcd13a6548328), (0x371d5986e5068b9e, 0xba70a5f4affbe604), (0x36c041d0dc32e320, 0xba384ccca4432680), (0xb652e0a78e43b84d, 0x39d8c95636d09811), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc5e9088e9ff2518, 0xbfc4b2a38f1ab9b4), (0x3bf658189763e4b9, 0x3f6b3878aadeb34d), (0xbc3525fe797e2126, 0x3f9b750d89a9b35f), (0x3bb2c48be700f9e6, 0xbf41f6911725a956), (0xbbed0a355d52c196, 0xbf55beee6fd51c8a), (0xbb8079c92f6ce1f4, 0x3efc3625d7a65089), (0xbba1cffb5ca00bc2, 0x3f005375a588a72b), (0xbb398a011960416e, 0xbea4ee5e4e7cb18b), (0xbb2804ad812748e6, 0xbe9c7b3d81b5ff94), (0x3aea91d5277c5345, 0x3e41fce14f48518c), (0xbadb70b3ae1d3fb1, 0x3e30346643c9d86e), (0xba7397dad107b33b, 0xbdd41c861bc1c34b), (0xba5410a8098eafad, 0xbdb9eeda214eabbe), (0x39f8372842605aa2, 0x3d5f8cf277ce6338), (0xb9de510926654c46, 0x3d3ec46e14cd5d9e), (0xb962703fb3cb397d, 0xbce2500181b463c7), (0xb95b2c04b73484a3, 0xbcbc24c2b350e45a), (0x3888f6781f273b56, 0x3c605d9c149f1b8a), (0x38d31e5cc968c925, 0x3c34752e1249314b), (0x387b7657eab8f7e8, 0xbbd73842b12b31ea), (0xb846e57a01049463, 0xbba83594fd823055), (0xb7e962546fd68b46, 0x3b4acb92f062a2fd), (0x37beb28a448a691b, 0x3b17c779242729e1), (0xb7536df5c047d7ba, 0xbab9a6de3d6e1877), (0x36e0ce403e109088, 0xba83b3c68747091c), (0x36bd2b9ab8c7eb26, 0x3a24b55c31763430), (0x36831011a1450327, 0x39ebeab3c6cb6a58), ], [ (0xbc4d00ae4313eed0, 0xbfc413644356a52b), (0x0000000000000000, 0x0000000000000000), (0x3c2e7840863e7c03, 0x3fb40bb88c6f2b85), (0x3bd5631193c7aba5, 0xbf5078d13cfc400e), (0x3c1a406bffcdbe35, 0xbf7a9191262ab9d5), (0x3bbe2809cb431b0a, 0x3f1a005297618f35), (0x3bc92fd90e2b1396, 0x3f2c0cbad847a60e), (0x3b6faeaea4946f0f, 0xbecd1a72e7c35fd8), (0x3b6a2e571e6832b0, 0xbecf9a2654099c40), (0x3b14a1a09cd63457, 0x3e70c6b06e20fcbe), (0xbb08c15da7295060, 0x3e66136d6425ea74), (0xbaa9c15db46970d1, 0xbe07977677c6badc), (0x3a91f266c960af6f, 0xbdf4f77b3143a31f), (0xba2ade992d25ffbb, 0x3d965720b0a36de3), (0x3a0635bc57fc436d, 0x3d7cd126dc5db8d4), (0x39b0b42ceb8837b9, 0xbd1e6d575a54f608), (0x399c1abf000da8a7, 0xbcfdfb4d0beacd2f), (0x3926e0efc20cf902, 0x3c9f3cccbe3a6b08), (0xb90208f2daceba75, 0x3c786f5c7a82aa3d), (0xb890e01b243ac14b, 0xbc190b8ec99be279), (0x386588585f7010ee, 0xbbf0061c1563865c), (0x3839090c97be6541, 0x3b901f2cce387f59), (0xb808c405323747f4, 0x3b61476b2aa5f9cd), (0x37aa73fdd9180681, 0xbb010995cf568203), (0x376999ab5e964dc7, 0xbacf2f8eadcda35c), (0xb6eef0a26c086d84, 0x3a6e19ecc98ab1c0), (0x36cbb3d7e3e4912f, 0x3a37e713fd44413e), (0x367917d21157a7a9, 0xb9d6910a2ab8996f), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c4997782859a00d, 0x3fc37aaceac987b9), (0xbc09de167b0f4e45, 0xbf66afe4fe0bc0f7), (0xbc3d91e80a0529b8, 0xbf99de7a33bc3a97), (0x3bdacaad4f266959, 0x3f3e024f567ac487), (0xbbf5aee36a6b58af, 0x3f548843c426abe0), (0xbb8ed7ac2e5eef51, 0xbef7a8e14711c0f5), (0x3b9b3675770103a2, 0xbefeeceb341ad833), (0xbb4d96e3726387e9, 0x3ea1a743e05b39ca), (0xbb36e8969001b255, 0x3e9b143d39c90dd5), (0xbad319f8c4237007, 0xbe3e8e00012321d3), (0x3aae89c8a788cf46, 0xbe2ef28e323e7496), (0x3a7f30cb64f4f0d2, 0x3dd137a1bf5bde2c), (0x3a5bf7dee3b649de, 0x3db8e087c7cb7f1d), (0x39fb7806a5d33650, 0xbd5b3dc9dd36d846), (0xb9c8eb799dd68c33, 0xbd3da6ae03deea14), (0x394156b16e9a68f1, 0x3cdfe64e83599736), (0xb93c20b358422ecc, 0x3cbb3e899a8275b8), (0x38e23edcbf53670c, 0xbc5cc15471c3a791), (0x38d6153c40fa8364, 0xbc33e34956740ffd), (0x387da1d09b7c1150, 0x3bd491cabcac2ce3), (0xb84c9d6b2a07c067, 0x3ba7a07e1fc0dd64), (0x37bbd51dd0af2201, 0xbb47ecb9d1547f7f), (0x37bc94c2359a7968, 0xbb174a2cfb1be55e), (0x375ec790d520dd3c, 0x3ab712c909b7eb19), (0x3721fa30708a2d3f, 0x3a835bca00a6162a), (0xb6b4073920a6f8c9, 0xba22c13871e75a28), (0x368fbab0e8ced2dd, 0xb9eb82223e5c0791), ], [ (0x3c4f123683cf20a8, 0x3fc2f4e70d6c7e01), (0x0000000000000000, 0x0000000000000000), (0xbc5702b97938a87e, 0xbfb2ef24d6f7526a), (0x3be17c9efd9928a1, 0x3f4bc33c9dc6ec82), (0xbc153a673a682d1a, 0x3f7920414ee2acbe), (0xbba8c8602e5501dd, 0xbf15f9173916a219), (0xbbbd01332ea23750, 0xbf2a94fdbdcec471), (0xbb6340ead67ee8d4, 0x3ec8b309990f950c), (0x3b62bfaf2a2bd5b2, 0x3ece087ff4517c02), (0x3b05bdd16bb39ef5, 0xbe6ca22ab12cb4b7), (0x3ad4981496e99ee8, 0xbe650d1f28635cda), (0x3aac3cc89e59b451, 0x3e04441552e259a7), (0xba95d08c5f0c93c3, 0x3df411b8a8258957), (0xb9eff3ddb842e46e, 0xbd9354e914c31b45), (0x3a11319e6211da5e, 0xbd7bb16f111ebae7), (0x39af5cff5d440351, 0x3d1a888536e27439), (0xb9967f728b3f0a85, 0x3cfced726c1026c9), (0x39328206ff6f6ec6, 0xbc9b745d75ff6377), (0xb91cb1d8bb8b1e84, 0xbc77aaea63220bec), (0xb8b1d26bdb3cb23f, 0x3c162ef6548b0ef1), (0xb85086d51f21de1e, 0x3bef27eac447efa0), (0xb81b0359e4922880, 0xbb8cc635a651ed03), (0xb7c265c1a580ae14, 0xbb60db1d9fbb3868), (0x379bfffc557e0311, 0x3afea050ba5a6c00), (0xb7616b89acbe6940, 0x3ace84aeda9b4b7b), (0xb690317b7234e3f2, 0xba6b3ca6e927e7ca), (0xb6d96744c0e38388, 0xba37754b584db1b4), (0xb67873c14331a4ce, 0x39d48c23ea283d56), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c6b7326e3fbaa70, 0xbfc2740819f1caaa), (0xbbad91d196951b1e, 0x3f6349369dc780bb), (0x3c211249d3675d98, 0x3f98868d7401bf2e), (0x3bab901426ad555e, 0xbf398cd1bebe1445), (0x3b8e845cf46e9c36, 0xbf537eef9aadeee2), (0xbb978bd7232789d5, 0x3ef43394c95b2d2b), (0x3b98d34686b724d9, 0x3efd6dfcdb026028), (0xbb39039620a1668b, 0xbe9e448fbc8a1f43), (0x3b1ab8335f5b2e44, 0xbe99d764ee07c839), (0xbad24a385ba857b8, 0x3e3a53958c8d74ff), (0x3aae692fcd7541f7, 0x3e2da0e1c8a08d37), (0xba682664a5ef0aa2, 0xbdcdd7f918de776f), (0xba55452efda66af5, 0xbdb7e68037d5c861), (0x39e92d13e5b8bdbb, 0x3d57c2e63bbe27ca), (0xb9b76fb98c811c8b, 0x3d3c973a175ffbb6), (0x3961655ae92c79f4, 0xbcdc033788921736), (0xb93459b0496214b2, 0xbcba5d9f2bdd8af3), (0xb8c9fbdcd265117f, 0x3c596cb946e78db0), (0x38ca3b3e172d732c, 0x3c335090afbe104f), (0xb87ce7df25d16bb8, 0xbbd24f9089431e12), (0x38470e95a1733e58, 0xbba7060105333e1d), (0x37e148c26a9d2e03, 0x3b457032c08fa72b), (0xb7bcc5adf699f555, 0x3b16c43d570a329d), (0xb7472f3277e653fc, 0xbab4ce5eeb2252e9), (0xb72e4e66be44e7f5, 0xba82fa99d3f60727), (0xb6c49cda263bbcc6, 0x3a21035a54fa4f71), (0xb682adf1bab34466, 0x39eb0a7a1202f74d), ], [ (0x3c34f78a7cfd8a8a, 0xbfc20198200b699d), (0x0000000000000000, 0x0000000000000000), (0x3c1ede75d6e0c0b0, 0x3fb1fd242a74e630), (0x3be31a446a0673c4, 0xbf47cf261dfbf19a), (0xbc0b11e38b0823f1, 0xbf77e4820ec1dde4), (0xbbbbba7e6db23817, 0x3f12e1bd281dfcbb), (0x3bc48aed48d0a248, 0x3f2950bb06c6fdf9), (0x3b5f50566d2c2881, 0xbec54a38ab6af546), (0xbb69fdc0d6c27c0b, 0xbecca94f38024fdc), (0xbaf76dde5144d48d, 0x3e68c7e75971c85c), (0xbb0678751b2ddc2c, 0x3e6423fc7e251ca9), (0x3aab4294ffe166f7, 0xbe019fe1d8e51b96), (0xba976b836ebd0291, 0xbdf34198c795142c), (0x3a1b6fa7e1df9192, 0x3d90e78cdab26dd9), (0xba1a2a34bc1f8645, 0x3d7aa74cb5ba4b0e), (0xb9a65f2dd9b4219b, 0xbd1756ee8369797d), (0xb98cae4f94465269, 0xbcfbee3ccbac62a4), (0xb93edac05af99c66, 0x3c984c93627c1364), (0x39192f873368f6f8, 0x3c76ecd2977e750f), (0x3893a3df310cde1b, 0xbc13c1ad2197e738), (0xb83e79b62fc45f90, 0xbbee45c9096ecdab), (0x3808f4906192c428, 0x3b89c8e8d1127213), (0xb7d635517d589b2c, 0x3b606d492670f0ba), (0xb772bd51822a155e, 0xbafb9c058bf87bc8), (0xb755af5326fb8ade, 0xbacdd33a39371327), (0xb6fa0c8a817bd238, 0x3a68b21edf0d733b), (0x36ce1e27351bb092, 0x3a36fc3cd1a4c613), (0xb678b7b2ca8c7003, 0xb9d2bb8db2dfce26), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc4081c2a50ad27b, 0x3fc192f2627a74e3), (0x3c06268e5916da13, 0xbf60a846a83fecf2), (0xbc1be434e30d7a64, 0xbf975eceaabf7f86), (0x3bbc2d7f1eb14a8d, 0x3f3617c581be35b1), (0xbbb0beeca29a2b7c, 0x3f529934b7a84483), (0xbb91b58b66aaaf71, 0xbef18123e875188a), (0x3b94740ce7aaa9f5, 0xbefc1f05a2d85165), (0xbb3fd873b639f93b, 0x3e9a4e0bc0926545), (0xbb233d21389cb3a0, 0x3e98be81ad44d933), (0xbabb1f9cab4acd40, 0xbe36f73795e25c01), (0x3ababafdeab2d269, 0xbe2c70ab158cd19a), (0x3a5796ce7385bd76, 0x3dca262190472d9a), (0x3a444e202e2ab843, 0x3db70112aab52bc2), (0xb9f5bd722355d797, 0xbd54ec163f88c02f), (0x39d5477d64dc86b2, 0xbd3b991575a9daff), (0x39314b432a7313b8, 0x3cd8cbabadfd45c5), (0xb953683d210d31e2, 0x3cb9867f1ea8526f), (0x38f1cbbb05b76a2a, 0xbc56a0c58ce9652e), (0x38dd3e4ed9b9011d, 0xbc32c10fa17839d7), (0x387159e93c92ec73, 0x3bd06304545a75ab), (0x3831184208b9509c, 0x3ba66b5f3f801768), (0xb7bf7ef3af29f9f4, 0xbb434a75e18850f7), (0xb7b72f867bfa08f9, 0xbb163af2240f11d6), (0x374e71e41ce0bd04, 0x3ab2d27f5aad2f87), (0xb70e338eb53b4d25, 0x3a82947c379d043b), (0xb6a879620ef8dcbc, 0xba1ef0cd1e11d5d6), (0xb68cfba8dcf4726a, 0xb9ea897622f547ac), ], [ (0x3c68f71f103b6bf8, 0x3fc12f9870d68e18), (0x0000000000000000, 0x0000000000000000), (0xbc5fd0d25668ad6b, 0xbfb12c11811945f9), (0x3bebc70ffc015b97, 0x3f44b638f21f0f76), (0x3c1bc10a4e0506fd, 0x3f76d2a897d58353), (0x3ba5de76c7b42be1, 0xbf10732e5458ba20), (0x3bcfca03362738f1, 0xbf2835929300df3f), (0x3b4992f62f113a88, 0x3ec297283816a83b), (0xbb50d6dea529ee4f, 0x3ecb73adedf11a43), (0xbb0dce80931068a0, 0xbe65b455b903f09c), (0x3b029572874fb52c, 0xbe6353f0797a6699), (0xba8bf23ef2ca5a38, 0x3dfefc9ac17b1eeb), (0xba878bfeeecafab3, 0x3df28535463ce067), (0xba096b62f6b59354, 0xbd8dd894cbbee3f9), (0xba0f655d10343892, 0xbd79b288cc392b5b), (0x3986335c7e33b227, 0x3d14b2ec9ace070c), (0xb998edce804ba0e3, 0x3cfaff72f6057832), (0xb936e4ec62dfa238, 0xbc95a7bfada02748), (0x39060aebd6f74bda, 0xbc7637b7b45ad224), (0x38b5e34b545164b0, 0x3c11b216f1fba65d), (0x387400818419c16a, 0x3bed6a4aa25cbcad), (0x38222d3819e4ad1c, 0xbb873661259c7b49), (0xb7c47385cbfe72a2, 0xbb6000a243c0a825), (0x3790aa941ed924d2, 0x3af8faeb08a0872d), (0x374285ea5fb533a8, 0x3acd2042259aeb3b), (0xb70ef65d241a95c5, 0xba66742de4a4a980), (0xb6dbeb8e3fb1ee6a, 0xba367fbd4af52810), (0xb666550a2bc73761, 0x39d11cea7748dd35), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c60c06e2860e868, 0xbfc0cf3ee98f769b), (0xbbfc2c390327e0f7, 0x3f5d26e7af251f79), (0xbc394225ed089995, 0x3f965d05948a946a), (0xbbcb3460aae30c17, 0xbf335959b8482e40), (0xbbf744279fabe84a, 0xbf51cff175d05c2a), (0xbb83714c1d2b4ff3, 0x3eeeb59416879106), (0xbb89158b4542d2c4, 0x3efaf7544eeac766), (0x3b284917e9900e02, 0xbe9720522bb1fc81), (0xbb31671693e842ab, 0xbe97c41261705419), (0x3a886ab60cf89699, 0x3e343fa0ea5e007d), (0xbab8f90fa25a8f71, 0x3e2b5e23abebd7a4), (0x3a64e5cdf3a099a5, 0xbdc722397e750312), (0xba51768b235cacdf, 0xbdb62f2174e6be49), (0xb9fb8faac380f50e, 0x3d5294ab060a163a), (0xb9de9b0cd3f3a20f, 0x3d3aace944141c61), (0xb96472a1bdce3160, 0xbcd61cc8146cdfa2), (0xb9583fcfac500424, 0xbcb8bb3c270a284c), (0xb8f56040266e6114, 0x3c54449d96647c28), (0xb8c4997de83d7967, 0x3c323712fdd32979), (0xb84d0513eb7ddb33, 0xbbcd7cedd05f23ee), (0xb8138c0b1312b9f5, 0xbba5d3f2f4d18257), (0xb7d6343b2af8488e, 0x3b416f9a8cd62e2d), (0xb7b741512b4836ab, 0x3b15b1f1d821a3b4), (0x375de94b9017c7ec, 0xbab116d887db5467), (0xb720b9ee354d1861, 0xba822c96cd78a74c), (0xb6b7416d012e04a4, 0x3a1c3754078e6137), (0x3688b4af62f8f0ae, 0x39ea0388f41538a5), ], [ (0xbc6742aa46ea9b31, 0xbfc077eede4a0d89), (0x0000000000000000, 0x0000000000000000), (0x3c3cabc5883fc763, 0x3fb0751548b2924d), (0x3bd8c3b817f5bd1a, 0xbf423b5d46a73864), (0x3c1e7b0b0210cbce, 0xbf75e2467c8fb832), (0xbb9abdc3996174ac, 0x3f0cfe5c189d6e4d), (0xbbcf4c0c63a8394c, 0x3f273bbd8c7aef2d), (0x3b6d9272577eb6ff, 0xbec06974d3d04287), (0xbb56fb637949537f, 0xbeca6081d36e6a2b), (0xbaee9b9b25b5c745, 0x3e6334a83cf6092b), (0xbb0e3539c19e4313, 0x3e6299571cb4e1fb), (0xba80b2cd2f45d38c, 0xbdfb7f5bc0aada50), (0xba81831c37e0afc0, 0xbdf1da63b4d6f878), (0xba03f6e20cbba970, 0x3d8a9288ceccd9f2), (0x3a17055344e86eaa, 0x3d78d1d74c88ee4c), (0x39a439e54f23f947, 0xbd127eed3a482d7f), (0xb9766b420f9bcda0, 0xbcfa2143706ccb79), (0x3933ce1edc9f0854, 0x3c936d1464c4bf11), (0x3907d2e3e5d4bfa8, 0x3c758cc3ad07daa3), (0xb89bcc0a4f099447, 0xbc0fe0c8ce969c5e), (0x38838ca595ab732b, 0xbbec97f785528e08), (0x3821507942984ee9, 0x3b84fee6252fe140), (0xb7df46f0f7734483, 0x3b5f2dcbce169f1a), (0x379086aaae683dab, 0xbaf6b095bc2831d4), (0xb76de10fe678bda7, 0xbacc6f522af04f90), (0xb703ee192a62f4f4, 0x3a647af3c1c3a557), (0x36d76dc7bb35ad50, 0x3a3602a9d860d2a3), (0xb66b7ac21c3ed2e5, 0xb9cf58721d5d6786), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c61166b7995967a, 0x3fc0230ba90f2871), (0x3bfb746b17280b83, 0xbf59ca16f0c9734e), (0xbc375b99fcae0fa4, 0xbf9579c1bdbcfc99), (0x3bc1259c7efa1ad5, 0x3f3120ecfac5c017), (0xbbd35a76e06cda58, 0x3f511dd26bbe2946), (0x3b72ed405d5bc473, 0xbeeb37e7c9a57149), (0xbb86e93d7c515f0c, 0xbef9f01e7c1909a0), (0xbb2f562d62e60e11, 0x3e94887fe7a88c2c), (0xbad010f87629f8e9, 0x3e96e37238841d4b), (0xba99b7f19b7b3b20, 0xbe3204b644d6a04b), (0xbacc8fcda8a1a29b, 0xbe2a659b13eebf8a), (0x3a42b743f24d4d7e, 0x3dc4a40c87601c97), (0xba577207717e09cd, 0x3db56f0250e4fcac), (0xb9f8225d38237f55, 0xbd50a1011bf4a7dd), (0x39d5262f16494ab9, 0xbd39d22a6dc5a57c), (0x397bb4017d6e9239, 0x3cd3db0f19da31da), (0x392600d1fe84f91f, 0x3cb7fc7d4070961b), (0xb8c183aaceabe7cd, 0xbc5243aa7bbc81ca), (0x38c5abd4abae47a9, 0xbc31b3c3dd0d783d), (0xb86b0ca32f2b28ba, 0x3bcaabdcaba1878d), (0xb83fe00611a5322d, 0x3ba541bb402b78f0), (0xb7d85111e57bb4b2, 0xbb3fa915cdaddb2d), (0xb798d2801af024f8, 0xbb152ba16ad63ba9), (0xb7344e83ea6e82fc, 0x3aaf26322e6939a3), (0x36eecf18659e6ff5, 0x3a81c51fa64eb3db), (0x36ba22c423e879e5, 0xba19d00760b94df4), (0xb6523572ecb98917, 0xb9e97bff11d536c1), ], [ (0xbc446154ab44acb3, 0x3fbfab0b166d23d8), (0x0000000000000000, 0x0000000000000000), (0x3c4290cc8b89531c, 0xbfafa65c1ce7ebd6), (0x3be9bdd7d19e67a3, 0x3f4035bf503ffc1f), (0x3be801473cc85f32, 0x3f750d1b04713c41), (0x3babe22a416a82d0, 0xbf09cd14a92842a2), (0x3bca868e6f4e4828, 0xbf265d504af5d8fe), (0x3b5814b5b963313b, 0x3ebd3feeb33d9cee), (0xbb4c05f6b4f39a25, 0x3ec96a257062f76e), (0x3b0b04fde272af41, 0xbe61254f302b36b2), (0x3ad771b26251f405, 0xbe61f11585e04fca), (0x3a8b3d53767b22ba, 0x3df89a7674dd98cd), (0x3a7b6db02fadeed1, 0x3df13f0ba48c1692), (0x3a248f4db1fc6761, 0xbd87d67b47fd268e), (0x3a0a84c861831984, 0xbd780381812ad9b0), (0xb98981455f0897cf, 0x3d10a41213b1209a), (0xb98573618414b59a, 0x3cf9530714f8af8a), (0x393f79d60d660532, 0xbc918884a9ff4796), (0x3912da336a20734e, 0xbc74ec3ce9f29027), (0x3896c9321058ffc6, 0x3c0cde4ce08c6119), (0x38894686518435ab, 0x3bebd00bdae20153), (0x37ff64113a65f339, 0xbb831454d0bd6f49), (0x37e88cc5762134d4, 0xbb5e623854cff634), (0x3793b39a55f6f728, 0x3af4b117674c743f), (0xb76c32187c451ad3, 0x3acbc2c0ede2286c), (0xb7077e3bc9fbf218, 0xba62be3ca56b47a4), (0x36dcde9bceca3e29, 0xba35870a752de79f), (0x361b91f4f1f1a50f, 0x39ccc9aaaa2d7785), ], [ (0x0000000000000000, 0x0000000000000000), (0x3c50db2c50623ec0, 0xbfbf13fb0c0e6fcd), (0x3bf63fd50ee5b7c3, 0x3f5706ed3d935d00), (0x3c3a7c91ef9a7da1, 0x3f94af74cbd77bef), (0xbbac31e3b8ee4b9e, 0xbf2e9a9e66e5a792), (0x3bf35ae9733a6eb6, 0xbf507ec9ed824fcb), (0xbb4a1610320898f4, 0x3ee856d4518ab29e), (0xbb9af9c37c81d002, 0x3ef9040de830649e), (0x3af6ec0adcce1274, 0xbe9262f69c56c652), (0xbb34da0db90f5974, 0xbe9618c94a54734d), (0x3acfc6bc581d66ff, 0x3e3029d2c8bf70d6), (0x3ab60f30da5c2b13, 0x3e2983bca0a3e67c), (0x3a60395605657e5e, 0xbdc28e2a00002a82), (0xba51c639ac25ee1a, 0xbdb4beeacafc4fad), (0x39ed7df744a0b21a, 0x3d4df880e37a5060), (0x39d1f98cd4e6ac14, 0x3d3907be43054aec), (0xb95bcb238e3393c6, 0xbcd1f10ff685083d), (0xb948ad06b5e0f6af, 0xbcb74a1dc71abca4), (0xb8f9b8f70559bd9a, 0x3c508d41117c93a5), (0xb8b35b059841e08e, 0x3c313795880a7796), (0x3865f51a8e31e18f, 0xbbc83ea1cebb3c84), (0x3838606560ae8152, 0xbba4b5cc8ded02e2), (0xb7df776dd1580636, 0x3b3cdf002471ce45), (0x37b71f6e27bbe64e, 0x3b14a97cafad6c19), (0x374d40fd5c1285de, 0xbaac7f1793e7126e), (0xb6f7da220c547e42, 0xba815f93ab822e98), (0xb6a0911cfb822772, 0x3a17b0d93bc7bbc8), (0xb6846b70143e3a42, 0x39e8f533a6e89c51), ], [ (0xbc5bf01bf61d8ed3, 0xbfbe891b327da16d), (0x0000000000000000, 0x0000000000000000), (0xbc3636379e4f582e, 0x3fae8533ce07bdb8), (0x3bc53b9dd0e187fa, 0xbf3d1253218e31b0), (0xbc1eae521e3467c6, 0xbf744e6826476498), (0xbb6864ec60e7a724, 0x3f07271a9b5e3cb4), (0x3bace83941ef46ea, 0x3f2595b697c8ec04), (0xbb5f57ab96615e4a, 0xbeba46b03ecb38cc), (0xbb4dc38fda916c56, 0xbec88c173e07621e), (0x3add237c79a7a74d, 0x3e5ed9b1754fbd3c), (0xbb0d6748ba8d2dd7, 0x3e615891ef314e18), (0x3a8caeca005426a6, 0xbdf62ca352cf904e), (0x3a7916c3c0550fc0, 0xbdf0b14767c2b010), (0x3a25951d764f773e, 0x3d85879bb4a2a8ac), (0xb9f96759cfddd4b5, 0x3d7745bbca5b0e82), (0xb99c649f85048056, 0xbd0e21736ab8469f), (0x399387632a0c4eab, 0xbcf893b256068d4e), (0x39225636fb1c995b, 0x3c8fd42c80d0363c), (0xb919336e177a135c, 0x3c7455e80611a38d), (0xb894f0ece16e6c03, 0xbc0a4682da825109), (0x388f20cb0640e817, 0xbbeb12f0bb38aa78), (0xb7ff5df786b91715, 0x3b816a7f586e7ed5), (0xb7ff8ddcae160d2a, 0x3b5d9fa09d2f4601), (0xb7808a35f4fc1e15, 0xbaf2f1ad1590d095), (0x373f1307c6b6dcfd, 0xbacb1c0038406c42), (0x36f40bb96d08f57f, 0x3a61363c85b6c4db), (0x36cb8e8704706c26, 0x3a350e3e866a311e), (0xb666cdfdf4125dc0, 0xb9ca841b08aca0a3), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc3b9f1d130797af, 0x3fbe018dac1c17e3), (0x3be072789a66cf0c, 0xbf54b994dd05c1fb), (0xbc338b4f0d3a4111, 0xbf93f9e0db07e7ef), (0xbb9a899561323713, 0x3f2b8e55b75b13ab), (0xbbd251fa83bbf98d, 0x3f4fdf68a78bb3d2), (0xbb783beff5b1db62, 0xbee5ee9d17106a08), (0x3b70935ad53575b8, 0xbef82ee6dfdfedeb), (0xbb36eeb8b4341708, 0x3e90962d7f6d61a6), (0x3b3ddb699c127f13, 0x3e9560edce7d682d), (0xbaadbe6f075c9b8e, 0xbe2d34381d02bdbe), (0xbab5faefe806c858, 0xbe28b5a0e74ae0d3), (0xba651c26d41110d4, 0x3dc0cab953f05720), (0xba4cdfa2ed9741f0, 0x3db41d21c68d7ed3), (0x39efbfd30004913c, 0xbd4b2d2dd7cb3c52), (0xb9d97fd3cf0000fa, 0xbd384c5369d2e33d), (0x3968bd8125247874, 0x3cd04e17ab25ece9), (0xb928ec3a9bb7352b, 0x3cb6a38e0aef9402), (0x38ed2d1073a2c3f0, 0xbc4e28099fc927bb), (0x38d2c69d895d6715, 0xbc30c28e6023fb13), (0xb8509810eebec087, 0x3bc62487323559ca), (0xb84607b5c3508235, 0x3ba430a24f21f4b6), (0x37dcd1d9a6fb187a, 0xbb3a70372a5a35f5), (0xb7ba9055f83c1a46, 0xbb142c5d07f39eeb), (0x3747d181d0f16b66, 0x3aaa2aaf684b8a30), (0x371c65863116b54e, 0x3a80fce718ed7a5e), (0xb6b4123df1746b77, 0xba15d07c57e5f8fc), (0xb6898be9e1a577c3, 0xb9e870c605b22513), ], [ (0xbc4d7a7b8d722118, 0x3fbd84391bb2748d), (0x0000000000000000, 0x0000000000000000), (0x3c4b439a88ed803c, 0xbfad80edb3c4ea05), (0xbbd902d343595b94, 0x3f3a431f5421f7ef), (0xbc13a66c5c4dc37b, 0x3f73a282fe7b63a8), (0x3bacf6f60b03558d, 0xbf04ed653e607bdd), (0xbbb378680e9561c9, 0xbf24e15832bda3c4), (0xbb5464c53ca44363, 0x3eb7c5832dd1374f), (0x3b40f0848ee7f0af, 0x3ec7c2b80da8df98), (0xbadb963cfc74e722, 0xbe5bf160ccd35445), (0xbac9dbc6baadaa9d, 0xbe60cda2141b2a1e), (0x3a876692ed94eb99, 0x3df41d31d2a419e4), (0xba8205fd4d4f295d, 0x3df02f6ca850168a), (0xba12525d1774cdfa, 0xbd83901f61054085), (0xba17ee02df9f104d, 0xbd7696ce2b748d02), (0x39ad0bfbcbf0de66, 0x3d0b6e82997a390e), (0x39911978fd395acf, 0x3cf7e214796bec19), (0x38f14ad6e06bfc76, 0xbc8d0a3822eede44), (0x38ea8d322da40464, 0xbc73c944a2b7aa9b), (0x38a984e57b8c632b, 0x3c080748c2fd3ed7), (0xb88ca608783691d5, 0x3bea608ebfb61101), (0xb7fd3b588ddf9629, 0xbb7fee483d06f76f), (0x37f5b0b20d62c293, 0xbb5ce67588df7595), (0x37950cdd33b84f9d, 0x3af168f59e870bd0), (0x376249d762f468f2, 0x3aca7bdf85923387), (0xb6fefd0fec5de258, 0xba5fb7c898747d3e), (0x36de35ad136a6653, 0xba349926b4cfc177), (0xb6321892fca8dd05, 0x39c87ee43e8319a5), ], [ (0x0000000000000000, 0x0000000000000000), (0xbc56edd809f4ec43, 0xbfbd09b21e36c0bd), (0xbbfd63853cd1251f, 0x3f52c84acfb586b4), (0x3c340975d5184af6, 0x3f9355b904fbf7ee), (0xbbc2e53f276aee1d, 0xbf28fb570465af0d), (0x3bdedf2b372334ad, 0xbf4edc3292ba6cfd), (0xbb81b7d6d1c233d4, 0x3ee3e552ee8c2577), (0xbb9b6ea46d6db74f, 0x3ef76d44f6a83523), (0x3b2fdb93f3ce1be4, 0xbe8e1ee2dc4a3bda), (0x3b3cccd4251153ff, 0xbe94b944bbd4c7bf), (0xbac468738fc1e577, 0x3e2a8c3a4ce36f16), (0x3ac2a4a12f818a06, 0x3e27f8c9ef47068e), (0xba40acae788b04d5, 0xbdbe9295749ee471), (0x3a1164a101ab66dc, 0xbdb38813c3eb77e4), (0x39e5c1a4e6a441fe, 0x3d48c7cda44b7754), (0xb9a073f8f8b180ec, 0x3d379e90468589ab), (0xb96fed4f7bb5b2dd, 0xbccdca323fb2ed13), (0xb95878df442a1f61, 0xbcb6080be2ba756c), (0x387f1fa3709d7eff, 0x3c4b9a8e33ba54fc), (0xb8dc56a14b4f3362, 0x3c3054766d105243), (0xb857137346804b31, 0xbbc44fda8d0857c1), (0x384bb0403ea0d8f3, 0xbba3b2575150baf6), (0xb7a85fe85251016c, 0x3b384ea306ad146b), (0x37b304a7ebd0a72a, 0x3b13b4adf072996e), (0x3748b8e00542081f, 0xbaa81d1af5c14291), (0x372aac7dc3b524ef, 0xba809dac6fd771cd), (0x36baf45596c923ee, 0x3a14269f3ec695f6), (0x36759ddc6feb07d0, 0x39e7efc8823b70ff), ], [ (0xbc579e384ae35818, 0xbfbc97d79918527d), (0x0000000000000000, 0x0000000000000000), (0x3c415f3ee939a0c0, 0x3fac95081ab2b511), (0x3bd3c58af0675f79, 0xbf37e0b14f7d7c3f), (0x3c167e93b7727b21, 0xbf730688f6836a76), (0xbb9eaad919470a89, 0x3f030941f6e78e36), (0x3bb70db1e3b31015, 0x3f243d5898657a6f), (0xbb39f8046976f799, 0xbeb5a39a94f2ad54), (0xbb5db47207819abe, 0xbec70b18406146f7), (0x3af60534adb9126c, 0x3e597607f9532274), (0xbad703287fac9a7c, 0x3e604e788f4f63b9), (0xba876fad0fcbbb39, 0xbdf2598919473e7e), (0xba640135e9b4a88f, 0xbdef70154273be01), (0xba130237cf72ed16, 0x3d81df5c1ca3869c), (0x3a1164e3491c1c38, 0x3d75f5256665e918), (0x3995f76e145eb882, 0xbd091a176f7295bc), (0xb9928726702a883a, 0xbcf73cf989310b2d), (0x39202ef4e750363b, 0x3c8a9f0a04e769ab), (0x38f077c349f5886f, 0x3c7345b205781db7), (0xb8add8bb23d58463, 0xbc0611e4c0bb0b33), (0xb87f88c08a95c014, 0xbbe9b88423fdad3a), (0xb8109abefbf8e094, 0x3b7d637382cff4b7), (0x37f703e341c86f9e, 0x3b5c36bddd0beae2), (0xb7802c952716a8be, 0xbaf00eec29705267), (0xb755facd187ba820, 0xbac9e2beddaac35c), (0xb6e129db12cb1ab9, 0x3a5d51fa8552737e), (0xb6cd627e8469503b, 0x3a342847a5dc8d0a), (0xb66dc34aae9113ef, 0xb9c6b1f64bc800a0), ], ]; pxfm-0.1.23/src/bessel/y1f.rs000064400000000000000000000252621046102023000140010ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bessel::j0f::j1f_rsqrt; use crate::bessel::j1f::{j1f_asympt_alpha, j1f_asympt_beta}; use crate::bessel::y1f_coeffs::{Y1_ZEROS, Y1_ZEROS_VALUES, Y1F_COEFFS}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::fast_logf; use crate::polyeval::{f_polyeval10, f_polyeval18, f_polyeval19}; use crate::sin_helper::cos_small; use crate::sincos_reduce::rem2pif_any; /// Bessel of the second kind of order 1 (Y1) /// /// Max ULP 0.5 pub fn f_y1f(x: f32) -> f32 { if x < 0. { return f32::NAN; } if (x.to_bits() & 0x0007_ffff) == 0 { if x == 0. { return f32::NEG_INFINITY; } if x.is_nan() { return x + x; } if x.is_infinite() { if x.is_sign_negative() { return f32::NAN; } return 0.; } } let xb = x.to_bits(); if xb <= 0x3fb5c28fu32 { // 1.42 return y1f_near_zero(x); } // transient zone from 1.42 to 2 have bad behaviour for log poly already, // and not yet good to be easily covered, thus it use its own poly if xb <= 0x40000000u32 { // 2 return y1_transient_area(x); } if xb <= 0x424e0000u32 { // 51.5 return y1f_small_argument_path(x); } // Exceptions let bx = x.to_bits(); if bx == 0x47037a3d { return f32::from_bits(0x2deededb); } else if bx == 0x65ce46e4 { return f32::from_bits(0x9eed85c4); } else if bx == 0x6bf68a7b { return f32::from_bits(0x9dc70a09); } else if bx == 0x76d84625 { return f32::from_bits(0x15d7a68b); } else if bx == 0x7e3dcda0 { return f32::from_bits(0x12b81111); } y1f_asympt(x) } /** Generated by SageMath: Evaluates: y2 = -J1(x)*log(x) + 1/x * (1 - sum((-1)^m*(H(m)+H(m-1))/(2^m*m!*(m-1)!)*x^(2*m)) Y1(x) = 2/pi*(-y2(x)+(euler_gamma - log(2))*J1(x)) expressed as: Y1(x)=log(x)*W1(x) - Z1(x) - 2/(pi*x) ```python from sage.all import * R = LaurentSeriesRing(RealField(300), 'x',default_prec=300) x = R.gen() N = 16 # Number of terms (adjust as needed) gamma = RealField(300)(euler_gamma) d2 = RealField(300)(2) pi = RealField(300).pi() log2 = RealField(300)(2).log() def j_series(n, x): return sum([(-1)**m * (x/2)**(ZZ(n) + ZZ(2)*ZZ(m)) / (ZZ(m).factorial() * (ZZ(m) + ZZ(n)).factorial()) for m in range(N)]) J1_series = j_series(1, x) def harmony(m): return sum(RealField(300)(1)/RealField(300)(k) for k in range(1, m+1)) def z_series(x): return sum([(-1)**m * (x)**(ZZ(2)*ZZ(m)) / (ZZ(2)**(2*m) * ZZ(m).factorial() * (ZZ(m) - ZZ(1)).factorial()) * (harmony(m) + harmony(m - 1)) for m in range(1, N)]) W1 = d2/pi * J1_series Z1 = -(d2/(x*pi) * z_series(x) + d2/pi * gamma * J1_series(x) - d2/pi * log2 * J1_series(x)) # see the series print(W0) print(Z0) ``` See ./notes/bessel_y1_taylor.ipynb for generation **/ #[inline] fn y1f_near_zero(x: f32) -> f32 { const W: [u64; 10] = [ 0x3fd45f306dc9c883, 0xbfa45f306dc9c883, 0x3f5b2995e7b7b604, 0xbf021bb945252402, 0x3e9cf9286ea1d337, 0xbe2ee7a29824147f, 0x3db78be9987d036d, 0xbd3ae90af76a4d0f, 0x3cb7eb97f85e7d62, 0xbc31028e3376648a, ]; let dx = x as f64; let x2 = dx * dx; let w0 = f_polyeval10( x2, f64::from_bits(W[0]), f64::from_bits(W[1]), f64::from_bits(W[2]), f64::from_bits(W[3]), f64::from_bits(W[4]), f64::from_bits(W[5]), f64::from_bits(W[6]), f64::from_bits(W[7]), f64::from_bits(W[8]), f64::from_bits(W[9]), ) * dx; const Z: [u64; 10] = [ 0x3fc91866143cbc8a, 0xbfabd3975c75b4a7, 0x3f6835b97894be5b, 0xbf12c7dbffcde97d, 0x3eb0a780ac776eac, 0xbe432e5a4ddeea30, 0x3dcf0ce34d2066a6, 0xbd52a4e1aea45c18, 0x3cd1474ade9154ac, 0xbc4978ba84f218c0, ]; let z0 = f_polyeval10( x2, f64::from_bits(Z[0]), f64::from_bits(Z[1]), f64::from_bits(Z[2]), f64::from_bits(Z[3]), f64::from_bits(Z[4]), f64::from_bits(Z[5]), f64::from_bits(Z[6]), f64::from_bits(Z[7]), f64::from_bits(Z[8]), f64::from_bits(Z[9]), ) * dx; let w_log = fast_logf(x); const TWO_OVER_PI: f64 = f64::from_bits(0x3fe45f306dc9c883); let recip = 1. / dx; let z = f_fmla(w0, w_log, -z0); f_fmla(recip, -TWO_OVER_PI, z) as f32 } #[inline] fn y1_transient_area(x: f32) -> f32 { let dx = x as f64; // first Y0 bessel zero const ZERO: DoubleDouble = DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243)); let r = (dx - ZERO.hi) - ZERO.lo; /* Poly generated by Wolfram Matematica: <120] poly=error[[1]]; coeffs=CoefficientList[poly,x]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] */ let p = f_polyeval18( r, f64::from_bits(0x3d9b15a8283b069b), f64::from_bits(0x3fe0aa484455fd09), f64::from_bits(0xbfbe56f80802fa38), f64::from_bits(0xbfa0d2ac9d0409ad), f64::from_bits(0xbf73a619b3551650), f64::from_bits(0x3f7e6c480057ecbb), f64::from_bits(0xbf650dc773a5df4d), f64::from_bits(0x3f531e9ccab7d4da), f64::from_bits(0xbf29b76999169b0e), f64::from_bits(0x3f509c829abceaf7), f64::from_bits(0x3f575aee5697c4d8), f64::from_bits(0x3f63f7f9598be176), f64::from_bits(0x3f67a6ae61541282), f64::from_bits(0x3f665e6d3de19021), f64::from_bits(0x3f5ee8837b9197f6), f64::from_bits(0x3f4e6924f270fd7e), f64::from_bits(0x3f32ca61e5b74925), f64::from_bits(0x3f0725735bc3890b), ); p as f32 } /// This method on small range searches for nearest zero or extremum. /// Then picks stored series expansion at the point end evaluates the poly at the point. #[inline] fn y1f_small_argument_path(x: f32) -> f32 { let x_abs = x as f64; // let avg_step = 51.03 / 33.0; // let inv_step = 1.0 / avg_step; // // println!("inv_step {}", inv_step); const INV_STEP: f64 = 0.6466784244562023; let fx = x_abs * INV_STEP; const Y1_ZEROS_COUNT: f64 = (Y1_ZEROS.len() - 1) as f64; let idx0 = fx.min(Y1_ZEROS_COUNT) as usize; let idx1 = fx.ceil().min(Y1_ZEROS_COUNT) as usize; let found_zero0 = DoubleDouble::from_bit_pair(Y1_ZEROS[idx0]); let found_zero1 = DoubleDouble::from_bit_pair(Y1_ZEROS[idx1]); let dist0 = (found_zero0.hi - x_abs).abs(); let dist1 = (found_zero1.hi - x_abs).abs(); let (found_zero, idx, dist) = if dist0 < dist1 { (found_zero0, idx0, dist0) } else { (found_zero1, idx1, dist1) }; if idx == 0 { // Really should not happen here, but if it is then to log expansion return y1f_near_zero(x); } // We hit exact zero, value, better to return it directly if dist == 0. { return f64::from_bits(Y1_ZEROS_VALUES[idx]) as f32; } let c = &Y1F_COEFFS[idx - 1]; let r = (x_abs - found_zero.hi) - found_zero.lo; let p = f_polyeval19( r, f64::from_bits(c[0]), f64::from_bits(c[1]), f64::from_bits(c[2]), f64::from_bits(c[3]), f64::from_bits(c[4]), f64::from_bits(c[5]), f64::from_bits(c[6]), f64::from_bits(c[7]), f64::from_bits(c[8]), f64::from_bits(c[9]), f64::from_bits(c[10]), f64::from_bits(c[11]), f64::from_bits(c[12]), f64::from_bits(c[13]), f64::from_bits(c[14]), f64::from_bits(c[15]), f64::from_bits(c[16]), f64::from_bits(c[17]), f64::from_bits(c[18]), ); p as f32 } /* Evaluates: Y1 = sqrt(2/(PI*x)) * beta(x) * sin(x - 3*PI/4 - alpha(x)) Discarding 1/2*PI gives: Y1 = sqrt(2/(PI*x)) * beta(x) * (-cos(x - PI/4 - alpha(x))) */ #[inline] fn y1f_asympt(x: f32) -> f32 { let dx = x as f64; let alpha = j1f_asympt_alpha(dx); let beta = j1f_asympt_beta(dx); let angle = rem2pif_any(x); const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651); const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18); let x0pi34 = MPI_OVER_4 - alpha; let r0 = angle + x0pi34; let m_cos = -cos_small(r0); let z0 = beta * m_cos; let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx); (scale * z0) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_bessel_zero() { assert_eq!(f_y1f(700.76), 0.024876066); assert_eq!(f_y1f(35.76), 0.121432826); assert_eq!(f_y1f(1.76), -0.24787569); assert_eq!(f_y1f(0.87), -0.9030042); assert_eq!(f_y1f(f32::INFINITY), 0.0); assert!(f_y1f(f32::NEG_INFINITY).is_nan()); assert!(f_y1f(f32::NAN).is_nan()); } } pxfm-0.1.23/src/bessel/y1f_coeffs.rs000064400000000000000000000620701046102023000153240ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Y1 zeros and extremum on [0, 52] interval Generated by SageMath: ```python R120 = RealField(120) zeros = [] mp.prec = 150 step = mpf("0.1") epsilon = mpf("1e-35") x = mpf("1.25") previous_zero = R120(0) y1_zeros = [] while x < mpf("52.0"): f1 = bessely(1, x) f2 = bessely(1, x + step) if f1 * f2 < 0: zero = findroot(lambda t: bessely(1, t), (x, x + step), solver='secant', tol=mp.mpf("1e-41")) previous_zero = zero y1_zeros.append(zero) if previous_zero is not None and abs(x - mpf(f'{round(x)}')) < epsilon: zeros.append(previous_zero) x += step y1_extrema = [] x = mpf("1.25") while x < mpf("52.0"): d1 = mp.diff(lambda t: bessely(1, t), x) d2 = mp.diff(lambda t: bessely(1, t), x + step) if d1 * d2 < 0: extremum = findroot(lambda t: mp.diff(lambda u: bessely(1, u), t), (x, x + step), solver='secant', tol=mp.mpf("1e-41")) y1_extrema.append(extremum) x += step y1_zeros.extend(y1_extrema) y1_zeros = sorted(y1_zeros) print(f"pub(crate) static Y1_ZEROS: [(u64, u64); {len(y1_zeros)}] = [") print(f"(0x0, 0x0),") for z in y1_zeros: k = split_double_double(z) hi = double_to_hex(k[1]) lo = double_to_hex(k[0]) print(f"({lo}, {hi}),") print("];") ``` **/ pub(crate) static Y1_ZEROS: [(u64, u64); 33] = [ (0x0, 0x0), // not really used, just a stab to avoid indices messing (0xbc8bd1e50d219bfd, 0x400193bed4dff243), (0x3c53bac0714e4129, 0x400d76d4affba175), (0x3cbdfe7bac228e8c, 0x4015b7fe4e87b02e), (0x3ca7960b6b1c46ac, 0x401bc41890588553), (0x3cb479cc068d9046, 0x40213127ae6169b4), (0x3cc8f4ba5d68e440, 0x40243f2ee51e8c7e), (0x3c80fc786ce06080, 0x40277f9138d43206), (0xbcaf6ef7a3571593, 0x402a924ee4a3e52c), (0xbcc5e091a50f8e05, 0x402dcb7d88de848b), (0x3cc07320221cd5e5, 0x403070a7a43daae6), (0xbcda1ee4c5487ede, 0x40320b1c695f1e3b), (0xbcd2903124fef7e3, 0x4033971a15717510), (0x3cd391b14410528f, 0x40353025492188cd), (0xbcc15ec09721b746, 0x4036bcefd7de87a3), (0x3cb52f75f025b205, 0x403854fa303820ca), (0x3cb6f57f7696f493, 0x4039e262715f12a9), (0xbcbcf130fbea3b24, 0x403b79acee8cfb7d), (0xbc912142b10a5c65, 0x403d079247e8f51b), (0xbc9e7a77047d6166, 0x403e9e480605283c), (0x3cb1452eb07cd937, 0x40401649819af8fa), (0xbce96beabef7ecf4, 0x4040e16907f8fb56), (0x3cec6086fb5dd335, 0x4041a8b8a142d536), (0x3cd2481e87adfe57, 0x404273a7b35a7aff), (0x3cd7df5b6f701c7a, 0x40433b1ac0375e31), (0x3cda8ffacaac8461, 0x404405e18393afb5), (0xbce5b5acaff0a867, 0x4044cd72d2adfb0c), (0x3cbfe463face2c1c, 0x4045981787d668db), (0xbcefcba6ea61df1b, 0x40465fc2f7ca5b81), (0xbce26390f25f01cb, 0x40472a4a85cc317e), (0xbcbba46ca6ef9b6f, 0x4047f20cbfc32967), (0xbcdcc667e557a177, 0x4048bc7b10ed3960), (0x3cea473d4f209faf, 0x4049845158040451), ]; /** Value at zero or extremum of Y1 belongs to [Y1_ZEROS] Generated by MPFR: ```text let mut arr = vec![]; for zeros in Y1_ZEROS.iter() { if zeros.1 == 0 { arr.push(0); } else { let mpfr = Float::with_val(107, f64::from_bits(zeros.1)).y1(); arr.push(mpfr.to_f64().to_bits()); } } println!( "arr: [{}]", arr.iter() .map(|x| format!("0x{:016x}", x)) .collect::>() .join(", ") ); ``` **/ pub(crate) static Y1_ZEROS_VALUES: [u64; 33] = [ 0x0000000000000000, 0x3c7cf9f8d5e1a475, 0x3fdaabb4011ed330, 0x3ca46a40b234169c, 0xbfd36732d4b96094, 0xbc963bc010b45f46, 0x3fd00ef3745e0e3c, 0x3c5f96d32c02f147, 0xbfcc075da85beb4f, 0x3ca213201464272b, 0x3fc931a5a0ae5aa0, 0xbcb39d4c41d5839f, 0xbfc713fc51664c74, 0xbcab20138dd047ec, 0x3fc56b97f8091ac5, 0x3c8b67dbfd3bd179, 0xbfc413644356a52b, 0x3c919e290514c619, 0x3fc2f4e70d6c7e01, 0xbc719366994a86bc, 0xbfc20198200b699d, 0x3cbbec2345ac18e2, 0x3fc12f9870d68e18, 0x3ca334eb74fdcfd1, 0xbfc077eede4a0d89, 0xbcaaca291aee3c35, 0x3fbfab0b166d23d8, 0x3c8ef92aa9c8e53c, 0xbfbe891b327da16d, 0x3cb13e3c695ea088, 0x3fbd84391bb2748d, 0xbcaa1c861fdd1438, 0xbfbc97d79918527d, ]; /** Series expansion at point for Y1 Generated by SageMath and Sollya: ```python def compute_intervals(zeros): intervals = [] for i in range(0, len(zeros)): if i == 0: a = 2 - zeros[i] b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) elif i + 1 > len(zeros) - 1: a = (zeros[i - 1] + zeros[i]) / 2 - 0.05 - zeros[i] b = (zeros[i]) + 0.83 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) else: a = (zeros[i - 1] + zeros[i]) / 2 - zeros[i] - 0.05 b = (zeros[i] + zeros[i + 1]) / 2 + 0.05 - zeros[i] intervals.append((RealField(18)(a), RealField(18)(b), RealField(110)(zeros[i]))) return intervals intervals = compute_intervals(y1_zeros) def build_sollya_script(a, b, zero, deg): return f""" prec = 250; bessel_y1 = library("./notes/bessel_sollya/cmake-build-release/libbessel_sollya.dylib"); f = bessel_y1(x + {zero}); d = [{a}, {b}]; pf = remez(f, {deg}, d); for i from 0 to degree(pf) do {{ write(coeff(pf, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RR(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(a, b, zero, degree=12): sollya_script = build_sollya_script(a, b, zero, degree) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return degree = 18 print(f"pub(crate) static Y1F_COEFFS: [[u64;{degree + 1}]; {len(intervals)}] = [") for i in range(0, len(intervals)): interval = intervals[i] call_sollya_on_interval(interval[0], interval[1], interval[2], degree) coeffs = load_coefficients(f"coefficients.txt") print("[") for c in coeffs: print(double_to_hex(c) + ",") print("],") print("];") ``` **/ pub(crate) static Y1F_COEFFS: [[u64; 19]; 32] = [ [ 0x3bdca2ee18606a4b, 0x3fe0aa48442f014b, 0xbfbe56f82217b8f4, 0xbfa0d2af4e932400, 0xbf73a6dec3726cd5, 0x3f7e671c7d12ea48, 0xbf65429dc5c0e9d4, 0x3f517ab4af4655e4, 0xbf40b2d8647a250d, 0x3f2eea7b1b675766, 0xbf1c3fb728e7d2ff, 0x3f09d1da72e12f44, 0xbef7964bf8511e22, 0x3ee57c2a83e1f972, 0xbed33f4211a00375, 0x3ec02bcdac2103fd, 0xbea6fefcf033ab9d, 0x3e874128ed97d3bb, 0xbe57d5b1eac16658, ], [ 0x3fdaabb4011ed330, 0x3c54da7c52fcf446, 0xbfc8b45babe797b6, 0x3f8e147099a6f00d, 0x3f88c5af1eeb2143, 0xbf4133fa47d8ea48, 0xbf3bf8af93e7a2f0, 0x3f021d64bd4e2cd8, 0x3eb44d2c32fdaf23, 0x3eb14c3b9e7960c1, 0xbe9b8ee25c629be6, 0x3e7a85b5b497dc6c, 0xbe5bfa422fb8d949, 0x3e3f0ad81d293f5a, 0xbe20e6844c6faba7, 0x3e0214b2d826d072, 0xbde4ff658967d425, 0x3dcb549cdc774a83, 0xbda6b5df4d9c1682, ], [ 0x3b7ff35240713789, 0xbfd5c7c556f0c19a, 0x3fa00b9f8571ca1f, 0x3faa15d92dfe3e27, 0xbf710a329e2c23f5, 0xbf61be6db9923ac9, 0x3f2337c7e138eb84, 0x3f085b940eb5f37f, 0xbec80619146a1e65, 0xbea255e6cf4b3254, 0x3e5b62ccdc392c5a, 0x3e380b1a5a61e6b5, 0xbdfa7ec7fd0d2925, 0x3d840d04ff01d1b2, 0xbd938dc1b2e33eca, 0x3d74839c586126ca, 0xbd4b045bc7ad769b, 0x3d261d10a8575c45, 0xbd052a6cc14bcc54, ], [ 0xbfd36732d4b96094, 0x3b3886a5ed6fd628, 0x3fc3001c8002caf8, 0xbf7bf5a03bab4999, 0xbf8751ea028c1953, 0x3f423874cd8d0402, 0x3f364f6610d6493b, 0xbef02978de38394f, 0xbed72f0766d0d9c7, 0x3e8f2081874e556c, 0x3e6defd5dce91973, 0xbe2205c70046a2c7, 0xbdfb6432eb3ab7ea, 0x3db028a1c0572973, 0x3d807791dcab03a0, 0xbd29778204deee13, 0xbd08342db2e7148e, 0x3cc898efb37f9dad, 0xbc84e2adc305e2ab, ], [ 0xbac1435819592d4c, 0x3fd15f993fceab5c, 0xbf902b3933cf21b1, 0xbfa6395dfe49fcd4, 0x3f63ced2a2e69180, 0x3f607a678d6000bb, 0xbf1b50d7e1d3201e, 0xbf06f7bab104f34b, 0x3ec176e72bf94a3a, 0x3ea2becb2b6bacd1, 0xbe5a384eebfb23c2, 0xbe341e7a921f7f66, 0x3de9e3284b918a26, 0x3dbec40b21f2c78f, 0xbd726865da6190a9, 0xbd416f4fe7eed351, 0x3cf3160bd2bd6c64, 0x3cbf6d61c945b95c, 0xbc706809636e0aec, ], [ 0x3fd00ef3745e0e3c, 0x3aff192f298c81c3, 0xbfbfcdacdda138f2, 0x3f706cc34cd829fa, 0x3f84641bb10c16cb, 0xbf37fac943e2a16d, 0xbf34769ed32e14a2, 0x3ee80608ecda1508, 0x3ed5cc8242d77e23, 0xbe888c8f2538feb8, 0xbe6ce5908c1e5174, 0x3e1ed16257e17417, 0x3dfa30d623eda066, 0xbdaa5076123e3ecf, 0xbd814cd297d2be7e, 0x3d306166947e23e9, 0x3d01635f73179569, 0xbcaeafcf4c2f127b, 0xbc7b0828175d92fa, ], [ 0x3aba1488e1b7782d, 0xbfcdc14ea14e89f9, 0x3f84429fef5b5fbd, 0x3fa367d7d608e4ba, 0xbf59d6eb2bc49e35, 0xbf5dc4f991b3db86, 0x3f1315ec04d6e6bb, 0x3f0571814a1aa2f5, 0xbeba2977fa42f00f, 0xbea1e864230850b8, 0x3e54a7b82d3fa1e5, 0x3e33906609f9fe4c, 0xbde549e8b0e16969, 0xbdbe32cf2ce99d6f, 0x3d6eff542dd345c3, 0x3d415e2a9c2f4933, 0xbcf0d48dde3c3ffe, 0xbcbeac3c36b4bce2, 0x3c6af1612c5ddab0, ], [ 0xbfcc075da85beb4f, 0xbafcfa84f4024782, 0x3fbbdeb6ff9f55e1, 0xbf661eefb74da882, 0xbf8229ea914b846e, 0x3f30cbcc6778fd37, 0x3f32aa59f5091f7b, 0xbee1c15d5251ae54, 0xbed4583f15abd654, 0x3e831d151a12624a, 0x3e6b74e57c21e022, 0xbe19044f1339b061, 0xbdf93b1ec70c7bbc, 0x3da61a4e437e8105, 0x3d80d4305f038451, 0xbd2c3aad6f3b35c7, 0xbd010dec3a02c58c, 0x3cab15901b6d0925, 0x3c7ab2531f00c501, ], [ 0xbab392a85abdc950, 0x3fca7022be084d99, 0xbf7c650b6b83109a, 0xbfa163191c30aa62, 0x3f526b045287ddca, 0x3f5b17602840abf5, 0xbf0c0a9cee3c8429, 0xbf03e398cbc472de, 0x3eb3f35db1ff19f5, 0x3ea0e9b612dbc0ea, 0xbe5056babcd79a11, 0xbe32c1a8c8d768b1, 0x3de161b6a84838d0, 0x3dbd4ca9d2d67d78, 0xbd69fdd67a999eab, 0xbd4101919ce84a07, 0x3cecd91fa7851496, 0x3cbe3f8588ebbfdf, 0xbc67a4499c96e38d, ], [ 0x3fc931a5a0ae5aa0, 0x3afa23fd08be9891, 0xbfb919c8a3f203fa, 0x3f602a38da6262a9, 0x3f807ced48910819, 0xbf2900f33a00690a, 0xbf31278d46fd153c, 0x3edb2595529cf19f, 0x3ed2f7c2d608e0bb, 0xbe7e212d23787793, 0xbe69f3fcf3631e9c, 0x3e144fbf033f1974, 0x3df82268e7ab0cdb, 0xbda26cc2714815d4, 0xbd80418b35c32375, 0x3d28122e50410f0a, 0x3d009aba27e11464, 0xbca78943175d4e84, 0xbc7a379f959c0224, ], [ 0x3aaf25ce7e30cbc6, 0xbfc80781c32422e7, 0x3f754eda697a0098, 0x3f9fbe6df840847f, 0xbf4be318d61276e1, 0xbf58efee4094379c, 0x3f059145b4f0e4dd, 0x3f0282d26a74c382, 0xbeaf56c29d9ad6c8, 0xbe9fdd03174f6b47, 0x3e4a44a7907d0ec6, 0x3e31df6533090779, 0xbddc96e9cb6ee22b, 0xbdbc3439a99213c4, 0x3d65d387fc8083e0, 0x3d40830db4ec8a6e, 0xbce8ad426f9ce3f5, 0xbcbd93c0cf35d116, 0x3c649b19a5449ffa, ], [ 0xbfc713fc51664c74, 0xbaf73aab14face16, 0x3fb7049760cde490, 0xbf58ef5f1cbe4874, 0xbf7e5f53caf3bead, 0x3f237b0b62ddadd1, 0x3f2fd3bac08286da, 0xbed5789803de3adb, 0xbed1c0faa8999393, 0x3e7845b49b063dc7, 0x3e6886872800e226, 0xbe10b03677687883, 0xbdf7049d17bd230b, 0x3d9edd9ca057f252, 0x3d7f445f42a168e6, 0xbd24866878075342, 0xbd0015a37275b46d, 0x3ca463bd3d4059be, 0x3c79974848138496, ], [ 0xbaa9a62f9227c851, 0x3fc62d94d97e859c, 0xbf70bf614807033c, 0xbf9d5f857a2a6107, 0x3f46081b0b7fe572, 0x3f57307b03e248f8, 0xbf0132c0aa83d0db, 0xbf0154ed4598d2e4, 0x3ea94f64f476e3f5, 0x3e9e1272585385c0, 0xbe4588c758dd66db, 0xbe31021cdd7a4f3a, 0x3dd7cfa7a39f5d48, 0x3dbb0e00d41ec645, 0xbd6276c9a451cdb1, 0xbd3fe8cf17671ae1, 0x3ce52f1a6f7ae06f, 0x3cbcc2eb893d62ce, 0xbc61f4c0af8bd0fb, ], [ 0x3fc56b97f8091ac5, 0x3af48a947d2475cd, 0xbfb560fcc8c08469, 0x3f53fafa39618883, 0x3f7c49141623372f, 0xbf1f69980694fd17, 0xbf2dc5f848aa9d33, 0x3ed178fc979b779d, 0x3ed0b494a4bafca8, 0xbe73fc3884c243a5, 0xbe673afb9fb48ff7, 0x3e0bd903464b077a, 0x3df5f3bafabcdabe, 0xbd9a1c27612b5f03, 0xbd7e04553366c10e, 0x3d219970f1564c7c, 0x3cff128fbd867c78, 0xbca1b4d2be53f3ad, 0xbc78e13fb654b036, ], [ 0x3aa5951bb8e2b477, 0xbfc4b2a38f1ab9b4, 0x3f6b3878aadeb34d, 0x3f9b750d89a9b35f, 0xbf41f6911725a956, 0xbf55beee6fd51c8a, 0x3efc3625d7a65087, 0x3f005375a588a71f, 0xbea4ee5e4e7cafc0, 0xbe9c7b3d81b5dc31, 0x3e41fce14f464e1e, 0x3e30346643a98dcb, 0xbdd41c86191a49ce, 0xbdb9eed9da04017a, 0x3d5f8cee5e5b42b4, 0x3d3ec41075d33352, 0xbce24e44459e28b0, 0xbcbbe16f7d769c15, 0x3c5f670ad9138f1f, ], [ 0xbfc413644356a52b, 0xbaf22d9ab9060f8f, 0x3fb40bb88c6f2b85, 0xbf5078d13cfc400e, 0xbf7a9191262ab9d5, 0x3f1a005297618f35, 0x3f2c0cbad847a60e, 0xbecd1a72e7c35fa0, 0xbecf9a2654099c0b, 0x3e70c6b06e20d1c0, 0x3e66136d6425acf0, 0xbe0797767778226d, 0xbdf4f77b30ed58c3, 0x3d96572059bf2445, 0x3d7cd12649b82d6f, 0xbd1e6ce514a88f2d, 0xbcfdfabaf5c37514, 0x3c9eea8202989176, 0x3c782260f7596e02, ], [ 0xbaa27e57c2b07d4b, 0x3fc37aaceac987b9, 0xbf66afe4fe0bc0f7, 0xbf99de7a33bc3a97, 0x3f3e024f567ac487, 0x3f548843c426abe0, 0xbef7a8e14711c0f4, 0xbefeeceb341ad81c, 0x3ea1a743e05b383f, 0x3e9b143d39c8eb5f, 0xbe3e8e00011fabc3, 0xbe2ef28e31ff924c, 0x3dd137a1bd136742, 0x3db8e0878264a773, 0xbd5b3dc655a5a5f4, 0xbd3da652e8239897, 0x3cdfe34eace42448, 0x3cbafd0cc7251807, 0xbc5b9b0102453020, ], [ 0x3fc2f4e70d6c7e01, 0x3af022defda0ec45, 0xbfb2ef24d6f7526a, 0x3f4bc33c9dc6ec82, 0x3f7920414ee2acbe, 0xbf15f9173916a219, 0xbf2a94fdbdcec471, 0x3ec8b309990f94db, 0x3ece087ff4517bd5, 0xbe6ca22ab12c685c, 0xbe650d1f28632753, 0x3e044415529c950b, 0x3df411b8a7d9d1bc, 0xbd9354e8c7a8bfd7, 0xbd7bb16e8ee8c711, 0x3d1a881fddcb8d86, 0x3cfcecee70233b69, 0xbc9b2b6cccd3802a, 0xbc77637662fa6ba8, ], [ 0x3aa00f5dbb23e90b, 0xbfc2740819f1caaa, 0x3f6349369dc780bb, 0x3f98868d7401bf2e, 0xbf398cd1bebe1445, 0xbf537eef9aadeee2, 0x3ef43394c95b2d29, 0x3efd6dfcdb026013, 0xbe9e448fbc8a1c95, 0xbe99d764ee07a6b7, 0x3e3a53958c8a71d8, 0x3e2da0e1c86368ce, 0xbdcdd7f914e496e5, 0xbdb7e67ff45daf48, 0x3d57c2e32861f41c, 0x3d3c96e18ab6db69, 0xbcdc0099b11f0478, 0xbcba1dfeafeb6e19, 0x3c586b4c940f74bc, ], [ 0xbfc20198200b699d, 0xbaecc875d54af9d0, 0x3fb1fd242a74e630, 0xbf47cf261dfbf19a, 0xbf77e4820ec1dde4, 0x3f12e1bd281dfcba, 0x3f2950bb06c6fdf9, 0xbec54a38ab6af51a, 0xbecca94f38024fb4, 0x3e68c7e75971843f, 0x3e6423fc7e24ed40, 0xbe019fe1d8a6e0d8, 0xbdf34198c7517f5a, 0x3d90e78c95f157aa, 0x3d7aa74c4042e051, 0xbd1756942b9afcaf, 0xbcfbedc3e7dae4e4, 0x3c980b9567289463, 0x3c76a9e024cc6a52, ], [ 0xba9c33661811b8ff, 0x3fc192f2627a74e3, 0xbf60a846a83fecf2, 0xbf975eceaabf7f86, 0x3f3617c581be35b1, 0x3f529934b7a84483, 0xbef18123e8751889, 0xbefc1f05a2d85150, 0x3e9a4e0bc09262e9, 0x3e98be81ad44b8a4, 0xbe36f73795dfb5c7, 0xbe2c70ab155167d1, 0x3dca26218cc79400, 0x3db7011269271056, 0xbd54ec138a5f86cd, 0xbd3b98bf6fa2fe47, 0x3cd8c95d73f0c84c, 0x3cb948b2dd021429, 0xbc55bd7c63fa9765, ], [ 0x3fc12f9870d68e18, 0x3ae9cd1ac1fa64f9, 0xbfb12c11811945f9, 0x3f44b638f21f0f76, 0x3f76d2a897d58353, 0xbf10732e5458ba20, 0xbf2835929300df3e, 0x3ec297283816a814, 0x3ecb73adedf11a1f, 0xbe65b455b903b389, 0xbe6353f0797a3bf1, 0x3dfefc9ac10b87d9, 0x3df2853545ffa79d, 0xbd8dd8945079a88f, 0xbd79b28860cd63f8, 0x3d14b29ba2797832, 0x3cfaff02f362ca7e, 0xbc956d8436ee55ed, 0xbc75f881bb0137f5, ], [ 0x3a9900b85a085cfa, 0xbfc0cf3ee98f769b, 0x3f5d26e7af251f79, 0x3f965d05948a946a, 0xbf335959b8482e40, 0xbf51cff175d05c2a, 0x3eeeb59416879104, 0x3efaf7544eeac751, 0xbe9720522bb1fa69, 0xbe97c41261703475, 0x3e343fa0ea5ba663, 0x3e2b5e23abb21a5f, 0xbdc722397b59adb6, 0xbdb62f213532a0b8, 0x3d5294a89e377c98, 0x3d3aac95aead6ada, 0xbcd61abb584f3fc2, 0xbcb87f3345758fd5, 0x3c537a3b70fc94b7, ], [ 0xbfc077eede4a0d89, 0xbae73fb2e67b1968, 0x3fb0751548b2924d, 0xbf423b5d46a73864, 0xbf75e2467c8fb832, 0x3f0cfe5c189d6e4d, 0x3f273bbd8c7aef2c, 0xbec06974d3d04263, 0xbeca6081d36e6a0b, 0x3e6334a83cf5d21d, 0x3e6299571cb4bb1e, 0xbdfb7f5bc046450f, 0xbdf1da63b49ed896, 0x3d8a92885fb339ae, 0x3d78d1d6e93bb23d, 0xbd127ea4434f9fb5, 0xbcfa20dab6b920e9, 0x3c93389d892643a0, 0x3c7550b88147fd02, ], [ 0xba96582ab366c758, 0x3fc0230ba90f2871, 0xbf59ca16f0c9734e, 0xbf9579c1bdbcfc99, 0x3f3120ecfac5c017, 0x3f511dd26bbe2946, 0xbeeb37e7c9a57147, 0xbef9f01e7c19098c, 0x3e94887fe7a88a4d, 0x3e96e3723883fe87, 0xbe3204b644d485a1, 0xbe2a659b13b69c6b, 0x3dc4a40c8498625a, 0x3db56f0212f628e4, 0xbd50a0fef4ac5a44, 0xbd39d1d92cf50973, 0x3cd3d93917ae0666, 0x3cb7c222c421cbf8, 0xbc518e27cddeecfd, ], [ 0x3fbfab0b166d23d8, 0x3ae50cd9856106aa, 0xbfafa65c1ce7ebd6, 0x3f4035bf503ffc1f, 0x3f750d1b04713c41, 0xbf09cd14a92842a1, 0xbf265d504af5d8fe, 0x3ebd3feeb33d9cae, 0x3ec96a257062f750, 0xbe61254f302b04d0, 0xbe61f11585e02bfc, 0x3df89a7674827723, 0x3df13f0ba458182e, 0xbd87d67ae3559fb7, 0xbd78038124810666, 0x3d10a3cffab7b16e, 0x3cf952a4679b4020, 0xbc9158ffabf6b26f, 0xbc74b2e8c7ca451f, ], [ 0x3a9422b204fbf27f, 0xbfbf13fb0c0e6fcd, 0x3f5706ed3d935d00, 0x3f94af74cbd77bef, 0xbf2e9a9e66e5a792, 0xbf507ec9ed824fcb, 0x3ee856d4518ab29c, 0x3ef9040de830648a, 0xbe9262f69c56c4a2, 0xbe9618c94a54555e, 0x3e3029d2c8bd8b0e, 0x3e2983bca06d479e, 0xbdc28e29fd7e309a, 0xbdb4beea8ebaabe8, 0x3d4df87d00b82fa1, 0x3d39076f370434b4, 0xbcd1ef67bd03c16c, 0xbcb7115a994eb5d5, 0x3c4fd28ad1effa7c, ], [ 0xbfbe891b327da16d, 0xbae325aba995f36e, 0x3fae8533ce07bdb8, 0xbf3d1253218e31b0, 0xbf744e6826476498, 0x3f07271a9b5e3cb4, 0x3f2595b697c8ec04, 0xbeba46b03ecb3892, 0xbec88c173e076203, 0x3e5ed9b1754f626a, 0x3e615891ef312cd4, 0xbdf62ca3527c988f, 0xbdf0b14767922479, 0x3d85879b58ff9d05, 0x3d7745bb7346aea9, 0xbd0e20fb122a7c2a, 0xbcf89354d05f7b8c, 0x3c8f7da941b1f5c8, 0x3c741ef462ba56a3, ], [ 0xba923c4506ec812e, 0x3fbe018dac1c17e3, 0xbf54b994dd05c1fb, 0xbf93f9e0db07e7ef, 0x3f2b8e55b75b13ab, 0x3f4fdf68a78bb3d2, 0xbee5ee9d17106a07, 0xbef82ee6dfdfedd8, 0x3e90962d7f6d601e, 0x3e9560edce7d4b08, 0xbe2d34381cff4d39, 0xbe28b5a0e715b17d, 0x3dc0cab951aa6b0b, 0x3db41d218be1cc79, 0xbd4b2d2a51de7089, 0xbd384c06737cf8d9, 0x3cd04c96e113bd0a, 0x3cb66c4b3dc74284, 0xbc4cfe4908cedcb8, ], [ 0x3fbd84391bb2748d, 0x3ae17f232c3596e7, 0xbfad80edb3c4ea05, 0x3f3a431f5421f7ef, 0x3f73a282fe7b63a8, 0xbf04ed653e607bdc, 0xbf24e15832bda3c4, 0x3eb7c5832dd13719, 0x3ec7c2b80da8df7e, 0xbe5bf160ccd30135, 0xbe60cda2141b0afb, 0x3df41d31d25837e8, 0x3df02f6ca822716e, 0xbd83901f0d351db4, 0xbd7696cdd91c27b7, 0x3d0b6e1487e46414, 0x3cf7e1bb61dba0fc, 0xbc8cbb194749390a, 0xbc7394699d841c82, ], [ 0x3a909e71c2163ed3, 0xbfbd09b21e36c0bd, 0x3f52c84acfb586b4, 0x3f9355b904fbf7ee, 0xbf28fb570465af0d, 0xbf4edc3292ba6cfd, 0x3ee3e552ee8c2575, 0x3ef76d44f6a83510, 0xbe8e1ee2dc4a3910, 0xbe94b944bbd4ab57, 0x3e2a8c3a4ce04c1b, 0x3e27f8c9ef133245, 0xbdbe92957079603b, 0xbdb388138abed52f, 0x3d48c7ca6d80cb32, 0x3d379e45475751e8, 0xbccdc773f7abde68, 0xbcb5d2331c76adb9, 0x3c4a8aa5ca753696, ], [ 0xbfbc97d79918527d, 0xbae4d780a21f2057, 0x3fac95081ab2b511, 0xbf37e0b14f7d7c3f, 0xbf730688f6836a76, 0x3f030941f6e78e36, 0x3f243d5898657a6f, 0xbeb5a39a94f2ad1c, 0xbec70b18406146b4, 0x3e597607f952cd69, 0x3e604e788f4f18d9, 0xbdf2598918fbb9ee, 0xbdef701541acccd2, 0x3d81df5bcb47b899, 0x3d75f524c73bc009, 0xbd0919aede2dcbf2, 0xbcf73c65c9ce91ed, 0x3c8a553df0f1b569, 0x3c72fe9f3f0dcae2, ], ]; pxfm-0.1.23/src/bits.rs000064400000000000000000000054451046102023000127670ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #[inline] pub(crate) const fn get_exponent_f32(x: f32) -> i32 { let bits = x.to_bits(); (((bits >> 23) & 0xFF) as i32).wrapping_sub(127) } #[inline] pub(crate) const fn mantissa_f32(x: f32) -> u32 { x.to_bits() & ((1u32 << 23) - 1) } #[inline] pub(crate) const fn mantissa_f64(x: f64) -> u64 { x.to_bits() & ((1u64 << 52) - 1) } #[inline] pub(crate) const fn get_exponent_f64(x: f64) -> i64 { ((x.to_bits() as i64 & EXP_MASK as i64) >> 52).wrapping_sub(1023) } #[inline] pub(crate) const fn biased_exponent_f64(x: f64) -> i64 { (x.to_bits() as i64 & EXP_MASK as i64) >> 52 } #[inline] pub(crate) const fn mask_trailing_ones(len: u64) -> u64 { if len >= 64 { u64::MAX } else { (1u64 << len).wrapping_sub(1) } } pub(crate) const EXP_MASK: u64 = mask_trailing_ones(11) << 52; #[inline] pub(crate) fn set_exponent_f64(x: u64, new_exp: u64) -> u64 { let encoded_mask = new_exp.wrapping_shl(52) & EXP_MASK; x ^ ((x ^ encoded_mask) & EXP_MASK) } #[inline] pub(crate) const fn min_normal_f32(sign: bool) -> f32 { let sign_bit = if sign { 1u32 << 31 } else { 0 }; let exponent = 1u32 << 23; f32::from_bits(sign_bit | exponent) } pxfm-0.1.23/src/ceil.rs000064400000000000000000000102421046102023000127310ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{get_exponent_f32, get_exponent_f64}; #[inline] pub const fn ceilf(x: f32) -> f32 { // If x is infinity NaN or zero, return it. if !x.is_normal() { return x; } let is_neg = x.is_sign_negative(); let exponent = get_exponent_f32(x); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. const FRACTION_LENGTH: u32 = 23; if exponent >= FRACTION_LENGTH as i32 { return x; } if exponent <= -1 { return if is_neg { -0.0 } else { 1.0 }; } let trim_size = (FRACTION_LENGTH as i32).wrapping_sub(exponent); let x_u = x.to_bits(); let trunc_u = x_u .wrapping_shr(trim_size as u32) .wrapping_shl(trim_size as u32); // If x is already an integer, return it. if trunc_u == x_u { return x; } let trunc_value = f32::from_bits(trunc_u); // If x is negative, the ceil operation is equivalent to the trunc operation. if is_neg { return trunc_value; } trunc_value + 1.0 } #[inline] pub const fn ceil(x: f64) -> f64 { // If x is infinity NaN or zero, return it. if !x.is_normal() { return x; } let is_neg = x.is_sign_negative(); let exponent = get_exponent_f64(x); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. const FRACTION_LENGTH: u64 = 52; if exponent >= FRACTION_LENGTH as i64 { return x; } if exponent <= -1 { return if is_neg { -0.0 } else { 1.0 }; } let trim_size = (FRACTION_LENGTH as i64).wrapping_sub(exponent); let x_u = x.to_bits(); let trunc_u = x_u .wrapping_shr(trim_size as u32) .wrapping_shl(trim_size as u32); // If x is already an integer, return it. if trunc_u == x_u { return x; } let trunc_value = f64::from_bits(trunc_u); // If x is negative, the ceil operation is equivalent to the trunc operation. if is_neg { return trunc_value; } trunc_value + 1.0 } #[cfg(test)] mod tests { use super::*; #[test] fn test_ceilf() { assert_eq!(ceilf(0.0), 0.0); assert_eq!(ceilf(10.0), 10.0); assert_eq!(ceilf(10.1), 11.0); assert_eq!(ceilf(-9.0), -9.0); assert_eq!(ceilf(-9.5), -9.0); } #[test] fn test_ceil() { assert_eq!(ceil(0.0), 0.0); assert_eq!(ceil(10.0), 10.0); assert_eq!(ceil(10.1), 11.0); assert_eq!(ceil(-9.0), -9.0); assert_eq!(ceil(-9.5), -9.0); } } pxfm-0.1.23/src/common.rs000064400000000000000000000164301046102023000133120ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 num_traits::MulAdd; use std::ops::{Add, Mul}; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] #[inline(always)] pub(crate) fn mlaf + Add + MulAdd>( acc: T, a: T, b: T, ) -> T { MulAdd::mul_add(a, b, acc) } #[inline(always)] #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] pub(crate) fn mlaf + Add + MulAdd>( acc: T, a: T, b: T, ) -> T { acc + a * b } #[inline] pub(crate) const fn rintfk(x: f32) -> f32 { (if x < 0. { x - 0.5 } else { x + 0.5 }) as i32 as f32 } #[inline(always)] pub(crate) const fn fmlaf(a: f32, b: f32, c: f32) -> f32 { c + a * b } #[inline(always)] pub(crate) fn f_fmlaf(a: f32, b: f32, c: f32) -> f32 { mlaf(c, a, b) } #[inline(always)] pub(crate) const fn fmla(a: f64, b: f64, c: f64) -> f64 { c + a * b } /// Optional FMA, if it is available hardware FMA will use, if not then just scalar `c + a * b` #[inline(always)] pub(crate) fn f_fmla(a: f64, b: f64, c: f64) -> f64 { mlaf(c, a, b) } /// Executes mandatory FMA /// if not available will be simulated through Dekker and Veltkamp #[inline(always)] pub(crate) fn dd_fmla(a: f64, b: f64, c: f64) -> f64 { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { f_fmla(a, b, c) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::DoubleDouble; DoubleDouble::dd_f64_mul_add(a, b, c) } } // Executes mandatory FMA // if not available will be simulated through dyadic float 128 #[inline(always)] pub(crate) fn dyad_fmla(a: f64, b: f64, c: f64) -> f64 { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { f_fmla(a, b, c) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::dyadic_float::DyadicFloat128; let z = DyadicFloat128::new_from_f64(a); let k = DyadicFloat128::new_from_f64(b); let p = z * k + DyadicFloat128::new_from_f64(c); p.fast_as_f64() } } // Executes mandatory FMA // if not available will be simulated through Dekker and Veltkamp #[inline(always)] #[allow(unused)] pub(crate) fn dd_fmlaf(a: f32, b: f32, c: f32) -> f32 { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { f_fmlaf(a, b, c) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { (a as f64 * b as f64 + c as f64) as f32 } } #[allow(dead_code)] #[inline(always)] pub(crate) fn c_mlaf + Add + MulAdd>( a: T, b: T, c: T, ) -> T { mlaf(c, a, b) } /// Copies sign from `y` to `x` #[inline] pub const fn copysignfk(x: f32, y: f32) -> f32 { f32::from_bits((x.to_bits() & !(1 << 31)) ^ (y.to_bits() & (1 << 31))) } // #[inline] // // Founds n in ln(𝑥)=ln(𝑎)+𝑛ln(2) // pub(crate) const fn ilogb2kf(d: f32) -> i32 { // (((d.to_bits() as i32) >> 23) & 0xff) - 0x7f // } // // #[inline] // // Founds a in x=a+𝑛ln(2) // pub(crate) const fn ldexp3kf(d: f32, n: i32) -> f32 { // f32::from_bits(((d.to_bits() as i32) + (n << 23)) as u32) // } #[inline] pub(crate) const fn pow2if(q: i32) -> f32 { f32::from_bits((q.wrapping_add(0x7f) as u32) << 23) } /// Round towards whole integral number #[inline] pub(crate) const fn rintk(x: f64) -> f64 { (if x < 0. { x - 0.5 } else { x + 0.5 }) as i64 as f64 } /// Computes 2^n #[inline(always)] pub(crate) const fn pow2i(q: i32) -> f64 { f64::from_bits((q.wrapping_add(0x3ff) as u64) << 52) } // #[inline] // pub(crate) const fn ilogb2k(d: f64) -> i32 { // (((d.to_bits() >> 52) & 0x7ff) as i32) - 0x3ff // } // // #[inline] // pub(crate) const fn ldexp3k(d: f64, e: i32) -> f64 { // f64::from_bits(((d.to_bits() as i64) + ((e as i64) << 52)) as u64) // } /// Copies sign from `y` to `x` #[inline] pub const fn copysignk(x: f64, y: f64) -> f64 { f64::from_bits((x.to_bits() & !(1 << 63)) ^ (y.to_bits() & (1 << 63))) } #[inline] pub(crate) const fn min_normal_f64() -> f64 { let exponent_bits = 1u64 << 52; let bits = exponent_bits; f64::from_bits(bits) } #[inline] const fn mask_trailing_ones_u32(len: u32) -> u32 { if len >= 32 { u32::MAX // All ones if length is 64 or more } else { (1u32 << len).wrapping_sub(1) } } pub(crate) const EXP_MASK_F32: u32 = mask_trailing_ones_u32(8) << 23; #[inline] pub(crate) fn set_exponent_f32(x: u32, new_exp: u32) -> u32 { let encoded_mask = new_exp.wrapping_shl(23) & EXP_MASK_F32; x ^ ((x ^ encoded_mask) & EXP_MASK_F32) } pxfm-0.1.23/src/compound/compound_d.rs000064400000000000000000000414661046102023000160040ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::{log1p_f64_dyadic, log1p_fast_dd}; use crate::pow::{is_integer, is_odd_integer}; use crate::pow_exec::{exp_dyadic, pow_exp_dd}; use crate::triple_double::TripleDouble; /// Computes (1+x)^y /// pub fn f_compound(x: f64, y: f64) -> f64 { /* Rules from IEEE 754-2019 for compound (x, n) with n integer: (a) compound (x, 0) is 1 for x >= -1 or quiet NaN (b) compound (-1, n) is +Inf and signals the divideByZero exception for n < 0 (c) compound (-1, n) is +0 for n > 0 (d) compound (+/-0, n) is 1 (e) compound (+Inf, n) is +Inf for n > 0 (f) compound (+Inf, n) is +0 for n < 0 (g) compound (x, n) is qNaN and signals the invalid exception for x < -1 (h) compound (qNaN, n) is qNaN for n <> 0. */ let x_sign = x.is_sign_negative(); let y_sign = y.is_sign_negative(); let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff; let y_abs = y.to_bits() & 0x7fff_ffff_ffff_ffff; const MANTISSA_MASK: u64 = (1u64 << 52) - 1; let y_mant = y.to_bits() & MANTISSA_MASK; let x_u = x.to_bits(); let x_a = x_abs; let y_a = y_abs; // If x or y is signaling NaN if x.is_nan() || y.is_nan() { return f64::NAN; } let mut s = 1.0; let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff; let ay = y.to_bits() & 0x7fff_ffff_ffff_ffff; // The double precision number that is closest to 1 is (1 - 2^-53), which has // log2(1 - 2^-53) ~ -1.715...p-53. // So if |y| > |1075 / log2(1 - 2^-53)|, and x is finite: // |y * log2(x)| = 0 or > 1075. // Hence, x^y will either overflow or underflow if x is not zero. if y_mant == 0 || y_a > 0x43d7_4910_d52d_3052 || x_u == 1f64.to_bits() || x_u >= f64::INFINITY.to_bits() || x_u < f64::MIN.to_bits() { // Exceptional exponents. if y == 0.0 { return 1.0; } // (h) compound(qNaN, n) is qNaN for n ≠ 0 if x.is_nan() { if y != 0. { return x; } // propagate qNaN return 1.0; } // (d) compound(±0, n) is 1 if x == 0.0 { return 1.0; } // (e, f) compound(+Inf, n) if x.is_infinite() && x > 0.0 { return if y > 0. { x } else { 0.0 }; } // (g) compound(x, n) is qNaN and signals invalid for x < -1 if x < -1.0 { // Optional: raise invalid explicitly return f64::NAN; } // (b, c) compound(-1, n) if x == -1.0 { return if y < 0. { f64::INFINITY } else { 0.0 }; } match y_a { 0x3fe0_0000_0000_0000 => { // TODO: speed up x^(-1/2) with rsqrt(x) when available. if x == 0.0 { return 1.0; } let z = DoubleDouble::from_full_exact_add(x, 1.0).sqrt(); return if y_sign { z.recip().to_f64() } else { z.to_f64() }; } 0x3ff0_0000_0000_0000 => { return if y_sign { const ONES: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let z = DyadicFloat128::new_from_f64(x) + ONES; z.reciprocal().fast_as_f64() } else { DoubleDouble::from_full_exact_add(x, 1.0).to_f64() }; } 0x4000_0000_0000_0000 => { let z0 = DoubleDouble::from_full_exact_add(x, 1.0); let z = DoubleDouble::quick_mult(z0, z0); return if y_sign { z.recip().to_f64() } else { f64::copysign(z.to_f64(), x) }; } _ => {} } // |y| > |1075 / log2(1 - 2^-53)|. if y_a >= 0x7ff0_0000_0000_0000 { // y is inf or nan if y_mant != 0 { // y is NaN // pow(1, NaN) = 1 // pow(x, NaN) = NaN return if x_u == 1f64.to_bits() { 1.0 } else { y }; } // Now y is +-Inf if f64::from_bits(x_abs).is_nan() { // pow(NaN, +-Inf) = NaN return x; } if x == 0.0 && y_sign { // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO return f64::INFINITY; } // pow (|x| < 1, -inf) = +inf // pow (|x| < 1, +inf) = 0.0 // pow (|x| > 1, -inf) = 0.0 // pow (|x| > 1, +inf) = +inf return if (x_a < 1f64.to_bits()) == y_sign { f64::INFINITY } else { 0.0 }; } // y is finite and non-zero. if x == 0.0 { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { // pow(0, negative number) = inf return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } // pow(0, positive number) = 0 return if out_is_neg { -0.0 } else { 0.0 }; } if x_a == f64::INFINITY.to_bits() { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { return if out_is_neg { -0.0 } else { 0.0 }; } return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_a > f64::INFINITY.to_bits() { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } // x is finite and negative, and y is a finite integer. if x_sign { if is_integer(y) { if is_odd_integer(y) { // sign = -1.0; static CS: [f64; 2] = [1.0, -1.0]; // set sign to 1 for y even, to -1 for y odd let y_parity = if (y.abs()) >= f64::from_bits(0x4340000000000000) { 0usize } else { (y as i64 & 0x1) as usize }; s = CS[y_parity]; } } else { // pow( negative, non-integer ) = NaN return f64::NAN; } } // y is finite and non-zero. if x_u == 1f64.to_bits() { // compound(1, y) = 1 return 2.0; } if x == 0.0 { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { // pow(0, negative number) = inf return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } // pow(0, positive number) = 0 return if out_is_neg { -0.0 } else { 0.0 }; } if x_a == f64::INFINITY.to_bits() { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { return if out_is_neg { -0.0 } else { 0.0 }; } return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_a > f64::INFINITY.to_bits() { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } let min_abs = f64::min(f64::from_bits(ax), f64::from_bits(ay)).to_bits(); let max_abs = f64::max(f64::from_bits(ax), f64::from_bits(ay)).to_bits(); let min_exp = min_abs.wrapping_shr(52); let max_exp = max_abs.wrapping_shr(52); if max_exp > 0x7ffu64 - 128u64 || min_exp < 128u64 { let scale_up = min_exp < 128u64; let scale_down = max_exp > 0x7ffu64 - 128u64; // At least one input is denormal, multiply both numerator and denominator // then will go with hard path if scale_up || scale_down { return compound_accurate(x, y, s); } } } #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] let straight_path_precondition: bool = true; #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] let straight_path_precondition: bool = y.is_sign_positive(); // this is correct only for positive exponent number without FMA, // otherwise reciprocal may overflow. // y is integer and in [-102;102] and |x|<2^10 if y.floor() == y && y_a <= 0x4059800000000000u64 && x_a <= 0x4090000000000000u64 && x_a > 0x3cc0_0000_0000_0000 && straight_path_precondition { let mut s = DoubleDouble::from_full_exact_add(1.0, x); let mut iter_count = y.abs() as usize; // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { DoubleDouble::new(0., 1.) }; while { iter_count >>= 1; iter_count } != 0 { s = DoubleDouble::mult(s, s); if iter_count % 2 != 0 { acc = DoubleDouble::mult(acc, s); } } let dz = if y.is_sign_negative() { acc.recip() } else { acc }; let ub = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), -dz.hi, dz.lo); // 2^-59 let lb = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), dz.hi, dz.lo); // 2^-59 if ub == lb { return dz.to_f64(); } return mul_fixed_power_hard(x, y); } let l = log1p_fast_dd(x); let ey = ((y.to_bits() >> 52) & 0x7ff) as i32; if ey < 0x36 || ey >= 0x7f5 { return compound_accurate(x, y, s); } let r = DoubleDouble::quick_mult_f64(l, y); let res = pow_exp_dd(r, s); let res_min = res.hi + f_fmla(f64::from_bits(0x3bf0000000000000), -res.hi, res.lo); let res_max = res.hi + f_fmla(f64::from_bits(0x3bf0000000000000), res.hi, res.lo); if res_min == res_max { return res_max; } compound_accurate(x, y, s) } #[cold] fn compound_accurate(x: f64, y: f64, s: f64) -> f64 { /* the idea of returning res_max instead of res_min is due to Laurent Théry: it is better in case of underflow since res_max = +0 always. */ let f_y = DyadicFloat128::new_from_f64(y); let r = log1p_f64_dyadic(x) * f_y; let mut result = exp_dyadic(r); // 2^R.ex <= R < 2^(R.ex+1) /* case R < 2^-1075: underflow case */ if result.exponent < -1075 { return 0.5 * (s * f64::from_bits(0x0000000000000001)); } if result.exponent >= 1025 { return 1.0; } result.sign = if s == -1.0 { DyadicSign::Neg } else { DyadicSign::Pos }; result.fast_as_f64() } #[cold] #[inline(never)] fn mul_fixed_power_hard(x: f64, y: f64) -> f64 { let mut s = TripleDouble::from_full_exact_add(1.0, x); let mut iter_count = y.abs() as usize; // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { TripleDouble::new(0., 0., 1.) }; while { iter_count >>= 1; iter_count } != 0 { s = TripleDouble::quick_mult(s, s); if iter_count % 2 != 0 { acc = TripleDouble::quick_mult(acc, s); } } if y.is_sign_negative() { acc.recip().to_f64() } else { acc.to_f64() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_compound() { assert_eq!(f_compound(4831835136., -13.),0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012780345669344118 ); assert_eq!( f_compound(11468322278342656., 2.9995136260713475), 1481455956234813000000000000000000000000000000000. ); assert_eq!(f_compound(0.9999999999999999, 3.), 7.999999999999999); assert_eq!( f_compound(1.0039215087890625, 10.000000000349134), 1044.2562119607103 ); assert_eq!(f_compound(10., 18.0), 5559917313492231000.0); assert_eq!( f_compound(131071.65137729312, 2.000001423060894), 17180328027.532265 ); assert_eq!(f_compound(2., 5.), 243.); assert_eq!(f_compound(126.4324324, 126.4324324), 1.4985383310514043e266); assert_eq!(f_compound(0.4324324, 126.4324324), 5.40545942023447e19); assert!(f_compound(-0.4324324, 126.4324324).is_nan()); assert_eq!(f_compound(0.0, 0.0), 1.0); assert_eq!(f_compound(0.0, -1. / 2.), 1.0); assert_eq!(f_compound(-1., -1. / 2.), f64::INFINITY); assert_eq!(f_compound(f64::INFINITY, -1. / 2.), 0.0); assert_eq!(f_compound(f64::INFINITY, 1. / 2.), f64::INFINITY); assert_eq!(f_compound(46.3828125, 46.3828125), 5.248159634773675e77); } #[test] fn test_compound_exotic_cases() { assert_eq!(f_compound(0.9999999850987819, -1.), 0.5000000037253046); assert_eq!( f_compound(22427285907987670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000., -1.), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004458854290718438 ); assert_eq!(f_compound(0.786438105629145, 607.999512419221), 1616461095392737200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!(f_compound( 1.0000002381857613, 960.8218657970428), 17228671476562465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!(f_compound(1., 1.0000000000000284), 2.); assert_eq!(f_compound(1., f64::INFINITY), f64::INFINITY); assert_eq!( f_compound(10.000000000000007, -8.), 0.00000000466507380209731 ); } } pxfm-0.1.23/src/compound/compound_m1.rs000064400000000000000000000523741046102023000160760ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log1p_fast_dd; use crate::pow::{is_integer, is_odd_integer}; use crate::pow_exec::pow_expm1_1; /// Computes (1+x)^y - 1 /// /// max found ULP 0.56 pub fn f_compound_m1(x: f64, y: f64) -> f64 { /* Rules from IEEE 754-2019 for compound (x, n) with n integer: (a) compound (x, 0) is 1 for x >= -1 or quiet NaN (b) compound (-1, n) is +Inf and signals the divideByZero exception for n < 0 (c) compound (-1, n) is +0 for n > 0 (d) compound (+/-0, n) is 1 (e) compound (+Inf, n) is +Inf for n > 0 (f) compound (+Inf, n) is +0 for n < 0 (g) compound (x, n) is qNaN and signals the invalid exception for x < -1 (h) compound (qNaN, n) is qNaN for n <> 0. */ let x_sign = x.is_sign_negative(); let y_sign = y.is_sign_negative(); let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff; let y_abs = y.to_bits() & 0x7fff_ffff_ffff_ffff; const MANTISSA_MASK: u64 = (1u64 << 52) - 1; let y_mant = y.to_bits() & MANTISSA_MASK; let x_u = x.to_bits(); let x_a = x_abs; let y_a = y_abs; // If x or y is signaling NaN if x.is_nan() || y.is_nan() { return f64::NAN; } let mut s = 1.0; // The double precision number that is closest to 1 is (1 - 2^-53), which has // log2(1 - 2^-53) ~ -1.715...p-53. // So if |y| > |1075 / log2(1 - 2^-53)|, and x is finite: // |y * log2(x)| = 0 or > 1075. // Hence, x^y will either overflow or underflow if x is not zero. if y_mant == 0 || y_a > 0x43d7_4910_d52d_3052 || x_u == 1f64.to_bits() || x_u >= f64::INFINITY.to_bits() || x_u < f64::MIN.to_bits() { // Exceptional exponents. if y == 0.0 { return 0.0; } // (h) compound(qNaN, n) is qNaN for n ≠ 0 if x.is_nan() { if y != 0. { return x; } // propagate qNaN return 0.0; } // (d) compound(±0, n) is 1 if x == 0.0 { return 0.0; } // (e, f) compound(+Inf, n) if x.is_infinite() && x > 0.0 { return if y > 0. { x } else { -1.0 }; } // (g) compound(x, n) is qNaN and signals invalid for x < -1 if x < -1.0 { // Optional: raise invalid explicitly return f64::NAN; } // (b, c) compound(-1, n) if x == -1.0 { return if y < 0. { f64::INFINITY } else { -1.0 }; } match y_a { // 0x3fe0_0000_0000_0000 => { // if x == 0.0 { // return 0.0; // } // let z = Dekker::from_full_exact_add(x, 1.0).sqrt(); // if y_sign { // const M_ONES: DyadicFloat128 = DyadicFloat128 { // sign: DyadicSign::Neg, // exponent: -127, // mantissa: 0x80000000_00000000_00000000_00000000_u128, // }; // let z = DyadicFloat128::new_from_f64(z.to_f64()); // (z.reciprocal() + M_ONES).fast_as_f64() // } else { // const M_ONES: DyadicFloat128 = DyadicFloat128 { // sign: DyadicSign::Neg, // exponent: -127, // mantissa: 0x80000000_00000000_00000000_00000000_u128, // }; // let z = DyadicFloat128::new_from_f64(z.to_f64()); // (z + M_ONES).fast_as_f64() // }; // } 0x3ff0_0000_0000_0000 => { return if y_sign { let z = DyadicFloat128::new_from_f64(x); const ONES: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; const M_ONES: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let p = (z + ONES).reciprocal() + M_ONES; p.fast_as_f64() } else { x }; } 0x4000_0000_0000_0000 => { const ONES: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let z0 = DyadicFloat128::new_from_f64(x) + ONES; let z = z0 * z0; const M_ONES: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; return if y_sign { (z.reciprocal() + M_ONES).fast_as_f64() } else { f64::copysign((z + M_ONES).fast_as_f64(), x) }; } _ => {} } // |y| > |1075 / log2(1 - 2^-53)|. if y_a >= 0x7ff0_0000_0000_0000 { // y is inf or nan if y_mant != 0 { // y is NaN // pow(1, NaN) = 1 // pow(x, NaN) = NaN return if x_u == 1f64.to_bits() { 1.0 } else { y }; } // Now y is +-Inf if f64::from_bits(x_abs).is_nan() { // pow(NaN, +-Inf) = NaN return x; } if x_a == 0x3ff0_0000_0000_0000 { // pow(+-1, +-Inf) = 1.0 return 0.0; } if x == 0.0 && y_sign { // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO return f64::INFINITY; } // pow (|x| < 1, -inf) = +inf // pow (|x| < 1, +inf) = 0.0 // pow (|x| > 1, -inf) = 0.0 // pow (|x| > 1, +inf) = +inf return if (x_a < 1f64.to_bits()) == y_sign { f64::INFINITY } else { -1.0 }; } // y is finite and non-zero. if x_u == 1f64.to_bits() { // pow(1, y) = 1 return 0.0; } if x == 0.0 { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { // pow(0, negative number) = inf return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } // pow(0, positive number) = 0 return -1.0; } if x_a == f64::INFINITY.to_bits() { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { return if out_is_neg { -1.0 } else { 1.0 }; } return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_a > f64::INFINITY.to_bits() { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } // x is finite and negative, and y is a finite integer. if x_sign { if is_integer(y) { if is_odd_integer(y) { // sign = -1.0; static CS: [f64; 2] = [1.0, -1.0]; // set sign to 1 for y even, to -1 for y odd let y_parity = if (y.abs()) >= f64::from_bits(0x4340000000000000) { 0usize } else { (y as i64 & 0x1) as usize }; s = CS[y_parity]; } } else { // pow( negative, non-integer ) = NaN return f64::NAN; } } // y is finite and non-zero. if x_u == 1f64.to_bits() { // pow(1, y) = 1 return 0.0; } if x == 0.0 { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { // pow(0, negative number) = inf return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } // pow(0, positive number) = 0 return if out_is_neg { -0.0 } else { 0.0 }; } if x_a == f64::INFINITY.to_bits() { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { return -1.; } return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_a > f64::INFINITY.to_bits() { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } } // evaluate (1+x)^y explicitly for integer y in [-1024,1024] range and |x|<2^64 #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] let straight_path_precondition: bool = true; #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] let straight_path_precondition: bool = y.is_sign_positive(); // this is correct only for positive exponent number without FMA, // otherwise reciprocal may overflow. if y.floor() == y && y_a <= 0x4059800000000000u64 && x_a <= 0x4090000000000000u64 && x_a > 0x3cc0_0000_0000_0000 && straight_path_precondition { let mut s = DoubleDouble::from_full_exact_add(1.0, x); let mut iter_count = y.abs() as usize; // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { DoubleDouble::new(0., 1.) }; while { iter_count >>= 1; iter_count } != 0 { s = DoubleDouble::mult(s, s); if iter_count % 2 != 0 { acc = DoubleDouble::mult(acc, s); } } let mut dz = if y.is_sign_negative() { acc.recip() } else { acc }; dz = DoubleDouble::full_add_f64(dz, -1.); let ub = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), -dz.hi, dz.lo); // 2^-59 let lb = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), dz.hi, dz.lo); // 2^-59 if ub == lb { return dz.to_f64(); } return mul_fixed_power_hard(x, y); } // approximate log1p(x) let l = log1p_fast_dd(x); let ey = ((y.to_bits() >> 52) & 0x7ff) as i32; if ey < 0x36 || ey >= 0x7f5 { return 0.; } let r = DoubleDouble::quick_mult_f64(l, y); let res = pow_expm1_1(r, s); res.to_f64() } #[cold] #[inline(never)] fn mul_fixed_power_hard(x: f64, y: f64) -> f64 { const ONE: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; const M_ONE: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let mut s = DyadicFloat128::new_from_f64(x) + ONE; let mut iter_count = y.abs() as usize; // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { ONE }; while { iter_count >>= 1; iter_count } != 0 { s = s * s; if iter_count % 2 != 0 { acc = acc * s; } } if y.is_sign_negative() { (acc.reciprocal() + M_ONE).fast_as_f64() } else { (acc + M_ONE).fast_as_f64() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_compound_exotic() { assert_eq!( f_compound_m1(0.000152587890625, -8.484374999999998), -0.0012936766014690006 ); assert_eq!( f_compound_m1( 0.00000000000000799360578102344, -0.000000000000000000000001654361225106131 ), -0.000000000000000000000000000000000000013224311452909338 ); assert_eq!( f_compound_m1( 4.517647064592699, 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055329046628180653), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009449932890153435 ); assert_eq!(f_compound_m1( 11944758478933760000000000000000000000000000000000000000000000000000000000000000000000000000000000000000., -1242262631503757300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000., ), -1.); } #[test] fn test_compound_m1() { assert_eq!( f_compound_m1(0.0000000000000009991998751296936, -4.), -0.000000000000003996799500518764 ); assert_eq!(f_compound_m1(-0.003173828125, 25.), -0.0763960132649781); assert_eq!(f_compound_m1(3., 2.8927001953125), 54.154259038961406); assert_eq!( f_compound_m1(-0.43750000000000044, 19.), -0.9999821216263793 ); assert_eq!( f_compound_m1(127712., -2.0000000000143525), -0.9999999999386903 ); assert_eq!( f_compound_m1(-0.11718749767214207, 2893226081485815000000000000000.), -1. ); assert_eq!( f_compound_m1(2418441935074801400000000., 512.), f64::INFINITY ); assert_eq!( f_compound_m1(32.50198364245834, 128000.00000000093), f64::INFINITY ); assert_eq!( f_compound_m1(1.584716796877785, 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004168916810703412), 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003958869879428553 ); assert_eq!( f_compound_m1( -0.000000000000000000000000000000001997076793037533, 366577337071337140000000000000000f64 ), -0.5190938261758579 ); assert_eq!(f_compound_m1(2.1075630259863374, 0.5), 00.7628281328553664); assert_eq!(f_compound_m1(2.1078916412661783, 0.5), 0.7629213372315222); assert_eq!(f_compound_m1(3.0000000000001115, -0.5), -0.500000000000007); assert_eq!( f_compound_m1(0.0004873839215895903, 3.), 0.0014628645098045245 ); assert_eq!(f_compound_m1(-0.483765364602732, 3.), -0.862424399516842); assert_eq!(f_compound_m1(3.0000001192092896, -2.), -0.9375000037252902); assert_eq!(f_compound_m1(29.38323424607434, -1.), -0.9670871115332561); assert_eq!(f_compound_m1(-0.4375, 4.), -0.8998870849609375); assert_eq!( f_compound_m1(-0.0039033182037826464, 3.), -0.011664306402886494 ); assert_eq!( f_compound_m1(0.000000000000000000000000000000000000007715336350455947, -262034087537726030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), -1., ); assert_eq!(f_compound_m1(10.000000059604645, 10.), 25937426005.44638); assert_eq!(f_compound_m1(10., -308.25471555814863), -1.0); assert_eq!( f_compound_m1(5.4172231599824623E-312, 9.4591068440831498E+164), 5.124209266851586e-147 ); assert_eq!( f_compound_m1(5.8776567263633397E-39, 3.4223548116804511E-310), 0.0 ); assert_eq!( f_compound_m1(5.8639503496997932E-148, -7.1936801558778956E+305), 0.0 ); assert_eq!( f_compound_m1(0.9908447265624999, -19032028850336152000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), -1. ); assert_eq!( f_compound_m1(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006952247559980936, 5069789834563405000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), 3.524643400695958e-163 ); assert_eq!( f_compound_m1(1.000000000000341, -69261261804788370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), -1. ); assert_eq!( f_compound_m1( 0.0000000000000001053438024827798, 0.0000000000000001053438024827798 ), 0.000000000000000000000000000000011097316721530923 ); assert_eq!( f_compound_m1( 0.00000000000000010755285551056508, 0.00000000000000010755285551056508 ), 0.00000000000000000000000000000001156761672847649 ); assert_eq!(f_compound_m1(2.4324324, 1.4324324), 4.850778380908823); assert_eq!(f_compound_m1(2., 5.), 242.); assert_eq!(f_compound_m1(0.4324324, 126.4324324), 5.40545942023447e19); assert!(f_compound_m1(-0.4324324, 126.4324324).is_nan()); assert_eq!(f_compound_m1(0.0, 0.0), 0.0); assert_eq!(f_compound_m1(0.0, -1. / 2.), 0.0); assert_eq!(f_compound_m1(-1., -1. / 2.), f64::INFINITY); assert_eq!(f_compound_m1(f64::INFINITY, -1. / 2.), -1.0); assert_eq!(f_compound_m1(f64::INFINITY, 1. / 2.), f64::INFINITY); assert_eq!(f_compound_m1(46.3828125, 46.3828125), 5.248159634773675e77); } } pxfm-0.1.23/src/compound/compound_m1f.rs000064400000000000000000000366551046102023000162500ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use crate::compound::compoundf::{ COMPOUNDF_EXP2_T, COMPOUNDF_EXP2_U, compoundf_exp2_poly2, compoundf_log2p1_accurate, compoundf_log2p1_fast, }; use crate::double_double::DoubleDouble; use crate::exponents::exp2m1_accurate_tiny; use std::hint::black_box; // INVLOG2 = 1/log(2) * (1 + eps1) with |eps1| < 2^-55.976 const INVLOG2: f64 = f64::from_bits(0x3ff71547652b82fe); #[cold] #[inline(never)] fn as_compoundm1f_special(x: f32, y: f32) -> f32 { let nx = x.to_bits(); let ny = y.to_bits(); let ax: u32 = nx.wrapping_shl(1); let ay: u32 = ny.wrapping_shl(1); if ax == 0 || ay == 0 { // x or y is 0 if ax == 0 { // compound(0,y) = 1 except for y = sNaN return if y.is_nan() { x + y } else { 0.0 }; } if ay == 0 { // compound (x, 0) if x.is_nan() { return x + y; } // x = sNaN return if x < -1.0 { f32::NAN // rule (g) } else { 0.0 }; // rule (a) } } let mone = (-1.0f32).to_bits(); if ay >= 0xffu32 << 24 { // y=Inf/NaN // the case x=0 was already checked above if ax > 0xffu32 << 24 { return x + y; } // x=NaN if ay == 0xffu32 << 24 { // y = +/-Inf if nx > mone { return f32::NAN; } // rule (g) let sy = ny >> 31; // sign bit of y if nx == mone { return if sy == 0 { -1. // Rule (c) } else { f32::INFINITY // Rule (b) }; } if x < 0.0 { return if sy == 0 { -1. } else { f32::INFINITY }; } if x > 0.0 { return if sy != 0 { -1. } else { f32::INFINITY }; } return 0.0; } return x + y; // case y=NaN } if nx >= mone || nx >= 0xffu32 << 23 { // x is Inf, NaN or <= -1 if ax == 0xffu32 << 24 { // x is +Inf or -Inf if (nx >> 31) != 0 { return f32::NAN; } // x = -Inf, rule (g) // (1 + Inf)^y = +Inf for y > 0, +0 for y < 0 return (if (ny >> 31) != 0 { 1.0 / x } else { x }) - 1.; } if ax > 0xffu32 << 24 { return x + y; } // x is NaN if nx > mone { return f32::NAN; // x < -1.0: rule (g) } // now x = -1 return if (ny >> 31) != 0 { // y < 0 f32::INFINITY } else { // y > 0 -1.0 }; } -1. } /* for |z| <= 2^-6, returns an approximation of 2^z with absolute error < 2^-43.540 */ #[inline] pub(crate) fn compoundf_expf_poly(z: f64) -> f64 { /* Q is a degree-4 polynomial generated by Sollya (cf compoundf_expf.sollya) with absolute error < 2^-43.549 */ const Q: [u64; 5] = [ 0x3fe62e42fefa39ef, 0x3fcebfbdff8098eb, 0x3fac6b08d7045dc3, 0x3f83b2b276ce985d, 0x3f55d8849c67ace4, ]; let z2 = z * z; let c3 = dd_fmla(f64::from_bits(Q[4]), z, f64::from_bits(Q[3])); let c0 = dd_fmla(f64::from_bits(Q[1]), z, f64::from_bits(Q[0])); let c2 = dd_fmla(c3, z, f64::from_bits(Q[2])); dd_fmla(c2, z2, c0) * z } /* return the correct rounding of (1+x)^y, otherwise -1.0 where t is an approximation of y*log2(1+x) with absolute error < 2^-40.680, assuming 0x1.7154759a0df53p-24 <= |t| <= 150 exact is non-zero iff (1+x)^y is exact or midpoint */ fn exp2m1_fast(t: f64) -> f64 { let k = t.round_ties_even(); // 0 <= |k| <= 150 let mut r = t - k; // |r| <= 1/2, exact let mut v: u64 = (3.015625 + r).to_bits(); // 2.5 <= v <= 3.5015625 // we add 2^-6 so that i is rounded to nearest let i: i32 = (v >> 46) as i32 - 0x10010; // 0 <= i <= 32 r -= f64::from_bits(COMPOUNDF_EXP2_T[i as usize]); // exact // now |r| <= 2^-6 // 2^t = 2^k * exp2_U[i][0] * 2^r let mut s = f64::from_bits(COMPOUNDF_EXP2_U[i as usize].1); let su = ((k as u64).wrapping_add(0x3ffu64)) << 52; s *= f64::from_bits(su); let q_poly = compoundf_expf_poly(r); v = q_poly.to_bits(); /* the absolute error on exp2_U[i][0] is bounded by 2^-53.092, with exp2_U[i][0] < 2^0.5, and that on q1(r) is bounded by 2^-43.540, with |q1(r)| < 1.011, thus |v| < 1.43, and the absolute error on v is bounded by ulp(v) + 2^0.5s * 2^-43.540 + 2^-53.092 * 1.011 < 2^-43.035. Now t approximates u := y*log2(1+x) with |t-u| < 2^-40.680 thus 2^u = 2^t * (1 + eps) with eps < 2^(2^-40.680)-1 < 2^-41.208. The total absolute error is thus bounded by 2^-43.035 + 2^-41.208 < 2^-40.849. */ let mut err: u64 = 0x3d61d00000000000; // 2^-40.849 < 0x1.1dp-41 #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v = f_fmla(f64::from_bits(v), s, s - 1f64).to_bits(); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let p0 = DoubleDouble::from_full_exact_add(s, -1.); let z = DoubleDouble::from_exact_mult(f64::from_bits(v), s); v = DoubleDouble::add(z, p0).to_f64().to_bits(); } // in case of potential underflow, we defer to the accurate path if f64::from_bits(v) < f64::from_bits(0x3d61d00000000000) { return -1.0; } err = err.wrapping_add(((k as i64) << 52) as u64); // scale the error by 2^k too let lb = (f64::from_bits(v) - f64::from_bits(err)) as f32; let rb = (f64::from_bits(v) + f64::from_bits(err)) as f32; if lb != rb { return -1.0; } // rounding test failed f64::from_bits(v) } fn compoundf_exp2m1_accurate(x_dd: DoubleDouble, x: f32, y: f32) -> f32 { if y == 1.0 { let res = x; return res; } // check easy cases h+l is tiny thus 2^(h+l) rounds to 1, 1- or 1+ // if x_dd.hi.abs() <= f64::from_bits(0x3fc0000000000000u64) { // /* the relative error between h and y*log2(1+x) is bounded by // (1 + 2^-48.445) * (1 + 2^-91.120) - 1 < 2^-48.444. // 2^h rounds to 1 to nearest for |h| <= H0 := 0x1.715476af0d4d9p-25. // The above threshold is such that h*(1+2^-48.444) < H0. */ // return exp2m1_accurate_tiny(x_dd.to_f64()) as f32; // } let k = x_dd.hi.round_ties_even(); // |k| <= 150 // check easy cases h+l is tiny thus 2^(h+l) rounds to 1, 1- or 1+ if k == 0. && x_dd.hi.abs() <= f64::from_bits(0x3e6715476af0d4c8) { /* the relative error between h and y*log2(1+x) is bounded by (1 + 2^-48.445) * (1 + 2^-91.120) - 1 < 2^-48.444. 2^h rounds to 1 to nearest for |h| <= H0 := 0x1.715476af0d4d9p-25. The above threshold is such that h*(1+2^-48.444) < H0. */ // let z0 = 1.0 + x_dd.hi * 0.5; // let k = Dekker::from_exact_sub(z0, 1.); // return k.to_f64() as f32; return exp2m1_accurate_tiny(x_dd.to_f64()) as f32; } let r = x_dd.hi - k; // |r| <= 1/2, exact // since r is an integer multiple of ulp(h), fast_two_sum() below is exact let mut v_dd = DoubleDouble::from_exact_add(r, x_dd.lo); let mut v = (3.015625 + v_dd.hi).to_bits(); // 2.5 <= v <= 3.5015625 // we add 2^-6 so that i is rounded to nearest let i: i32 = ((v >> 46) as i32).wrapping_sub(0x10010); // 0 <= i <= 32 // h is near (i-16)/2^5 v_dd.hi -= f64::from_bits(COMPOUNDF_EXP2_T[i as usize]); // exact // now |h| <= 2^-6 // 2^(h+l) = 2^k * exp2_U[i] * 2^(h+l) v_dd = DoubleDouble::from_exact_add(v_dd.hi, v_dd.lo); let q = compoundf_exp2_poly2(v_dd); /* we have 0.989 < qh < 1.011, |ql| < 2^-51.959, and |qh + ql - 2^(h+l)| < 2^-85.210 */ let exp2u = DoubleDouble::from_bit_pair(COMPOUNDF_EXP2_U[i as usize]); let mut q = DoubleDouble::quick_mult(exp2u, q); q = DoubleDouble::from_exact_add(q.hi, q.lo); let mut du = (k as i64).wrapping_add(0x3ff).wrapping_shl(52) as u64; du = f64::from_bits(du).to_bits(); let scale = f64::from_bits(du); q.hi *= scale; q.lo *= scale; let zf: DoubleDouble = DoubleDouble::from_full_exact_add(q.hi, -1.0); q.lo += zf.lo; q.hi = zf.hi; v = q.to_f64().to_bits(); f64::from_bits(v) as f32 } // at input, exact is non-zero iff (1+x)^y is exact // x,y=0x1.0f6f1ap+1,0x1.c643bp+5: 49 identical bits after round bit // x,y=0x1.ef272cp+15,-0x1.746ab2p+1: 55 identical bits after round bit // x,y=0x1.07ffcp+0,-0x1.921a8ap+4: 47 identical bits after round bit #[cold] #[inline(never)] fn compoundm1f_accurate(x: f32, y: f32) -> f32 { let mut v = compoundf_log2p1_accurate(x as f64); v = DoubleDouble::quick_mult_f64(v, y as f64); compoundf_exp2m1_accurate(v, x, y) } /// Computes compound (1.0 + x)^y - 1 /// /// Max ULP 0.5 #[inline] pub fn f_compound_m1f(x: f32, y: f32) -> f32 { /* Rules from IEEE 754-2019 for compound (x, n) with n integer: (a) compound (x, 0) is 1 for x >= -1 or quiet NaN (b) compound (-1, n) is +Inf and signals the divideByZero exception for n < 0 (c) compound (-1, n) is +0 for n > 0 (d) compound (+/-0, n) is 1 (e) compound (+Inf, n) is +Inf for n > 0 (f) compound (+Inf, n) is +0 for n < 0 (g) compound (x, n) is qNaN and signals the invalid exception for x < -1 (h) compound (qNaN, n) is qNaN for n <> 0. */ let mone = (-1.0f32).to_bits(); let nx = x.to_bits(); let ny = y.to_bits(); if nx >= mone { return as_compoundm1f_special(x, y); } // x <= -1 // now x > -1 let ax: u32 = nx.wrapping_shl(1); let ay: u32 = ny.wrapping_shl(1); if ax == 0 || ax >= 0xffu32 << 24 || ay == 0 || ay >= 0xffu32 << 24 { return as_compoundm1f_special(x, y); } // x=+-0 || x=+-inf/nan || y=+-0 || y=+-inf/nan // evaluate (1+x)^y explicitly for integer y in [-16,16] range and |x|<2^64 if y.floor() == y && ay <= 0x83000000u32 && ax <= 0xbefffffeu32 { if ax <= 0x62000000u32 { return 1.0 + y * x; } // does it work for |x|<2^-29 and |y|<=16? let mut s = x as f64 + 1.; let mut iter_count = y.abs() as usize; // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { 1. }; while { iter_count >>= 1; iter_count } != 0 { s = s * s; if iter_count % 2 != 0 { acc *= s; } } let dz = if y.is_sign_negative() { 1. / acc } else { acc }; return DoubleDouble::from_full_exact_add(dz, -1.).to_f64() as f32; } let xd = x as f64; let yd = y as f64; let tx = xd.to_bits(); let ty = yd.to_bits(); let l: f64 = if ax < 0x62000000u32 { // |x| < 2^-29 /* |log2(1+x) - 1/log(2) * (x - x^2/2)| < 2^-59.584 * |log2(1+x)| (cf compoundf.sollya) */ let t = xd - (xd * xd) * 0.5; /* since x is epresentable in binary32, x*x is exact, and so is (x * x) * 0.5. Thus the only error in the computation of t is the final rounding, which is bounded by ulp(t): t = (x - x^2/2) * (1 + eps2) with |eps2| < 2^-52 */ INVLOG2 * t /* since INVLOG2 = 1/log(2) * (1 + eps1) and and t = (x - x^2/2) * (1 + eps2) let u = o(INVLOG2 * t) then u = INVLOG2 * t * (1 + eps3) with |eps3|<2^-53 thus u = 1/log(2) * (x - x^2/2) * (1 + eps1)*(1 + eps2)*(1 + eps3) = 1/log(2) * (x - x^2/2) * (1 + eps4) with |eps4| < 2^-50.954 Now Sollya says the relative error by approximating log2(1+x) by 1/log(2) * (x - x^2/2) for |x| < 2^-29 is bounded by 2^-59.584 (file compoundf.sollya), thus: u = log2(1+x) * (1+eps4)*(1+eps5) with |eps5| < 2^-59.584 = log2(1+x) * (1+eps6) with |eps6| < 2^-50.950 */ } else { compoundf_log2p1_fast(f64::from_bits(tx)) }; /* l approximates log2(1+x) with relative error < 2^-47.997, and 2^-149 <= |l| < 128 */ let t: u64 = (l * f64::from_bits(ty)).to_bits(); /* since 2^-149 <= |l| < 128 and 2^-149 <= |y| < 2^128, we have 2^-298 <= |t| < 2^135, thus no underflow/overflow in double is possible. The relative error is bounded by (1+2^-47.997)*(1+2^-52)-1 < 2^-47.909 */ // detect overflow/underflow if (t.wrapping_shl(1)) >= (0x406u64 << 53) { // |t| >= 128 if t >= 0x3018bu64 << 46 { // t <= -150 return black_box(f32::from_bits(0x00800000)) * black_box(f32::from_bits(0x00800000)); } else if (t >> 63) == 0 { // t >= 128: overflow return black_box(f32::from_bits(0x7e800000)) * black_box(f32::from_bits(0x7e800000)); } } let res = exp2m1_fast(f64::from_bits(t)); if res != -1.0 { return res as f32; } compoundm1f_accurate(x, y) } #[cfg(test)] mod tests { use super::*; use crate::compound::compound_m1f::{compoundf_exp2m1_accurate, exp2m1_fast}; use crate::double_double::DoubleDouble; #[test] fn test_compoundf() { assert_eq!( f_compound_m1f(-0.000000000000001191123, -0.000000000000001191123), 0.0000000000000000000000000000014187741 ); assert_eq!(f_compound_m1f(-0.000000000000001191123, 16.), 1.0); assert_eq!(f_compound_m1f(0.91123, 16.), 31695.21); assert_eq!(f_compound_m1f(0.91123, -16.), -0.99996847); } #[test] fn test_compoundf_expm1_fast() { assert_eq!(exp2m1_fast(3.764), 12.585539943149435); } #[test] fn test_compoundf_expm1_accurate() { assert_eq!( compoundf_exp2m1_accurate(DoubleDouble::new(0., 2.74), 12., 53.), 5.680703, ); } } pxfm-0.1.23/src/compound/compoundf.rs000064400000000000000000001054371046102023000156460ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::dd_fmla; use crate::double_double::DoubleDouble; use std::hint::black_box; #[cold] #[inline(never)] fn as_compoundf_special(x: f32, y: f32) -> f32 { let nx = x.to_bits(); let ny = y.to_bits(); let ax: u32 = nx.wrapping_shl(1); let ay: u32 = ny.wrapping_shl(1); if ax == 0 || ay == 0 { // x or y is 0 if ax == 0 { // compound(0,y) = 1 except for y = sNaN return if y.is_nan() { x + y } else { 1.0 }; } if ay == 0 { // compound (x, 0) if x.is_nan() { return x + y; } // x = sNaN return if x < -1.0 { f32::NAN // rule (g) } else { 1.0 }; // rule (a) } } let mone = (-1.0f32).to_bits(); if ay >= 0xffu32 << 24 { // y=Inf/NaN // the case x=0 was already checked above if ax > 0xffu32 << 24 { return x + y; } // x=NaN if ay == 0xffu32 << 24 { // y = +/-Inf if nx > mone { return f32::NAN; } // rule (g) let sy = ny >> 31; // sign bit of y if nx == mone { return if sy == 0 { 0.0 // Rule (c) } else { f32::INFINITY // Rule (b) }; } if x < 0.0 { return if sy == 0 { 0.0 } else { f32::INFINITY }; } if x > 0.0 { return if sy != 0 { 0.0 } else { f32::INFINITY }; } return 1.0; } return x + y; // case y=NaN } if nx >= mone || nx >= 0xffu32 << 23 { // x is Inf, NaN or <= -1 if ax == 0xffu32 << 24 { // x is +Inf or -Inf if (nx >> 31) != 0 { return f32::NAN; } // x = -Inf, rule (g) // (1 + Inf)^y = +Inf for y > 0, +0 for y < 0 return if (ny >> 31) != 0 { 1.0 / x } else { x }; } if ax > 0xffu32 << 24 { return x + y; } // x is NaN if nx > mone { return f32::NAN; // x < -1.0: rule (g) } // now x = -1 return if (ny >> 31) != 0 { // y < 0 f32::INFINITY } else { // y > 0 0.0 }; } 0.0 } #[inline] pub(crate) fn log2p1_polyeval_1(z: f64) -> f64 { // we include P[0] = 0 so that P[i] corresponds to degree i // this degree-8 polynomial generated by Sollya (cf p1.sollya) // has relative error < 2^-50.98 const P: [u64; 8] = [ 0x0000000000000000, 0x3ff71547652b82fe, 0xbfe71547652b8d11, 0x3fdec709dc3a5014, 0xbfd715475b144983, 0x3fd2776c3fda300e, 0xbfcec990162358ce, 0x3fca645337c29e27, ]; let z2 = z * z; let mut c5 = dd_fmla(f64::from_bits(P[6]), z, f64::from_bits(P[5])); let c3 = dd_fmla(f64::from_bits(P[4]), z, f64::from_bits(P[3])); let mut c1 = dd_fmla(f64::from_bits(P[2]), z, f64::from_bits(P[1])); let z4 = z2 * z2; c5 = dd_fmla(f64::from_bits(P[7]), z2, c5); c1 = dd_fmla(c3, z2, c1); c1 = dd_fmla(c5, z4, c1); z * c1 } // for 0<=i<46, inv[i] approximates 1/t for 1/2+(i+13)/64 <= t < 1/2+(i+14)/64 pub(crate) static LOG2P1_COMPOUNDF_INV: [u64; 46] = [ 0x3ff6800000000000, 0x3ff6000000000000, 0x3ff5800000000000, 0x3ff5000000000000, 0x3ff4c00000000000, 0x3ff4400000000000, 0x3ff4000000000000, 0x3ff3800000000000, 0x3ff3400000000000, 0x3ff2c00000000000, 0x3ff2800000000000, 0x3ff2000000000000, 0x3ff1c00000000000, 0x3ff1800000000000, 0x3ff1400000000000, 0x3ff1000000000000, 0x3ff0c00000000000, 0x3ff0800000000000, 0x3ff0000000000000, 0x3ff0000000000000, 0x3fef400000000000, 0x3feec00000000000, 0x3fee400000000000, 0x3fee000000000000, 0x3fed800000000000, 0x3fed000000000000, 0x3feca00000000000, 0x3fec400000000000, 0x3febe00000000000, 0x3feb800000000000, 0x3feb200000000000, 0x3feac00000000000, 0x3fea800000000000, 0x3fea200000000000, 0x3fe9c00000000000, 0x3fe9800000000000, 0x3fe9200000000000, 0x3fe8c00000000000, 0x3fe8800000000000, 0x3fe8400000000000, 0x3fe8000000000000, 0x3fe7c00000000000, 0x3fe7600000000000, 0x3fe7200000000000, 0x3fe6e00000000000, 0x3fe6a00000000000, ]; /* log2inv[i][0]+log2inv[i][1] is a double-double approximation of -log2(inv[i]), with log2inv[i][0] having absolute error < 2^-54.462, and log2inv[i][0]+log2inv[i][1] absolute error < 2^-109.101 */ pub(crate) static LOG2P1_COMPOUNDF_LOG2_INV: [(u64, u64); 46] = [ (0x3c68f3673ffdd785, 0xbfdf7a8568cb06cf), (0x3c1c141e66faaaad, 0xbfdd6753e032ea0f), (0x3c76fae441c09d76, 0xbfdb47ebf73882a1), (0x3c72d352bea51e59, 0xbfd91bba891f1709), (0xbc69575b04fa6fbd, 0xbfd800a563161c54), (0x3c7817fd3b7d7e5d, 0xbfd5c01a39fbd688), (0x3c1b6d40900b2502, 0xbfd49a784bcd1b8b), (0x3c7f6e91ad16ecff, 0xbfd24407ab0e073a), (0x3c6a7b47d2c352d9, 0xbfd11307dad30b76), (0x3c5b85a54d7ee2fd, 0xbfcd49ee4c325970), (0x3c401ee1343fe7ca, 0xbfcacf5e2db4ec94), (0x3c6817fd3b7d7e5d, 0xbfc5c01a39fbd688), (0xbc4f51f2c075a74c, 0xbfc32ae9e278ae1a), (0x3c6a7610e40bd6ab, 0xbfc08c588cda79e4), (0xbc58ecb169b9465f, 0xbfbbc84240adabba), (0xbc5f3314e0985116, 0xbfb663f6fac91316), (0x3c530c22d15199b8, 0xbfb0eb389fa29f9b), (0xbc389b03784b5be1, 0xbfa6bad3758efd87), (0x0000000000000000, 0x0000000000000000), (0x0000000000000000, 0x0000000000000000), (0x3c3491f06c085bc2, 0x3fa184b8e4c56af8), (0x3c0155660710eb2a, 0x3fad6ebd1f1febfe), (0x3c2c141e66faaaad, 0x3fb4c560fe68af88), (0x3c59ced1447e30ad, 0x3fb7d60496cfbb4c), (0x3c592ce9636c90a0, 0x3fbe0b1ae8f2fd56), (0xbc5696e2866c718e, 0x3fc22dadc2ab3497), (0xbc61562d61af73f8, 0x3fc494f863b8df35), (0xbc60798d1aa21694, 0x3fc7046031c79f85), (0xbc6e95734abd2fcc, 0x3fc97c1cb13c7ec1), (0x3c2bc0af7b82e7d7, 0x3fcbfc67a7fff4cc), (0xbc6086fce864a1f6, 0x3fce857d3d361368), (0xbc53d56efe4338fe, 0x3fd08bce0d95fa38), (0x3c7c8d43e017579b, 0x3fd169c05363f158), (0xbc50132ae5e417cd, 0x3fd2baa0c34be1ec), (0xbc7c658d602e66b0, 0x3fd4106017c3eca3), (0x3c7e393a16b94b52, 0x3fd4f6fbb2cec598), (0x3c7ac9080333c605, 0x3fd6552b49986277), (0x3c68f89e2eb553b2, 0x3fd7b89f02cf2aad), (0x3c799aa6df8b7d83, 0x3fd8a8980abfbd32), (0x3c7bca36fd02def0, 0x3fd99b072a96c6b2), (0x3c5817fd3b7d7e5d, 0x3fda8ff971810a5e), (0xbc501d98c3531027, 0x3fdb877c57b1b070), (0x3c78a38b4175d665, 0x3fdcffae611ad12b), (0x3c438c8946414c6a, 0x3fddfdd89d586e2b), (0x3c76d261f1753e0b, 0x3fdefec61b011f85), (0xbc87398fe685f171, 0x3fe0014332be0033), ]; /* for |z| <= 2^-6, returns an approximation of 2^z with absolute error < 2^-43.540 */ #[inline] fn compoundf_expf_poly(z: f64) -> f64 { /* Q is a degree-4 polynomial generated by Sollya (cf q1.sollya) with absolute error < 2^-43.549 */ const Q: [u64; 5] = [ 0x3ff0000000000000, 0x3fe62e42fef6d01a, 0x3fcebfbdff7feeba, 0x3fac6b167e579bee, 0x3f83b2b3428d06de, ]; let z2 = z * z; let c3 = dd_fmla(f64::from_bits(Q[4]), z, f64::from_bits(Q[3])); let c0 = dd_fmla(f64::from_bits(Q[1]), z, f64::from_bits(Q[0])); let c2 = dd_fmla(c3, z, f64::from_bits(Q[2])); dd_fmla(c2, z2, c0) } pub(crate) fn compoundf_log2p1_fast(x: f64) -> f64 { /* for x > 0, 1+x is exact when 2^-29 <= x < 2^53 for x < 0, 1+x is exact when -1 < x <= 2^-30 */ // double u = (x >= 0x1p53) ? x : 1.0 + x; let u = 1.0 + x; /* For x < 0x1p53, x + 1 is exact thus u = x+1. For x >= 2^53, we estimate log2(x) instead of log2(1+x), since log2(1+x) = log2(x) + log2(1+1/x), log2(x) >= 53 and |log2(1+1/x)| < 2^-52.471, the additional relative error is bounded by 2^-52.471/53 < 2^-58.198 */ let mut v = u.to_bits(); let m: u64 = v & 0xfffffffffffffu64; let e: i64 = (v >> 52) as i64 - 0x3ff + (m >= 0x6a09e667f3bcdu64) as i64; // 2^e/sqrt(2) < u < 2^e*sqrt(2), with -29 <= e <= 128 v = v.wrapping_sub((e << 52) as u64); let t = f64::from_bits(v); // u = 2^e*t with 1/sqrt(2) < t < sqrt(2) // thus log2(u) = e + log2(t) v = (f64::from_bits(v) + 2.0).to_bits(); // add 2 so that v.f is always in the binade [2, 4) let i = (v >> 45) as i32 - 0x2002d; // 0 <= i <= 45 let r = f64::from_bits(LOG2P1_COMPOUNDF_INV[i as usize]); let z = dd_fmla(r, t, -1.0); // exact, -1/64 <= z <= 1/64 // we approximates log2(t) by -log2(r) + log2(r*t) let p = log2p1_polyeval_1(z); // p approximates log2(r*t) with rel. error < 2^-49.642, and |p| < 2^-5.459 e as f64 + (f64::from_bits(LOG2P1_COMPOUNDF_LOG2_INV[i as usize].1) + p) } pub(crate) static COMPOUNDF_EXP2_T: [u64; 33] = [ 0xbfe0000000000000, 0xbfde000000000000, 0xbfdc000000000000, 0xbfda000000000000, 0xbfd8000000000000, 0xbfd6000000000000, 0xbfd4000000000000, 0xbfd2000000000000, 0xbfd0000000000000, 0xbfcc000000000000, 0xbfc8000000000000, 0xbfc4000000000000, 0xbfc0000000000000, 0xbfb8000000000000, 0xbfb0000000000000, 0xbfa0000000000000, 0x0000000000000000, 0x3fa0000000000000, 0x3fb0000000000000, 0x3fb8000000000000, 0x3fc0000000000000, 0x3fc4000000000000, 0x3fc8000000000000, 0x3fcc000000000000, 0x3fd0000000000000, 0x3fd2000000000000, 0x3fd4000000000000, 0x3fd6000000000000, 0x3fd8000000000000, 0x3fda000000000000, 0x3fdc000000000000, 0x3fde000000000000, 0x3fe0000000000000, ]; /* exp2_U[i] is a double-double approximation h+l of 2^exp2_T[i] so that h approximates 2^exp2_T[i] with absolute error < 2^-53.092, and h+l approximates 2^exp2_T[i] with absolute error < 2^-107.385 */ pub(crate) static COMPOUNDF_EXP2_U: [(u64, u64); 33] = [ (0xbc8bdd3413b26456, 0x3fe6a09e667f3bcd), (0xbc716e4786887a99, 0x3fe71f75e8ec5f74), (0xbc741577ee04992f, 0x3fe7a11473eb0187), (0xbc8d4c1dd41532d8, 0x3fe82589994cce13), (0x3c86e9f156864b27, 0x3fe8ace5422aa0db), (0xbc575fc781b57ebc, 0x3fe93737b0cdc5e5), (0x3c6c7c46b071f2be, 0x3fe9c49182a3f090), (0xbc8d2f6edb8d41e1, 0x3fea5503b23e255d), (0x3c87a1cd345dcc81, 0x3feae89f995ad3ad), (0xbc65584f7e54ac3b, 0x3feb7f76f2fb5e47), (0x3c711065895048dd, 0x3fec199bdd85529c), (0x3c6503cbd1e949db, 0x3fecb720dcef9069), (0x3c72ed02d75b3707, 0x3fed5818dcfba487), (0xbc81a5cd4f184b5c, 0x3fedfc97337b9b5f), (0xbc8e9c23179c2893, 0x3feea4afa2a490da), (0x3c89d3e12dd8a18b, 0x3fef50765b6e4540), (0x0000000000000000, 0x3ff0000000000000), (0x3c8d73e2a475b465, 0x3ff059b0d3158574), (0x3c98a62e4adc610b, 0x3ff0b5586cf9890f), (0xbc96c51039449b3a, 0x3ff11301d0125b51), (0xbc819041b9d78a76, 0x3ff172b83c7d517b), (0x3c9e016e00a2643c, 0x3ff1d4873168b9aa), (0x3c99b07eb6c70573, 0x3ff2387a6e756238), (0x3c8612e8afad1255, 0x3ff29e9df51fdee1), (0x3c86f46ad23182e4, 0x3ff306fe0a31b715), (0xbc963aeabf42eae2, 0x3ff371a7373aa9cb), (0x3c8ada0911f09ebc, 0x3ff3dea64c123422), (0x3c489b7a04ef80d0, 0x3ff44e086061892d), (0x3c7d4397afec42e2, 0x3ff4bfdad5362a27), (0xbc807abe1db13cad, 0x3ff5342b569d4f82), (0x3c96324c054647ad, 0x3ff5ab07dd485429), (0xbc9383c17e40b497, 0x3ff6247eb03a5585), (0xbc9bdd3413b26456, 0x3ff6a09e667f3bcd), ]; /* return the correct rounding of (1+x)^y, otherwise -1.0 where t is an approximation of y*log2(1+x) with absolute error < 2^-40.680, assuming 0x1.7154759a0df53p-24 <= |t| <= 150 exact is non-zero iff (1+x)^y is exact or midpoint */ fn exp2_fast(t: f64) -> f64 { let k = t.round_ties_even(); // 0 <= |k| <= 150 let mut r = t - k; // |r| <= 1/2, exact let mut v: u64 = (3.015625 + r).to_bits(); // 2.5 <= v <= 3.5015625 // we add 2^-6 so that i is rounded to nearest let i: i32 = (v >> 46) as i32 - 0x10010; // 0 <= i <= 32 r -= f64::from_bits(COMPOUNDF_EXP2_T[i as usize]); // exact // now |r| <= 2^-6 // 2^t = 2^k * exp2_U[i][0] * 2^r v = (f64::from_bits(COMPOUNDF_EXP2_U[i as usize].1) * compoundf_expf_poly(r)).to_bits(); /* the absolute error on exp2_U[i][0] is bounded by 2^-53.092, with exp2_U[i][0] < 2^0.5, and that on q1(r) is bounded by 2^-43.540, with |q1(r)| < 1.011, thus |v| < 1.43, and the absolute error on v is bounded by ulp(v) + 2^0.5 * 2^-43.540 + 2^-53.092 * 1.011 < 2^-43.035. Now t approximates u := y*log2(1+x) with |t-u| < 2^-40.680 thus 2^u = 2^t * (1 + eps) with eps < 2^(2^-40.680)-1 < 2^-41.208. The total absolute error is thus bounded by 2^-43.035 + 2^-41.208 < 2^-40.849. */ let mut err: u64 = 0x3d61d00000000000; // 2^-40.849 < 0x1.1dp-41 v = v.wrapping_add((k as i64).wrapping_shl(52) as u64); // scale v by 2^k // in case of potential underflow, we defer to the accurate path if f64::from_bits(v) < f64::from_bits(0x38100000000008e2) { return -1.0; } err = err.wrapping_add(((k as i64) << 52) as u64); // scale the error by 2^k too let lb = (f64::from_bits(v) - f64::from_bits(err)) as f32; let rb = (f64::from_bits(v) + f64::from_bits(err)) as f32; if lb != rb { return -1.0; } // rounding test failed f64::from_bits(v) } // 2^e/sqrt(2) < h < 2^e*sqrt(2), with -29 <= e <= 128 // divide h, l by 2^e pub(crate) static LOG2P1_SCALE: [u64; 158] = [ 0x41c0000000000000, 0x41b0000000000000, 0x41a0000000000000, 0x4190000000000000, 0x4180000000000000, 0x4170000000000000, 0x4160000000000000, 0x4150000000000000, 0x4140000000000000, 0x4130000000000000, 0x4120000000000000, 0x4110000000000000, 0x4100000000000000, 0x40f0000000000000, 0x40e0000000000000, 0x40d0000000000000, 0x40c0000000000000, 0x40b0000000000000, 0x40a0000000000000, 0x4090000000000000, 0x4080000000000000, 0x4070000000000000, 0x4060000000000000, 0x4050000000000000, 0x4040000000000000, 0x4030000000000000, 0x4020000000000000, 0x4010000000000000, 0x4000000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fd0000000000000, 0x3fc0000000000000, 0x3fb0000000000000, 0x3fa0000000000000, 0x3f90000000000000, 0x3f80000000000000, 0x3f70000000000000, 0x3f60000000000000, 0x3f50000000000000, 0x3f40000000000000, 0x3f30000000000000, 0x3f20000000000000, 0x3f10000000000000, 0x3f00000000000000, 0x3ef0000000000000, 0x3ee0000000000000, 0x3ed0000000000000, 0x3ec0000000000000, 0x3eb0000000000000, 0x3ea0000000000000, 0x3e90000000000000, 0x3e80000000000000, 0x3e70000000000000, 0x3e60000000000000, 0x3e50000000000000, 0x3e40000000000000, 0x3e30000000000000, 0x3e20000000000000, 0x3e10000000000000, 0x3e00000000000000, 0x3df0000000000000, 0x3de0000000000000, 0x3dd0000000000000, 0x3dc0000000000000, 0x3db0000000000000, 0x3da0000000000000, 0x3d90000000000000, 0x3d80000000000000, 0x3d70000000000000, 0x3d60000000000000, 0x3d50000000000000, 0x3d40000000000000, 0x3d30000000000000, 0x3d20000000000000, 0x3d10000000000000, 0x3d00000000000000, 0x3cf0000000000000, 0x3ce0000000000000, 0x3cd0000000000000, 0x3cc0000000000000, 0x3cb0000000000000, 0x3ca0000000000000, 0x3c90000000000000, 0x3c80000000000000, 0x3c70000000000000, 0x3c60000000000000, 0x3c50000000000000, 0x3c40000000000000, 0x3c30000000000000, 0x3c20000000000000, 0x3c10000000000000, 0x3c00000000000000, 0x3bf0000000000000, 0x3be0000000000000, 0x3bd0000000000000, 0x3bc0000000000000, 0x3bb0000000000000, 0x3ba0000000000000, 0x3b90000000000000, 0x3b80000000000000, 0x3b70000000000000, 0x3b60000000000000, 0x3b50000000000000, 0x3b40000000000000, 0x3b30000000000000, 0x3b20000000000000, 0x3b10000000000000, 0x3b00000000000000, 0x3af0000000000000, 0x3ae0000000000000, 0x3ad0000000000000, 0x3ac0000000000000, 0x3ab0000000000000, 0x3aa0000000000000, 0x3a90000000000000, 0x3a80000000000000, 0x3a70000000000000, 0x3a60000000000000, 0x3a50000000000000, 0x3a40000000000000, 0x3a30000000000000, 0x3a20000000000000, 0x3a10000000000000, 0x3a00000000000000, 0x39f0000000000000, 0x39e0000000000000, 0x39d0000000000000, 0x39c0000000000000, 0x39b0000000000000, 0x39a0000000000000, 0x3990000000000000, 0x3980000000000000, 0x3970000000000000, 0x3960000000000000, 0x3950000000000000, 0x3940000000000000, 0x3930000000000000, 0x3920000000000000, 0x3910000000000000, 0x3900000000000000, 0x38f0000000000000, 0x38e0000000000000, 0x38d0000000000000, 0x38c0000000000000, 0x38b0000000000000, 0x38a0000000000000, 0x3890000000000000, 0x3880000000000000, 0x3870000000000000, 0x3860000000000000, 0x3850000000000000, 0x3840000000000000, 0x3830000000000000, 0x3820000000000000, 0x3810000000000000, 0x3800000000000000, 0x37f0000000000000, ]; /* put in h+l an approximation of log2(1+zh+zl) for |zh| <= 1/64 + 2^-51.508, |zl| < 2^-58 and |zl| < ulp(zh). We have |h|, |h+l| < 2^-5.459, |l| < 2^-56.162, the relative error is bounded by 2^-91.196, and |l| < 2^-50.523 |h| (see analyze_p2() in compoundf.sage). */ /* degree-13 polynomial generated by Sollya which approximates log2(1+z) for |z| <= 1/64 with relative error < 2^-93.777 (cf file p2.sollya) */ static LOG2P1_LOG2_POLY: [u64; 18] = [ 0x3ff71547652b82fe, 0x3c7777d0ffda0d80, 0xbfe71547652b82fe, 0xbc6777d0fd20b49c, 0x3fdec709dc3a03fd, 0x3c7d27f05171b74a, 0xbfd71547652b82fe, 0xbc57814e70b828b0, 0x3fd2776c50ef9bfe, 0x3c7e4f63e12bff83, 0xbfcec709dc3a03f4, 0x3fca61762a7adecc, 0xbfc71547652d8849, 0x3fc484b13d7e7029, 0xbfc2776c1b2a40fd, 0x3fc0c9a80f9b7c1c, 0xbfbecc6801121200, 0x3fbc6e4b91fd10e5, ]; fn log2_poly2(z: DoubleDouble) -> DoubleDouble { /* since we can't expect a relative accuracy better than 2^-93.777, the lower part of the double-double approximation only needs to have about 94-53 = 41 accurate bits. Since |p7*z^7/p1| < 2^-44, we evaluate terms of degree 7 or more in double precision only. */ let mut h = f64::from_bits(LOG2P1_LOG2_POLY[4 + 13]); // degree 13 for i in 7..=12 { h = dd_fmla(z.hi, z.hi, f64::from_bits(LOG2P1_LOG2_POLY[4 + i])); } let mut v = DoubleDouble::quick_mult_f64(z, h); let t = DoubleDouble::from_exact_add(v.hi, f64::from_bits(LOG2P1_LOG2_POLY[10])); v.hi = t.hi; v.lo += t.lo; v = DoubleDouble::quick_mult(v, z); let t = DoubleDouble::from_exact_add(v.hi, f64::from_bits(LOG2P1_LOG2_POLY[8])); v.hi = t.hi; v.lo += t.lo + f64::from_bits(LOG2P1_LOG2_POLY[9]); v = DoubleDouble::quick_mult(v, z); let t = DoubleDouble::from_exact_add(v.hi, f64::from_bits(LOG2P1_LOG2_POLY[6])); v.hi = t.hi; v.lo += t.lo + f64::from_bits(LOG2P1_LOG2_POLY[7]); v = DoubleDouble::quick_mult(v, z); let t = DoubleDouble::from_exact_add(v.hi, f64::from_bits(LOG2P1_LOG2_POLY[4])); v.hi = t.hi; v.lo += t.lo + f64::from_bits(LOG2P1_LOG2_POLY[5]); v = DoubleDouble::quick_mult(v, z); let t = DoubleDouble::from_exact_add(v.hi, f64::from_bits(LOG2P1_LOG2_POLY[2])); v.hi = t.hi; v.lo += t.lo + f64::from_bits(LOG2P1_LOG2_POLY[3]); v = DoubleDouble::quick_mult(v, z); let t = DoubleDouble::from_exact_add(v.hi, f64::from_bits(LOG2P1_LOG2_POLY[0])); v.hi = t.hi; v.lo += t.lo + f64::from_bits(LOG2P1_LOG2_POLY[1]); v = DoubleDouble::quick_mult(v, z); v } /* assuming -1 < x < 2^128, and x is representable in binary32, put in h+l a double-double approximation of log2(1+x), with relative error bounded by 2^-91.123, and |l| < 2^-48.574 |h| (see analyze_log2p1_accurate() in compoundf.sage) */ pub(crate) fn compoundf_log2p1_accurate(x: f64) -> DoubleDouble { let mut v_dd = if 1.0 >= x { // then 1.0 >= |x| since x > -1 if (x as f32).abs() >= f32::from_bits(0x25000000) { DoubleDouble::from_exact_add(1.0, x) } else { DoubleDouble::new(x, 1.0) } } else { // fast_two_sum() is exact when |x| < 2^54 by Lemma 1 condition (ii) of [1] DoubleDouble::from_exact_add(x, 1.0) }; // now h + l = 1 + x + eps with |eps| <= 2^-105 |h| and |l| <= ulp(h) let mut v = v_dd.hi.to_bits(); let m = v & 0xfffffffffffffu64; let e: i64 = (v >> 52) as i64 - 0x3ff + (m >= 0x6a09e667f3bcdu64) as i64; let scale = f64::from_bits(LOG2P1_SCALE[e.wrapping_add(29) as usize]); v_dd.hi *= scale; v_dd.lo *= scale; // now |h| < sqrt(2) and |l| <= ulp(h) <= 2^-52 // now 1 + x ~ 2^e * (h + l) thus log2(1+x) ~ e + log2(h+l) v = (2.0 + v_dd.hi).to_bits(); // add 2 so that v.f is always in the binade [2, 4) let i: i32 = (v >> 45) as i32 - 0x2002d; // h is near 1/2+(i+13)/64 let r = f64::from_bits(LOG2P1_COMPOUNDF_INV[i as usize]); let mut z_dd = DoubleDouble::new(r * v_dd.lo, dd_fmla(r, v_dd.hi, -1.0)); // exact, -1/64 <= zh <= 1/64 // since |r| <= 0x1.68p+0 and |l| <= 2^-52, |zl| <= 2^-51.508 // zh + zl = r*(h+l)-1 // log2(h+l) = -log2(r) + log2(r*(h+l)) = -log2(r) + log2(1+zh+zl) z_dd = DoubleDouble::from_exact_add(z_dd.hi, z_dd.lo); // now |zh| <= 1/64 + 2^-51.508 and |zl| < 2^-58 /* the relative error of fast_two_sum() is bounded by 2^-105, this amplified the relative error on p2() as follows: (1+2^-91.196)*(1+2^-105)-1 < 2^-91.195. */ // now |zh| <= 1/64 + 2^-51.508 and |zl| < 2^-58 /* the relative error of fast_two_sum() is bounded by 2^-105, this amplified the relative error on p2() as follows: (1+2^-91.196)*(1+2^-105)-1 < 2^-91.195. */ let log_p = log2_poly2(z_dd); // ph + pl approximates log2(1+zh+zl) with relative error < 2^-93.471 /* since |log2inv[i][0]| < 1 and e is integer, the precondition of fast_two_sum is fulfilled: either |e| >= 1, or e=0 and fast_two_sum is exact */ let log2_inv = LOG2P1_COMPOUNDF_LOG2_INV[i as usize]; v_dd = DoubleDouble::from_exact_add(e as f64, f64::from_bits(log2_inv.1)); v_dd.lo += f64::from_bits(log2_inv.0); let mut p = DoubleDouble::from_exact_add(v_dd.hi, log_p.hi); p.lo += v_dd.lo + log_p.lo; p } pub(crate) fn compoundf_exp2_poly2(z: DoubleDouble) -> DoubleDouble { /* Q2 is a degree-8 polynomial generated by Sollya (cf q2.sollya) with absolute error < 2^-85.218 */ static Q2: [u64; 12] = [ 0x3ff0000000000000, 0x3fe62e42fefa39ef, 0x3c7abc9d45534d06, 0x3fcebfbdff82c58f, 0xbc65e4383cf9ddf7, 0x3fac6b08d704a0c0, 0xbc46cbc55586c8f1, 0x3f83b2ab6fba4e77, 0x3f55d87fe789aec5, 0x3f2430912f879daa, 0x3eeffcc774b2367a, 0x3eb62c017b9bdfe6, ]; let h2 = z.hi * z.hi; let c7 = dd_fmla(f64::from_bits(Q2[11]), z.hi, f64::from_bits(Q2[10])); let mut c5 = dd_fmla(f64::from_bits(Q2[9]), z.hi, f64::from_bits(Q2[8])); c5 = dd_fmla(c7, h2, c5); // since ulp(c5*h^5) <= 2^-86, we still compute c5*z as double let z_vqh = c5 * z.hi; let mut q = DoubleDouble::from_exact_add(f64::from_bits(Q2[7]), z_vqh); // multiply by z q = DoubleDouble::quick_mult(q, z); // add coefficient of degree 3 let t = DoubleDouble::from_exact_add(f64::from_bits(Q2[5]), q.hi); q.hi = t.hi; q.lo += t.lo + f64::from_bits(Q2[6]); // multiply by z and add coefficient of degree 2 q = DoubleDouble::quick_mult(q, z); let t = DoubleDouble::from_exact_add(f64::from_bits(Q2[3]), q.hi); q.hi = t.hi; q.lo += t.lo + f64::from_bits(Q2[4]); // multiply by h+l and add coefficient of degree 1 q = DoubleDouble::quick_mult(q, z); let t = DoubleDouble::from_exact_add(f64::from_bits(Q2[1]), q.hi); q.hi = t.hi; q.lo += t.lo + f64::from_bits(Q2[2]); // multiply by h+l and add coefficient of degree 0 q = DoubleDouble::quick_mult(q, z); let t = DoubleDouble::from_exact_add(f64::from_bits(Q2[0]), q.hi); q.hi = t.hi; q.lo += t.lo; q } /* return the correct rounding of (1+x)^y or -1 if the rounding test failed, where t is an approximation of y*log2(1+x). We assume |h+l| < 150, |l/h| < 2^-48.445 |h|, and the relative error between h+l and y*log2(1+x) is < 2^-91.120. x and y are the original inputs of compound. */ fn compoundf_exp2_accurate(x_dd: DoubleDouble, x: f32, y: f32) -> f32 { if y == 1.0 { let res = 1.0 + x; return res; } let k = x_dd.hi.round_ties_even(); // |k| <= 150 // check easy cases h+l is tiny thus 2^(h+l) rounds to 1, 1- or 1+ if k == 0. && x_dd.hi.abs() <= f64::from_bits(0x3e6715476af0d4c8) { /* the relative error between h and y*log2(1+x) is bounded by (1 + 2^-48.445) * (1 + 2^-91.120) - 1 < 2^-48.444. 2^h rounds to 1 to nearest for |h| <= H0 := 0x1.715476af0d4d9p-25. The above threshold is such that h*(1+2^-48.444) < H0. */ return (1.0 + x_dd.hi * 0.5) as f32; } let r = x_dd.hi - k; // |r| <= 1/2, exact // since r is an integer multiple of ulp(h), fast_two_sum() below is exact let mut v_dd = DoubleDouble::from_exact_add(r, x_dd.lo); let mut v = (3.015625 + v_dd.hi).to_bits(); // 2.5 <= v <= 3.5015625 // we add 2^-6 so that i is rounded to nearest let i: i32 = ((v >> 46) as i32).wrapping_sub(0x10010); // 0 <= i <= 32 // h is near (i-16)/2^5 v_dd.hi -= f64::from_bits(COMPOUNDF_EXP2_T[i as usize]); // exact // now |h| <= 2^-6 // 2^(h+l) = 2^k * exp2_U[i] * 2^(h+l) v_dd = DoubleDouble::from_exact_add(v_dd.hi, v_dd.lo); let q = compoundf_exp2_poly2(v_dd); /* we have 0.989 < qh < 1.011, |ql| < 2^-51.959, and |qh + ql - 2^(h+l)| < 2^-85.210 */ let exp2u = DoubleDouble::from_bit_pair(COMPOUNDF_EXP2_U[i as usize]); let mut q = DoubleDouble::quick_mult(exp2u, q); q = DoubleDouble::from_exact_add(q.hi, q.lo); /* Total error: * at input we have a relative error between h+l and y*log2(1+x) bounded by 2^-91.120: h + l = y*log2(1+x) * (1 + eps1) with |eps1| < 2^-91.120. Since |h+l| <= 150, this yields an absolute error bounded by 150*2^-91.120 < 2^-83.891: h + l = y*log2(1+x) + eps2 with |eps2| <= 150*2^-91.120 < 2^-83.891. * the absolute error in q2() is bounded by 2^-85.210 and is multiplied by exp2_U[i] < 1.415 * the absolute d_mul() error is bounded by 2^-102.199 * the fast_two_sum() error is bounded by 2^-105 All this yields an absolute error on qh+ql bounded by: 2^-83.891 + 2^-85.210*1.415 + 2^-102.199 + 2^-105 < 2^-83.242. We distinguish the "small" case when at input |h+l| <= 2^-9. In this case k=0, i=16, thus exp2_T[i]=0, exp2_U[i]=1, and absolute error in q2() is bounded by 2^-102.646, and remains unchanged since the d_mul() call does not change qh, ql. */ /* Rounding test: since |ql| < ulp(qh), and the error is less than ulp(qh), the rounding test can fail only when the last 53-25 = 28 bits of qh represent a signed number in [-1,1] (when it is -2 or 2, adding ql and the error cannot cross a rounding boundary). */ let mut w = q.hi.to_bits(); if ((w.wrapping_add(1)) & 0xfffffffu64) <= 2 { static ERR: [u64; 2] = [0x3abb100000000000, 0x3a2d800000000000]; let small: bool = k == 0. && i == 16 && x_dd.hi <= f64::from_bits(0x3f60000000000000); let err = f64::from_bits(ERR[small as usize]); w = (q.hi + (q.lo + err)).to_bits(); w = w.wrapping_add((k as i64).wrapping_shl(52) as u64); } /* multiply qh+ql by 2^k: since 0.989 < qh_in < 1.011 and 0.707 < exp2_U[i] < 1.415, we have 0.69 < qh+ql < 1.44 */ v = (q.hi + q.lo).to_bits(); /* For RNDN, if qh fits exactly in 25 bits, and ql is tiny, so that qh + ql rounds to qh, then we might have a double-rounding issue. */ if (w.wrapping_shl(36)) == 0 && f64::from_bits(v) == q.hi && q.lo != 0. { v = v.wrapping_add((if q.lo > 0. { 1i64 } else { -1i64 }) as u64); // simulate round to odd } v = v.wrapping_add((k as i64).wrapping_shl(52) as u64); // there is no underflow/overflow in the scaling by 2^k since |k| <= 150 f64::from_bits(v) as f32 } // at input, exact is non-zero iff (1+x)^y is exact // x,y=0x1.0f6f1ap+1,0x1.c643bp+5: 49 identical bits after round bit // x,y=0x1.ef272cp+15,-0x1.746ab2p+1: 55 identical bits after round bit // x,y=0x1.07ffcp+0,-0x1.921a8ap+4: 47 identical bits after round bit #[cold] #[inline(never)] fn compoundf_accurate(x: f32, y: f32) -> f32 { let mut v = compoundf_log2p1_accurate(x as f64); /* h + l is a double-double approximation of log(1+x), with relative error bounded by 2^-91.123, and |l| < 2^-48.574 |h| */ v = DoubleDouble::quick_mult_f64(v, y as f64); /* h + l is a double-double approximation of y*log(1+x). Since 2^-149 <= |h_in+l_in| < 128 and 2^-149 <= |y| < 2^128, we have 2^-298 <= |h+l| < 2^135, thus no underflow/overflow in double is possible. The s_mul() error is bounded by ulp(l). Since |l_in| < 2^-48.574 |h_in|, and the intermediate variable lo in s_mul() satisfies |lo| < ulp(h), we have |l| < ulp(h) + |y l_in| <= ulp(h) + 2^-48.574 |y h_in| < (2^-52 + 2^-48.574) |h| < 2^-48.445 |h|. The s_mul() error is thus bounded by 2^-48.445*2^-52 = 2^-100.445 |h|. This yields a total relative error bounded by (1+2^-91.123)*(1+2^-100.445)-1 < 2^-91.120. */ compoundf_exp2_accurate(v, x, y) } /// Computes compound function (1.0 + x)^y /// /// Max ULP 0.5 #[inline] pub fn f_compoundf(x: f32, y: f32) -> f32 { /* Rules from IEEE 754-2019 for compound (x, n) with n integer: (a) compound (x, 0) is 1 for x >= -1 or quiet NaN (b) compound (-1, n) is +Inf and signals the divideByZero exception for n < 0 (c) compound (-1, n) is +0 for n > 0 (d) compound (+/-0, n) is 1 (e) compound (+Inf, n) is +Inf for n > 0 (f) compound (+Inf, n) is +0 for n < 0 (g) compound (x, n) is qNaN and signals the invalid exception for x < -1 (h) compound (qNaN, n) is qNaN for n <> 0. */ let mone = (-1.0f32).to_bits(); let nx = x.to_bits(); let ny = y.to_bits(); if nx >= mone { return as_compoundf_special(x, y); } // x <= -1 // now x > -1 let ax: u32 = nx.wrapping_shl(1); let ay: u32 = ny.wrapping_shl(1); if ax == 0 || ax >= 0xffu32 << 24 || ay == 0 || ay >= 0xffu32 << 24 { return as_compoundf_special(x, y); } // x=+-0 || x=+-inf/nan || y=+-0 || y=+-inf/nan // evaluate (1+x)^y explicitly for integer y in [-16,16] range and |x|<2^64 if y.floor() == y && ay <= 0x83000000u32 && ax <= 0xbefffffeu32 { if ax <= 0x62000000u32 { return 1.0 + y * x; } // does it work for |x|<2^-29 and |y|<=16? let mut s = x as f64 + 1.; let mut iter_count = y.abs() as usize; // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { 1. }; while { iter_count >>= 1; iter_count } != 0 { s = s * s; if iter_count % 2 != 0 { acc *= s; } } let dz = if y.is_sign_negative() { 1. / acc } else { acc }; return dz as f32; } let xd = x as f64; let yd = y as f64; let tx = xd.to_bits(); let ty = yd.to_bits(); let l: f64 = compoundf_log2p1_fast(f64::from_bits(tx)); /* l approximates log2(1+x) with relative error < 2^-47.997, and 2^-149 <= |l| < 128 */ let t: u64 = (l * f64::from_bits(ty)).to_bits(); /* since 2^-149 <= |l| < 128 and 2^-149 <= |y| < 2^128, we have 2^-298 <= |t| < 2^135, thus no underflow/overflow in double is possible. The relative error is bounded by (1+2^-47.997)*(1+2^-52)-1 < 2^-47.909 */ // detect overflow/underflow if (t.wrapping_shl(1)) >= (0x406u64 << 53) { // |t| >= 128 if t >= 0x3018bu64 << 46 { // t <= -150 return black_box(f32::from_bits(0x00800000)) * black_box(f32::from_bits(0x00800000)); } else if (t >> 63) == 0 { // t >= 128: overflow return black_box(f32::from_bits(0x7e800000)) * black_box(f32::from_bits(0x7e800000)); } } /* since |t| < 150, the absolute error on t is bounded by 150*2^-47.909 < 2^-40.680 */ // 2^t rounds to 1 to nearest when |t| <= 0x1.715476ba97f14p-25 if (t.wrapping_shl(1)) <= 0x3e6715476ba97f14u64 { return if (t >> 63) != 0 { black_box(1.0) - black_box(f32::from_bits(0x33000000)) } else { black_box(1.0) + black_box(f32::from_bits(0x33000000)) }; } let res = exp2_fast(f64::from_bits(t)); if res != -1.0 { return res as f32; } compoundf_accurate(x, y) } #[cfg(test)] mod tests { use super::*; #[test] fn test_compoundf() { assert_eq!( f_compoundf( 0.000000000000000000000000000000000000011754944, -170502050000000000000000000000000000000. ), 1. ); assert_eq!(f_compoundf(1.235, 1.432), 3.1634824); assert_eq!(f_compoundf(2., 3.0), 27.); assert!(f_compoundf(-2., 5.0).is_nan()); assert_eq!(f_compoundf(1., f32::INFINITY), f32::INFINITY); assert_eq!(f_compoundf(1., f32::NEG_INFINITY), 0.0); } } pxfm-0.1.23/src/compound/mod.rs000064400000000000000000000036121046102023000144230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod compound_d; mod compound_m1; mod compound_m1f; mod compoundf; mod powm1; mod powm1f; pub use compound_d::f_compound; pub use compound_m1::f_compound_m1; pub use compound_m1f::f_compound_m1f; pub use compoundf::f_compoundf; pub use powm1::f_powm1; pub use powm1f::f_powm1f; pxfm-0.1.23/src/compound/powm1.rs000064400000000000000000000173531046102023000147160ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::exponents::{EXPM1_T0, EXPM1_T1, ldexp}; use crate::pow::{is_integer, is_odd_integer}; use crate::pow_exec::pow_log_1; /// Computes x^y - 1 pub fn f_powm1(x: f64, y: f64) -> f64 { let ax: u64 = x.to_bits().wrapping_shl(1); let ay: u64 = y.to_bits().wrapping_shl(1); // filter out exceptional cases if ax == 0 || ax >= 0x7ffu64 << 53 || ay == 0 || ay >= 0x7ff64 << 53 { if x.is_nan() || y.is_nan() { return f64::NAN; } // Handle infinities if x.is_infinite() { return if x.is_sign_positive() { if y.is_infinite() { return f64::INFINITY; } else if y > 0.0 { f64::INFINITY // inf^positive -> inf } else if y < 0.0 { -1.0 // inf^negative -> 0, so powm1 = -1 } else { f64::NAN // inf^0 -> NaN (0^0 conventionally 1, inf^0 = NaN) } } else { // x = -inf if y.is_infinite() { return -1.0; } if is_integer(y) { // Negative base: (-inf)^even = +inf, (-inf)^odd = -inf let pow = if y as i32 % 2 == 0 { f64::INFINITY } else { f64::NEG_INFINITY }; pow - 1.0 } else { f64::NAN // Negative base with non-integer exponent } }; } // Handle y infinite if y.is_infinite() { return if x.abs() > 1.0 { if y.is_sign_positive() { f64::INFINITY } else { -1.0 } } else if x.abs() < 1.0 { if y.is_sign_positive() { -1.0 } else { f64::INFINITY } } else { // |x| == 1 f64::NAN // 1^inf or -1^inf is undefined }; } // Handle zero base if x == 0.0 { return if y > 0.0 { -1.0 // 0^positive -> 0, powm1 = -1 } else if y < 0.0 { f64::INFINITY // 0^negative -> inf } else { 0.0 // 0^0 -> conventionally 1, powm1 = 0 }; } } let y_integer = is_integer(y); let mut negative_parity: bool = false; let mut x = x; // Handle negative base with non-integer exponent if x < 0.0 { if !y_integer { return f64::NAN; // x < 0 and non-integer y } x = x.abs(); if is_odd_integer(y) { negative_parity = true; } } let (mut l, _) = pow_log_1(x); l = DoubleDouble::from_exact_add(l.hi, l.lo); let r = DoubleDouble::quick_mult_f64(l, y); if r.hi < -37.42994775023705 { // underflow return -1.; } let res = powm1_expm1_1(r); // For x < 0 and integer y = n: // if n is even: x^n = |x|^n → powm1 = |x|^n - 1 (same sign as res). // if n is odd: x^n = -|x|^n → powm1 = -|x|^n - 1 = - (|x|^n + 1). if negative_parity { DoubleDouble::full_add_f64(-res, -2.).to_f64() } else { res.to_f64() } } #[inline] pub(crate) fn powm1_expm1_1(r: DoubleDouble) -> DoubleDouble { let ax = r.hi.to_bits() & 0x7fffffffffffffffu64; const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); if ax <= 0x3f80000000000000 { // |x| < 2^-7 if ax < 0x3970000000000000 { // |x| < 2^-104 return r; } let d = crate::pow_exec::expm1_poly_dd_tiny(r); return d; } const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); let k = (r.hi * INVLOG2).round_ties_even(); let z = DoubleDouble::mul_f64_add(DoubleDouble::new(LOG2L, LOG2H), -k, r); let bk = k as i64; /* Note: k is an integer, this is just a conversion. */ let mk = (bk >> 12) + 0x3ff; let i2 = (bk >> 6) & 0x3f; let i1 = bk & 0x3f; let t0 = DoubleDouble::from_bit_pair(EXPM1_T0[i2 as usize]); let t1 = DoubleDouble::from_bit_pair(EXPM1_T1[i1 as usize]); let tbh = DoubleDouble::quick_mult(t1, t0); let mut de = tbh; // exp(k)=2^k*exp(r) + (2^k - 1) let q = crate::pow_exec::expm1_poly_fast(z); de = DoubleDouble::quick_mult(de, q); de = DoubleDouble::add(tbh, de); let ie = mk - 0x3ff; let off: f64 = f64::from_bits((2048i64 + 1023i64).wrapping_sub(ie).wrapping_shl(52) as u64); let e: f64; if ie < 53 { let fhz = DoubleDouble::from_exact_add(off, de.hi); de.hi = fhz.hi; e = fhz.lo; } else if ie < 104 { let fhz = DoubleDouble::from_exact_add(de.hi, off); de.hi = fhz.hi; e = fhz.lo; } else { e = 0.; } de.lo += e; de.hi = ldexp(de.to_f64(), ie as i32); de.lo = 0.; de } #[cfg(test)] mod tests { use super::*; #[test] fn test_powm1() { assert_eq!(f_powm1(f64::INFINITY, f64::INFINITY), f64::INFINITY); assert_eq!(f_powm1(50850368932909610000000000., 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023201985303960773), 1.3733470789307166e-303); assert_eq!(f_powm1(-3.375, -9671689000000000000000000.), -1.); assert_eq!(f_powm1(1.83329e-40, 2.4645883e-32), -2.255031542428047e-30); assert_eq!(f_powm1(3., 2.), 8.); assert_eq!(f_powm1(3., 3.), 26.); assert_eq!(f_powm1(5., 2.), 24.); assert_eq!(f_powm1(5., -2.), 1. / 25. - 1.); assert_eq!(f_powm1(-5., 2.), 24.); assert_eq!(f_powm1(-5., 3.), -126.); assert_eq!( f_powm1(196560., 0.000000000000000000000000000000000000001193773), 1.4550568430468268e-38 ); } } pxfm-0.1.23/src/compound/powm1f.rs000064400000000000000000000216561046102023000150650ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use crate::compound::compound_m1f::compoundf_expf_poly; use crate::compound::compoundf::{ COMPOUNDF_EXP2_T, COMPOUNDF_EXP2_U, LOG2P1_COMPOUNDF_INV, LOG2P1_COMPOUNDF_LOG2_INV, }; use crate::powf::{is_integer, is_odd_integer}; use std::hint::black_box; #[inline] fn powm1f_log2_fast(x: f64) -> f64 { /* for x > 0, 1+x is exact when 2^-29 <= x < 2^53 for x < 0, 1+x is exact when -1 < x <= 2^-30 */ // double u = (x >= 0x1p53) ? x : 1.0 + x; /* For x < 0x1p53, x + 1 is exact thus u = x+1. For x >= 2^53, we estimate log2(x) instead of log2(1+x), since log2(1+x) = log2(x) + log2(1+1/x), log2(x) >= 53 and |log2(1+1/x)| < 2^-52.471, the additional relative error is bounded by 2^-52.471/53 < 2^-58.198 */ let mut v = x.to_bits(); let m: u64 = v & 0xfffffffffffffu64; let e: i64 = (v >> 52) as i64 - 0x3ff + (m >= 0x6a09e667f3bcdu64) as i64; // 2^e/sqrt(2) < u < 2^e*sqrt(2), with -29 <= e <= 128 v = v.wrapping_sub((e << 52) as u64); let t = f64::from_bits(v); // u = 2^e*t with 1/sqrt(2) < t < sqrt(2) // thus log2(u) = e + log2(t) v = (f64::from_bits(v) + 2.0).to_bits(); // add 2 so that v.f is always in the binade [2, 4) let i = (v >> 45) as i32 - 0x2002d; // 0 <= i <= 45 let r = f64::from_bits(LOG2P1_COMPOUNDF_INV[i as usize]); let z = dd_fmla(r, t, -1.0); // exact, -1/64 <= z <= 1/64 // we approximates log2(t) by -log2(r) + log2(r*t) let p = crate::compound::compoundf::log2p1_polyeval_1(z); // p approximates log2(r*t) with rel. error < 2^-49.642, and |p| < 2^-5.459 e as f64 + (f64::from_bits(LOG2P1_COMPOUNDF_LOG2_INV[i as usize].1) + p) } /// Computes x^y - 1 pub fn f_powm1f(x: f32, y: f32) -> f32 { let ax: u32 = x.to_bits().wrapping_shl(1); let ay: u32 = y.to_bits().wrapping_shl(1); // filter out exceptional cases if ax == 0 || ax >= 0xffu32 << 24 || ay == 0 || ay >= 0xffu32 << 24 { if x.is_nan() || y.is_nan() { return f32::NAN; } // Handle infinities if x.is_infinite() { return if x.is_sign_positive() { if y.is_infinite() { return f32::INFINITY; } else if y > 0.0 { f32::INFINITY // inf^positive -> inf } else if y < 0.0 { -1.0 // inf^negative -> 0, so powm1 = -1 } else { f32::NAN // inf^0 -> NaN (0^0 conventionally 1, inf^0 = NaN) } } else { // x = -inf if y.is_infinite() { return -1.0; } if is_integer(y) { // Negative base: (-inf)^even = +inf, (-inf)^odd = -inf let pow = if y as i32 % 2 == 0 { f32::INFINITY } else { f32::NEG_INFINITY }; pow - 1.0 } else { f32::NAN // Negative base with non-integer exponent } }; } // Handle y infinite if y.is_infinite() { return if x.abs() > 1.0 { if y.is_sign_positive() { f32::INFINITY } else { -1.0 } } else if x.abs() < 1.0 { if y.is_sign_positive() { -1.0 } else { f32::INFINITY } } else { // |x| == 1 f32::NAN // 1^inf or -1^inf is undefined }; } // Handle zero base if x == 0.0 { return if y > 0.0 { -1.0 // 0^positive -> 0, powm1 = -1 } else if y < 0.0 { f32::INFINITY // 0^negative -> inf } else { 0.0 // 0^0 -> conventionally 1, powm1 = 0 }; } } let y_integer = is_integer(y); let mut negative_parity: bool = false; let mut x = x; // Handle negative base with non-integer exponent if x < 0.0 { if !y_integer { return f32::NAN; // x < 0 and non-integer y } x = x.abs(); if is_odd_integer(y) { negative_parity = true; } } let xd = x as f64; let yd = y as f64; let tx = xd.to_bits(); let ty = yd.to_bits(); let l: f64 = powm1f_log2_fast(f64::from_bits(tx)); /* l approximates log2(1+x) with relative error < 2^-47.997, and 2^-149 <= |l| < 128 */ let dt = l * f64::from_bits(ty); let t: u64 = dt.to_bits(); // detect overflow/underflow if (t.wrapping_shl(1)) >= (0x406u64 << 53) { // |t| >= 128 if t >= 0x3018bu64 << 46 { // t <= -150 return -1.; } else if (t >> 63) == 0 { // t >= 128: overflow return black_box(f32::from_bits(0x7e800000)) * black_box(f32::from_bits(0x7e800000)); } } let res = powm1_exp2m1_fast(f64::from_bits(t)); // For x < 0 and integer y = n: // if n is even: x^n = |x|^n → powm1 = |x|^n - 1 (same sign as res). // if n is odd: x^n = -|x|^n → powm1 = -|x|^n - 1 = - (|x|^n + 1). if negative_parity { (-res - 2.) as f32 } else { res as f32 } } #[inline] pub(crate) fn powm1_exp2m1_fast(t: f64) -> f64 { let k = t.round_ties_even(); // 0 <= |k| <= 150 let mut r = t - k; // |r| <= 1/2, exact let mut v: f64 = 3.015625 + r; // 2.5 <= v <= 3.5015625 // we add 2^-6 so that i is rounded to nearest let i: i32 = (v.to_bits() >> 46) as i32 - 0x10010; // 0 <= i <= 32 r -= f64::from_bits(COMPOUNDF_EXP2_T[i as usize]); // exact // now |r| <= 2^-6 // 2^t = 2^k * exp2_U[i][0] * 2^r let mut s = f64::from_bits(COMPOUNDF_EXP2_U[i as usize].1); let su = (k as i64) << 52; s = f64::from_bits(s.to_bits().wrapping_add(su as u64)); let q_poly = compoundf_expf_poly(r); v = q_poly; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v = f_fmla(v, s, s - 1f64); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::DoubleDouble; let p0 = DoubleDouble::from_full_exact_add(s, -1.); let z = DoubleDouble::from_exact_mult(v, s); v = DoubleDouble::add(z, p0).to_f64(); } v } #[cfg(test)] mod tests { use super::*; #[test] fn test_powm1f() { assert_eq!(f_powm1f(1.83329e-40, 2.4645883e-32), -2.2550315e-30); assert_eq!(f_powm1f(f32::INFINITY, f32::INFINITY), f32::INFINITY); assert_eq!(f_powm1f(-3.375, -9671689000000000000000000.), -1.); assert_eq!(f_powm1f(3., 2.), 8.); assert_eq!(f_powm1f(3., 3.), 26.); assert_eq!(f_powm1f(5., 2.), 24.); assert_eq!(f_powm1f(5., -2.), 1. / 25. - 1.); assert_eq!(f_powm1f(-5., 2.), 24.); assert_eq!(f_powm1f(-5., 3.), -126.); assert_eq!( f_powm1f(196560., 0.000000000000000000000000000000000000001193773), 1.455057e-38 ); } } pxfm-0.1.23/src/cosm1.rs000064400000000000000000000175331046102023000130510ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::polyeval::f_polyeval4; use crate::sin::{range_reduction_small, sincos_eval}; use crate::sin_helper::sincos_eval_dd; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_reduce::LargeArgumentReduction; #[cold] #[inline(never)] fn cosm1_accurate(y: DoubleDouble, sin_k: DoubleDouble, cos_k: DoubleDouble) -> f64 { let r_sincos = sincos_eval_dd(y); // k is an integer and -pi / 256 <= y <= pi / 256. // Then sin(x) = sin((k * pi/128 + y) // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; // Computing cos(x) - 1 as follows: // cos(x) - 1 = -2*sin^2(x/2) rr = DoubleDouble::from_exact_add(rr.hi, rr.lo); rr = DoubleDouble::quick_mult(rr, rr); rr = DoubleDouble::quick_mult_f64(rr, -2.); rr.to_f64() } #[cold] fn cosm1_tiny_hard(x: f64) -> f64 { // Generated by Sollya: // d = [2^-27, 2^-7]; // f_cosm1 = cos(x) - 1; // Q = fpminimax(f_cosm1, [|2,4,6,8|], [|0, 107...|], d); // See ./notes/cosm1_hard.sollya const C: [(u64, u64); 3] = [ (0x3c453997dc8ae20d, 0x3fa5555555555555), (0x3bf6100c76a1827a, 0xbf56c16c16c15749), (0x3b918f45acdd1fb2, 0x3efa019ddf5a583a), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(C[2]), DoubleDouble::from_bit_pair(C[1]), ); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[0])); p = DoubleDouble::mul_add_f64(x2, p, f64::from_bits(0xbfe0000000000000)); p = DoubleDouble::quick_mult(p, x2); p.to_f64() } /// Computes cos(x) - 1 pub fn f_cosm1(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-7 if x_e < E_BIAS - 7 { // |x| < 2^-26 if x_e < E_BIAS - 27 { // Signed zeros. if x == 0.0 { return 0.0; } // Taylor expansion for small cos(x) - 1 ~ -x^2/2 + x^4/24 + O(x^6) let x_sqr = x * x; const A0: f64 = -1. / 2.; const A1: f64 = 1. / 24.; let r0 = f_fmla(x_sqr, A1, A0); return r0 * x_sqr; } // Generated by Sollya: // d = [2^-27, 2^-7]; // f_cosm1 = (cos(x) - 1); // Q = fpminimax(f_cosm1, [|2,4,6,8|], [|0, D...|], d); // See ./notes/cosm1.sollya let x2 = DoubleDouble::from_exact_mult(x, x); let p = f_polyeval4( x2.hi, f64::from_bits(0xbfe0000000000000), f64::from_bits(0x3fa5555555555555), f64::from_bits(0xbf56c16c16b9c2b7), f64::from_bits(0x3efa014d03f38855), ); let r = DoubleDouble::quick_mult_f64(x2, p); let eps = x * f_fmla( x2.hi, f64::from_bits(0x3d00000000000000), // 2^-47 f64::from_bits(0x3be0000000000000), // 2^-65 ); let ub = r.hi + (r.lo + eps); let lb = r.hi + (r.lo - eps); if ub == lb { return r.to_f64(); } return cosm1_tiny_hard(x); } else { // // Small range reduction. (y, k) = range_reduction_small(x * 0.5); } } else { // Inf or NaN if x_e > 2 * E_BIAS { // cos(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. // k = argument_reduction.high_part(x); (k, y) = argument_reduction.reduce(x * 0.5); } // Computing cos(x) - 1 as follows: // cos(x) - 1 = -2*sin^2(x/2) let r_sincos = sincos_eval(y); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = DoubleDouble::from_exact_add(rr.hi, rr.lo); rr = DoubleDouble::quick_mult(rr, rr); rr = DoubleDouble::quick_mult_f64(rr, -2.); let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return rr.to_f64(); } cosm1_accurate(y, sin_k, cos_k) } #[cfg(test)] mod tests { use super::*; #[test] fn f_cosm1f_test() { assert_eq!(f_cosm1(0.0017700195313803402), -0.000001566484161754997); assert_eq!( f_cosm1(0.0000000011641532182693484), -0.0000000000000000006776263578034406 ); assert_eq!(f_cosm1(0.006164513528517324), -0.000019000553351160402); assert_eq!(f_cosm1(6.2831853071795862), -2.999519565323715e-32); assert_eq!(f_cosm1(0.00015928394), -1.2685686744140693e-8); assert_eq!(f_cosm1(0.0), 0.0); assert_eq!(f_cosm1(0.0), 0.0); assert_eq!(f_cosm1(std::f64::consts::PI), -2.); assert_eq!(f_cosm1(0.5), -0.12241743810962728); assert_eq!(f_cosm1(0.7), -0.23515781271551153); assert_eq!(f_cosm1(1.7), -1.1288444942955247); assert!(f_cosm1(f64::INFINITY).is_nan()); assert!(f_cosm1(f64::NEG_INFINITY).is_nan()); assert!(f_cosm1(f64::NAN).is_nan()); assert_eq!(f_cosm1(0.0002480338), -3.0760382813519806e-8); } } pxfm-0.1.23/src/csc.rs000064400000000000000000000131641046102023000125730ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::sin::{get_sin_k_rational, range_reduction_small, sincos_eval}; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::{range_reduction_small_f128, sincos_eval_dyadic}; use crate::sincos_reduce::LargeArgumentReduction; #[cold] fn csc_accurate(x: f64, argument_reduction: &mut LargeArgumentReduction, x_e: u64, k: u64) -> f64 { const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let u_f128 = if x_e < EXP_BIAS + 16 { range_reduction_small_f128(x) } else { argument_reduction.accurate() }; let sin_cos = sincos_eval_dyadic(&u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sin_k_f128 = get_sin_k_rational(k); let cos_k_f128 = get_sin_k_rational(k.wrapping_add(64)); // sin(x) = sin(k * pi/128 + u) // = sin(u) * cos(k*pi/128) + cos(u) * sin(k*pi/128) let r = (sin_k_f128 * sin_cos.v_cos) + (cos_k_f128 * sin_cos.v_sin); r.reciprocal().fast_as_f64() } /// Cosecant for double precision /// /// ULP 0.5 pub fn f_csc(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-26 if x_e < E_BIAS - 26 { // Signed zeros. if x == 0.0 { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_e < E_BIAS - 52 { return 1. / x; } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. let rcp = DoubleDouble::from_quick_recip(x); return DoubleDouble::f64_mul_f64_add(x, f64::from_bits(0x3fc5555555555555), rcp) .to_f64(); } // // Small range reduction. (y, k) = range_reduction_small(x); } else { // Inf or NaN if x_e > 2 * E_BIAS { // sin(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = rr.recip_raphson(); let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return rr.to_f64(); } csc_accurate(x, &mut argument_reduction, x_e, k) } #[cfg(test)] mod tests { use super::*; #[test] fn test_csc() { assert_eq!(f_csc(0.000000014901161055069778), 67108864.62500001); assert_eq!(f_csc( 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000541722315998), f64::INFINITY); assert_eq!(f_csc(0.0), f64::INFINITY); assert_eq!(f_csc(-0.0), f64::NEG_INFINITY); assert!(f_csc(f64::NAN).is_nan()); assert_eq!(f_csc(1.0), 1.1883951057781212); assert_eq!(f_csc(-0.5), -2.085829642933488); } } pxfm-0.1.23/src/cube_roots/cbrt.rs000064400000000000000000000131621046102023000151170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::cube_roots::cbrtf::halley_refine_d; use crate::double_double::DoubleDouble; use crate::exponents::fast_ldexp; use crate::polyeval::f_polyeval4; /// Computes cube root /// /// Max found ULP 0.5 pub fn f_cbrt(x: f64) -> f64 { // 1; 2^{1/3}; 2^{2/3} static ESCALE: [f64; 3] = [ 1.0, f64::from_bits(0x3ff428a2f98d728b), f64::from_bits(0x3ff965fea53d6e3d), ]; let bits = x.to_bits(); let mut exp = ((bits >> 52) & 0x7ff) as i32; let mut mant = bits & ((1u64 << 52) - 1); if exp == 0x7ff || x == 0.0 { return x + x; } // Normalize subnormal if exp == 0 && x != 0.0 { let norm = x * f64::from_bits(0x4350000000000000); // * 2^54 let norm_bits = norm.to_bits(); mant = norm_bits & ((1u64 << 52) - 1); exp = ((norm_bits >> 52) & 0x7ff) as i32 - 54; } exp -= 1023; mant |= 0x3ff << 52; let m = f64::from_bits(mant); // Polynomial for x^(1/3) on [1.0; 2.0] // Generated by Sollya: // d = [1.0, 2.0]; // f_cbrt = x^(1/3); // Q = fpminimax(f_cbrt, 4, [|D...|], d, relative, floating); // See ./notes/cbrt.sollya let p = f_polyeval4( m, f64::from_bits(0x3fe1b0babceeaafa), f64::from_bits(0x3fe2c9a3e8e06a3c), f64::from_bits(0xbfc4dc30afb71885), f64::from_bits(0x3f97a8d3e05458e4), ); // split exponent e = 3*q + r with r in {0,1,2} // use div_euclid/rem_euclid to get r >= 0 let q = exp.div_euclid(3); let rem_scale = exp.rem_euclid(3); let z = p * ESCALE[rem_scale as usize]; let mm = fast_ldexp(m, rem_scale); // bring mantissa into [1;8] let r = 1.0 / mm; // One Halley's method step // then refine in partial double-double precision with Newton-Raphson iteration let y0 = halley_refine_d(z, mm); let d2y = DoubleDouble::from_exact_mult(y0, y0); let d3y = DoubleDouble::quick_mult_f64(d2y, y0); // Newton-Raphson step // h = (x^3 - a) * r // y1 = y0 - 1/3 * h * y0 let h = ((d3y.hi - mm) + d3y.lo) * r; // y1 = y0 - 1/3*y0*(h.lo + h.hi) = y0 - 1/3 *y0*h.lo - 1/3 * y0 * h.hi let y = f_fmla(-f64::from_bits(0x3fd5555555555555), y0 * h, y0); f64::copysign(fast_ldexp(y, q), x) } #[cfg(test)] mod tests { use super::*; #[test] fn test_cbrt() { assert_eq!(f_cbrt(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005432309223745), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017579026781511548); assert_eq!(f_cbrt(1.225158611559834), 1.0700336588124544); assert_eq!(f_cbrt(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139491540182158), 1.1173329935611586e-103); assert_eq!(f_cbrt(27.0), 3.0); assert_eq!(f_cbrt(64.0), 4.0); assert_eq!(f_cbrt(125.0), 5.0); assert_eq!(f_cbrt(216.0), 6.0); assert_eq!(f_cbrt(343.0), 7.0); assert_eq!(f_cbrt(512.0), 8.0); assert_eq!(f_cbrt(729.0), 9.0); assert_eq!(f_cbrt(-729.0), -9.0); assert_eq!(f_cbrt(-512.0), -8.0); assert_eq!(f_cbrt(-343.0), -7.0); assert_eq!(f_cbrt(-216.0), -6.0); assert_eq!(f_cbrt(-125.0), -5.0); assert_eq!(f_cbrt(-64.0), -4.0); assert_eq!(f_cbrt(-27.0), -3.0); assert_eq!(f_cbrt(0.0), 0.0); assert_eq!(f_cbrt(f64::INFINITY), f64::INFINITY); assert_eq!(f_cbrt(f64::NEG_INFINITY), f64::NEG_INFINITY); assert!(f_cbrt(f64::NAN).is_nan()); } } pxfm-0.1.23/src/cube_roots/cbrtf.rs000064400000000000000000000101451046102023000152630ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; #[inline(always)] pub(crate) fn halley_refine_d(x: f64, a: f64) -> f64 { let tx = x * x * x; x * f_fmla(2., a, tx) / f_fmla(2., tx, a) } #[inline(always)] const fn halley_refine(x: f32, a: f32) -> f32 { let tx = x * x * x; x * (tx + 2f32 * a) / (2f32 * tx + a) } /// Cbrt for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn cbrtf(x: f32) -> f32 { let u = x.to_bits(); let au = u.wrapping_shl(1); if au < (1u32 << 24) || au >= (0xffu32 << 24) { if au >= (0xffu32 << 24) { return x + x; /* inf, nan */ } if au == 0 { return x; /* +-0 */ } } const B1: u32 = 709958130; let mut t: f32; let mut ui: u32 = x.to_bits(); let mut hx: u32 = ui & 0x7fffffff; hx = (hx / 3).wrapping_add(B1); ui &= 0x80000000; ui |= hx; t = f32::from_bits(ui); t = halley_refine(t, x); halley_refine(t, x) } /// Computes cube root /// /// Peak ULP on 64 bit = 0.49999577 #[inline] pub fn f_cbrtf(x: f32) -> f32 { let u = x.to_bits(); let au = u.wrapping_shl(1); if au < (1u32 << 24) || au >= (0xffu32 << 24) { if au >= (0xffu32 << 24) { return x + x; /* inf, nan */ } if au == 0 { return x; /* +-0 */ } } let mut ui: u32 = x.to_bits(); let mut hx: u32 = ui & 0x7fffffff; if hx < 0x00800000 { /* zero or subnormal? */ if hx == 0 { return x; /* cbrt(+-0) is itself */ } const TWO_EXP_24: f32 = f32::from_bits(0x4b800000); ui = (x * TWO_EXP_24).to_bits(); hx = ui & 0x7fffffff; const B2: u32 = 642849266; hx = (hx / 3).wrapping_add(B2); } else { const B1: u32 = 709958130; hx = (hx / 3).wrapping_add(B1); } ui &= 0x80000000; ui |= hx; let mut t = f32::from_bits(ui) as f64; let dx = x as f64; t = halley_refine_d(t, dx); halley_refine_d(t, dx) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_fcbrtf() { assert_eq!(f_cbrtf(0.0), 0.0); assert_eq!(f_cbrtf(-27.0), -3.0); assert_eq!(f_cbrtf(27.0), 3.0); assert_eq!(f_cbrtf(64.0), 4.0); assert_eq!(f_cbrtf(-64.0), -4.0); assert_eq!(f_cbrtf(f32::NEG_INFINITY), f32::NEG_INFINITY); assert_eq!(f_cbrtf(f32::INFINITY), f32::INFINITY); assert!(f_cbrtf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/cube_roots/mod.rs000064400000000000000000000034121046102023000147410ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod cbrt; mod cbrtf; mod rcbrt; mod rcbrtf; pub use cbrt::f_cbrt; pub use cbrtf::{cbrtf, f_cbrtf}; pub use rcbrt::f_rcbrt; pub use rcbrtf::f_rcbrtf; pxfm-0.1.23/src/cube_roots/rcbrt.rs000064400000000000000000000163701046102023000153050ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::exponents::fast_ldexp; use crate::polyeval::f_polyeval6; // // // y1 = y0 + 1/3 * y0 * (1 - a * y0 * y0 * y0) // #[inline] // fn raphson_step(x: f64, a: f64) -> f64 { // let h = f_fmla(-a * x, x * x, 1.0); // f_fmla(1. / 3. * h, x, x) // } // y1 = y0(k1 − c(k2 − k3c), c = x*y0*y0*y0 // k1 = 14/9 , k2 = 7/9 , k3 = 2/9 #[inline(always)] fn halleys_div_free(x: f64, a: f64) -> f64 { const K3: f64 = 2. / 9.; const K2: f64 = 7. / 9.; const K1: f64 = 14. / 9.; let c = a * x * x * x; let mut y = f_fmla(-K3, c, K2); y = f_fmla(-c, y, K1); y * x } /// Computes 1/cbrt(x) /// /// ULP 0.5 pub fn f_rcbrt(a: f64) -> f64 { // Decompose a = m * 2^e, with m in [0.5, 1) let xu = a.to_bits(); let exp = ((xu >> 52) & 0x7ff) as i32; let mut e = ((xu >> 52) & 0x7ff) as i32; let mut mant = xu & ((1u64 << 52) - 1); if exp == 0x7ff { if a.is_infinite() { return if a.is_sign_negative() { -0.0 } else { 0.0 }; } return a + a; } if exp == 0 && a == 0. { return if a.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } // Normalize subnormal if exp == 0 { let norm = a * f64::from_bits(0x4350000000000000); // * 2^54 let norm_bits = norm.to_bits(); mant = norm_bits & ((1u64 << 52) - 1); e = ((norm_bits >> 52) & 0x7ff) as i32 - 54; } e -= 1023; mant |= 0x3ff << 52; let m = f64::from_bits(mant); // Polynomial for x^(-1/3) on [1.0; 2.0] // Generated by Sollya: // d = [1.0, 2.0]; // f_inv_cbrt = x^(-1/3); // Q = fpminimax(f_inv_cbrt, 5, [|D...|], d, relative, floating); // See ./notes/inv_cbrt.sollya let p = f_polyeval6( m, f64::from_bits(0x3ffc7f365bceaf71), f64::from_bits(0xbff90e741fb9c896), f64::from_bits(0x3ff3e68b9b2cd237), f64::from_bits(0xbfe321c5eb24a185), f64::from_bits(0x3fc3fa269b897f69), f64::from_bits(0xbf916d6f13849fd1), ); // split exponent e = 3*q + r with r in {0,1,2} // use div_euclid/rem_euclid to get r >= 0 let q = e.div_euclid(3); let rem_scale = e.rem_euclid(3); // 1; 2^{-1/3}; 2^{-2/3} static ESCALE: [u64; 3] = [1.0f64.to_bits(), 0x3fe965fea53d6e3d, 0x3fe428a2f98d728b]; let z = p * f64::from_bits(ESCALE[rem_scale as usize]); let mm = fast_ldexp(m, rem_scale); // bring domain into [1;8] // One Halley's method step // then refine in partial double-double precision with Newton-Raphson iteration let y0 = halleys_div_free(z, mm); let d2y = DoubleDouble::from_exact_mult(y0, y0); let d3y = DoubleDouble::quick_mult_f64(d2y, y0); let hb = DoubleDouble::quick_mult_f64(d3y, mm); let y: f64; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { // decompose double-double in linear FMA sums // r = (1.0 - hb.hi - hb.lo) * y0 = y0 - hb.hi * y0 - hb.lo * y0 = fma(-hb.lo, y0, fma(-hb.hi, y0, y0)) let r = f_fmla(-hb.lo, y0, f_fmla(hb.hi, -y0, y0)); // // y1 = y0 + 1/3 * y0 * (1 - a * y0 * y0 * y0) = y0 + 1/3 * r y = f_fmla(1. / 3., r, y0); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let m_hb = DoubleDouble::full_add_f64(-hb, 1.0); let r = DoubleDouble::quick_mult_f64(m_hb, y0); y = f_fmla(1. / 3., r.to_f64(), y0); } f64::copysign(fast_ldexp(y, -q), a) } #[cfg(test)] mod tests { use super::*; #[test] fn test_rcbrt() { assert_eq!(f_rcbrt(0.9999999999999717), 1.0000000000000095); assert_eq!(f_rcbrt(-68355745214719140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), -0.000000000000000000000000000000000000000002445728958868668); assert_eq!(f_rcbrt(-96105972807656840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), -0.0000000000000000000000000000000000000000000000000000000002183148143573148); assert_eq!(f_rcbrt(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139491540182158), 8949883389846071000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!(f_rcbrt(0.00008386280387617153), 22.846001824951983); assert_eq!(f_rcbrt(-125.0), -0.2); assert_eq!(f_rcbrt(125.0), 0.2); assert_eq!(f_rcbrt(1.0), 1.0); assert_eq!(f_rcbrt(-1.0), -1.0); assert_eq!(f_rcbrt(0.0), f64::INFINITY); assert_eq!(f_rcbrt(-27.0), -1. / 3.); assert_eq!( f_rcbrt(2417851639214765300000000.), 0.000000007450580596938716 ); assert_eq!(f_rcbrt(27.0), 1. / 3.); assert_eq!(f_rcbrt(64.0), 0.25); assert_eq!(f_rcbrt(-64.0), -0.25); assert_eq!(f_rcbrt(f64::NEG_INFINITY), -0.0); assert_eq!(f_rcbrt(f64::INFINITY), 0.0); assert!(f_rcbrt(f64::NAN).is_nan()); } } pxfm-0.1.23/src/cube_roots/rcbrtf.rs000064400000000000000000000101041046102023000154400ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; // // y1 = y0 * (2+x*y0^3)/(1+2*x*y0^3) // #[inline(always)] // fn halley_refine_d(x: f64, a: f64) -> f64 { // let tx = x * x * x; // x * f_fmla(tx, a, 2.0) / f_fmla(2. * a, tx, 1.0) // } #[inline(always)] fn rapshon_refine_inv_cbrt(x: f64, a: f64) -> f64 { x * f_fmla(-1. / 3. * a, x * x * x, 4. / 3.) } // y1 = y0(k1 − c(k2 − k3c), c = x*y0*y0*y0 // k1 = 14/9 , k2 = 7/9 , k3 = 2/9 #[inline(always)] fn halleys_div_free(x: f64, a: f64) -> f64 { const K3: f64 = 2. / 9.; const K2: f64 = 7. / 9.; const K1: f64 = 14. / 9.; let c = a * x * x * x; let mut y = f_fmla(-K3, c, K2); y = f_fmla(-c, y, K1); y * x } /// Computes 1/cbrt(x) /// /// ULP 0.5 #[inline] pub fn f_rcbrtf(x: f32) -> f32 { let u = x.to_bits(); let au = u.wrapping_shl(1); if au < (1u32 << 24) || au >= (0xffu32 << 24) { if x.is_infinite() { return if x.is_sign_negative() { -0.0 } else { 0.0 }; } if au >= (0xffu32 << 24) { return x + x; /* inf, nan */ } if x == 0. { return if x.is_sign_positive() { f32::INFINITY } else { f32::NEG_INFINITY }; /* +-inf */ } } let mut ui: u32 = x.to_bits(); let mut hx: u32 = ui & 0x7fffffff; if hx < 0x00800000 { /* zero or subnormal? */ if hx == 0 { return x; /* cbrt(+-0) is itself */ } const TWO_EXP_24: f32 = f32::from_bits(0x4b800000); ui = (x * TWO_EXP_24).to_bits(); hx = ui & 0x7fffffff; const B: u32 = 0x54a21d2au32 + (8u32 << 23); hx = B.wrapping_sub(hx / 3); } else { hx = 0x54a21d2au32.wrapping_sub(hx / 3); } ui &= 0x80000000; ui |= hx; let t = f32::from_bits(ui) as f64; let dx = x as f64; let mut t = halleys_div_free(t, dx); t = halleys_div_free(t, dx); t = rapshon_refine_inv_cbrt(t, dx); t as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_fcbrtf() { assert_eq!(f_rcbrtf(0.0), f32::INFINITY); assert_eq!(f_rcbrtf(-0.0), f32::NEG_INFINITY); assert_eq!(f_rcbrtf(-27.0), -1. / 3.); assert_eq!(f_rcbrtf(27.0), 1. / 3.); assert_eq!(f_rcbrtf(64.0), 0.25); assert_eq!(f_rcbrtf(-64.0), -0.25); assert_eq!(f_rcbrtf(f32::NEG_INFINITY), -0.0); assert_eq!(f_rcbrtf(f32::INFINITY), 0.0); assert!(f_rcbrtf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/double_double.rs000064400000000000000000000776511046102023000146420ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::get_exponent_f64; #[allow(unused_imports)] use crate::common::*; use std::ops::{Mul, Neg}; // https://hal.science/hal-01351529v3/document #[derive(Copy, Clone, Default, Debug)] pub(crate) struct DoubleDouble { pub(crate) lo: f64, pub(crate) hi: f64, } impl Neg for DoubleDouble { type Output = Self; #[inline] fn neg(self) -> Self::Output { Self { hi: -self.hi, lo: -self.lo, } } } impl DoubleDouble { #[inline] pub(crate) const fn from_bit_pair(pair: (u64, u64)) -> Self { Self { lo: f64::from_bits(pair.0), hi: f64::from_bits(pair.1), } } #[inline] pub(crate) const fn new(lo: f64, hi: f64) -> Self { DoubleDouble { lo, hi } } // Non FMA helper #[allow(dead_code)] #[inline] pub(crate) const fn split(a: f64) -> DoubleDouble { // CN = 2^N. const CN: f64 = (1 << 27) as f64; const C: f64 = CN + 1.0; let t1 = C * a; let t2 = a - t1; let r_hi = t1 + t2; let r_lo = a - r_hi; DoubleDouble::new(r_lo, r_hi) } // Non FMA helper #[allow(dead_code)] #[inline] fn from_exact_mult_impl_non_fma(asz: DoubleDouble, a: f64, b: f64) -> Self { let bs = DoubleDouble::split(b); let r_hi = a * b; let t1 = asz.hi * bs.hi - r_hi; let t2 = asz.hi * bs.lo + t1; let t3 = asz.lo * bs.hi + t2; let r_lo = asz.lo * bs.lo + t3; DoubleDouble::new(r_lo, r_hi) } // valid only for |a| > b #[inline] pub(crate) const fn from_exact_add(a: f64, b: f64) -> DoubleDouble { let r_hi = a + b; let t = r_hi - a; let r_lo = b - t; DoubleDouble::new(r_lo, r_hi) } // valid only for |a| > b #[inline] pub(crate) const fn from_exact_sub(a: f64, b: f64) -> DoubleDouble { let r_hi = a - b; let t = a - r_hi; let r_lo = t - b; DoubleDouble::new(r_lo, r_hi) } #[inline] pub(crate) const fn from_full_exact_add(a: f64, b: f64) -> DoubleDouble { let r_hi = a + b; let t1 = r_hi - a; let t2 = r_hi - t1; let t3 = b - t1; let t4 = a - t2; let r_lo = t3 + t4; DoubleDouble::new(r_lo, r_hi) } #[allow(unused)] #[inline] pub(crate) fn dd_f64_mul_add(a: f64, b: f64, c: f64) -> f64 { let ddx2 = DoubleDouble::from_exact_mult(a, b); let zv = DoubleDouble::full_add_f64(ddx2, c); zv.to_f64() } #[inline] pub(crate) const fn from_full_exact_sub(a: f64, b: f64) -> Self { let r_hi = a - b; let t1 = r_hi - a; let t2 = r_hi - t1; let t3 = -b - t1; let t4 = a - t2; let r_lo = t3 + t4; DoubleDouble::new(r_lo, r_hi) } #[inline] pub(crate) fn add(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let s = a.hi + b.hi; let d = s - a.hi; let l = ((b.hi - d) + (a.hi + (d - s))) + (a.lo + b.lo); DoubleDouble::new(l, s) } #[inline] pub(crate) fn quick_dd_add(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let DoubleDouble { hi: sh, lo: sl } = DoubleDouble::from_full_exact_add(a.hi, b.hi); let v = a.lo + b.lo; let w = sl + v; DoubleDouble::from_exact_add(sh, w) } #[inline] pub(crate) fn quick_dd_sub(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let DoubleDouble { hi: sh, lo: sl } = DoubleDouble::from_full_exact_sub(a.hi, b.hi); let v = a.lo - b.lo; let w = sl + v; DoubleDouble::from_exact_add(sh, w) } #[inline] pub(crate) fn full_dd_add(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let DoubleDouble { hi: sh, lo: sl } = DoubleDouble::from_full_exact_add(a.hi, b.hi); let DoubleDouble { hi: th, lo: tl } = DoubleDouble::from_full_exact_add(a.lo, b.lo); let c = sl + th; let v = DoubleDouble::from_exact_add(sh, c); let w = tl + v.lo; DoubleDouble::from_exact_add(v.hi, w) } #[inline] pub(crate) fn full_dd_sub(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { DoubleDouble::full_dd_add(a, -b) } #[inline] pub(crate) fn sub(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let s = a.hi - b.hi; let d = s - a.hi; let l = ((-b.hi - d) + (a.hi + (d - s))) + (a.lo - b.lo); DoubleDouble::new(l, s) } /// DoubleDouble-style square root for a double-double number #[inline] pub(crate) fn sqrt(self) -> DoubleDouble { let a = self.hi + self.lo; if a == 0.0 { return DoubleDouble { hi: 0.0, lo: 0.0 }; } if a < 0.0 || a.is_nan() { return DoubleDouble { hi: f64::NAN, lo: 0.0, }; } if a.is_infinite() { return DoubleDouble { hi: f64::INFINITY, lo: 0.0, }; } let x = a.sqrt(); let x2 = DoubleDouble::from_exact_mult(x, x); // Residual = self - x² let mut r = self.hi - x2.hi; r += self.lo; r -= x2.lo; let dx = r / (2.0 * x); let hi = x + dx; let lo = (x - hi) + dx; DoubleDouble { hi, lo } } /// DoubleDouble-style square root for a double-double number #[inline] pub(crate) fn fast_sqrt(self) -> DoubleDouble { let a = self.hi + self.lo; let x = a.sqrt(); let x2 = DoubleDouble::from_exact_mult(x, x); // Residual = self - x² let mut r = self.hi - x2.hi; r += self.lo; r -= x2.lo; let dx = r / (2.0 * x); let hi = x + dx; let lo = (x - hi) + dx; DoubleDouble { hi, lo } } /// `a*b+c` /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* #[inline] pub(crate) fn mul_add_f64(a: DoubleDouble, b: DoubleDouble, c: f64) -> DoubleDouble { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_full_exact_add(c, h); DoubleDouble::new(r + q, p) } /// `a*b+c` /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* #[inline] pub(crate) fn quick_mul_add_f64(a: DoubleDouble, b: DoubleDouble, c: f64) -> DoubleDouble { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_exact_add(c, h); DoubleDouble::new(r + q, p) } /// `a*b+c` /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* #[inline] pub(crate) fn mul_f64_add_f64(a: DoubleDouble, b: f64, c: f64) -> DoubleDouble { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult_f64(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_full_exact_add(c, h); DoubleDouble::new(r + q, p) } /// Accurate reciprocal: 1 / self #[inline] pub(crate) fn recip_raphson(self) -> DoubleDouble { let y0 = DoubleDouble::recip(self); let z = DoubleDouble::mul_add_f64(-self, y0, 1.0); DoubleDouble::mul_add(y0, z, y0) } /// Accurate reciprocal: 1 / self #[inline] pub(crate) fn recip(self) -> DoubleDouble { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let y = 1. / self.hi; let e1 = f_fmla(-self.hi, y, 1.0); let e2 = f_fmla(-self.lo, y, e1); let e = y * e2; DoubleDouble::new(e, y) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let y = 1.0 / self.hi; let DoubleDouble { hi: p1, lo: err1 } = DoubleDouble::from_exact_mult(self.hi, y); let e1 = (1.0 - p1) - err1; let DoubleDouble { hi: p2, lo: err2 } = DoubleDouble::from_exact_mult(self.lo, y); let e2 = (e1 - p2) - err2; let e = y * e2; DoubleDouble::new(e, y) } } #[inline] pub(crate) fn from_recip(b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let x_hi = 1.0 / b; let err = f_fmla(-x_hi, b, 1.0); let x_lo = err / b; Self::new(x_lo, x_hi) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let x_hi = 1.0 / b; let prod = Self::from_exact_mult(x_hi, b); let err = (1.0 - prod.hi) - prod.lo; let x_lo = err / b; Self::new(x_lo, x_hi) } } #[inline] pub(crate) fn from_quick_recip(b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let h = 1.0 / b; let hl = f_fmla(h, -b, 1.) * h; DoubleDouble::new(hl, h) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let h = 1.0 / b; let pr = DoubleDouble::from_exact_mult(h, b); let err = (1.0 - pr.hi) - pr.lo; let hl = err * h; DoubleDouble::new(hl, h) } } #[inline] pub(crate) fn from_exact_div(a: f64, b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let q_hi = a / b; let r = f_fmla(-q_hi, b, a); let q_lo = r / b; Self::new(q_lo, q_hi) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let q_hi = a / b; let p = DoubleDouble::from_exact_mult(q_hi, b); let r = DoubleDouble::from_exact_sub(a, p.hi); let r = r.hi + (r.lo - p.lo); let q_lo = r / b; Self::new(q_lo, q_hi) } } // Resistant to overflow without FMA #[inline] pub(crate) fn from_exact_safe_div(a: f64, b: f64) -> Self { let q_hi = a / b; let r = f64::mul_add(-q_hi, b, a); let q_lo = r / b; Self::new(q_lo, q_hi) } #[inline] pub(crate) fn from_sqrt(x: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let h = x.sqrt(); /* h = sqrt(x) * (1 + e1) with |e1| < 2^-52 thus h^2 = x * (1 + e2) with |e2| < 2^-50.999 */ let e = -f_fmla(h, h, -x); // exact /* e = x - h^2 */ let l = e / (h + h); DoubleDouble::new(l, h) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let h = x.sqrt(); let prod_hh = DoubleDouble::from_exact_mult(h, h); let e = (x - prod_hh.hi) - prod_hh.lo; // exact /* e = x - h^2 */ let l = e / (h + h); DoubleDouble::new(l, h) } } /// Safe to overflow underflow division using mandatory FMA. #[inline] #[allow(dead_code)] pub(crate) fn div_safe_dd_f64(a: DoubleDouble, b: f64) -> Self { let q1 = a.hi / b; let r = f64::mul_add(-q1, b, a.hi); let r = r + a.lo; let q2 = r / b; DoubleDouble::new(q2, q1) } #[inline] pub(crate) fn div_dd_f64(a: DoubleDouble, b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let q1 = a.hi / b; let r = f_fmla(-q1, b, a.hi); let r = r + a.lo; let q2 = r / b; DoubleDouble::new(q2, q1) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let th = a.hi / b; let prod = DoubleDouble::from_exact_mult(th, b); let beta_h = a.hi - prod.hi; let beta_l = beta_h - prod.lo; let beta = beta_l + a.lo; let tl = beta / b; DoubleDouble::new(tl, th) } } /// Dekker division with one refinement step #[inline] pub(crate) fn div_dd_f64_newton_raphson(a: DoubleDouble, b: f64) -> Self { // Initial estimate q = a / b let q = DoubleDouble::div_dd_f64(a, b); // One Newton-Raphson refinement step: // e = a - q * b let qb = DoubleDouble::quick_mult_f64(q, b); let e = DoubleDouble::sub(a, qb); let e_div_b = DoubleDouble::div_dd_f64(e, b); DoubleDouble::add(q, e_div_b) } // /// Dekker division with two Newton-Raphson refinement steps // #[inline] // pub(crate) fn div_dd_f64_newton_raphson_2(a: Dekker, b: f64) -> Self { // // First estimate: q = a / b (one round of Dekker division) // let q1 = Dekker::div_dd_f64(a, b); // // // First refinement: q2 = q1 + (a - q1 * b) / b // let qb1 = Dekker::quick_mult_f64(q1, b); // let e1 = Dekker::sub(a, qb1); // let dq1 = Dekker::div_dd_f64(e1, b); // let q2 = Dekker::add(q1, dq1); // // // Second refinement: q3 = q2 + (a - q2 * b) / b // let qb2 = Dekker::quick_mult_f64(q2, b); // let e2 = Dekker::sub(a, qb2); // let dq2 = Dekker::div_dd_f64(e2, b); // // Dekker::add(q2, dq2) // } // #[inline] // pub(crate) fn neg(self) -> Self { // Self { // lo: -self.lo, hi: -self.hi, // } // } #[inline] pub(crate) fn from_f64_div_dd(a: f64, b: DoubleDouble) -> Self { let q1 = a / b.hi; let prod = DoubleDouble::from_exact_mult(q1, b.hi); let prod_lo = f_fmla(q1, b.lo, prod.lo); let rem = f_fmla(-1.0, prod.hi, a) - prod_lo; let q2 = rem / b.hi; DoubleDouble::new(q2, q1) } // #[inline] // pub(crate) fn mla_f64(a: Dekker, b: f64, c: f64) -> Self { // let q = Dekker::mult_f64(a, b); // Dekker::add_f64(q, c) // } // // #[inline] // pub(crate) fn mla_dd_f64(a: Dekker, b: Dekker, c: f64) -> Self { // let q = Dekker::quick_mult(a, b); // Dekker::add_f64(q, c) // } #[inline] pub(crate) fn div(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let q = 1.0 / b.hi; let r_hi = a.hi * q; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let e_hi = f_fmla(b.hi, -r_hi, a.hi); let e_lo = f_fmla(b.lo, -r_hi, a.lo); let r_lo = q * (e_hi + e_lo); DoubleDouble::new(r_lo, r_hi) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let b_hi_r_hi = DoubleDouble::from_exact_mult(b.hi, -r_hi); let b_lo_r_hi = DoubleDouble::from_exact_mult(b.lo, -r_hi); let e_hi = (a.hi + b_hi_r_hi.hi) + b_hi_r_hi.lo; let e_lo = (a.lo + b_lo_r_hi.hi) + b_lo_r_hi.lo; let r_lo = q * (e_hi + e_lo); DoubleDouble::new(r_lo, r_hi) } } #[inline] pub(crate) fn from_exact_mult(a: f64, b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let r_hi = a * b; let r_lo = f_fmla(a, b, -r_hi); DoubleDouble::new(r_lo, r_hi) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let splat = DoubleDouble::split(a); DoubleDouble::from_exact_mult_impl_non_fma(splat, a, b) } } // #[inline] // pub(crate) fn add_f64(&self, other: f64) -> DoubleDouble { // let r = DoubleDouble::from_exact_add(self.hi, other); // Dekker::from_exact_add(r.hi, r.lo + self.lo) // } // #[inline] // pub(crate) fn to_triple(self) -> TripleDouble { // TripleDouble::new(0., self.lo, self.hi) // } /// Computes `a * b + c` /// `b` is an `f64`, `a` and `c` are `DoubleDouble`. /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* #[inline] pub(crate) fn mul_f64_add(a: DoubleDouble, b: f64, c: DoubleDouble) -> Self { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult_f64(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::full_add_f64(c, h); DoubleDouble::new(r + q, p) } /// Computes `a * b + c` /// `b` is an `f64`, `a` and `c` are `DoubleDouble`. /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* /// /// *Correctness* /// |c.hi| > |a.hi * b.hi| #[inline] pub(crate) fn quick_mul_f64_add(a: DoubleDouble, b: f64, c: DoubleDouble) -> Self { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult_f64(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::add_f64(c, h); DoubleDouble::new(r + q, p) } /// Computes `a * b + c` /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* /// /// *Correctness* /// |c.hi| > |a.hi * b.hi| #[inline] pub(crate) fn quick_mul_f64_add_f64(a: DoubleDouble, b: f64, c: f64) -> Self { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult_f64(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_exact_add(c, h); DoubleDouble::new(r + q, p) } // #[inline] // pub(crate) fn mul_f64_add_full(a: DoubleDouble, b: f64, c: DoubleDouble) -> Self { // /* // double _t1, _t2, _t3, _t4, _t5, _t6, _t7, _t8; \ // \ // Mul12(&_t1,&_t2,(a),(bh)); \ // Add12(_t3,_t4,(ch),_t1); \ // _t5 = (bl) * (a); \ // _t6 = (cl) + _t2; \ // _t7 = _t5 + _t6; \ // _t8 = _t7 + _t4; \ // Add12((*(resh)),(*(resl)),_t3,_t8); \ // */ // let DoubleDouble { hi: t1, lo: t2 } = DoubleDouble::from_exact_mult(a.hi, b); // let DoubleDouble { hi: t3, lo: t4 } = DoubleDouble::from_full_exact_add(c.hi, t1); // let t5 = a.lo * b; // let t6 = c.lo + t2; // let t7 = t5 + t6; // let t8 = t7 + t4; // DoubleDouble::from_full_exact_add(t3, t8) // } /// Computes `a * b + c` /// `b` is an `f64`, `a` and `c` are `DoubleDouble`. /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* #[inline] pub(crate) fn f64_mul_f64_add(a: f64, b: f64, c: DoubleDouble) -> Self { let DoubleDouble { hi: h, lo: r } = DoubleDouble::from_exact_mult(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::full_add_f64(c, h); DoubleDouble::new(r + q, p) } // /// Computes `a * b + c` // /// `b` is an `f64`, `a` and `c` are `DoubleDouble`. // /// // /// *Accurate dot product (Ogita, Rump and Oishi 2004)* // #[inline] // pub(crate) fn single_mul_add(a: f64, b: f64, c: f64) -> Self { // let DoubleDouble { hi: h, lo: r } = DoubleDouble::from_exact_mult(a, b); // let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_full_exact_add(c, h); // DoubleDouble::new(r + q, p) // } // /// Computes `a * b + c` safe to overflow without FMA // /// `b` is an `f64`, `a` and `c` are `DoubleDouble`. // /// // /// *Accurate dot product (Ogita, Rump and Oishi 2004)* // #[inline] // pub(crate) fn mul_f64_safe_add(a: DoubleDouble, b: f64, c: DoubleDouble) -> Self { // let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult_safe_f64(a, b); // let DoubleDouble { hi: p, lo: q } = DoubleDouble::full_add_f64(c, h); // DoubleDouble::new(r + q, p) // } /// `a*b+c` /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* #[inline] pub(crate) fn mul_add(a: DoubleDouble, b: DoubleDouble, c: DoubleDouble) -> Self { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::full_add_f64(c, h); DoubleDouble::new(r + q, p) } /// `a*b+c` /// /// *Accurate dot product (Ogita, Rump and Oishi 2004)* /// /// *Correctness* /// |c.hi| > |a.hi * b.hi| #[inline] pub(crate) fn quick_mul_add(a: DoubleDouble, b: DoubleDouble, c: DoubleDouble) -> Self { let DoubleDouble { hi: h, lo: r } = DoubleDouble::quick_mult(a, b); let DoubleDouble { hi: p, lo: q } = DoubleDouble::add_f64(c, h); DoubleDouble::new(r + q, p) } #[inline] pub(crate) fn quick_mult(a: DoubleDouble, b: DoubleDouble) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let mut r = DoubleDouble::from_exact_mult(a.hi, b.hi); let t1 = f_fmla(a.hi, b.lo, r.lo); let t2 = f_fmla(a.lo, b.hi, t1); r.lo = t2; r } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let DoubleDouble { hi: ch, lo: cl1 } = DoubleDouble::from_exact_mult(a.hi, b.hi); let tl1 = a.hi * b.lo; let tl2 = a.lo * b.hi; let cl2 = tl1 + tl2; let cl3 = cl1 + cl2; DoubleDouble::new(cl3, ch) } } #[inline] pub(crate) fn mult(a: DoubleDouble, b: DoubleDouble) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let DoubleDouble { hi: ch, lo: cl1 } = DoubleDouble::from_exact_mult(a.hi, b.hi); let tl0 = a.lo * b.lo; let tl1 = f_fmla(a.hi, b.lo, tl0); let cl2 = f_fmla(a.lo, b.hi, tl1); let cl3 = cl1 + cl2; DoubleDouble::from_exact_add(ch, cl3) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let DoubleDouble { hi: ch, lo: cl1 } = DoubleDouble::from_exact_mult(a.hi, b.hi); let tl1 = a.hi * b.lo; let tl2 = a.lo * b.hi; let cl2 = tl1 + tl2; let cl3 = cl1 + cl2; DoubleDouble::from_exact_add(ch, cl3) } } #[inline] pub(crate) fn mult_f64(a: DoubleDouble, b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let DoubleDouble { hi: ch, lo: cl1 } = DoubleDouble::from_exact_mult(a.hi, b); let cl3 = f_fmla(a.lo, b, cl1); DoubleDouble::from_exact_add(ch, cl3) } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let DoubleDouble { hi: ch, lo: cl1 } = DoubleDouble::from_exact_mult(a.hi, b); let cl2 = a.lo * b; let t = DoubleDouble::from_exact_add(ch, cl2); let tl2 = t.lo + cl1; DoubleDouble::from_exact_add(t.hi, tl2) } } #[inline] pub(crate) fn quick_f64_mult(a: f64, b: DoubleDouble) -> DoubleDouble { DoubleDouble::quick_mult_f64(b, a) } #[inline] pub(crate) fn quick_mult_f64(a: DoubleDouble, b: f64) -> Self { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let h = b * a.hi; let l = f_fmla(b, a.lo, f_fmla(b, a.hi, -h)); Self { lo: l, hi: h } } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let DoubleDouble { hi: ch, lo: cl1 } = DoubleDouble::from_exact_mult(a.hi, b); let cl2 = a.lo * b; let cl3 = cl1 + cl2; DoubleDouble::new(cl3, ch) } } // /// Double-double multiplication safe to overflow without FMA // #[inline] // pub(crate) fn quick_mult_safe_f64(a: DoubleDouble, b: f64) -> Self { // let h = b * a.hi; // let l = f64::mul_add(b, a.lo, f64::mul_add(b, a.hi, -h)); // Self { lo: l, hi: h } // } /// Valid only |a.hi| > |b| #[inline] pub(crate) fn add_f64(a: DoubleDouble, b: f64) -> Self { let t = DoubleDouble::from_exact_add(a.hi, b); let l = a.lo + t.lo; Self { lo: l, hi: t.hi } } #[inline] pub(crate) fn full_add_f64(a: DoubleDouble, b: f64) -> Self { let t = DoubleDouble::from_full_exact_add(a.hi, b); let l = a.lo + t.lo; Self { lo: l, hi: t.hi } } /// Valid only |b| > |a.hi| #[inline] pub(crate) fn f64_add(b: f64, a: DoubleDouble) -> Self { let t = DoubleDouble::from_exact_add(b, a.hi); let l = a.lo + t.lo; Self { lo: l, hi: t.hi } } #[inline] pub(crate) const fn to_f64(self) -> f64 { self.lo + self.hi } // #[inline] // pub(crate) fn from_rsqrt(x: f64) -> DoubleDouble { // let r = DoubleDouble::div_dd_f64(DoubleDouble::from_sqrt(x), x); // let rx = DoubleDouble::quick_mult_safe_f64(r, x); // let drx = DoubleDouble::mul_f64_safe_add(r, x, -rx); // let h = DoubleDouble::mul_add(r, drx, DoubleDouble::mul_add_f64(r, rx, -1.0)); // let dr = DoubleDouble::quick_mult(DoubleDouble::quick_mult_f64(r, 0.5), h); // DoubleDouble::add(r, dr) // } #[inline] pub(crate) fn from_rsqrt_fast(x: f64) -> DoubleDouble { let sqrt_x = DoubleDouble::from_sqrt(x); sqrt_x.recip() } } impl Mul for DoubleDouble { type Output = Self; #[inline] fn mul(self, rhs: DoubleDouble) -> Self::Output { DoubleDouble::quick_mult(self, rhs) } } /// check if number is valid for Exact mult #[allow(dead_code)] #[inline] pub(crate) fn two_product_compatible(x: f64) -> bool { let exp = get_exponent_f64(x); !(exp >= 970 || exp <= -970) } #[cfg(test)] mod tests { use super::*; #[test] fn test_f64_mult() { let d1 = 1.1231; let d2 = DoubleDouble::new(1e-22, 3.2341); let p = DoubleDouble::quick_f64_mult(d1, d2); assert_eq!(p.hi, 3.6322177100000004); assert_eq!(p.lo, -1.971941841373783e-16); } #[test] fn test_mult_64() { let d1 = 1.1231; let d2 = DoubleDouble::new(1e-22, 3.2341); let p = DoubleDouble::mult_f64(d2, d1); assert_eq!(p.hi, 3.6322177100000004); assert_eq!(p.lo, -1.971941841373783e-16); } #[test] fn recip_test() { let d1 = 1.54352432142; let recip = DoubleDouble::new(0., d1).recip(); assert_eq!(recip.hi, d1.recip()); assert_ne!(recip.lo, 0.); } #[test] fn from_recip_test() { let d1 = 1.54352432142; let recip = DoubleDouble::from_recip(d1); assert_eq!(recip.hi, d1.recip()); assert_ne!(recip.lo, 0.); } #[test] fn from_quick_recip_test() { let d1 = 1.54352432142; let recip = DoubleDouble::from_quick_recip(d1); assert_eq!(recip.hi, d1.recip()); assert_ne!(recip.lo, 0.); } } pxfm-0.1.23/src/dyadic_float.rs000064400000000000000000000654711046102023000144550ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::EXP_MASK; use crate::common::f_fmla; use std::ops::{Add, Mul, Sub}; #[repr(u8)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] pub(crate) enum DyadicSign { Pos = 0, Neg = 1, } impl DyadicSign { #[inline] pub(crate) fn negate(self) -> Self { match self { DyadicSign::Pos => DyadicSign::Neg, DyadicSign::Neg => DyadicSign::Pos, } } #[inline] pub(crate) const fn to_bit(self) -> u8 { match self { DyadicSign::Pos => 0, DyadicSign::Neg => 1, } } #[inline] pub(crate) const fn mult(self, rhs: Self) -> Self { if (self as u8) ^ (rhs as u8) != 0 { DyadicSign::Neg } else { DyadicSign::Pos } } } const BITS: u32 = 128; #[derive(Copy, Clone, Debug)] pub(crate) struct DyadicFloat128 { pub(crate) sign: DyadicSign, pub(crate) exponent: i16, pub(crate) mantissa: u128, } #[inline] pub(crate) const fn f64_from_parts(sign: DyadicSign, exp: u64, mantissa: u64) -> f64 { let r_sign = (if sign.to_bit() == 0 { 0u64 } else { 1u64 }).wrapping_shl(63); let r_exp = exp.wrapping_shl(52); f64::from_bits(r_sign | r_exp | mantissa) } #[inline] pub(crate) fn mulhi_u128(a: u128, b: u128) -> u128 { let a_lo = a as u64 as u128; let a_hi = (a >> 64) as u64 as u128; let b_lo = b as u64 as u128; let b_hi = (b >> 64) as u64 as u128; let lo_lo = a_lo * b_lo; let lo_hi = a_lo * b_hi; let hi_lo = a_hi * b_lo; let hi_hi = a_hi * b_hi; let carry = (lo_lo >> 64) .wrapping_add(lo_hi & 0xffff_ffff_ffff_ffff) .wrapping_add(hi_lo & 0xffff_ffff_ffff_ffff); let mid = (lo_hi >> 64) .wrapping_add(hi_lo >> 64) .wrapping_add(carry >> 64); hi_hi.wrapping_add(mid) } #[inline] const fn explicit_exponent(x: f64) -> i16 { let exp = ((x.to_bits() >> 52) & ((1u64 << 11) - 1u64)) as i16 - 1023; if x == 0. { return 0; } else if x.is_subnormal() { const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; return 1i16 - EXP_BIAS as i16; } exp } #[inline] const fn explicit_mantissa(x: f64) -> u64 { const MASK: u64 = (1u64 << 52) - 1; let sig_bits = x.to_bits() & MASK; if x.is_subnormal() || x == 0. { return sig_bits; } (1u64 << 52) | sig_bits } impl DyadicFloat128 { #[inline] pub(crate) const fn zero() -> Self { Self { sign: DyadicSign::Pos, exponent: 0, mantissa: 0, } } #[inline] pub(crate) const fn new_from_f64(x: f64) -> Self { let sign = if x.is_sign_negative() { DyadicSign::Neg } else { DyadicSign::Pos }; let exponent = explicit_exponent(x) - 52; let mantissa = explicit_mantissa(x) as u128; let mut new_val = Self { sign, exponent, mantissa, }; new_val.normalize(); new_val } #[inline] pub(crate) fn new(sign: DyadicSign, exponent: i16, mantissa: u128) -> Self { let mut new_item = DyadicFloat128 { sign, exponent, mantissa, }; new_item.normalize(); new_item } #[inline] pub(crate) fn accurate_reciprocal(a: f64) -> Self { let mut r = DyadicFloat128::new_from_f64(4.0 / a); /* accurate to about 53 bits */ r.exponent -= 2; /* we use Newton's iteration: r -> r + r*(1-a*r) */ let ba = DyadicFloat128::new_from_f64(-a); let mut q = ba * r; const F128_ONE: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }; q = F128_ONE + q; q = r * q; r + q } #[inline] pub(crate) fn from_div_f64(a: f64, b: f64) -> Self { let reciprocal = DyadicFloat128::accurate_reciprocal(b); let da = DyadicFloat128::new_from_f64(a); reciprocal * da } /// Multiply self by integer scalar `b`. /// Returns a new normalized DyadicFloat128. #[inline] pub(crate) fn mul_int64(&self, b: i64) -> DyadicFloat128 { if b == 0 { return DyadicFloat128::zero(); } let abs_b = b.unsigned_abs(); let sign = if (b < 0) ^ (self.sign == DyadicSign::Neg) { DyadicSign::Neg } else { DyadicSign::Pos }; let mut hi_prod = (self.mantissa >> 64).wrapping_mul(abs_b as u128); let m = hi_prod.leading_zeros(); hi_prod <<= m; let mut lo_prod = (self.mantissa & 0xffff_ffff_ffff_ffff).wrapping_mul(abs_b as u128); lo_prod = (lo_prod << (m - 1)) >> 63; let (mut product, overflow) = hi_prod.overflowing_add(lo_prod); let mut result = DyadicFloat128 { sign, exponent: self.exponent + 64 - m as i16, mantissa: product, }; if overflow { // Overflow means an implicit bit in the 129th place, which we shift down. product += product & 0x1; result.mantissa = (product >> 1) | (1u128 << 127); result.shift_right(1); } result.normalize(); result } #[inline] fn shift_right(&mut self, amount: u32) { if amount < BITS { self.exponent += amount as i16; self.mantissa = self.mantissa.wrapping_shr(amount); } else { self.exponent = 0; self.mantissa = 0; } } #[inline] fn shift_left(&mut self, amount: u32) { if amount < BITS { self.exponent -= amount as i16; self.mantissa = self.mantissa.wrapping_shl(amount); } else { self.exponent = 0; self.mantissa = 0; } } // Don't forget to call if manually created #[inline] pub(crate) const fn normalize(&mut self) { if self.mantissa != 0 { let shift_length = self.mantissa.leading_zeros(); self.exponent -= shift_length as i16; self.mantissa = self.mantissa.wrapping_shl(shift_length); } } #[inline] pub(crate) fn negated(&self) -> Self { Self { sign: self.sign.negate(), exponent: self.exponent, mantissa: self.mantissa, } } #[inline] pub(crate) fn quick_sub(&self, rhs: &Self) -> Self { self.quick_add(&rhs.negated()) } #[inline] pub(crate) fn quick_add(&self, rhs: &Self) -> Self { if self.mantissa == 0 { return *rhs; } if rhs.mantissa == 0 { return *self; } let mut a = *self; let mut b = *rhs; let exp_diff = a.exponent.wrapping_sub(b.exponent); // If exponent difference is too large, b is negligible if exp_diff.abs() >= BITS as i16 { return if a.sign == b.sign { // Adding very small number to large: return a return if a.exponent > b.exponent { a } else { b }; } else if a.exponent > b.exponent { a } else { b }; } // Align exponents if a.exponent > b.exponent { b.shift_right((a.exponent - b.exponent) as u32); } else if b.exponent > a.exponent { a.shift_right((b.exponent - a.exponent) as u32); } let mut result = DyadicFloat128::zero(); if a.sign == b.sign { // Addition result.sign = a.sign; result.exponent = a.exponent; result.mantissa = a.mantissa; let (sum, is_overflow) = result.mantissa.overflowing_add(b.mantissa); result.mantissa = sum; if is_overflow { // Mantissa addition overflow. result.shift_right(1); result.mantissa |= 1u128 << 127; } // Result is already normalized. return result; } // Subtraction if a.mantissa >= b.mantissa { result.sign = a.sign; result.exponent = a.exponent; result.mantissa = a.mantissa.wrapping_sub(b.mantissa); } else { result.sign = b.sign; result.exponent = b.exponent; result.mantissa = b.mantissa.wrapping_sub(a.mantissa); } result.normalize(); result } #[inline] pub(crate) fn quick_mul(&self, rhs: &Self) -> Self { let mut result = DyadicFloat128 { sign: if self.sign != rhs.sign { DyadicSign::Neg } else { DyadicSign::Pos }, exponent: self.exponent + rhs.exponent + BITS as i16, mantissa: 0, }; if !(self.mantissa == 0 || rhs.mantissa == 0) { result.mantissa = mulhi_u128(self.mantissa, rhs.mantissa); // Check the leading bit directly, should be faster than using clz in // normalize(). if result.mantissa >> 127 == 0 { result.shift_left(1); } } else { result.mantissa = 0; } result } #[inline] pub(crate) fn fast_as_f64(&self) -> f64 { if self.mantissa == 0 { return if self.sign == DyadicSign::Pos { 0. } else { -0.0 }; } // Assume that it is normalized, and output is also normal. const PRECISION: u32 = 52 + 1; // SIG_MASK - FRACTION_MASK const SIG_MASK: u64 = (1u64 << 52) - 1; const FRACTION_MASK: u64 = (1u64 << 52) - 1; const IMPLICIT_MASK: u64 = SIG_MASK - FRACTION_MASK; const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut exp_hi = self.exponent as i32 + ((BITS - 1) as i32 + EXP_BIAS as i32); if exp_hi > 2 * EXP_BIAS as i32 { // Results overflow. let d_hi = f64_from_parts(self.sign, 2 * EXP_BIAS, IMPLICIT_MASK); // volatile prevents constant propagation that would result in infinity // always being returned no matter the current rounding mode. let two = 2.0f64; let r = two * d_hi; return r; } let mut denorm = false; let mut shift = BITS - PRECISION; if exp_hi <= 0 { // Output is denormal. denorm = true; shift = (BITS - PRECISION) + (1 - exp_hi) as u32; exp_hi = EXP_BIAS as i32; } let exp_lo = exp_hi.wrapping_sub(PRECISION as i32).wrapping_sub(1); let m_hi = if shift >= BITS { 0 } else { self.mantissa >> shift }; let d_hi = f64_from_parts( self.sign, exp_hi as u64, (m_hi as u64 & SIG_MASK) | IMPLICIT_MASK, ); let round_mask = if shift > BITS { 0 } else { 1u128.wrapping_shl(shift.wrapping_sub(1)) }; let sticky_mask = round_mask.wrapping_sub(1u128); let round_bit = (self.mantissa & round_mask) != 0; let sticky_bit = (self.mantissa & sticky_mask) != 0; let round_and_sticky = round_bit as i32 * 2 + sticky_bit as i32; let d_lo: f64; if exp_lo <= 0 { // d_lo is denormal, but the output is normal. let scale_up_exponent = 1 - exp_lo; let scale_up_factor = f64_from_parts( DyadicSign::Pos, EXP_BIAS + scale_up_exponent as u64, IMPLICIT_MASK, ); let scale_down_factor = f64_from_parts( DyadicSign::Pos, EXP_BIAS - scale_up_exponent as u64, IMPLICIT_MASK, ); d_lo = f64_from_parts( self.sign, (exp_lo + scale_up_exponent) as u64, IMPLICIT_MASK, ); return f_fmla(d_lo, round_and_sticky as f64, d_hi * scale_up_factor) * scale_down_factor; } d_lo = f64_from_parts(self.sign, exp_lo as u64, IMPLICIT_MASK); // Still correct without FMA instructions if `d_lo` is not underflow. let r = f_fmla(d_lo, round_and_sticky as f64, d_hi); if denorm { const SIG_LEN: u64 = 52; // Exponent before rounding is in denormal range, simply clear the // exponent field. let clear_exp: u64 = (exp_hi as u64) << SIG_LEN; let mut r_bits: u64 = r.to_bits() - clear_exp; if r_bits & EXP_MASK == 0 { // Output is denormal after rounding, clear the implicit bit for 80-bit // long double. r_bits -= IMPLICIT_MASK; } return f64::from_bits(r_bits); } r } // Approximate reciprocal - given a nonzero `a`, make a good approximation to 1/a. // The method is Newton-Raphson iteration, based on quick_mul. #[inline] pub(crate) fn reciprocal(self) -> DyadicFloat128 { // Computes the reciprocal using Newton-Raphson iteration: // Given an approximation x ≈ 1/a, we refine via: // x' = x * (2 - a * x) // This squares the error term: if ax ≈ 1 - e, then ax' ≈ 1 - e². let guess = 1. / self.fast_as_f64(); let mut x = DyadicFloat128::new_from_f64(guess); // The constant 2, which we'll need in every iteration let twos = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; x = x * (twos - (self * x)); x = x * (twos - (self * x)); x } // // Approximate reciprocal - given a nonzero `a`, make a good approximation to 1/a. // // The method is Newton-Raphson iteration, based on quick_mul. // // *This is very crude guess* // #[inline] // fn approximate_reciprocal(&self) -> DyadicFloat128 { // // Given an approximation x to 1/a, a better one is x' = x(2-ax). // // // // You can derive this by using the Newton-Raphson formula with the function // // f(x) = 1/x - a. But another way to see that it works is to say: suppose // // that ax = 1-e for some small error e. Then ax' = ax(2-ax) = (1-e)(1+e) = // // 1-e^2. So the error in x' is the square of the error in x, i.e. the number // // of correct bits in x' is double the number in x. // // // An initial approximation to the reciprocal // let mut x = DyadicFloat128 { // sign: DyadicSign::Pos, // exponent: -32 - self.exponent - BITS as i16, // mantissa: self.mantissa >> (BITS - 32), // }; // x.normalize(); // // // The constant 2, which we'll need in every iteration // let two = DyadicFloat128::new(DyadicSign::Pos, 1, 1); // // // We expect at least 31 correct bits from our 32-bit starting approximation // let mut ok_bits = 31usize; // // // The number of good bits doubles in each iteration, except that rounding // // errors introduce a little extra each time. Subtract a bit from our // // accuracy assessment to account for that. // while ok_bits < BITS as usize { // x = x * (two - (*self * x)); // ok_bits = 2 * ok_bits - 1; // } // // x // } } impl Add for DyadicFloat128 { type Output = DyadicFloat128; #[inline] fn add(self, rhs: DyadicFloat128) -> Self::Output { self.quick_add(&rhs) } } impl DyadicFloat128 { #[inline] pub(crate) fn biased_exponent(&self) -> i16 { self.exponent + (BITS as i16 - 1) } #[inline] pub(crate) fn trunc_to_i64(&self) -> i64 { if self.exponent <= -(BITS as i16) { // Absolute value of x is greater than equal to 0.5 but less than 1. return 0; } let hi = self.mantissa >> 64; let norm_exp = self.biased_exponent(); if norm_exp > 63 { return if self.sign == DyadicSign::Neg { i64::MIN } else { i64::MAX }; } let r: i64 = (hi >> (63 - norm_exp)) as i64; if self.sign == DyadicSign::Neg { -r } else { r } } #[inline] pub(crate) fn round_to_nearest(&self) -> DyadicFloat128 { if self.exponent == -(BITS as i16) { // Absolute value of x is greater than equal to 0.5 but less than 1. return DyadicFloat128 { sign: self.sign, exponent: -(BITS as i16 - 1), mantissa: 0x80000000_00000000_00000000_00000000_u128, }; } if self.exponent <= -((BITS + 1) as i16) { // Absolute value of x is greater than equal to 0.5 but less than 1. return DyadicFloat128 { sign: self.sign, exponent: 0, mantissa: 0u128, }; } const FRACTION_LENGTH: u32 = BITS - 1; let trim_size = (FRACTION_LENGTH as i64).wrapping_sub(self.exponent as i64 + (BITS - 1) as i64) as u128; let half_bit_set = self.mantissa & (1u128.wrapping_shl(trim_size.wrapping_sub(1) as u32)) != 0; let trunc_u: u128 = self .mantissa .wrapping_shr(trim_size as u32) .wrapping_shl(trim_size as u32); if trunc_u == self.mantissa { return *self; } let truncated = DyadicFloat128::new(self.sign, self.exponent, trunc_u); if !half_bit_set { // Franctional part is less than 0.5 so round value is the // same as the trunc value. truncated } else if self.sign == DyadicSign::Neg { let ones = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -(BITS as i16 - 1), mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }; truncated - ones } else { let ones = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -(BITS as i16 - 1), mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }; truncated + ones } } #[inline] pub(crate) fn round_to_nearest_f64(&self) -> f64 { self.round_to_nearest().fast_as_f64() } } impl Sub for DyadicFloat128 { type Output = DyadicFloat128; #[inline] fn sub(self, rhs: DyadicFloat128) -> Self::Output { self.quick_sub(&rhs) } } impl Mul for DyadicFloat128 { type Output = DyadicFloat128; #[inline] fn mul(self, rhs: DyadicFloat128) -> Self::Output { self.quick_mul(&rhs) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_dyadic_float() { let ones = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let cvt = ones.fast_as_f64(); assert_eq!(cvt, 1.0); let minus_0_5 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let cvt0 = minus_0_5.fast_as_f64(); assert_eq!(cvt0, -1.0 / 2.0); let minus_1_f4 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }; let cvt0 = minus_1_f4.fast_as_f64(); assert_eq!(cvt0, -1.0 / 24.0); let minus_1_f8 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd00d00d0_0d00d00d_00d00d00_d00d00d0_u128, }; let cvt0 = minus_1_f8.fast_as_f64(); assert_eq!(cvt0, 1.0 / 40320.0); } #[test] fn dyadic_float_add() { let ones = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let cvt = ones.fast_as_f64(); assert_eq!(cvt, 1.0); let minus_0_5 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let cvt0 = ones.quick_add(&minus_0_5).fast_as_f64(); assert_eq!(cvt0, 0.5); } #[test] fn dyadic_float_mul() { let ones = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let cvt = ones.fast_as_f64(); assert_eq!(cvt, 1.0); let minus_0_5 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let product = ones.quick_mul(&minus_0_5); let cvt0 = product.fast_as_f64(); assert_eq!(cvt0, -0.5); let twos = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let cvt = twos.fast_as_f64(); assert_eq!(cvt, 2.0); } #[test] fn dyadic_round_trip() { let z00 = 0.0; let zvt00 = DyadicFloat128::new_from_f64(z00); let b00 = zvt00.fast_as_f64(); assert_eq!(b00, z00); let zvt000 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0, }; let b000 = zvt000.fast_as_f64(); assert_eq!(b000, z00); let z0 = 1.0; let zvt0 = DyadicFloat128::new_from_f64(z0); let b0 = zvt0.fast_as_f64(); assert_eq!(b0, z0); let z1 = 0.5; let zvt1 = DyadicFloat128::new_from_f64(z1); let b1 = zvt1.fast_as_f64(); assert_eq!(b1, z1); let z2 = -0.5; let zvt2 = DyadicFloat128::new_from_f64(z2); let b2 = zvt2.fast_as_f64(); assert_eq!(b2, z2); let z3 = -532322.54324324232; let zvt3 = DyadicFloat128::new_from_f64(z3); let b3 = zvt3.fast_as_f64(); assert_eq!(b3, z3); } #[test] fn dyadic_float_reciprocal() { let ones = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, } .reciprocal(); let cvt = ones.fast_as_f64(); assert_eq!(cvt, 1.0); let minus_0_5 = DyadicFloat128::new_from_f64(4.).reciprocal(); let cvt0 = minus_0_5.fast_as_f64(); assert_eq!(cvt0, 0.25); } #[test] fn dyadic_float_from_div() { let from_div = DyadicFloat128::from_div_f64(1.0, 4.0); let cvt = from_div.fast_as_f64(); assert_eq!(cvt, 0.25); } #[test] fn dyadic_float_accurate_reciprocal() { let from_div = DyadicFloat128::accurate_reciprocal(4.0); let cvt = from_div.fast_as_f64(); assert_eq!(cvt, 0.25); } #[test] fn dyadic_float_mul_int() { let from_div = DyadicFloat128::new_from_f64(4.0); let m1 = from_div.mul_int64(-2); assert_eq!(m1.fast_as_f64(), -8.0); let from_div = DyadicFloat128::new_from_f64(-4.0); let m1 = from_div.mul_int64(-2); assert_eq!(m1.fast_as_f64(), 8.0); let from_div = DyadicFloat128::new_from_f64(2.5); let m1 = from_div.mul_int64(2); assert_eq!(m1.fast_as_f64(), 5.0); } #[test] fn dyadic_float_round() { let from_div = DyadicFloat128::new_from_f64(2.5); let m1 = from_div.round_to_nearest_f64(); assert_eq!(m1, 3.0); let from_div = DyadicFloat128::new_from_f64(0.5); let m1 = from_div.round_to_nearest_f64(); assert_eq!(m1, 1.0); let from_div = DyadicFloat128::new_from_f64(-0.5); let m1 = from_div.round_to_nearest_f64(); assert_eq!(m1, -1.0); let from_div = DyadicFloat128::new_from_f64(-0.351); let m1 = from_div.round_to_nearest_f64(); assert_eq!(m1, (-0.351f64).round()); let from_div = DyadicFloat128::new_from_f64(0.351); let m1 = from_div.round_to_nearest_f64(); assert_eq!(m1, 0.351f64.round()); let z00 = 25.6; let zvt00 = DyadicFloat128::new_from_f64(z00); let b00 = zvt00.round_to_nearest_f64(); assert_eq!(b00, 26.); } #[test] fn dyadic_int_trunc() { let from_div = DyadicFloat128::new_from_f64(-2.5); let m1 = from_div.trunc_to_i64(); assert_eq!(m1, -2); let from_div = DyadicFloat128::new_from_f64(2.5); let m1 = from_div.trunc_to_i64(); assert_eq!(m1, 2); let from_div = DyadicFloat128::new_from_f64(0.5); let m1 = from_div.trunc_to_i64(); assert_eq!(m1, 0); let from_div = DyadicFloat128::new_from_f64(-0.5); let m1 = from_div.trunc_to_i64(); assert_eq!(m1, 0); let from_div = DyadicFloat128::new_from_f64(-0.351); let m1 = from_div.trunc_to_i64(); assert_eq!(m1, 0); let from_div = DyadicFloat128::new_from_f64(0.351); let m1 = from_div.trunc_to_i64(); assert_eq!(m1, 0); } } pxfm-0.1.23/src/dyadic_float256.rs000064400000000000000000000733201046102023000147020ustar 00000000000000// /* // * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. // * // // * // 3. Neither the name of the copyright holder nor the names of its // * // contributors may be used to endorse or promote products derived from // * // this software without specific prior written permission. // * // // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::EXP_MASK; // use crate::common::f_fmla; // use crate::dyadic_float::{DyadicSign, f64_from_parts}; // use crate::u256::{mulhi_u256, u256}; // use std::ops::{Add, Mul, Shr, Sub}; // // const BITS: u32 = 256; // // #[derive(Copy, Clone, Debug)] // pub(crate) struct DyadicFloat256 { // pub(crate) sign: DyadicSign, // pub(crate) exponent: i16, // pub(crate) mantissa: u256, // } // // #[inline] // const fn explicit_exponent(x: f64) -> i16 { // let exp = ((x.to_bits() >> 52) & ((1u64 << 11) - 1u64)) as i16 - 1023; // if x == 0. { // return 0; // } else if x.is_subnormal() { // const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; // return 1i16 - EXP_BIAS as i16; // } // exp // } // // #[inline] // const fn explicit_mantissa(x: f64) -> u64 { // const MASK: u64 = (1u64 << 52) - 1; // let sig_bits = x.to_bits() & MASK; // if x.is_subnormal() || x == 0. { // return sig_bits; // } // (1u64 << 52) | sig_bits // } // // impl DyadicFloat256 { // #[inline] // pub(crate) const fn zero() -> Self { // Self { // sign: DyadicSign::Pos, // exponent: 0, // mantissa: u256::ZERO, // } // } // // #[inline] // pub(crate) fn new_from_f64(x: f64) -> Self { // let sign = if x.is_sign_negative() { // DyadicSign::Neg // } else { // DyadicSign::Pos // }; // let exponent = explicit_exponent(x) - 52; // let mantissa = u256::from_u64(explicit_mantissa(x)); // let mut new_val = Self { // sign, // exponent, // mantissa, // }; // new_val.normalize(); // new_val // } // // #[inline] // pub(crate) fn new(sign: DyadicSign, exponent: i16, mantissa: u256) -> Self { // let mut new_item = DyadicFloat256 { // sign, // exponent, // mantissa, // }; // new_item.normalize(); // new_item // } // // #[inline] // pub(crate) fn accurate_reciprocal(a: f64) -> Self { // // we convert 4/a and divide by 4 to avoid a spurious underflow // let mut r = DyadicFloat256::new_from_f64(4.0 / a); /* accurate to about 53 bits */ // r.exponent -= 2; // /* we use Newton's iteration: r -> r + r*(1-a*r) */ // let ba = DyadicFloat256::new_from_f64(-a); // let mut q = ba * r; // const F256_ONE: DyadicFloat256 = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, // lo: 0x0u128, // }, // }; // q = F256_ONE + q; // q = r * q; // // let mut q2 = ba * q; // q2 = F256_ONE + q2; // q2 = q * q2; // // let mut q3 = ba * q2; // q3 = F256_ONE + q3; // q3 = q2 * q3; // r + q3 // } // // #[inline] // pub(crate) fn from_div_f64(a: f64, b: f64) -> Self { // let reciprocal = DyadicFloat256::accurate_reciprocal(b); // let da = DyadicFloat256::new_from_f64(a); // reciprocal * da // } // // // /// Multiply self by integer scalar `b`. // // /// Returns a new normalized DyadicFloat256. // // #[inline] // // pub(crate) fn mul_int64(&self, b: i64) -> DyadicFloat256 { // // if b == 0 { // // return DyadicFloat256::zero(); // // } // // // // let abs_b = b.unsigned_abs(); // // let sign = if (b < 0) ^ (self.sign == DyadicSign::Neg) { // // DyadicSign::Neg // // } else { // // DyadicSign::Pos // // }; // // // // let mut hi_prod = (self.mantissa >> 64).wrapping_mul(abs_b as u128); // // let m = hi_prod.leading_zeros(); // // hi_prod <<= m; // // // // let mut lo_prod = (self.mantissa & 0xffff_ffff_ffff_ffff).wrapping_mul(abs_b as u128); // // lo_prod = (lo_prod << (m - 1)) >> 63; // // // // let (mut product, overflow) = hi_prod.overflowing_add(lo_prod); // // // // let mut result = DyadicFloat256 { // // sign, // // exponent: self.exponent + 64 - m as i16, // // mantissa: product, // // }; // // // // if overflow { // // // Overflow means an implicit bit in the 129th place, which we shift down. // // product += product & 0x1; // // result.mantissa = (product >> 1) | (1u128 << 127); // // result.shift_right(1); // // } // // // // result.normalize(); // // result // // } // // #[inline] // fn shift_right(&mut self, amount: u32) { // if amount < BITS { // self.exponent += amount as i16; // self.mantissa = self.mantissa.shr(amount); // } else { // self.exponent = 0; // self.mantissa = u256::ZERO; // } // } // // #[inline] // fn shift_left(&mut self, amount: u32) { // if amount < BITS { // self.exponent -= amount as i16; // self.mantissa = self.mantissa.wrapping_shl(amount); // } else { // self.exponent = 0; // self.mantissa = u256::ZERO; // } // } // // // Don't forget to call if manually created // #[inline] // pub(crate) fn normalize(&mut self) { // if self.mantissa != u256::ZERO { // let shift_length = self.mantissa.leading_zeros(); // self.exponent -= shift_length as i16; // self.mantissa = self.mantissa.wrapping_shl(shift_length); // } // } // // #[inline] // pub(crate) fn negated(&self) -> Self { // Self { // sign: self.sign.negate(), // exponent: self.exponent, // mantissa: self.mantissa, // } // } // // #[inline] // pub(crate) fn quick_sub(&self, rhs: &Self) -> Self { // self.quick_add(&rhs.negated()) // } // // #[inline] // pub(crate) fn quick_add(&self, rhs: &Self) -> Self { // if self.mantissa == u256::ZERO { // return *rhs; // } // if rhs.mantissa == u256::ZERO { // return *self; // } // let mut a = *self; // let mut b = *rhs; // // let exp_diff = a.exponent.wrapping_sub(b.exponent); // // // If exponent difference is too large, b is negligible // if exp_diff.abs() >= BITS as i16 { // return if a.sign == b.sign { // // Adding very small number to large: return a // return if a.exponent > b.exponent { a } else { b }; // } else if a.exponent > b.exponent { // a // } else { // b // }; // } // // // Align exponents // if a.exponent > b.exponent { // b.shift_right((a.exponent - b.exponent) as u32); // } else if b.exponent > a.exponent { // a.shift_right((b.exponent - a.exponent) as u32); // } // // let mut result = DyadicFloat256::zero(); // // if a.sign == b.sign { // // Addition // result.sign = a.sign; // result.exponent = a.exponent; // result.mantissa = a.mantissa; // let (sum, is_overflow) = result.mantissa.overflowing_add(b.mantissa); // result.mantissa = sum; // if is_overflow { // // Mantissa addition overflow. // result.shift_right(1); // result.mantissa |= u256::ONE.wrapping_shl(255); // } // // Result is already normalized. // return result; // } // // // Subtraction // if a.mantissa >= b.mantissa { // result.sign = a.sign; // result.exponent = a.exponent; // result.mantissa = a.mantissa.wrapping_sub(b.mantissa); // } else { // result.sign = b.sign; // result.exponent = b.exponent; // result.mantissa = b.mantissa.wrapping_sub(a.mantissa); // } // // result.normalize(); // result // } // // #[inline] // pub(crate) fn quick_mul(&self, rhs: &Self) -> Self { // let mut result = DyadicFloat256 { // sign: if self.sign != rhs.sign { // DyadicSign::Neg // } else { // DyadicSign::Pos // }, // exponent: self.exponent + rhs.exponent + BITS as i16, // mantissa: u256::ZERO, // }; // // if !(self.mantissa == u256::ZERO || rhs.mantissa == u256::ZERO) { // result.mantissa = mulhi_u256(self.mantissa, rhs.mantissa); // // Check the leading bit directly, should be faster than using clz in // // normalize(). // if result.mantissa >> 255 == u256::ZERO { // result.shift_left(1); // } // } else { // result.mantissa = u256::ZERO; // } // result // } // // #[inline] // pub(crate) fn fast_as_f64(&self) -> f64 { // if self.mantissa == u256::ZERO { // return if self.sign == DyadicSign::Pos { // 0. // } else { // -0.0 // }; // } // // // Assume that it is normalized, and output is also normal. // const PRECISION: u32 = 52 + 1; // // // SIG_MASK - FRACTION_MASK // const SIG_MASK: u64 = (1u64 << 52) - 1; // const FRACTION_MASK: u64 = (1u64 << 52) - 1; // const IMPLICIT_MASK: u64 = SIG_MASK - FRACTION_MASK; // const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; // // let mut exp_hi = self.exponent as i32 + ((BITS - 1) as i32 + EXP_BIAS as i32); // // if exp_hi > 2 * EXP_BIAS as i32 { // // Results overflow. // let d_hi = f64_from_parts(self.sign, 2 * EXP_BIAS, IMPLICIT_MASK); // // volatile prevents constant propagation that would result in infinity // // always being returned no matter the current rounding mode. // let two = 2.0f64; // let r = two * d_hi; // return r; // } // // let mut denorm = false; // let mut shift = BITS - PRECISION; // if exp_hi <= 0 { // // Output is denormal. // denorm = true; // shift = (BITS - PRECISION) + (1 - exp_hi) as u32; // // exp_hi = EXP_BIAS as i32; // } // // let exp_lo = exp_hi.wrapping_sub(PRECISION as i32).wrapping_sub(1); // // let m_hi = if shift >= BITS { // 0u64 // } else { // (self.mantissa >> shift).to_u64() // }; // // let d_hi = f64_from_parts(self.sign, exp_hi as u64, (m_hi & SIG_MASK) | IMPLICIT_MASK); // // let round_mask = if shift > BITS { // u256::ZERO // } else { // u256::ONE.wrapping_shl(shift.wrapping_sub(1)) // }; // let sticky_mask = round_mask.wrapping_sub(u256::ONE); // // let round_bit = (self.mantissa & round_mask) != u256::ZERO; // let sticky_bit = (self.mantissa & sticky_mask) != u256::ZERO; // let round_and_sticky = round_bit as i32 * 2 + sticky_bit as i32; // // let d_lo: f64; // // if exp_lo <= 0 { // // d_lo is denormal, but the output is normal. // let scale_up_exponent = 1 - exp_lo; // let scale_up_factor = f64_from_parts( // DyadicSign::Pos, // EXP_BIAS + scale_up_exponent as u64, // IMPLICIT_MASK, // ); // let scale_down_factor = f64_from_parts( // DyadicSign::Pos, // EXP_BIAS - scale_up_exponent as u64, // IMPLICIT_MASK, // ); // // d_lo = f64_from_parts( // self.sign, // (exp_lo + scale_up_exponent) as u64, // IMPLICIT_MASK, // ); // // return f_fmla(d_lo, round_and_sticky as f64, d_hi * scale_up_factor) // * scale_down_factor; // } // // d_lo = f64_from_parts(self.sign, exp_lo as u64, IMPLICIT_MASK); // // // Still correct without FMA instructions if `d_lo` is not underflow. // let r = f_fmla(d_lo, round_and_sticky as f64, d_hi); // // if denorm { // const SIG_LEN: u64 = 52; // // Exponent before rounding is in denormal range, simply clear the // // exponent field. // let clear_exp: u64 = (exp_hi as u64) << SIG_LEN; // let mut r_bits: u64 = r.to_bits() - clear_exp; // // if r_bits & EXP_MASK == 0 { // // Output is denormal after rounding, clear the implicit bit for 80-bit // // long double. // r_bits -= IMPLICIT_MASK; // } // // return f64::from_bits(r_bits); // } // // r // } // // // Approximate reciprocal - given a nonzero `a`, make a good approximation to 1/a. // // The method is Newton-Raphson iteration, based on quick_mul. // #[inline] // pub(crate) fn reciprocal(self) -> DyadicFloat256 { // // Computes the reciprocal using Newton-Raphson iteration: // // Given an approximation x ≈ 1/a, we refine via: // // x' = x * (2 - a * x) // // This squares the error term: if ax ≈ 1 - e, then ax' ≈ 1 - e². // // let guess = 1. / self.fast_as_f64(); // let mut x = DyadicFloat256::new_from_f64(guess); // // // The constant 2, which we'll need in every iteration // let twos = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 2), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // // x = x * (twos - (self * x)); // x = x * (twos - (self * x)); // x = x * (twos - (self * x)); // x = x * (twos - (self * x)); // x = x * (twos - (self * x)); // x // } // // // // Approximate reciprocal - given a nonzero `a`, make a good approximation to 1/a. // // // The method is Newton-Raphson iteration, based on quick_mul. // // // *This is very crude guess* // // #[inline] // // fn approximate_reciprocal(&self) -> DyadicFloat256 { // // // Given an approximation x to 1/a, a better one is x' = x(2-ax). // // // // // // You can derive this by using the Newton-Raphson formula with the function // // // f(x) = 1/x - a. But another way to see that it works is to say: suppose // // // that ax = 1-e for some small error e. Then ax' = ax(2-ax) = (1-e)(1+e) = // // // 1-e^2. So the error in x' is the square of the error in x, i.e. the number // // // of correct bits in x' is double the number in x. // // // // // An initial approximation to the reciprocal // // let mut x = DyadicFloat256 { // // sign: DyadicSign::Pos, // // exponent: -32 - self.exponent - BITS as i16, // // mantissa: self.mantissa >> (BITS - 32), // // }; // // x.normalize(); // // // // // The constant 2, which we'll need in every iteration // // let two = DyadicFloat256::new(DyadicSign::Pos, 1, 1); // // // // // We expect at least 31 correct bits from our 32-bit starting approximation // // let mut ok_bits = 31usize; // // // // // The number of good bits doubles in each iteration, except that rounding // // // errors introduce a little extra each time. Subtract a bit from our // // // accuracy assessment to account for that. // // while ok_bits < BITS as usize { // // x = x * (two - (*self * x)); // // ok_bits = 2 * ok_bits - 1; // // } // // // // x // // } // } // // impl Add for DyadicFloat256 { // type Output = DyadicFloat256; // #[inline] // fn add(self, rhs: DyadicFloat256) -> Self::Output { // self.quick_add(&rhs) // } // } // // impl DyadicFloat256 { // #[inline] // pub(crate) fn biased_exponent(&self) -> i16 { // self.exponent + (BITS as i16 - 1) // } // // // #[inline] // // pub(crate) fn trunc_to_i64(&self) -> i64 { // // if self.exponent <= -(BITS as i16) { // // // Absolute value of x is greater than equal to 0.5 but less than 1. // // return 0; // // } // // let hi = self.mantissa >> 64; // // let norm_exp = self.biased_exponent(); // // if norm_exp > 63 { // // return if self.sign == DyadicSign::Neg { // // i64::MIN // // } else { // // i64::MAX // // }; // // } // // let r: i64 = (hi >> (63 - norm_exp)) as i64; // // // // if self.sign == DyadicSign::Neg { -r } else { r } // // } // // #[inline] // pub(crate) fn round_to_nearest(&self) -> DyadicFloat256 { // if self.exponent == -(BITS as i16) { // // Absolute value of x is greater than equal to 0.5 but less than 1. // return DyadicFloat256 { // sign: self.sign, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // } // if self.exponent <= -((BITS + 1) as i16) { // // Absolute value of x is greater than equal to 0.5 but less than 1. // return DyadicFloat256 { // sign: self.sign, // exponent: 0, // mantissa: u256::ZERO, // }; // } // const FRACTION_LENGTH: u32 = BITS - 1; // let trim_size = // (FRACTION_LENGTH as i64).wrapping_sub(self.exponent as i64 + (BITS - 1) as i64) as u32; // let half_bit_set = // self.mantissa & (u256::ONE.wrapping_shl(trim_size.wrapping_sub(1))) != u256::ZERO; // let trunc_u: u256 = (self.mantissa >> trim_size).wrapping_shl(trim_size); // if trunc_u == self.mantissa { // return *self; // } // // let truncated = DyadicFloat256::new(self.sign, self.exponent, trunc_u); // // if !half_bit_set { // // Franctional part is less than 0.5 so round value is the // // same as the trunc value. // truncated // } else if self.sign == DyadicSign::Neg { // let ones = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, // lo: 0x0u128, // }, // }; // truncated - ones // } else { // let ones = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, // lo: 0x0u128, // }, // }; // truncated + ones // } // } // // #[inline] // pub(crate) fn round_to_nearest_f64(&self) -> f64 { // self.round_to_nearest().fast_as_f64() // } // } // // impl Sub for DyadicFloat256 { // type Output = DyadicFloat256; // #[inline] // fn sub(self, rhs: DyadicFloat256) -> Self::Output { // self.quick_sub(&rhs) // } // } // // impl Mul for DyadicFloat256 { // type Output = DyadicFloat256; // #[inline] // fn mul(self, rhs: DyadicFloat256) -> Self::Output { // self.quick_mul(&rhs) // } // } // // #[cfg(test)] // mod tests { // use super::*; // // #[test] // fn test_dyadic_float() { // let ones = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // let cvt = ones.fast_as_f64(); // assert_eq!(cvt, 1.0); // // let minus_0_5 = DyadicFloat256 { // sign: DyadicSign::Neg, // exponent: -(BITS as i16), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // let cvt0 = minus_0_5.fast_as_f64(); // assert_eq!(cvt0, -1.0 / 2.0); // // let minus_1_f4 = DyadicFloat256 { // sign: DyadicSign::Neg, // exponent: -(BITS as i16 + 4), // mantissa: u256 { // hi: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, // lo: 0x0u128, // }, // }; // let cvt0 = minus_1_f4.fast_as_f64(); // assert_eq!(cvt0, -1.0 / 24.0); // // let minus_1_f8 = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 + 15), // mantissa: u256 { // hi: 0xd00d00d0_0d00d00d_00d00d00_d00d00d0_u128, // lo: 0x0u128, // }, // }; // let cvt0 = minus_1_f8.fast_as_f64(); // assert_eq!(cvt0, 1.0 / 40320.0); // } // // #[test] // fn dyadic_float_add() { // let ones = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // // let cvt = ones.fast_as_f64(); // assert_eq!(cvt, 1.0); // // let minus_0_5 = DyadicFloat256 { // sign: DyadicSign::Neg, // exponent: -(BITS as i16), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // let cvt0 = ones.quick_add(&minus_0_5).fast_as_f64(); // assert_eq!(cvt0, 0.5); // } // // #[test] // fn dyadic_float_mul() { // let ones = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // // let cvt = ones.fast_as_f64(); // assert_eq!(cvt, 1.0); // // let minus_0_5 = DyadicFloat256 { // sign: DyadicSign::Neg, // exponent: -(BITS as i16), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // let product = ones.quick_mul(&minus_0_5); // let cvt0 = product.fast_as_f64(); // assert_eq!(cvt0, -0.5); // // let twos = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 2), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // }; // // let cvt = twos.fast_as_f64(); // assert_eq!(cvt, 2.0); // } // // #[test] // fn dyadic_round_trip() { // let z00 = 0.0; // let zvt00 = DyadicFloat256::new_from_f64(z00); // let b00 = zvt00.fast_as_f64(); // assert_eq!(b00, z00); // // let zvt000 = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: 0, // mantissa: u256::ZERO, // }; // let b000 = zvt000.fast_as_f64(); // assert_eq!(b000, z00); // // let z0 = 1.0; // let zvt0 = DyadicFloat256::new_from_f64(z0); // let b0 = zvt0.fast_as_f64(); // assert_eq!(b0, z0); // // let z1 = 0.5; // let zvt1 = DyadicFloat256::new_from_f64(z1); // let b1 = zvt1.fast_as_f64(); // assert_eq!(b1, z1); // // let z2 = -0.5; // let zvt2 = DyadicFloat256::new_from_f64(z2); // let b2 = zvt2.fast_as_f64(); // assert_eq!(b2, z2); // // let z3 = -532322.54324324232; // let zvt3 = DyadicFloat256::new_from_f64(z3); // let b3 = zvt3.fast_as_f64(); // assert_eq!(b3, z3); // } // // #[test] // fn dyadic_float_reciprocal() { // let ones = DyadicFloat256 { // sign: DyadicSign::Pos, // exponent: -(BITS as i16 - 1), // mantissa: u256 { // hi: 0x80000000_00000000_00000000_00000000_u128, // lo: 0x0u128, // }, // } // .reciprocal(); // // let cvt = ones.fast_as_f64(); // assert_eq!(cvt, 1.0); // // let minus_0_5 = DyadicFloat256::new_from_f64(4.).reciprocal(); // let cvt0 = minus_0_5.fast_as_f64(); // assert_eq!(cvt0, 0.25); // } // // #[test] // fn dyadic_float_from_div() { // let from_div = DyadicFloat256::from_div_f64(1.0, 4.0); // let cvt = from_div.fast_as_f64(); // assert_eq!(cvt, 0.25); // } // // #[test] // fn dyadic_float_accurate_reciprocal() { // let from_div = DyadicFloat256::accurate_reciprocal(4.0); // let cvt = from_div.fast_as_f64(); // assert_eq!(cvt, 0.25); // } // /* // #[test] // fn dyadic_float_mul_int() { // let from_div = DyadicFloat256::new_from_f64(4.0); // let m1 = from_div.mul_int64(-2); // assert_eq!(m1.fast_as_f64(), -8.0); // // let from_div = DyadicFloat256::new_from_f64(-4.0); // let m1 = from_div.mul_int64(-2); // assert_eq!(m1.fast_as_f64(), 8.0); // // let from_div = DyadicFloat256::new_from_f64(2.5); // let m1 = from_div.mul_int64(2); // assert_eq!(m1.fast_as_f64(), 5.0); // } // */ // #[test] // fn dyadic_float_round() { // let from_div = DyadicFloat256::new_from_f64(2.5); // let m1 = from_div.round_to_nearest_f64(); // assert_eq!(m1, 3.0); // // let from_div = DyadicFloat256::new_from_f64(0.5); // let m1 = from_div.round_to_nearest_f64(); // assert_eq!(m1, 1.0); // // let from_div = DyadicFloat256::new_from_f64(-0.5); // let m1 = from_div.round_to_nearest_f64(); // assert_eq!(m1, -1.0); // // let from_div = DyadicFloat256::new_from_f64(-0.351); // let m1 = from_div.round_to_nearest_f64(); // assert_eq!(m1, (-0.351f64).round()); // // let from_div = DyadicFloat256::new_from_f64(0.351); // let m1 = from_div.round_to_nearest_f64(); // assert_eq!(m1, 0.351f64.round()); // // let z00 = 25.6; // let zvt00 = DyadicFloat256::new_from_f64(z00); // let b00 = zvt00.round_to_nearest_f64(); // assert_eq!(b00, 26.); // } // /* // #[test] // fn dyadic_int_trunc() { // let from_div = DyadicFloat256::new_from_f64(-2.5); // let m1 = from_div.trunc_to_i64(); // assert_eq!(m1, -2); // // let from_div = DyadicFloat256::new_from_f64(2.5); // let m1 = from_div.trunc_to_i64(); // assert_eq!(m1, 2); // // let from_div = DyadicFloat256::new_from_f64(0.5); // let m1 = from_div.trunc_to_i64(); // assert_eq!(m1, 0); // // let from_div = DyadicFloat256::new_from_f64(-0.5); // let m1 = from_div.trunc_to_i64(); // assert_eq!(m1, 0); // // let from_div = DyadicFloat256::new_from_f64(-0.351); // let m1 = from_div.trunc_to_i64(); // assert_eq!(m1, 0); // // let from_div = DyadicFloat256::new_from_f64(0.351); // let m1 = from_div.trunc_to_i64(); // assert_eq!(m1, 0); // }*/ // } pxfm-0.1.23/src/err/erf.rs000064400000000000000000000312071046102023000133650ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::err::erf_poly::{ERF_POLY, ERF_POLY_C2}; /* double-double approximation of 2/sqrt(pi) to nearest */ const TWO_OVER_SQRT_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c71ae3a914fed80), f64::from_bits(0x3ff20dd750429b6d), ); pub(crate) struct Erf { pub(crate) result: DoubleDouble, pub(crate) err: f64, } /* for |z| < 1/8, assuming z >= 2^-61, thus no underflow can occur */ #[cold] fn cr_erf_accurate_tiny(x: f64) -> DoubleDouble { static P: [u64; 15] = [ 0x3ff20dd750429b6d, 0x3c71ae3a914fed80, 0xbfd812746b0379e7, 0x3c6ee12e49ca96ba, 0x3fbce2f21a042be2, 0xbc52871bc0a0a0d0, 0xbf9b82ce31288b51, 0x3c21003accf1355c, 0x3f7565bcd0e6a53f, 0xbf4c02db40040cc3, 0x3f1f9a326fa3cf50, 0xbeef4d25e3c73ce9, 0x3ebb9eb332b31646, 0xbe864a4bd5eca4d7, 0x3e6c0acc2502e94e, ]; let z2 = x * x; let mut h = f64::from_bits(P[21 / 2 + 4]); /* degree 21 */ for a in (12..=19).rev().step_by(2) { h = dd_fmla(h, z2, f64::from_bits(P[(a / 2 + 4) as usize])) } let mut l = 0.; for a in (8..=11).rev().step_by(2) { let mut t = DoubleDouble::from_exact_mult(h, x); t.lo = dd_fmla(l, x, t.lo); let mut k = DoubleDouble::from_exact_mult(t.hi, x); k.lo = dd_fmla(t.lo, x, k.lo); let p = DoubleDouble::from_exact_add(f64::from_bits(P[(a / 2 + 4) as usize]), k.hi); l = k.lo + p.lo; h = p.hi; } for a in (1..=7).rev().step_by(2) { let mut t = DoubleDouble::from_exact_mult(h, x); t.lo = dd_fmla(l, x, t.lo); let mut k = DoubleDouble::from_exact_mult(t.hi, x); k.lo = dd_fmla(t.lo, x, k.lo); let p = DoubleDouble::from_exact_add(f64::from_bits(P[a - 1]), k.hi); l = k.lo + p.lo + f64::from_bits(P[a]); h = p.hi; } /* multiply by z */ let p = DoubleDouble::from_exact_mult(h, x); l = dd_fmla(l, x, p.lo); DoubleDouble::new(l, p.hi) } /* Assuming 0 <= z <= 0x1.7afb48dc96626p+2, put in h+l an accurate approximation of erf(z). Assumes z >= 2^-61, thus no underflow can occur. */ #[cold] #[inline(never)] pub(crate) fn erf_accurate(x: f64) -> DoubleDouble { if x < 0.125 /* z < 1/8 */ { return cr_erf_accurate_tiny(x); } let v = (8.0 * x).floor(); let i: u32 = (8.0 * x) as u32; let z = (x - 0.0625) - 0.125 * v; /* now |z| <= 1/16 */ let p = ERF_POLY_C2[(i - 1) as usize]; let mut h = f64::from_bits(p[26]); /* degree-18 */ for a in (11..=17).rev() { h = dd_fmla(h, z, f64::from_bits(p[(8 + a) as usize])); /* degree j */ } let mut l: f64 = 0.; for a in (8..=10).rev() { let mut t = DoubleDouble::from_exact_mult(h, z); t.lo = dd_fmla(l, z, t.lo); let p = DoubleDouble::from_exact_add(f64::from_bits(p[(8 + a) as usize]), t.hi); h = p.hi; l = p.lo + t.lo; } for a in (0..=7).rev() { let mut t = DoubleDouble::from_exact_mult(h, z); t.lo = dd_fmla(l, z, t.lo); /* add p[2*j] + p[2*j+1] to th + tl: we use two_sum() instead of fast_two_sum because for example for i=3, the coefficient of degree 7 is tiny (0x1.060b78c935b8ep-13) with respect to that of degree 8 (0x1.678b51a9c4b0ap-7) */ let v = DoubleDouble::from_exact_add(f64::from_bits(p[(2 * a) as usize]), t.hi); h = v.hi; l = v.lo + t.lo + f64::from_bits(p[(2 * a + 1) as usize]); } DoubleDouble::new(l, h) } /* Assuming 0 <= z <= 5.9215871957945065, put in h+l an approximation of erf(z). Return err the maximal relative error: |(h + l)/erf(z) - 1| < err*|h+l| */ #[inline] pub(crate) fn erf_fast(x: f64) -> Erf { /* we split [0,5.9215871957945065] into intervals i/16 <= z < (i+1)/16, and for each interval, we use a minimax polynomial: * for i=0 (0 <= z < 1/16) we use a polynomial evaluated at zero, since if we evaluate in the middle 1/32, we will get bad accuracy for tiny z, and moreover z-1/32 might not be exact * for 1 <= i <= 94, we use a polynomial evaluated in the middle of the interval, namely i/16+1/32 */ if x < 0.0625 /* z < 1/16 */ { /* the following is a degree-11 minimax polynomial for erf(x) on [0,1/16] generated by Sollya, with double-double coefficients for degree 1 and 3, and double coefficients for degrees 5 to 11 (file erf0.sollya). The maximal relative error is 2^-68.935. */ let z2 = DoubleDouble::from_exact_mult(x, x); const C: [u64; 8] = [ 0x3ff20dd750429b6d, 0x3c71ae3a7862d9c4, 0xbfd812746b0379e7, 0x3c6f1a64d72722a2, 0x3fbce2f21a042b7f, 0xbf9b82ce31189904, 0x3f7565bbf8a0fe0b, 0xbf4bf9f8d2c202e4, ]; let z4 = z2.hi * z2.hi; let c9 = dd_fmla(f64::from_bits(C[7]), z2.hi, f64::from_bits(C[6])); let mut c5 = dd_fmla(f64::from_bits(C[5]), z2.hi, f64::from_bits(C[4])); c5 = dd_fmla(c9, z4, c5); /* compute c0[2] + c0[3] + z2h*c5 */ let mut t = DoubleDouble::from_exact_mult(z2.hi, c5); let mut v = DoubleDouble::from_exact_add(f64::from_bits(C[2]), t.hi); v.lo += t.lo + f64::from_bits(C[3]); /* compute c0[0] + c0[1] + (z2h + z2l)*(h + l) */ t = DoubleDouble::from_exact_mult(z2.hi, v.hi); let h_c = v.hi; t.lo += dd_fmla(z2.hi, v.lo, f64::from_bits(C[1])); v = DoubleDouble::from_exact_add(f64::from_bits(C[0]), t.hi); v.lo += dd_fmla(z2.lo, h_c, t.lo); v = DoubleDouble::quick_mult_f64(v, x); return Erf { result: v, err: f64::from_bits(0x3ba7800000000000), }; /* err < 2.48658249618372e-21, cf Analyze0() */ } let v = (16.0 * x).floor(); let i: u32 = (16.0 * x) as u32; /* i/16 <= z < (i+1)/16 */ /* For 0.0625 0 <= z <= 0x1.7afb48dc96626p+2, z - 0.03125 is exact: (1) either z - 0.03125 is in the same binade as z, then 0.03125 is an integer multiple of ulp(z), so is z - 0.03125 (2) if z - 0.03125 is in a smaller binade, both z and 0.03125 are integer multiple of the ulp() of that smaller binade. Also, subtracting 0.0625 * v is exact. */ let z = (x - 0.03125) - 0.0625 * v; /* now |z| <= 1/32 */ let c = ERF_POLY[(i - 1) as usize]; let z2 = z * z; let z4 = z2 * z2; /* the degree-10 coefficient is c[12] */ let c9 = dd_fmla(f64::from_bits(c[12]), z, f64::from_bits(c[11])); let mut c7 = dd_fmla(f64::from_bits(c[10]), z, f64::from_bits(c[9])); let c5 = dd_fmla(f64::from_bits(c[8]), z, f64::from_bits(c[7])); /* c3h, c3l <- c[5] + z*c[6] */ let mut c3 = DoubleDouble::from_exact_add(f64::from_bits(c[5]), z * f64::from_bits(c[6])); c7 = dd_fmla(c9, z2, c7); /* c3h, c3l <- c3h, c3l + c5*z2 */ let p = DoubleDouble::from_exact_add(c3.hi, c5 * z2); c3.hi = p.hi; c3.lo += p.lo; /* c3h, c3l <- c3h, c3l + c7*z4 */ let p = DoubleDouble::from_exact_add(c3.hi, c7 * z4); c3.hi = p.hi; c3.lo += p.lo; /* c2h, c2l <- c[4] + z*(c3h + c3l) */ let mut t = DoubleDouble::from_exact_mult(z, c3.hi); let mut c2 = DoubleDouble::from_exact_add(f64::from_bits(c[4]), t.hi); c2.lo += dd_fmla(z, c3.lo, t.lo); /* compute c[2] + c[3] + z*(c2h + c2l) */ t = DoubleDouble::from_exact_mult(z, c2.hi); let mut v = DoubleDouble::from_exact_add(f64::from_bits(c[2]), t.hi); v.lo += t.lo + dd_fmla(z, c2.lo, f64::from_bits(c[3])); /* compute c[0] + c[1] + z*(h + l) */ t = DoubleDouble::from_exact_mult(z, v.hi); t.lo = dd_fmla(z, v.lo, t.lo); v = DoubleDouble::from_exact_add(f64::from_bits(c[0]), t.hi); v.lo += t.lo + f64::from_bits(c[1]); Erf { result: v, err: f64::from_bits(0x3ba1100000000000), } /* err < 1.80414390200020e-21, cf analyze_p(1) (larger values of i yield smaller error bounds) */ } /// Error function /// /// Max ULP 0.5 pub fn f_erf(x: f64) -> f64 { let z = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); let mut t = z.to_bits(); let ux = t; /* erf(x) rounds to +/-1 for RNDN for |x| > 0x4017afb48dc96626 */ if ux > 0x4017afb48dc96626 // |x| > 0x4017afb48dc96626 { let os = f64::copysign(1.0, x); const MASK: u64 = 0x7ff0000000000000u64; if ux > MASK { return x + x; /* NaN */ } if ux == MASK { return os; /* +/-Inf */ } return f_fmla(-f64::from_bits(0x3c90000000000000), os, os); } /* now |x| <= 0x4017afb48dc96626 */ if z < f64::from_bits(0x3c20000000000000) { /* for x=-0 the code below returns +0 which is wrong */ if x == 0. { return x; } /* tiny x: erf(x) ~ 2/sqrt(pi) * x + O(x^3), where the ratio of the O(x^3) term to the main term is in x^2/3, thus less than 2^-123 */ let y = TWO_OVER_SQRT_PI.hi * x; /* tentative result */ /* scale x by 2^106 to get out the subnormal range */ let sx = x * f64::from_bits(0x4690000000000000); let mut p = DoubleDouble::quick_mult_f64(TWO_OVER_SQRT_PI, sx); /* now compute the residual h + l - y */ p.lo += f_fmla(-y, f64::from_bits(0x4690000000000000), p.hi); /* h-y*2^106 is exact since h and y are very close */ let res = dyad_fmla(p.lo, f64::from_bits(0x3950000000000000), y); return res; } let result = erf_fast(z); let mut u = result.result.hi.to_bits(); let mut v = result.result.lo.to_bits(); t = x.to_bits(); const SIGN_MASK: u64 = 0x8000000000000000u64; u ^= t & SIGN_MASK; v ^= t & SIGN_MASK; let left = f64::from_bits(u) + f_fmla(result.err, -f64::from_bits(u), f64::from_bits(v)); let right = f64::from_bits(u) + f_fmla(result.err, f64::from_bits(u), f64::from_bits(v)); if left == right { return left; } let a_results = erf_accurate(z); if x >= 0. { a_results.to_f64() } else { (-a_results.hi) + (-a_results.lo) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_erf() { assert_eq!(f_erf(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009456563898732), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010670589695636709); assert_eq!(f_erf(0.), 0.); assert_eq!(f_erf(1.), 0.8427007929497149); assert_eq!(f_erf(0.49866735123), 0.5193279892991808); assert_eq!(f_erf(-0.49866735123), -0.5193279892991808); } } pxfm-0.1.23/src/err/erf_poly.rs000064400000000000000000001470051046102023000144340ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #[rustfmt::skip] pub(crate) static ERF_POLY: [[u64; 13]; 94] = [ [ 0x3fbb0081148a873a, 0xbc2f0295f16ba5d8, 0x3ff1e565bca400d4, 0xbc962d0ac26c78d3, 0xbfbad8189af6013d, 0xbfd7712743c42914, 0x3faaafd4760d7634, 0x3fbba14988b4127e, 0xbf91afcdb244078a, 0xbf99d72ee25cf211, 0x3f719502f7beca8f, 0x3f73b955bfd46624, 0xbf4a4e2d4d32228b ], [ 0x3fc662a0bdf7a89f, 0xbc4ef7bc5856c2d4, 0x3ff19e5e92b964ab, 0x3c6cca4dec08a640, 0xbfc605f63767bdd6, 0xbfd6582e9b69c9a9, 0x3fb5aa32b580ec64, 0x3fb97594c2593d3e, 0xbf9c69c62749fb7f, 0xbf96fa7f611aacdc, 0x3f7bf1e628a4606e, 0x3f70e50e4329e8a9, 0xbf568ca9c1954b4c ], [ 0x3fcf190aa85540e2, 0xbc6e522ac9f718e6, 0x3ff135e3075d076b, 0xbc6e2d8ed30e4a48, 0xbfce1e4d4ce2ccfb, 0xbfd4c04e66e0d59b, 0x3fbd2855d59988e8, 0x3fb659a35f29781a, 0xbfa2cf6266a634c8, 0xbf92ef4180b1f3fa, 0x3f823199a6da60e3, 0x3f69e80d13a3368c, 0xbf5ba4e4eff641dd ], [ 0x3fd3c9aa8b84beda, 0x3c538ec27d3e5820, 0x3ff0ae54fa490723, 0xbc9d016b7bc67433, 0xbfd2c41f99922807, 0xbfd2b900b640a201, 0x3fc1c6c7eef8fa14, 0x3fb277ad7822021e, 0xbfa66c9b2023b9df, 0xbf8bf7e7b4e8559e, 0x3f853005de4b5751, 0x3f60737c6ba405f0, 0xbf606ccc916b15dc ], [ 0x3fd7e15944d9d3e4, 0xbc695f819cf77862, 0x3ff00abcf3e187a9, 0x3c85860d868dc542, 0xbfd60ec3cf561a89, 0xbfd05599bafe4ecc, 0x3fc451ef6280e70f, 0x3fac06c6e434be6f, 0xbfa8e2d73679096f, 0xbf80ea4a60550d9c, 0x3f86c911882cc99c, 0x3f48c65a9990353b, 0xbf61e8a88301a7b5 ], [ 0x3fdbccfec24855b8, 0xbc7472ab1c2b898c, 0x3fee9d5a8e4c934e, 0xbc79a002a2814a72, 0xbfd8dfd9939e37af, 0xbfcb588d8dc5bb96, 0x3fc62338788aee97, 0x3fa26cf85bc6dff9, 0xbfaa1bcaa91da902, 0xbf65b4a7d42d0f64, 0x3f86edef7de2b68d, 0xbf4037b458e2da8c, 0xbf5e8d6001a54334 ], [ 0x3fdf86faa9428f9d, 0x3c79996c0c376e32, 0x3fecfc41e36c7df9, 0xbc79be994724ea34, 0xbfdb2c7dc535b619, 0xbfc5a9de93f9c0d5, 0x3fc7317958d24aae, 0x3f9133e02ab7d777, 0xbfaa155bbde32db8, 0x3f672049c0cc8525, 0x3f85adde5c722d85, 0xbf5b0a7ec5dc80fc, 0xbf5aa9393b806535 ], [ 0x3fe1855a5fd3dd50, 0x3c88f6964e67d61a, 0x3feb3aafcc27502e, 0xbc7a9dd26edea8a2, 0xbfdcee5ac8e9c531, 0xbfbfa02983c853d1, 0x3fc77cd75ec73100, 0xbf5fa6f82f9333b7, 0xbfa8e0db5528e559, 0x3f800bf7062212bc, 0x3f83319e670adc9f, 0xbf658833e091aa36, 0xbf58f99b6e81e8f5 ], [ 0x3fe32a54cb8db67b, 0xbc696221f7e18978, 0x3fe96164fafd8de3, 0x3c70887f82841acc, 0xbfde23a7ea0d187e, 0xbfb3f5ee1564be49, 0x3fc70e469de06907, 0xbf93da6878ae6fd8, 0xbfa6a0d076468415, 0x3f88cf081f1fc304, 0x3f7f6d62866525e6, 0xbf6b93149d5701a4, 0xbf51a6c1a9f7ea73 ], [ 0x3fe4b13713ad3513, 0x3c6e944ee1b212e4, 0x3fe7791b886e7403, 0xbc6da43cb53d911c, 0xbfdecef42310f844, 0xbfa15c3c5ce705df, 0x3fc5f6890affa468, 0xbfa1da642fabd4da, 0xbfa385991202c7eb, 0x3f8fa4f37fc7c6d4, 0x3f77156b4e430998, 0xbf6f546a4377d648, 0xbf432e4e5abb1e1a ], [ 0x3fe61955607dd15d, 0x3c898ff39319ab83, 0x3fe58a445da7c74c, 0x3c808ec8e156809b, 0xbfdef6c246a12e7e, 0x3f7e83e0da030480, 0x3fc44cc65df8bfc7, 0xbfa87d3c8dd62c82, 0xbf9f9271a8a1d4e2, 0x3f9225234c1c0a0e, 0x3f6c0b0e055a0c48, 0xbf70585251f84919, 0xbf285bfb02436e0f ], [ 0x3fe762870f720c6f, 0x3c8118b1ba6da9a7, 0x3fe39ccc1b136d5a, 0x3c5faa9371c0dd80, 0xbfdea4feea4e5add, 0x3fa715e595343353, 0x3fc22cdbdb4cdd0c, 0xbfada50ae547e69e, 0xbf975578f87f217d, 0x3f9353319c65f251, 0x3f539db53a2d03d5, 0xbf6fc0364ce17870, 0x3f3272bc18b0f2ce ], [ 0x3fe88d1cd474a2e0, 0x3c86f571ada77d52, 0x3fe1b7e98fe26217, 0x3c7952bd607eb12e, 0xbfdde65a22ce0587, 0x3fb40686a3f3dc2b, 0x3fbf6b0cb6926c42, 0xbfb09c7caecd317d, 0xbf8da668f759eaea, 0x3f9364e72035e80a, 0xbf4d421975736447, 0xbf6cc98454e96141, 0x3f4a8860fdf17259 ], [ 0x3fe999d4192a5715, 0xbc8c888a5759a92c, 0x3fdfc3ee5d1524b0, 0xbc527e60faac0278, 0xbfdcc990045b293f, 0x3fbb37338e6ac814, 0x3fba0d11fe9ba61a, 0xbfb19bb2ca3816ba, 0xbf7a0b7d94791f03, 0x3f9274a59774d5e6, 0xbf664adea7b36f57, 0xbf683684bd8ef173, 0x3f538905afd229ff ], [ 0x3fea89c850b7d54d, 0xbc8e2752ebf0cd02, 0x3fdc40b0729ed548, 0xbc7c4c1c4927306d, 0xbfdb5eaaef09de9d, 0x3fc0847c7dad86af, 0x3fb47de0a4f796ca, 0xbfb1d9de8b54a3ec, 0x3f533252fb810c7c, 0x3f90ab3e329ded2f, 0xbf712d82076274ed, 0xbf6287bb4a78d728, 0x3f557d31bd574da0 ], [ 0x3feb5e62fce16095, 0x3c7bc3cff4400364, 0x3fd8eed36b886d93, 0x3c7ea7e17b96436d, 0xbfd9b64a06e4b100, 0x3fc2bb6e2c74d4fe, 0x3fadee322c062364, 0xbfb169960d5a983d, 0x3f7feab4ad0bfc14, 0x3f8c76eb94b07a5f, 0xbf7584474ae8f994, 0xbf588df75be9251f, 0x3f54edef50317090 ], [ 0x3fec194b1d49a184, 0xbc66770a58b27668, 0x3fd5d4fd33729015, 0xbc76db7d76e9e97b, 0xbfd7e0f4f0454d97, 0x3fc444bc66c35bc4, 0x3fa356dbb5432550, 0xbfb0643de6e8c574, 0x3f8b2e1f789415e4, 0x3f86ba6d9f4af32f, 0xbf78138bf4573a6a, 0xbf47e6e52a583322, 0x3f50f87322fa18a3 ], [ 0x3fecbc54b476248d, 0x3c81a5083b01ec0d, 0x3fd2f7cc3fe6f423, 0x3c79fbb4b774e85d, 0xbfd5ee8429e30a49, 0x3fc52a8395f96270, 0x3f9313759f199499, 0xbfadcf844d90282c, 0x3f91e45f25ab54a1, 0x3f8091cb68a58665, 0xbf78ea40b0ac8b7b, 0xbee6b91b1bf985f2, 0x3f5158d9c0e1c327 ], [ 0x3fed4970f9ce00d9, 0xbc756704209fca70, 0x3fd059f59af7a906, 0xbc70ce27da57f153, 0xbfd3eda354ddd5ff, 0x3fc57b85ad436067, 0x3f58e90c2a157e8d, 0xbfaa2893b28f4033, 0x3f94d6af4484a1cb, 0x3f74ccee8c8b1f57, 0xbf783304b9e2e312, 0x3f440cb679d0a832, 0x3f4d6b5f4bdef24b ], [ 0x3fedc29fb60715af, 0x3c8ab029f047a087, 0x3fcbf8e1b1ca2279, 0x3be0426e10a38000, 0xbfd1eb7095e57e16, 0x3fc549ea6f7a013f, 0xbf8b10f20d110552, 0xbfa61420b5b34a55, 0x3f9677b7ea46c6f2, 0x3f624f9940ffd840, 0xbf76304445e5f6ca, 0x3f5222fabfa75bb0, 0x3f3fdcf55be3c03e ], [ 0x3fee29e22a89d766, 0x3c8bcc9d569ed217, 0x3fc7bd5c7df3fe9c, 0x3c6488f3b06e1394, 0xbfcfe674493fde22, 0x3fc4a9feacf7e222, 0xbf9a0082c90a1b0d, 0xbfa1cf0e7655f99a, 0x3f96e3396f042620, 0xbf33a2d2cdd5650d, 0xbf7334add14b9a31, 0x3f57e12864580191, 0x3f3dae75c3e2be46 ], [ 0x3fee812fc64db369, 0x3c83c66a6a23d9a5, 0x3fc3fda6bc016994, 0x3c6586ddaff31a18, 0xbfcc1cb27861fc79, 0x3fc3b1051230b982, 0xbfa1e645a2a638ff, 0xbf9b1f643b14fd89, 0x3f964297d7a66c20, 0xbf63e365adfbccae, 0xbf6f2aa2b3ef5ec2, 0x3f5b3339ee2c8c49, 0x3f20ef5710223110 ], [ 0x3feeca6ccd709544, 0x3c6f3de8f1953470, 0x3fc0b3f52ce8c383, 0x3c6d1234b508bcfb, 0xbfc8885019f5df29, 0x3fc274275fc87eae, 0xbfa57f7386bfd263, 0xbf930769f45aaa8b, 0x3f94c8231709cfee, 0xbf70c2c99c75913f, 0xbf67514483efc090, 0x3f5c3ebcf121a533, 0x3eede2f1801b8480 ], [ 0x3fef0762fde45ee6, 0x3c89c3612a14fb77, 0x3fbbb1c972f23e50, 0x3c5ba69c564971e1, 0xbfc5341e3c0177b6, 0x3fc107929f6e7528, 0xbfa7e1b362eacfe6, 0xbf873b61e487b8a9, 0x3f92aa763e0343a9, 0xbf759a388fd2272d, 0xbf5eea3c7f50e8de, 0x3f5b5026fd87d0ca, 0xbf30f2c660125dc6 ], [ 0x3fef39bc242e43e6, 0xbc8dbae0fd9b967d, 0x3fb6c7e64e7281cb, 0x3c5aa87392dc4c20, 0xbfc2274b86833f6e, 0x3fbefb890e5b6633, 0xbfa92c7dbb880b5c, 0xbf74547708842f2b, 0x3f902047ab6c08c4, 0xbf7888355239e9ec, 0xbf50313bb85e86e1, 0x3f58ced9ddf3d834, 0xbf32d520499bd799 ], [ 0x3fef62fe80272419, 0xbc8b7c2d17fc31d3, 0x3fb297db960e4f63, 0xbc522bea9385fad9, 0xbfbecb83b087b37b, 0x3fbbce18363bbbb9, 0xbfa985aaf97891cb, 0x3f3cd95f2aa8601a, 0x3f8ab9d43270d20f, 0xbf79b93410d46789, 0xbf29b530b472cadf, 0x3f552f54de527458, 0xbf36844d43c7d693 ], [ 0x3fef848acb544e95, 0xbc8b27aa2c376c3c, 0x3fae1d4cf1e2450a, 0xbc4783e14555c1e9, 0xbfb9e12e1fde7354, 0x3fb8a27806de834f, 0xbfa91674e13a339a, 0x3f73bc75e8f9d448, 0x3f851b4d09ac47b8, 0xbf796dc7b5f9bd66, 0x3f3e16520532bde9, 0x3f50e742b323f434, 0xbf3ac319bfed91d4 ], [ 0x3fef9f9ba8d3c733, 0x3c8cd5790ff03ab3, 0x3fa83298d717210e, 0x3c4740e2b04276bf, 0xbfb58d101f909971, 0x3fb58f1456f7db5e, 0xbfa808d17b33b814, 0x3f80c1bdce673b10, 0x3f7f5ff1c06e9df2, 0xbf77f26b8865f398, 0x3f4f87060e6f6460, 0x3f48c6056bea9223, 0xbf3e3499a90b84f5 ], [ 0x3fefb54641aebbc9, 0xbc879975513f67e7, 0x3fa34ac36ad8dafe, 0x3c0902fb5363d360, 0xbfb1c8ec267fe9e2, 0x3fb2a52c5d83c050, 0xbfa68541b2c0582c, 0x3f85afe422155ad5, 0x3f756303c111cd8a, 0xbf7597ead749c06a, 0x3f557b0870a7b4cf, 0x3f3ffc0efb0ac024, 0xbf39e3ea349ab39e ], [ 0x3fefc67bcf2d7b8f, 0xbc80d2748f976e8c, 0x3f9e85c449e377f3, 0xbc3cb7ccd2616394, 0xbfad177f166cce53, 0x3fafe23b75845cdf, 0xbfa4b120f9dde895, 0x3f88d9906d138bd5, 0x3f69201b7e469e83, 0xbf72aceacb2954f0, 0x3f58d4e8140dc518, 0x3f300a33f7e93047, 0xbf372b7adfeee575 ], [ 0x3fefd40bd6d7a785, 0x3c860d45e630998f, 0x3f97f5188610ddc8, 0xbc360e8565137ecb, 0xbfa7954423f89a51, 0x3faaf5baae337ae6, 0xbfa2ad77b77d17dc, 0x3f8a7b8c4a8d53fe, 0x3f54593adc5d737a, 0xbf6ef1cf14455c9c, 0x3f5a1a04ce289b4b, 0x3f03d14f37840954, 0xbf350b861df174ee ], [ 0x3fefdea6e062d0c9, 0xbc764c70f379f670, 0x3f92a875b5ffab56, 0x3c0531231987c3b8, 0xbfa2f3178cd7aa03, 0x3fa68d1c45b96efe, 0xbfa09648dd332653, 0x3f8ad8b148089c02, 0xbf2f00fa01e6ca19, 0xbf68718785b34600, 0x3f59a7b0da775387, 0xbf2090258ede6532, 0xbf2b3980b454d442 ], [ 0x3fefe6e1742f7cf6, 0xbc8cebced8a49e04, 0x3f8cd5ec93c12432, 0xbc2bb85326a5eff3, 0xbf9e2ff3aaae31e4, 0x3fa2aa4e58242520, 0xbf9d049824fc44db, 0x3f8a34eda0fc336e, 0xbf5682d8d1801582, 0xbf6239bf51e17ea8, 0x3f57e761274bf059, 0xbf301e715d70d49f, 0xbf24d89f3d9c30d5 ], [ 0x3fefed37386190fb, 0x3c872b1549ea44ee, 0x3f861beae53b72b7, 0x3bf401790f84b248, 0xbf97d6193f2417ad, 0x3f9e947279e4a43b, 0xbf99060301092cdc, 0x3f88d14d4bdaa7f4, 0xbf61f795ac880380, 0xbf59222edb6bd145, 0x3f553f95c7b01615, 0xbf3529b07d094e1d, 0xbf15b533d0382e20 ], [ 0x3feff20e0a7ba8c2, 0xbc603f86c5a13f78, 0x3f80d1d69569b82d, 0xbc1a5e866bd1366e, 0xbf92a8ca0dc14852, 0x3f98cc071b719c43, 0xbf954a148886e917, 0x3f86e91361df3c9e, 0xbf665c02e0d08291, 0xbf4e94b0adc3b1ca, 0x3f5210781b57b089, 0xbf37b88f8c82fbff, 0xbf068df27e9a1688 ], [ 0x3feff5b8fb26f5f6, 0xbc87e917ec20b615, 0x3f79646f35a76624, 0xbc1f771f32fd191b, 0xbf8cf68ed932f081, 0x3f93e8735b5b73b1, 0xbf91e1611aabcbea, 0x3f84afd8cd100d70, 0xbf68c72005b1cfcf, 0xbf3c6a7216b336aa, 0x3f4d577412afc2e2, 0xbf3836a0c0e10a99, 0x3eca8f39f410252a ], [ 0x3feff87b1913e853, 0xbc73ca98afc58454, 0x3f730499b503957f, 0xbbfd1eabb1c04f50, 0xbf86496420203331, 0x3f8fa73d7eb1b70d, 0xbf8daa3005c2d3fe, 0x3f8250942c31c3ad, 0xbf6997578dc240a8, 0xbf03904177639e63, 0x3f46a6ed488a1f54, 0xbf371cf0c5789c7d, 0x3f043cb84231ab1c ], [ 0x3feffa89fe5b3625, 0x3c8934b2bcb7f9a3, 0x3f6c4412bf4b8f0b, 0xbbcbbcc9dca4ec60, 0xbf8100f34713740d, 0x3f88ebda0768e8e6, 0xbf8850c68e8e5c3c, 0x3f7fdac8346071b3, 0xbf6929de70d00321, 0x3f310c7101bc52d8, 0x3f4070f7e89ec1e2, 0xbf34e4b3dcf4f08d, 0x3f0f0d43b9869b19 ], [ 0x3feffc10194fcb64, 0x3c8ea14750ac9b59, 0x3f64d78bba8ca5fd, 0x3be4d9a93566b5b4, 0xbf79ba107a459ce4, 0x3f836f273fbd909b, 0xbf83b38708f7bef7, 0x3f7b3fdff1de2112, 0xbf67d55d55d262d8, 0x3f3eae5e05e74fcc, 0x3f35ebc1e53214a9, 0xbf31fd7c1cd5d63e, 0x3f149559a04c8568 ], [ 0x3feffd2eae369a07, 0xbc683b09df7f7db4, 0x3f5e7f232d9e2630, 0x3bfa26ac725599e5, 0xbf734c7442de142b, 0x3f7e066bed09942f, 0xbf7f914f2c60b9bb, 0x3f76f4662f6be13b, 0xbf65e664591d6604, 0x3f43a1598d880f36, 0x3f2965b2e78a4544, 0xbf2d8db42b193729, 0x3f1449172919598e ], [ 0x3feffdff92db56e5, 0xbc78aeef4ee0690a, 0x3f56235fbd7a4345, 0xbbe11380fe434056, 0xbf6cb5e029ba8f3d, 0x3f76fa4c7ef470e9, 0xbf7903a08305eeb0, 0x3f730f12c83fdb23, 0xbf639d769a774af1, 0x3f45d79439ceaefd, 0x3f15326883e7dfeb, 0xbf27199782285958, 0x3f147181c8911603 ], [ 0x3feffe96a78a04a9, 0xbc82816fe4528f9b, 0x3f4fe41cd9bb4eee, 0x3bde3be508cae7ec, 0xbf652d7b2896626a, 0x3f716c192d8803dc, 0xbf739bfce9b4ecc2, 0x3f6f376a554e5dec, 0xbf612e67cb7aa486, 0x3f466d6e460b1614, 0xbed54f70e4bde32b, 0xbf210e125571fe1e, 0x3f12842d46eb9f29 ], [ 0x3fefff0312b010b5, 0x3c8155dec9cdc96b, 0x3f46caa0d3582fe9, 0xbbc97d95851163fc, 0xbf5efb729f4be121, 0x3f6a2da7cec01564, 0xbf6e6c27ad2b1ce0, 0x3f693b1f34b17723, 0xbf5d8179cd2ad34f, 0x3f45cf51e0add9bb, 0xbf116d8f4b5119c7, 0xbf1768557564f5f5, 0x3f0f4fc9dde73f24 ], [ 0x3fefff50456dab8c, 0xbc5a197a986f0de0, 0x3f40295ef6591848, 0xbbd262bd83520706, 0xbf5679880e93e5c4, 0x3f637d38e3a705af, 0xbf675b371a264745, 0x3f64231c3bfe3e65, 0xbf58e184d4921105, 0x3f445d5b5a7f77fa, 0xbf1bf8ece4afedd2, 0xbf0ccd677aaa82f7, 0x3f09e5241d5b6b15 ], [ 0x3fefff86cfd3e657, 0xbc72e06adb26f84e, 0x3f36be02102b3520, 0x3bb448bcfd3cfe0c, 0xbf502b15777eb7c5, 0x3f5cc1d886874d5b, 0xbf61bff70664651d, 0x3f5fc0f76c943696, 0xbf54a22286622d3e, 0x3f4268887688a6e6, 0xbf20fa2692fd7da2, 0xbefcc13d1a82f742, 0x3f04153e6537aae5 ], [ 0x3fefffad0b901755, 0x3c670d5c9a92b65c, 0x3f2fc0d55470cf51, 0xbbc6f2b03553d4c8, 0xbf47121aff59f6a1, 0x3f5506d6992fc8ff, 0xbf5ab596015fc183, 0x3f58bdd79a098723, 0xbf50d88da9deb868, 0x3f4031cdd07e4507, 0xbf222fc41430a37d, 0xbedb5cc9546afcec, 0x3efd7ea1c7b8fdb6 ], [ 0x3fefffc7a37857d2, 0xbc797b30fd4b6b48, 0x3f25feada379d8b7, 0xbbc0546c4da57036, 0xbf405304df546ed8, 0x3f4e79c081b79ebc, 0xbf53e5dc1062db15, 0x3f530eb20ccc1f98, 0xbf4b1b06c20a060d, 0x3f3bd52fbd55e0ef, 0xbf2214afb8835b23, 0x3ee19ae9d16650a0, 0x3ef42d933ee154fd ], [ 0x3fefffd9fdeabcce, 0x3c80c43c3bc59762, 0x3f1e3bcf436a1a95, 0xbba6458a28a3f9b6, 0xbf36e95311166825, 0x3f45e3edf674e2db, 0xbf4d5be6d15abe3a, 0x3f4d07da13e640c2, 0xbf458106cc648748, 0x3f376c840985e5eb, 0xbf2111de112b1a2e, 0x3ef315fc34053fbd, 0x3ee939439a75a553 ], [ 0x3fefffe68f4fa777, 0x3c32f21786b76440, 0x3f149e17724f4d41, 0x3ba747684f0023e4, 0xbf2fe48c44d2ab81, 0x3f3f2bd95d72a532, 0xbf457389188a71a9, 0x3f45decc4058f7a1, 0xbf40d559cf0f2957, 0x3f33583904af6f83, 0xbf1efd7979333337, 0x3ef904cf9fa5c1f6, 0x3eda13a094bd56a2 ], [ 0x3fefffef1960d85d, 0xbc8f7cc78053f6ad, 0x3f0be6abbb10a5aa, 0xbb9e50b219d40126, 0xbf260403819b22b8, 0x3f35fff1dde5305e, 0xbf3f0c93c73e7f42, 0x3f404cbf67af6c26, 0xbf3a04893510426c, 0x3f2f66b51a7bc4a0, 0xbf1b410d7f2fd319, 0x3efb99f9eb427956, 0x3ebf26fcffb14441 ], [ 0x3feffff4db27f146, 0x3c8ddecdd5e1d408, 0x3f02bb5cc22e5db6, 0x3b9c5112eca8acde, 0xbf1e258948829ed1, 0x3f2ec8a8e59d9d5b, 0xbf36425722b9f3cd, 0x3f380a83a7103b4b, 0xbf33dbb9374004f9, 0x3f2913b301d37bde, 0xbf17563b0d94459f, 0x3efbc01eea9a10be, 0xbeb3df26463df6a5 ], [ 0x3feffff8b500e77c, 0xbc71014e1f83ed4c, 0x3ef8f4ccca7fc90d, 0x3b9a5d4ec8b9de43, 0xbf1478cffe1cd2ed, 0x3f2559f04ad4de62, 0xbf2f9e163b15c466, 0x3f318bda8b8c1315, 0xbf2df381bd3c058e, 0x3f23b94f531bb6be, 0xbf1385f32481ed94, 0x3efa414bd2b7cb3c, 0xbecac2bbe30f8767 ], [ 0x3feffffb43555b5f, 0x3c8c17f83b8d73a2, 0x3ef07ebd2a2d2844, 0x3b9d1bbdc704f49b, 0xbf0b93e442837f52, 0x3f1d5cf1514977f3, 0xbf263f5eb46877fd, 0x3f295a0411e668b1, 0xbf2652e5f2a88269, 0x3f1e950ddb7f5444, 0xbf0ffeb9383bdb3d, 0x3ef7c24392346fdd, 0xbed1f3b3254d7230 ], [ 0x3feffffcf23ff5fc, 0xbc8b18a8b25039c4, 0x3ee5a2adfa0b4bc4, 0x3b8eb6d61aaaf95c, 0xbf026c8826ed9e85, 0x3f140473571d5383, 0xbf1f057dbf365c0a, 0x3f22217929fed933, 0xbf207324014ddb42, 0x3f1762758a56d654, 0xbf09ba250c662e90, 0x3ef4c25759179e3d, 0xbed3e800358f1a7b ], [ 0x3feffffe0bd3e852, 0xbc5d7ece4ab53150, 0x3edc282cd3957eda, 0x3b6eb3cf4fd14280, 0xbef86ad6df7ba401, 0x3f0b0f313eeb65a6, 0xbf156e457745d637, 0x3f19ad1f65a78253, 0xbf17f92ad8542929, 0x3f11a5578c0d30b3, 0xbf04548d876bb0a3, 0x3ef19e60bf53b25a, 0xbed3f1745170e2d3 ], [ 0x3feffffec2641a9e, 0xbc8e7ba4fdaaa8c8, 0x3ed22df298214423, 0xbb5a9d49552152a4, 0xbef00c902a4d5e27, 0x3f022234eb745941, 0xbf0d57a2be01db67, 0x3f1200c2ffad65f1, 0xbf1147585d43f49a, 0x3f0a4b07aec797e9, 0xbeff9d088bbeff64, 0x3eed2b2be4e42422, 0xbed2bb57c0cf2941 ], [ 0x3fefffff37d63a36, 0xbc6753e3241c01b0, 0x3ec74adc8f4064d3, 0x3b6de8a904d5c372, 0xbee4ed4228b3da96, 0x3ef81918baca1979, 0xbf03e81c09c29601, 0x3f09004afed1bde9, 0xbf08a40e183ee3fc, 0x3f0359242a8b8c58, 0xbef834b953bcb845, 0x3ee79e345fb0b20d, 0xbed0bb2d323900ce ], [ 0x3fefffff82cdcf1b, 0x3c8046bbe9897fd5, 0x3ebd9c73698fb1dc, 0x3b588de36481dfb5, 0xbedb11017e7d5893, 0x3eefc0dfadc2c6d6, 0xbefac4e1aa499ac6, 0x3f0131810ab2e2e3, 0xbf01629d94abc864, 0x3efc22a71036c259, 0xbef244452f74de31, 0x3ee2bf17664310c1, 0xbeccd1b31a8349be ], [ 0x3fefffffb248c39d, 0x3c89b9a41713558c, 0x3eb2acee2f5ecdb8, 0xbb32d1692a9a105c, 0xbed15cc5700a2341, 0x3ee4be757b934819, 0xbef1d6ab6f8cbf7c, 0x3ef76c5a3035bdab, 0xbef847332578dfac, 0x3ef437f23f8d25ff, 0xbeeb305e625a092d, 0x3edd3886ff986fef, 0xbec81f2189b385a2 ], [ 0x3fefffffd01f36af, 0xbc8d41915db812ef, 0x3ea75fa8dbc84bec, 0x3b3a5cd79572a1a6, 0xbec6186d9fc357c5, 0x3edae02322e08822, 0xbee79082befd50ca, 0x3eef9c26e211b174, 0xbef0c768235c378b, 0x3eecba7164e1064f, 0xbee3f75c28c31ac8, 0x3ed663fcfff77e44, 0xbec3a6da35f36ee6 ], [ 0x3fefffffe2ba0ea5, 0xbc826cd7908cba2b, 0x3e9d06ad6ecdf971, 0xbb3020b74d9d30fb, 0xbebbe46aa879edb2, 0x3ed143860c49d129, 0xbededabcbc3e620d, 0x3ee52139c87e9c82, 0xbee6f567cd982028, 0x3ee42ebd266abd62, 0xbedcf2f0c6adfb3e, 0x3ed0e2c0ed67786c, 0xbebf50cb81b9b190 ], [ 0x3fefffffee3cc32c, 0x3c7e429188c949b8, 0x3e91e1e857adc568, 0x3b32439f8a1649bb, 0xbeb1769ce59fb2c8, 0x3ec5fe5d47560794, 0xbed405da04875e51, 0x3edbfc96a938083d, 0xbedf19ff5e59cbe9, 0x3edc0c4d50d275bf, 0xbed4b9df120462ae, 0x3ec916640ee35de4, 0xbeb874483d99c37e ], [ 0x3feffffff54dab72, 0xbc8a443df643729a, 0x3e85dcd669f2cd34, 0xbb1ceb1ec59e0c28, 0xbea5b11cbd1ee799, 0x3ebbc91a6b1c1839, 0xbec9c2c5d12dfa2c, 0x3ed25d1e3c70364f, 0xbed4dbe26c88e4f7, 0x3ed347bb8350b422, 0xbecd51d3280da8a0, 0x3ec25ed8e5b466b5, 0xbeb2b9c5d3390919 ], [ 0x3feffffff99b79d2, 0xbc758ff1c425f8de, 0x3e7a854ea14102a9, 0xbb121745e4b4fcb3, 0xbe9aba593e8384ae, 0x3eb167c252a45678, 0xbec06d78ca0424a3, 0x3ec7e0f59fcfa53d, 0xbecbb4d48383b847, 0x3eca39f3ad9a397f, 0xbec47e836879c374, 0x3eba89244d14b829, 0xbeac33e15a6dbe37 ], [ 0x3feffffffc355dfd, 0x3c688cb60fd4511c, 0x3e6febc107d5efab, 0xbaed9ed10902067c, 0xbe9055a3c70279a4, 0x3ea59ff37766e9a7, 0xbeb4c53adb9dcc4d, 0x3ebec49242997849, 0xbec23927ad6ac54f, 0x3ec1a6e0676c7463, 0xbebc5239f6a88a96, 0x3eb2e991308bf6fa, 0xbea4e276c09fe81b ], [ 0x3feffffffdc4ad7a, 0xbc8d75de787812d4, 0x3e630f93c3699079, 0xbaf8f941ab38e9da, 0xbe83ce2f890bb01d, 0x3e9aa5010863c83b, 0xbeaa08ef1ca16360, 0x3eb3a4a6af3cafac, 0xbeb7be1e832218f0, 0x3eb784775c30c386, 0xbeb3593046482ce3, 0x3eaa9d448178fbfd, 0xbe9e77bb85451c65 ], [ 0x3feffffffeb24467, 0x3c8bff89ef33d6dd, 0x3e56961b8d641d07, 0xbaf74a7fc97b1544, 0xbe77d2510f1f969d, 0x3e90476b165ac852, 0xbea02d3a3b9d195e, 0x3ea8db3567bef1df, 0xbeaea3ef4e3a126b, 0x3eaf03b0861a59ac, 0xbeaa250ca467705a, 0x3ea27e9995f6dfcd, 0xbe95e77b673c6d74 ], [ 0x3fefffffff3e8892, 0x3c5befbf8d294678, 0x3e4a8e405e651ab7, 0x3ab167a2d8cf6b18, 0xbe6c6c40e5083698, 0x3e83ba47a17512fd, 0xbe93ee334beef6ec, 0x3e9f2bf9e6c43e99, 0xbea395c08ac8e281, 0x3ea43ee4b521ccad, 0xbea178f0deeb9b20, 0x3e9964e51b0f0532, 0xbe8f0cc4ecca5c2f ], [ 0x3fefffffff90b2e3, 0xbc7d82d94a90f1e4, 0x3e3efac5187b2864, 0x3acf1301ae680614, 0xbe60d229044adeee, 0x3e77b5bc9db47d00, 0xbe88588212e670c2, 0x3e935f42db1989fa, 0xbe98cd98865c4ff0, 0x3e9a2b8587c48078, 0xbe971aa2de99af9c, 0x3e913a89805c15d9, 0xbe85b53ca1bcf01a ], [ 0x3fefffffffc0748f, 0x3c66ef7a9caef280, 0x3e31edfa3c5f5ccb, 0x3ac368f60e2e6cfa, 0xbe53c025a6810c37, 0x3e6c42f78a0989ad, 0xbe7d7c6c3583c6e3, 0x3e87dd6ccb5c93b4, 0xbe8f1ec2f699fdcc, 0x3e90bf7a04407a8c, 0xbe8e3aafe6dfd4e0, 0x3e871bc3a55b63f4, 0xbe7df66b11724e7c ], [ 0x3fefffffffdbff2a, 0x3c749438981099b2, 0x3e24979ac8b28928, 0xbacc2f44bcf3ce52, 0xbe47015eec37753a, 0x3e60b487791590cf, 0xbe71b44b64c3c995, 0x3e7d23ff3ef8dd83, 0xbe8357d673d1ccfc, 0x3e853a563ce0e9e3, 0xbe83921106a960f6, 0x3e7ea527d318f96e, 0xbe746bd6cea7103d ], [ 0x3fefffffffebc1a9, 0x3c7e0e5facabfab4, 0x3e177756ec9f78fb, 0x3aae20366d0e0306, 0xbe3a9530780ca70c, 0x3e53962ecb10df65, 0xbe651494525dee64, 0x3e71a2961b90efb0, 0xbe77d35cd0b404bf, 0x3e7aa596d9d73afb, 0xbe791493d8d43ba2, 0x3e74184505343c2d, 0xbe6b7d977f1a3402 ], [ 0x3feffffffff4b453, 0x3c859b25048a61cc, 0x3e0a887bd2b4404f, 0xba82556d8ad4dd44, 0xbe2e78be33fb01da, 0x3e46c6ef0b68629e, 0xbe58e36e9a44c497, 0x3e65286ee37c531e, 0xbe6d146395886537, 0x3e7090902855d5f0, 0xbe6fd0d1e8fcb6df, 0x3e6a10f65c3c5a7b, 0xbe624888c323daf3 ], [ 0x3feffffffff9bec8, 0xbc76755054654b62, 0x3dfdc479de0ef004, 0xba9c3434581af3b8, 0xbe21535aee3eb1b2, 0x3e3a4547ed264758, 0xbe4d2308d0dead0f, 0x3e5929d46a9a7edc, 0xbe6195dbfd4afd19, 0x3e646630f49ccd2f, 0xbe63fa4637c64ebc, 0x3e60b98a6e0cfc02, 0xbe58093f032972f3 ], [ 0x3feffffffffc901c, 0x3c69c951c943961c, 0x3df0916f04b6e18d, 0x3a81bdf9650721ea, 0xbe138b90f78fbe14, 0x3e2e0d7765326885, 0xbe40e9760d0ac127, 0x3e4daad91166722d, 0xbe5513c51b9838ed, 0x3e58e27fb85ba534, 0xbe58d6f6bd99eaff, 0x3e553c31e52fff08, 0xbe4f3bfd31796bc0 ], [ 0x3feffffffffe202d, 0x3c8a54841f566a61, 0x3de24caf2c32af16, 0x3a802e3358112fa1, 0xbe05dfa962d49548, 0x3e210ca1ff2af812, 0xbe3377c7e98dd9b4, 0x3e4156649e0b5dd2, 0xbe49092f4db426c5, 0x3e4e12a29b227972, 0xbe4e94e18d5271a9, 0x3e4aae38927ee69b, 0xbe441121b0293be1 ], [ 0x3feffffffffefc57, 0xbc68225a9658ef84, 0x3dd40dfd87456f4f, 0xba7a6d5c55f8e63b, 0xbdf848f101ce14c8, 0x3e132fed47f8dd28, 0xbe2638ff4a6975f2, 0x3e3416d25168a6b8, 0xbe3d78fb22f58668, 0x3e42009c6b4e61ea, 0xbe42a459e59c850b, 0x3e4096a3e8dac0ea, 0xbe397fba69de37d8 ], [ 0x3fefffffffff748e, 0x3c6ae15e36044aac, 0x3dc5ce9ab1670dd6, 0x3a4cc9bbfb723fc4, 0xbdeabf69bd9866f7, 0x3e056ae1e8abbbbf, 0xbe1927ca04d1a7a8, 0x3e2713d3b07d7a36, 0xbe31318f5d7d717b, 0x3e355ab94fdfd1f4, 0xbe368216fb90717a, 0x3e346ad5ce577d65, 0xbe30065a20073e81 ], [ 0x3fefffffffffb5b0, 0xbc850fb19119064f, 0x3db7872d9fa10ab2, 0xba57760afdf543a4, 0xbddd39eaac4a0b47, 0x3df7b67ab8af33d6, 0xbe0c3ced54e694ea, 0x3e1a4875d8a47f12, 0xbe23e213e6f5c296, 0x3e2919137301f897, 0xbe2aea6bd9b34930, 0x3e28e06e4ab5925f, 0xbe23ed1d979421b2 ], [ 0x3fefffffffffd8b3, 0xbc65182469c211e0, 0x3da92ff33023d5c3, 0xba42932180032bd1, 0xbdcfae4fe28d12dd, 0x3dea0a80964d6e97, 0xbdff6f47be478e2a, 0x3e0dad968cdacb13, 0xbe16ca68a8bfdb81, 0x3e1d3a79e5305b4a, 0xbe1fe1534ebf69c7, 0x3e1e01ee76d92779, 0xbe1883ed9069f3fd ], [ 0x3fefffffffffeb60, 0xbc74d3f53e684bf8, 0x3d9ac0f5f322937a, 0xba38e8ab19224e58, 0xbdc108dc99cf03e5, 0x3ddc5db17016a0c6, 0xbdf159f41ea079c3, 0x3e009ced3e9b7204, 0xbe09e4dace066800, 0x3e10dd5e0e9749b6, 0xbe12b3aa6599d0b5, 0x3e11eb5e8e4ffe8f, 0xbe0dd8955967ed31 ], [ 0x3feffffffffff542, 0x3c6b57ed63ed8110, 0x3d8c324c20e337e5, 0x3a253fd8abf42ed9, 0xbdb22c6b11327305, 0x3dcea5f66f89cbd4, 0xbde2ff1e0a81bedc, 0x3df270ddbd8e501f, 0xbdfd2992b5c25c93, 0x3e03492d76bdf266, 0xbe05bc7361853dde, 0x3e053121ae3f1d2e, 0xbe01fb0f7e3f242b ], [ 0x3feffffffffffa73, 0xbc76fead614b7934, 0x3d7d7c593130dd16, 0xba08e78574fe0514, 0xbda33c1e2f16e037, 0x3dc06c53fdc74764, 0xbdd4a029a87915ac, 0x3de44bd86238ff0d, 0xbdf0474ac3a80072, 0x3df5db2a89e9bc47, 0xbdf906f4b51a7f75, 0x3df8d189784c1f50, 0xbdf571a4760f483d ], [ 0x3feffffffffffd27, 0x3c719e1a84064c56, 0x3d6e9810295890f9, 0x3a0f998d55766fdb, 0xbd943262ab4b77b2, 0x3db1756eae580a28, 0xbdc6359d5b0d251e, 0x3dd626391bd58994, 0xbde203efc6c9f556, 0x3de88c0b111be900, 0xbdec8ca211a38811, 0x3decc911f684d612, 0xbde950e3edf09a71 ], [ 0x3feffffffffffe8d, 0x3c5e766e2c801398, 0x3d5f7f338086a87b, 0xb9ddfa0c27b527e0, 0xbd8509f766d9f287, 0x3da268e278ede221, 0xbdb7b7b43e9a1b0e, 0x3dc7f7aadab6b398, 0xbdd3c3cc6aafba0b, 0x3ddb52c69b4ab6de, 0xbde0222c438d1182, 0x3de0888e14314f83, 0xbddd96aaea63b362 ], [ 0x3fefffffffffff45, 0xbc85948eec884df5, 0x3d501647ba79874e, 0x3986d5d39dabc300, 0xbd75be1cf20840dc, 0x3d93418096320daf, 0xbda91e9beb94b447, 0x3db9b762261756a7, 0xbdc57f320a630c91, 0x3dce24b78ce82b11, 0xbdd2112fff5c77aa, 0x3dd2cfdd93a41786, 0xbdd11ea1f35b4d2b ], [ 0x3fefffffffffffa2, 0x3c6d07509a1a9440, 0x3d404e15ecc7f401, 0xb9d0858e34f7a6a6, 0xbd664ac1f9b95f96, 0x3d83fa8302ade993, 0xbd9a62b70897719e, 0x3dab5c619266e9f0, 0xbdb72de32129cbb8, 0x3dc07ae94305c398, 0xbdc40c45a9e95152, 0x3dc533d127efdf16, 0xbdc39dc242ba4cda ], [ 0x3fefffffffffffd1, 0x3c83b6fc0b729759, 0x3d3065b9616170e1, 0xb9c49459f5147526, 0xbd56acaa58a8be12, 0x3d748fb92d0947e7, 0xbd8b7ce1a1ea8ea5, 0x3d9cddc552bbebeb, 0xbda8c751cc1a5784, 0x3db1dc79b52007b0, 0xbdb60b3d17e7714c, 0x3db7ac1d379afc28, 0xbdb641ca84798564 ], [ 0x3fefffffffffffe9, 0xbc55fe91226dd510, 0x3d205ca50205d279, 0xb9c7a281f9edb8e6, 0xbd46e18ec0d42451, 0x3d64fdb051100a15, 0xbd7c66b3f3fe565e, 0x3d8e331281475b54, 0xbd9a42e6965b2b9a, 0x3da3301ef4931960, 0xbda804fcc1524d74, 0x3daa2ef0c13a3daa, 0xbda9028a915f98d3 ], [ 0x3feffffffffffff5, 0xbc8238f8ed17d9b3, 0x3d10330f0fd69931, 0x39ba2c00e0c6dcba, 0xbd36e8334c65749d, 0x3d5541d561058477, 0xbd6d1ac042ada69e, 0x3d7f54864c5a530e, 0xbd8b984c73c1d301, 0x3d946ec7009c291f, 0xbd99efc2df737760, 0x3d9cb12ac38f37ca, 0xbd9bd54fcd67b8d4 ], [ 0x3feffffffffffffb, 0xbc8efa4d64f59f62, 0x3cffd3de10d6287a, 0xb99e1fdae91c5cfe, 0xbd26c073be0916e6, 0x3d455a8eab9e129a, 0xbd5d94c87c1bc304, 0x3d701db0818bec24, 0xbd7cbfbe4c0ef6ee, 0x3d859179d8c519c4, 0xbd8bc172710440bd, 0x3d8f26a4f726814e, 0xbd8ead889e052555 ], [ 0x3feffffffffffffd, 0x3c86be96953fe014, 0x3cef05e82aae2be2, 0xb98070a8237b4337, 0xbd166b44c6d7ddb6, 0x3d35474bd9d072f3, 0xbd4dd1e8c33100cc, 0x3d60711486984913, 0xbd6db2522b66a6ce, 0x3d76919a06329739, 0xbd7d6fe8f87926e8, 0x3d80c1488010ff5c, 0xbd80bf9fa407e9ab ], [ 0x3fefffffffffffff, 0xbc80fecc5ed770de, 0x3cde00e9148a1d52, 0x394f7a503c7a2ad8, 0xbd05eaaa4200e355, 0x3d25088b6566fced, 0xbd3dd0b48e0f634e, 0x3d50a27116d7478e, 0xbd5e6a3e1d5c214f, 0x3d6769249755a4bc, 0xbd6ef16049050b69, 0x3d71dbf2744f66db, 0xbd721c636bd8f5a9 ], [ 0x3fefffffffffffff, 0x3c8989c6c5d51227, 0x3ccccaaea71ab110, 0x394152f323a1f3b4, 0xbcf541a2f15eb476, 0x3d149fd53e85cdf3, 0xbd2d9144beee6b4a, 0x3d40b09b02f533a1, 0xbd4ee312fcf48076, 0x3d5812ed2f01f60a, 0xbd601e6391f47ad7, 0x3d62dce8f6b8c896, 0xbd6365d5011db0df ], ]; #[rustfmt::skip] pub(crate) static ERF_POLY_C2: [[u64; 27]; 47] = [ [ 0x3fcac45e37fe2526, 0x3c648d48536c61e3, 0x3ff16e2d7093cd8c, 0x3c9979a52f906b4d, 0xbfca254428ddb453, 0x3c69c98838a77aea, 0xbfd59b3da8e1e176, 0xbc41f650c25d97b0, 0x3fb988648fe88219, 0xbc55aecf0c7bb6c1, 0x3fb803427310d199, 0xbc5a14576e703eb2, 0xbfa09e7bce5592c9, 0x3c3eb7c7f3e76998, 0xbf9516b205318414, 0xbc2941aa998b1fa4, 0x3f8038d3f3a16b57, 0x3f6e19d52695ad59, 0xbf59542e7ed01428, 0xbf41f9b6e46418dc, 0x3f30796a08a400f4, 0x3f12610d97c70323, 0xbf025d31d73f96d1, 0xbee05e1fa9e02f11, 0x3ed1e616f979139c, 0x3ea9b3d54f1f222a, 0xbe97ad96beea439a ], [ 0x3fd5da9f415ff23f, 0xbc4a72e51e191950, 0x3ff05fd3ecbec298, 0xbc9f17d49717adf8, 0xbfd477c8e7ee733d, 0xbc792236432236b7, 0xbfd1917b60acab73, 0x3c7c06e6c21b4b3b, 0x3fc322a728d4ed12, 0x3c3ffa8aef321410, 0x3fb04c50a9cd2c12, 0xbc4edd0562dce396, 0xbfa7ce764eeddd86, 0x3c29afeb391c029c, 0xbf868aac5801171d, 0x3c24f9655411fc03, 0x3f862aa895f51cd3, 0x3f56c003c3cedb10, 0xbf6079502dbbafff, 0xbf1d9c7cbb799b47, 0x3f345a995aede3f4, 0x3eb0c04ea8c98fc9, 0xbf057edfa53128d0, 0x3eba96286bf3ef56, 0x3ed3c8ab12e6d24b, 0xbe97454eba0cb203, 0xbe8f02a6f6847617 ], [ 0x3fddb081ce6e2a48, 0xbc77ff0a3296d9cb, 0x3fedd167c4cf9d2a, 0x3c844f2832f90a97, 0xbfda173acc35a985, 0xbc3c5432c9a22740, 0xbfc889a80f4ad955, 0xbc6f6123bf467942, 0x3fc6c2eea0d17b39, 0xbc61f4935c3cf5b1, 0x3f9b0645438e5d17, 0x3c37a5f08ebaf9d0, 0xbfaa3fd9fcbb6d6d, 0x3c494a1b58b5916f, 0x3f2060b78c935b8e, 0x3bb9cec375875a1c, 0x3f8678b51a9c4b0a, 0xbf51e03bfc8eebb4, 0xbf5e653535cab33f, 0x3f355f31366d2c5c, 0x3f30dcf1445cbb88, 0xbf1098913ad4dcc7, 0xbeff6e252329eeed, 0x3ee41ad0a5afe51d, 0x3ec8fd4609222f1c, 0xbeb4465926de1a35, 0xbea407a1f42b46d4 ], [ 0x3fe25b8a88b6dd7f, 0x3c89534a3b5bd215, 0x3fea5074e2157620, 0x3c7fad8c0ef6fae6, 0xbfdd9a837e5824e4, 0xbc71d19ec86adc7c, 0xbfb9c41d1d5fae55, 0x3c374c230d6afba4, 0x3fc75bebc1b18d1c, 0x3c501ece95d4dffc, 0xbf86410ad9332666, 0xbc216523d167a40c, 0xbfa7df8890b11fa7, 0x3c4d6a99d1387564, 0x3f84a54816d3608a, 0xbc2f810ad06699cc, 0x3f818f36eb18f3d7, 0xbf68d661c030e174, 0xbf53628ede23e249, 0x3f4438eb2b3c4d27, 0x3f1fd3c13e725e91, 0xbf1991b866a32c87, 0xbee1237c600dab6f, 0x3eea9c701140d4c0, 0x3e71801e61adfdda, 0xbeb785516863e6ce, 0xbe83e033ef590125 ], [ 0x3fe569243d2b3a9b, 0x3c78eef7012e8df4, 0x3fe681ff24b4ab04, 0xbc5dba6493354c70, 0xbfdef2bed2786b25, 0xbc7ae3f6b6b2b679, 0xbf8a4254557d722f, 0xbc20ff7bffd10053, 0x3fc532415c267962, 0x3c62eacc4bd2e841, 0xbfa558b4c55a835c, 0x3c3c21c40815d70a, 0xbfa1b7ad5b777f1b, 0xbc42115b2bd8d644, 0x3f91201d3bd0e758, 0xbc0b39b845442560, 0x3f72995e3a88a890, 0xbf70294c3e93cdb0, 0xbf3159644a564f83, 0x3f463daf9b3858ef, 0xbf03beeb4a1255ac, 0xbf180c5178c36c72, 0x3eed4f6f5bab7dfa, 0x3ee521deb6d2f46e, 0xbec4ef3208231a8b, 0xbeae7d2b4e06e4a2, 0x3e921536d5b8bdf9 ], [ 0x3fe7fb9bfaed8078, 0x3c766cf14bcad032, 0x3fe2a8dcede3673b, 0xbc77378e2c70325e, 0xbfde5267029187c0, 0x3c7add23841b110a, 0x3fafe0796bb9d05a, 0xbc37a992e13ce574, 0x3fc0fa23021ad0ac, 0xbc417f4228359928, 0xbfafa21ebca76761, 0x3c3278ca2820f66c, 0xbf931546d5c4edb4, 0x3c136fcf151892a0, 0x3f937e5469efb7a6, 0xbc39553630321d4f, 0x3f2097966e2e87ea, 0xbf6e82ab020887a7, 0x3f4318270c11ae74, 0x3f412652e433da97, 0xbf24dc9bd6368bb8, 0xbf0c441138d4ff53, 0x3efc91d8dc5b66ec, 0x3ecf3ba57b86d474, 0xbecdd3403d11a818, 0xbe731f497a106a7c, 0x3e9436dbcc93d342 ], [ 0x3fea1551a16aaeaf, 0x3c6a558a46df5f68, 0x3fddfca26f5bbf88, 0xbc6ddcbaf85587b6, 0xbfdc1cd84866038f, 0xbc7200885b97f453, 0x3fbe4c9975da0987, 0xbc5f162e7576c79c, 0x3fb747e31bf47af3, 0xbc56178f12d62ed9, 0xbfb1d1f00109e42a, 0x3c5002b06e023544, 0xbf647654175ceb42, 0x3bd683389ccacfa8, 0x3f91a817c594b8cb, 0x3c336ac477166efb, 0xbf6cb8acd699cca6, 0xbf657b72bf874db6, 0x3f524493dca8b6fa, 0x3f2f556774c6aaf6, 0xbf2b09ec5c8ba626, 0xbed09bd1a09f38e8, 0x3efd149c3e776976, 0xbec8f7c2a6575e92, 0xbec8391d4afaf16a, 0x3ea5a7552081d1d5, 0x3e932d1bb2d1d0ca ], [ 0x3febbef0fbde6221, 0xbc8322c1148e0d48, 0x3fd75a91a7f4d2ed, 0x3c56eb826a9df85c, 0xbfd8d03ac274201c, 0x3c57a5c56eb7f6a0, 0x3fc3954778d6a0df, 0xbc5863eca74d1838, 0x3fa88e0f7b183fc6, 0x3c4226527d05ce39, 0xbfb0f7c15f75ee13, 0xbc156f74f3513660, 0x3f85e22cfa1aab51, 0x3c24b49a250c6474, 0x3f89ad28c5557c22, 0x3c299920b730ecd5, 0xbf7704ec5d29fc83, 0xbf523360304f19ba, 0x3f543ca3fcdf079d, 0xbf0dcb97a9e04bd4, 0xbf2735e26c43d267, 0x3f0360c3b06ffbb4, 0x3ef29a6b5798e781, 0xbeddbc35e4cf98f5, 0xbeb2f6e8e81287bb, 0x3eaeeb2fdddad355, 0x3e81ae65e387ac52 ], [ 0x3fed0580b2cfd249, 0x3c84fca6318dfee9, 0x3fd1a0dc51a9934d, 0xbc6ca89d2d78fba4, 0xbfd4ef05a0f95eeb, 0xbc65f7c55a00231c, 0x3fc5648b5dc47417, 0xbc6fb8fa09976e07, 0x3f840fbaba44504c, 0x3bf435c75f61f1e0, 0xbfac0db89d0a41a4, 0xbc11dd02d9441b98, 0x3f9388c3ec056942, 0x3c38e7498172c914, 0x3f7aecb7463cf446, 0xbbe0d6701a009d70, 0xbf78bca53327e075, 0x3f34add4a8239f4a, 0x3f505ce4abd10484, 0xbf3183f198a0b620, 0xbf19cd1a9b9fc69b, 0x3f0d30363021af83, 0x3ecda66f2161c4c6, 0xbedf41f1f238827d, 0x3ea725a07b1177b7, 0x3ea84c3b2483eb6a, 0x3e6e30e89d6e85cd ], [ 0x3fedf85ea8db188e, 0xbc8f71e8254d11a9, 0x3fc9cb5bd549b111, 0xbc4973e73caa1edc, 0xbfd0ed7443f85c33, 0xbc574bf040302ad8, 0x3fc5066cda84bba9, 0x3c4beb86d9e281a8, 0xbf9419fa10b6ed7d, 0x3c35157491034c58, 0xbfa3f41761d5a941, 0x3c494a1c1f7af153, 0x3f96d1d724baaae4, 0x3c3c41090a704426, 0x3f4e377f5703f7ff, 0xbbea753be0c53963, 0xbf74cc916ad63c27, 0x3f5553ef0d12719f, 0x3f426240f55987fd, 0xbf36bbf0fffb7138, 0xbee320cf6663c40d, 0x3f0a9d4850aaa197, 0xbee17036c4011c91, 0xbed441ea26a91a02, 0x3ebd81eb8e2ef452, 0x3e917d7b798a4322, 0xbe4b7b0dfb2559d0 ], [ 0x3feea7730ed0bbb9, 0x3c82c5bd7ce1388b, 0x3fc24a7b84d38971, 0x3c6aa0c5e788ed5e, 0xbfca4b118ef01593, 0xbc3238e3e6a99de0, 0x3fc319c7a75f9187, 0x3c4a8f8fff24b0ac, 0xbfa3db5bed47faf6, 0x3c429cf699c8512c, 0xbf97019bda6c2fdd, 0x3c1dd56b84622d88, 0x3f959d3aa402c32e, 0xbc08de701f1e95e8, 0xbf6b324eab9c87a9, 0xbbec3a4329771a44, 0xbf6b4774d37d0dd6, 0x3f5c01377485a844, 0x3f1a5db5f627539b, 0xbf340d9c429b8932, 0x3f0e720d935ef7db, 0x3effc8295ac052de, 0xbeed1ccde95c6551, 0xbeb251c256ca45cb, 0x3ebe892cc5397b1b, 0xbe88f6831febdf3d, 0xbe9aa5ef30a52421 ], [ 0x3fef21c9f12f0677, 0xbc57efe429672268, 0x3fb92470a61b6965, 0x3c5c6acd40cee352, 0xbfc3a47801c56a57, 0xbc6033705aa16f01, 0x3fc0453f90d3bd35, 0xbc6686e281ba5405, 0xbfa8a7c6a239217b, 0x3c32a988808a7222, 0xbf8075c088031ee3, 0xbc1665bd0a645f40, 0x3f916f9c9c127b80, 0xbc1e1813af47374c, 0xbf774c2fc9bdfe97, 0x3c15cf2dbe53783b, 0xbf5760c522bd5bec, 0x3f5a3cdb656adb44, 0xbf302c3c1ab0a7ba, 0xbf292892013c7e15, 0x3f16e7b268d42034, 0x3ed970751eb9359f, 0xbeeb00b549bbdf58, 0x3ec033f8545bcc6a, 0x3eb2d8b6f0a2204a, 0xbe9c1c1335b105c5, 0x3e661bbb2d003b8a ], [ 0x3fef74a6d9a38383, 0x3c8c33a329423946, 0x3fb0bf97e95f2a64, 0xbc5446051f6fef82, 0xbfbc435059d09788, 0xbc4b93aeb5e5cf84, 0x3fba3687c1eaf1ad, 0x3c564513fb767a13, 0xbfa9647a30b16824, 0xbc486357831221be, 0x3f66981061dfbb09, 0xbbfccc83193c8742, 0x3f87e8755da47040, 0xbbec1eaeb3371490, 0xbf79be731fdab95d, 0xbc0ab79fedbfccd2, 0x3f23a95ae0a75542, 0x3f5319f780e962d8, 0xbf3b88dd51a4f261, 0xbf1037f168a8f581, 0x3f153fc5e83e3199, 0xbee9d5bf30917222, 0xbee03045c999d17a, 0x3ecb5d376e96179f, 0x3e8c66d2e5aa2274, 0xbe9aef24a52bcaca, 0x3e7b20b678e8a0c6 ], [ 0x3fefab0dd89d1309, 0xbc8ae61bd9db1bab, 0x3fa5a08e85af27e0, 0x3c4e4f9cfc8c2382, 0xbfb399812926bc23, 0xbc5b782644df6665, 0x3fb4140efb719cb0, 0x3c308fa5a48311e8, 0xbfa7535a61a4193d, 0x3c359e0501c376b2, 0x3f8374c88c7e6abd, 0x3bfc2578bd7e3f00, 0x3f7a40709e010e77, 0xbbf18c33197d9138, 0xbf76dc078888efa7, 0x3c02b49da4c86c70, 0x3f52ee6d200993b0, 0x3f444f175e22a161, 0xbf3c2fb051c92f92, 0x3f0523035ed3964b, 0x3f0bc7b666856fc1, 0xbef574549f39ee50, 0xbebc57f3c47b39d9, 0x3ec8acc76ac31fcd, 0xbe9f70e8b7deaa9a, 0xbe8e1a28a0c1a6a6, 0x3e6bfa0e5b606c5e ], [ 0x3fefcdacca0bfb73, 0xbc82c33d88729e43, 0x3f9b1160991ff737, 0xbc2d940a504353bc, 0xbfaa38d59456f77d, 0xbc1d625808eb9778, 0x3fad5bd91b6b0123, 0x3c222b86f5e3e16c, 0xbfa3b35dcbc80146, 0x3c482838d776d958, 0x3f89d76b0a0535c7, 0x3c260fda06bca0a0, 0x3f614c887a83a0e6, 0x3be55ef222558d68, 0xbf7117f42cc6e9f4, 0x3bed4213a7e14a18, 0x3f59b477bdad8e08, 0x3f21d219fb0e1bc8, 0xbf35bb59d3ca4fa9, 0x3f18ca373c577821, 0x3ef4a9b74153a4a3, 0xbef424a8a8831410, 0x3ec6ce0877965abc, 0x3ebc1ed3c11b1dd1, 0xbea86b0a731d831a, 0xbe55cea3996396c5, 0x3e9640950bde5eb3 ], [ 0x3fefe307f2b503d0, 0xbc68a555000387f8, 0x3f906ae13b0d3255, 0xbc388abd7f4be982, 0xbfa0ee3844e59be7, 0xbc40b0ec94b96d83, 0x3fa48b127f8ed8a5, 0x3c3b6a1f18c2c162, 0xbf9f155b4e7d8c3b, 0x3c3adb2d99b0c1fc, 0x3f8aa2c0753d569a, 0x3c29a37b9864b8e6, 0xbf4bbf7e2795837b, 0xbbe4784a66288abf, 0xbf65478d784d271c, 0x3be27115917a7ec0, 0x3f58eae08cdf9546, 0xbf292946556037e6, 0xbf290f27ae61444c, 0x3f1b076b78538f02, 0xbedb2906f1b92d5d, 0xbeea2f66822d4a01, 0x3ed3031c4f7c4a97, 0x3e941708ced2abd0, 0xbea45ffd6deae2a8, 0x3e7e844ebdc8456a, 0x3e7c0bbf2b711595 ], [ 0x3fefefcce6813974, 0xbc5b27cf5025d1c8, 0x3f834d7dbc76d7e5, 0x3c23780d6e7eb351, 0xbf951cc18621fc23, 0x3c2969629e4b64a6, 0x3f9b925a99886bb7, 0x3c29c8f65efdd1f4, 0xbf971e7d408c8c6f, 0xbc3c5621deaf4cfc, 0x3f87ea58080a81ef, 0xbc22f25b7f384ff3, 0xbf646eb9d203e071, 0x3beff569e38360a4, 0xbf5403333682fa5e, 0xbbe36256a95953a6, 0x3f53b37d5bd14a40, 0xbf36be130822dbdf, 0xbf103d4bcdafd553, 0x3f155848476c8142, 0xbef5492bf3c6eee6, 0xbed3823d4328e9c5, 0x3ed152fefc353e5a, 0xbea5199dbf7bc4c6, 0xbe94dda2bebe08f2, 0x3e83fb850b47210a, 0x3e6bcd1b284c4798 ], [ 0x3feff733814af88c, 0x3c70a87238cea4fa, 0x3f75ff2750fe7820, 0xbc15f184847ca667, 0xbf896f0575a63ae5, 0x3c295f4139297a96, 0x3f91c5a643f04363, 0xbc16ea87997fba3c, 0xbf904f5caaf2196f, 0x3c119502347d3b54, 0x3f8382a146afb9d2, 0xbc0f93bde902d2d0, 0xbf695cab93aa68d2, 0x3be0f716a5fc18c4, 0xbf2d2fd90fe62928, 0xbbb4e00d5fcc484a, 0x3f49f50fb94c0b86, 0xbf37d7378074399b, 0x3efcc0c9cb9ede1e, 0x3f092a3a29471895, 0xbef7c127858c909a, 0x3eb5a72fde935a48, 0x3ec57b9d90a92106, 0xbeafdb8443754cf7, 0xbe56c7d633eab55a, 0x3e7ddcfc714a2b67, 0xbe89fedf738e84b4 ], [ 0x3feffb5bdf67fe6f, 0x3c14e830346f6e80, 0x3f684ba3004a50d0, 0xbbf90b93d4632206, 0xbf7d9c2ea85a927d, 0xbc10bcf1ea93cfdc, 0x3f860898536e104a, 0xbc1ab6aa911c445e, 0xbf85eb1c899f0b70, 0x3c21bc22eed1f1fb, 0x3f7d854f73e74c87, 0x3c07a977a3364c40, 0xbf6897719a9d257e, 0xbbeab523e3f93994, 0x3f388cdc8b807c97, 0x3b94875acc7c06a0, 0x3f3b325a11c1f45a, 0xbf3381548f692740, 0x3f12b1fd05559bfa, 0x3ef1ed31cd6feb26, 0xbef29cf593fdf00a, 0x3ed1cea99b59228c, 0x3eaceff221e3598a, 0xbeab0ad4b899b2d9, 0x3e83761b047e21d1, 0x3e696c31c2256049, 0xbe60a714c57f7adf ], [ 0x3feffd9f78c7524a, 0x3c804ed6ff98e45d, 0x3f5a024365f771bd, 0x3bf3c8f5202cb405, 0xbf70a9732d5284dd, 0xbc11acbd0899ce7e, 0x3f7a4bf47a43042a, 0x3c0e6cb2580d0920, 0xbf7c23802d8a5bb7, 0xbbd9963700abfc80, 0x3f74f40070668329, 0xbc1e1fe1c0e1182a, 0xbf64c9a2c9dccd04, 0x3c080fb9c9cd78c1, 0x3f44f7a50b5bc019, 0xbbd40906b7a1de3a, 0x3f218b04eb90c737, 0xbf2a4c3880c0ea69, 0x3f14b7b82a86f423, 0xbed0bc762b1c2aaa, 0xbee589d6f8892acf, 0x3ed357ab63f7bdf9, 0xbe96675858bbff5e, 0xbe9ea96dcb12a15c, 0x3e88c572fcf5610e, 0xbe3700c93da86dee, 0x3e57ae9ceb75e26e ], [ 0x3feffed167b12ac2, 0xbc8ddc0ce3ed8fcb, 0x3f4afc85e0f82e12, 0x3bd438f22895e03e, 0xbf6221a9f326bef4, 0xbbf99642b37af330, 0x3f6e3c9aab90bcf4, 0x3bb7dcdfdccc72a0, 0xbf714b1b98141f21, 0x3c1af6edf50eba66, 0x3f6c1c19b9e63d70, 0x3bd4d1e9411f1d28, 0xbf5feac3dbeb5124, 0x3be2400e6ffbc1c8, 0x3f463e88178b0e49, 0x3be3e4ae97774f91, 0xbf04441c86c93f39, 0xbf1c8ceebc5fc50b, 0x3f1125b77a79aa6c, 0xbeeda7be990bc718, 0xbece019960474aff, 0x3ecd229185ef6279, 0xbeacea9fa10885e7, 0xbe8044fd6a2e447a, 0x3e83695f88fc641d, 0xbe60c0dc0ba0d589, 0xbe89194748828b93 ], [ 0x3fefff6dee89352e, 0x3c8b96c0ba13851d, 0x3f3b23a5a23e4210, 0x3bc727bce1be0014, 0xbf5315107613c673, 0xbbf823f8673f5b7a, 0x3f60c243329a9ca1, 0xbbf65e361cefe652, 0xbf64630116262084, 0xbc00ea6ee40daf79, 0x3f61e84d1022e8cb, 0xbbd9b77b85eed4f0, 0xbf56b41872716325, 0x3bd3e9e001100f64, 0x3f436edde582b265, 0xbbe1cb479a94e148, 0xbf1f7870ebc38e77, 0xbf051ecfdc37801d, 0x3f0711d817e0d3b6, 0xbef0ae90d500d1d8, 0x3eaa85b1bf54920c, 0x3ebfe73958205038, 0xbead222bfef33aa4, 0x3e7833f8b13b1a4e, 0x3e7233b5a19285db, 0xbe61adcf574b7db6, 0x3e7ab10bedc44532 ], [ 0x3fefffbb8f1049c6, 0x3c7d2c6266b51f26, 0x3f2a740684026555, 0xbba7e24cc3ac5710, 0xbf436d34c8f1c26a, 0xbbe69d73e7d1c977, 0x3f51eb6e14974a25, 0xbbf99b78600e0664, 0xbf5714eb8cc0947f, 0x3bf3613f37c7410b, 0x3f55bec08c01b1d7, 0xbbf3e3a262f6c68a, 0xbf4e4621d82dad12, 0x3bc302878843e2cc, 0x3f3e1b7b564b0e79, 0x3bcf894fc1f14d54, 0xbf224564b69716aa, 0x3ebbf8e3b47f3ccd, 0x3ef8f55a9be1a264, 0xbeeb3b76e6203281, 0x3ec713c795a07e0c, 0x3ea3bb092cfd93e0, 0xbea473b0a8333dee, 0x3e8645526869c143, 0x3e41a343e004b33d, 0xbe576c7e253faad1, 0x3e7e16080963cffe ], [ 0x3fefffe0e0140857, 0xbc66aa36f86c14dc, 0x3f18fdc1b2dcf7b9, 0x3b87050f50b8f308, 0xbf3322484cf12daa, 0x3bd4cc0408806d4f, 0x3f427dc1bc6cfef5, 0x3beffbb5229f6bb7, 0xbf49202f465eb421, 0x3ba8f3f063b40660, 0x3f493b4c9746835f, 0xbbe04e2d6df2fce5, 0xbf430e9e6142fe9b, 0xbbd0396045094744, 0x3f3555b9d5fb4825, 0x3bd9a40d2ca5ef0b, 0xbf2055983c4ac7a6, 0x3ef68e6c75a5d068, 0x3ee2d4a50d2757ce, 0xbee1de08b56479aa, 0x3ec9110ccc7fe6fd, 0xbe8bb3184d789af8, 0xbe94629a164e82a0, 0x3e8413b087ee5e4d, 0xbe5648d7786f9fbc, 0xbe4293289f8c327d, 0xbe6c283008e726f7 ], [ 0x3feffff2436a21dc, 0xbc83607959a29d36, 0x3f06e2367dc27f95, 0x3b6d96e6f0151020, 0xbf223c436c36fdab, 0x3bbf0d77fc600a50, 0x3f326bf00867a835, 0xbbdc92e1aecdc750, 0xbf3a51fb50b15f22, 0x3ba248227c6d2260, 0x3f3c0825378fda08, 0x3bd5a8a09c053451, 0xbf36c3dbfe0cbe4a, 0xbbde65769c33f8a1, 0x3f2c1dd1438378df, 0x3ba91bd161f34158, 0xbf194c36a9d7c0dc, 0x3efbf0aab116ca41, 0x3e86bdbd2f103930, 0xbed2b32e8d43ef25, 0x3ec3a7403459770b, 0xbea17411873320fa, 0xbe735bb2691c9b29, 0x3e798313537ed069, 0xbe5cb4b60e85a341, 0x3e02be214cf4c9eb, 0xbe8350a1a851865a ], [ 0x3feffffa1de8c582, 0x3c8832540129302a, 0x3ef44f21e49054f2, 0x3b8f338cf4086346, 0xbf10d18811478659, 0x3bb914a7a08b6a2b, 0x3f21b964d438f622, 0x3bca52c94c56aaaf, 0xbf2a8d7851f26bf0, 0x3bcc38dbf3ee1223, 0x3f2ddd6df9b6852d, 0xbbc3b0dd7eac9b91, 0xbf29e52b7aac1644, 0x3bc904036dfb5764, 0x3f2165b2034fcab2, 0x3bc27beac4bf3866, 0xbf11b75c3332673a, 0x3ef91a253c42f4e7, 0xbed020b498095051, 0xbebade63f30809ae, 0x3eb89bb0d75e59b7, 0xbea180c78d3dca28, 0x3e6cabfd39b38553, 0x3e66013ffba86cfd, 0xbe564f2b123e1f0b, 0x3e335bf3e5021105, 0xbe8177828ffd35af ], [ 0x3feffffd8e1a2f22, 0xbc8c10adf6b19989, 0x3ee1783ceac28910, 0xbb87f19d8ee58337, 0xbefe06a8b37e5b93, 0x3b824e8db1358f2e, 0x3f107978c7b8496b, 0x3bbf163b5580927c, 0xbf19d039884f8be5, 0x3bbfce53cd30b1eb, 0x3f1e8d1145e94a54, 0xbbbd0f6e009a99ee, 0xbf1c1f7251172a87, 0xbb83ce0f013dfe90, 0x3f1458b9e0854d68, 0xbbb897cf3950b1a7, 0xbf06eb0557245429, 0x3ef33045cf65279e, 0xbed42c8adf18ab62, 0x3e491109b80f9918, 0x3ea83a9b44249fbf, 0xbe99bcbaf0a8dfd1, 0x3e7900325b58a857, 0x3e34a3cf9c161684, 0xbe50cbcc4d0a916a, 0x3e34275e1b91f084, 0x3e839180c75350e1 ], [ 0x3fefffff039f9e8f, 0xbc89d1bcd6174e99, 0x3ecd21397ead99cb, 0xbb46abd9c029c47c, 0xbee9f19734d29cf9, 0x3b820c4383da36c1, 0x3efd982bd41d8954, 0x3b8d9bc9988e9666, 0xbf08320fc4836be5, 0x3b7526638b9926a8, 0x3f0e0a1cb1d071f3, 0x3b9d9f5d232bab90, 0xbf0d384223047b9c, 0xbba30d0b2b8a170d, 0x3f0696daf6422bd4, 0x3baba6ac732f399e, 0xbefbb6e2d311a93f, 0x3eea4fcb0ea87efb, 0xbed1c940c5303daf, 0x3ea7469913f4e9c6, 0x3e8ef4b4f8ab67ae, 0xbe8e189c28e8e041, 0x3e7678b281d5bc55, 0xbe49c3bf4e9f2b5d, 0xbe374c9ba997ffed, 0x3e2b4b843f8c7068, 0x3e6c901764507862 ], [ 0x3fefffff9d446ccc, 0xbc6bb06bab98bc80, 0x3eb789fb715aae95, 0xbaf226d93bf89b40, 0xbed5b333cc7f98f1, 0xbb76bd1091d25440, 0x3ee9b12fdbf90f62, 0x3b8d4b6b0ee9cf46, 0xbef5e06923144d70, 0x3b4c593194857860, 0x3efc6a071925631d, 0xbb8835ef595952e4, 0xbefd178cb0388a82, 0xbb9039272760f01c, 0x3ef7e29d33ac92b6, 0x3b921ff8b0e9d5eb, 0xbeef9203429baad6, 0x3ee094dadeee395c, 0xbeca771cf3500d9f, 0x3eab8fd1c29c21ea, 0xbe5cc8573d7de110, 0xbe7b0362da1722cb, 0x3e6e5eae518f94e9, 0xbe507963addd99a6, 0xbe23f496093d0bef, 0x3e199078a326092d, 0x3e842681ecfe4da1 ], [ 0x3fefffffda86faa9, 0xbc7d230252d68f26, 0x3ea26f9df8519bd7, 0xbb4e339871c015b7, 0xbec1926290adc888, 0xbb6e36d23dbb2644, 0x3ed5900c02d97304, 0x3b7fa7d21e3ed616, 0xbee3166de6a8c640, 0x3b8b014157867958, 0x3ee9dfcc328729e0, 0x3b820e9fee0b7665, 0xbeebcab1ed5ec38d, 0x3b6d9003794f0fe0, 0x3ee81cd74a57ce17, 0xbb8809fde9c0f6f5, 0xbee106e95b6bf556, 0x3ed379625a71385f, 0xbec1970a5b5bd443, 0x3ea74761c8333ff2, 0xbe80864e125c9951, 0xbe5b83bf9019aa3b, 0x3e60397611c35b28, 0xbe4a25392adb29ac, 0xbe17b832af40d9d4, 0x3df62a02eb79577b, 0x3e8a6da58ffe94f4 ], [ 0x3feffffff233ee1d, 0x3c8db123ed17221d, 0x3e8bfd7555a3bd68, 0x3b20151cf177b53a, 0xbeab8d7f804d2e73, 0x3b482b366f0bc2dc, 0x3ec17f93e5149289, 0x3b391997bfd26568, 0xbed013b0457d08fa, 0xbb60d6d5a7f06298, 0x3ed6b245d7e1d829, 0xbb79985e02c8ce3b, 0xbed98077548c6951, 0x3b701cd3f1d12c93, 0x3ed7492048ab3ceb, 0xbb70368a0dc0750e, 0xbed17506c7b39cb0, 0x3ec57e94a4c5f5a6, 0xbeb570971200d7db, 0x3ea0a0f956947b21, 0xbe81a9b7bd5bba32, 0x3e451bfc00de3146, 0x3e495b6967f79cbe, 0xbe3fe3c43cb3cf84, 0x3e32f364a7a2dc5f, 0xbdf007442a10cc14, 0xbe7ef5ab6fc5e849 ], [ 0x3feffffffb127525, 0x3c8504f382db4102, 0x3e74980cb3c80949, 0x3b17fbdd923f8057, 0xbe94ea6ce697296f, 0x3b3ea42f9c9de533, 0x3eab771d9b6f07b8, 0xbb1e9c1ca9662fe8, 0xbeba26c653fad5b8, 0xbb5146c4cee0e898, 0x3ec3302bb89379de, 0x3b64c55b83ef7a68, 0xbec67f42e5264334, 0xbb66779da26b4197, 0x3ec58b4adafb958e, 0x3b68351251b45e84, 0xbec10f576796285a, 0x3eb66ca44250dd07, 0xbea84ee0ada37543, 0x3e953b6065291e6b, 0xbe7c09ebfd0c581c, 0x3e563062625d59c0, 0x3e1e259c60eb7b83, 0xbe2e43802ad25514, 0x3e351bcdabe8cda5, 0xbdf930fc3df6e909, 0xbe881cdd770e1c81 ], [ 0x3feffffffe4aed5e, 0x3c4389c0f32ad0f0, 0x3e5d5f3a8dea7357, 0x3affa07c18622dd2, 0xbe7ebfb14c9170c0, 0x3b19e40632b4145d, 0x3e94d9228525f449, 0x3b2d35bd7f959136, 0xbea48b536addac5f, 0xbb461ace22b32569, 0x3eaf48ccf23a68e2, 0xbb4ee1d13c79c281, 0xbeb3183b6134cf03, 0x3b4e1f4d5fe2a06c, 0x3eb31efde2215f01, 0xbb564a7021e23fba, 0xbeafd9eeb0f18fdb, 0x3ea63414459ae298, 0xbe99dda81be20b5a, 0x3e88da7d306423c5, 0xbe7303da86a4fc28, 0x3e54f5e1327706b9, 0xbe23efb5eefcbe53, 0xbe131bc5ce1ce65d, 0xbe13eafe1b05c93f, 0xbdf47fc2d9cc851e, 0x3e7d27265006a9df ], [ 0x3fefffffff6d1e56, 0xbc864d969b4be4c4, 0x3e444d26de513197, 0x3ae76fc20fc4b365, 0xbe65e32de7af8977, 0xbaf888fd6ae18a1c, 0x3e7e9e05b3c8f38a, 0x3b17532141b12aa7, 0xbe8f2f6fa7db5b1d, 0x3b2b3bf498e3462c, 0x3e9899dcace485eb, 0x3b11885a0ae9e878, 0xbe9f34b7eef3c9b2, 0x3b3294a3b618b470, 0x3ea04be030272d14, 0xbb4df83095e40f79, 0xbe9c73bd22571559, 0x3e94edda838439f5, 0xbe89fc860b504677, 0x3e7b0d686a260420, 0xbe672370c2fdbe10, 0x3e4ee29f0d197d25, 0xbe2b4d88d500c5be, 0x3dc96014c45b0178, 0x3e0238f19dc8fd82, 0xbde8d34d46ae6567, 0xbe454105fe4a9cd8 ], [ 0x3fefffffffd01f89, 0xbc735e8e39884f62, 0x3e2b334fac4b9f99, 0x3ac32178ed1a4971, 0xbe4e2cec6323e50e, 0xbac0e5693f9d4908, 0x3e65c027d5bba36a, 0xbaefc46fb3cc7ae0, 0xbe76df4d024fffbe, 0xbb090fd7226ec57a, 0x3e82aaf7c205b9ea, 0x3b2dbec2005b45a8, 0xbe88902edfbfefdd, 0xbb2c353aca58d08a, 0x3e8ab2ab1b338249, 0x3b2b498186c39105, 0xbe885abe0ff198d3, 0x3e82d32f7c3621eb, 0xbe78c141c71dbc95, 0x3e6b9fa6fbb9b198, 0xbe59db5fe2c2f5b9, 0x3e43b8e07840483e, 0xbe26d95e5070d91d, 0x3dfd7616168b0e49, 0x3e1f2be0744b3a5f, 0xbdd737a375809985, 0xbe7936d4936fb865 ], [ 0x3feffffffff0dd2b, 0x3c80df73e7d2fc98, 0x3e11a94ff571654f, 0x3abfbf537b47967d, 0xbe34251f33f5578f, 0x3ad4c9cece8f41b2, 0x3e4de6bc1f75bb9b, 0x3a894afb459a3000, 0xbe6036b5fd1c4158, 0xbb0d582afa097896, 0x3e6b58f1385def96, 0xbaf8778854601996, 0xbe72a2347efb2133, 0xbb026f9e1ef0f378, 0x3e7508db866ffe00, 0x3b164de561a68a21, 0xbe73ffea934685b9, 0x3e702ff87b2e2576, 0xbe666e54eae5fa4b, 0x3e5a9ea2195c567d, 0xbe4ae3b91fecafa1, 0x3e36bb883d2e5ed1, 0xbe1ee10e97715c11, 0x3dfe2873d2b77f1f, 0xbdeaf385ae29d57b, 0xbdbd793eecfc2513, 0x3e420d80dcfa68d1 ], [ 0x3feffffffffb5be5, 0xbc7729d6819c7f34, 0x3df63ac6b4edc88e, 0xba7c45991835da24, 0xbe1a0ce0dc06a706, 0xbab1b72d11da9dab, 0x3e33e380dd7593a5, 0xbad8ad868a7b5674, 0xbe4638bc4fb02cba, 0x3a87a84506fcda40, 0x3e535753ad4c5875, 0x3aead190ab170366, 0xbe5b41f33cafccba, 0x3af0e3539bf61116, 0x3e5fe694e371a659, 0xbad3a84e01866ea8, 0xbe5f8af0121aa0ab, 0x3e5aa77274dab3d8, 0xbe53616fe8f6a259, 0x3e484fddf4c681a1, 0xbe3a3de05d1b8a31, 0x3e2822529aca9f83, 0xbe126c3dfba84378, 0x3df64c287a84aa09, 0xbe0107d2dac5d83b, 0xbd4e251d1ab1d873, 0x3e58f37005f17b42 ], [ 0x3feffffffffe9eb0, 0xbc5ea527e0bef1e8, 0x3ddb1e5acf351d87, 0x3a5dc96583ba19f0, 0xbe005042a0a5f3c3, 0xbaa2023f0f13867c, 0x3e199ac8fd63c66c, 0xbaabf57c5fd0501a, 0xbe2d72344378e114, 0x3acc77758959af41, 0x3e3a6be9a123435b, 0x3acdab4af8807c36, 0xbe433aacb4bf6dea, 0x3aebd241ea49ac35, 0x3e474b732e7ceaa7, 0x3adc7c89730b0264, 0xbe47e7eab6531ccb, 0x3e450959f2daae39, 0xbe3ffed4cef94261, 0x3e351c7f99f908a2, 0xbe282b5fd5fbedfc, 0x3e17e1c8e715c978, 0xbe051536822c861b, 0x3debe7e4c220ca82, 0x3e2f5bb67c461296, 0x3da1d7cf04529bf0, 0xbe8acc021ab828c4 ], [ 0x3fefffffffff9a1b, 0xbc66a87270d2450c, 0x3dc0084ff125639d, 0xba58ad61debedc86, 0xbde3ca42adaa26f6, 0x3a8c20c6583dccdd, 0x3dffe73513c67bf8, 0x3a920d28c0c7e686, 0xbe12dd9aa5a2bee3, 0x3aad76d7235461be, 0x3e216ef6b93944a8, 0xbacf07bd785566de, 0xbe2a2d58e9b22b26, 0xbab19e6ea91dd55e, 0x3e306389b9748f25, 0x3adfbcc52565c0be, 0xbe316cdd9eb58ba2, 0x3e2fdd861b55c500, 0xbe29457846c943d2, 0x3e2178f3905f435c, 0xbe1518cf20c53de2, 0x3e06329939a34b66, 0xbdf5ef3ad85e5d3b, 0x3ddf2b41494e49e9, 0x3e2bad43bc0b622d, 0x3da21a45fa9dcebf, 0xbe8790b3d88f69fe ], [ 0x3fefffffffffe380, 0x3c87ce07114e4fe0, 0x3da25f9ee0b923dc, 0xba4174c43a73a4d1, 0xbdc74105146a5162, 0xba47d0740e56625c, 0x3de33cde4f35d941, 0xba72a344950797c6, 0xbdf760fe7b666392, 0x3a9a8b77c82ed644, 0x3e063a70fd66d485, 0x3aa6b87715649d6d, 0xbe11324f6fb6dfa1, 0x3ab3fc045e39915f, 0x3e163a31a36b815c, 0xba502dec9bc1a700, 0xbe18724ca8970b91, 0x3e172e290891e5de, 0xbe131fc03858aab1, 0x3e0b9e8b0e7fa253, 0xbe01821a002637bd, 0x3df37ba5f3fba5eb, 0xbde3578bf23dc654, 0x3dcfdaf2015d7b54, 0x3df7f6a435069067, 0x3d99d14ee557ec62, 0xbe555f4c743ee571 ], [ 0x3feffffffffff845, 0x3c7b0edc5a89ab8e, 0x3d846897d4b69fc6, 0x3a2a74852415bb49, 0xbdaa77a4e7dcd735, 0xba434edb43ab7de6, 0x3dc67543695dcc12, 0xba329ae577004af8, 0xbddc05c1e2fc710e, 0x3a5dbbf42d2537a8, 0x3deb639419fedf8e, 0xba8ed72eb9e7a59e, 0xbdf5cfd7eb9bfe87, 0xba7e97db27125fc0, 0x3dfd11578959ba45, 0xba8c0635ac2b5768, 0xbe0082f9e9f7eb37, 0x3e00354ceadad8b3, 0xbdfbc2dee0154fc6, 0x3df4e11efdc66eae, 0xbdebb357c0253f64, 0x3de035f9889bc29c, 0xbdc8e7bdb10b7441, 0x3dbe364571102661, 0xbe212cffcf49a2e8, 0x3d8ee9362bcfec26, 0x3e7cc5b58dd85301 ], [ 0x3feffffffffffdf8, 0xbc8dcf8b10ff973b, 0x3d65f8b87a31bd85, 0x39d65b265455b658, 0xbd8d2e55024a0fb5, 0x3a2444e1d84cea02, 0x3da9612cc225df4b, 0xba4c784edb664ce7, 0xbdc03ee5f38b9b4d, 0xba691ca8efa41a30, 0x3dd04f2f71e2e96b, 0xba633f36a4e51350, 0xbddab7099f99ced9, 0xba54af7a67f2110c, 0x3de2554b8f609fd1, 0xba729e641eb44218, 0xbde57c87529ca968, 0x3de5cd182c967671, 0xbde3580a2517d57a, 0x3dde3be72b1be982, 0xbdd4e9908689ad08, 0x3dc9a61979d3395b, 0xbdb7b826aadd1c89, 0x3daad3a9fc4a0d1e, 0xbe00e9325ed20970, 0x3d80722198ff452c, 0x3e5c2ef85611aa11 ], [ 0x3fefffffffffff7b, 0x3c800fa07f7fb612, 0x3d46ed2f2515e933, 0x39d2bc1802a42b92, 0xbd6f2a6c1669c901, 0xba07b3e174cc1840, 0x3d8bc42ba38a13f8, 0x3a2460463d59d3df, 0xbda2391e135afae4, 0xba3bd08c8c5f7b18, 0x3db2c6c24550f64f, 0xba3fdc861a487110, 0xbdbf9a3c1b0d63ec, 0xba5843dc8d9ad3d5, 0x3dc6502546ab341a, 0x3a645f812e48eb98, 0xbdcaf223186006d1, 0x3dcc388dd1764f41, 0xbdc9e65a242b52aa, 0x3dc4fcd2787781eb, 0xbdbe3cbdb20a48d6, 0x3db35639e9fcd410, 0xbd55b8e97774b2c9, 0x3d966ffe6a100bc9, 0xbe15706c390c113e, 0x3d6ff0d11cf61949, 0x3e72054de347e3f8 ], [ 0x3fefffffffffffdf, 0x3c75669e670f914c, 0x3d272fd93e036cdc, 0x39b1c553d12fbbd0, 0xbd501f450d1e61b2, 0x39cbed807e60c078, 0x3d6d68fb81b2ed89, 0x39dc7ea3c4444cc0, 0xbd83c706aa4d2328, 0x3a2d6d2d51dd414d, 0x3d94e6479565838e, 0x3a350580f36c14c1, 0xbda20e9eb83b3dd9, 0xba104b6334a32fd0, 0x3daa35b9d2fcac80, 0x3a1c07c6978bf2f0, 0xbdb04a134f6e3dcb, 0x3db196579f27ddbe, 0xbdb0ab97aa74c700, 0x3dabf68355f542b1, 0xbda49da25a547134, 0x3d9bd64993a3958e, 0xbdc1193990186399, 0x3d81c0e98335ae18, 0x3e2e08edb685494a, 0x3d5cb9fcc058465b, 0xbe894cacccfb8964 ], [ 0x3feffffffffffff8, 0x3c70160ef15c497e, 0x3d06ba91ac734786, 0xb9af81d6fa69b5b2, 0xbd3028a39099f4db, 0xb9c83ed68de15404, 0x3d4e292863e1795e, 0xb9db292e812abb68, 0xbd64c4e690fbdd14, 0xba080991e1d4ef25, 0x3d767e6e5ac60fd1, 0x3a01d2ca68dcf0e8, 0xbd83f00d80afa00c, 0xba23e174dc7225ac, 0x3d8db88ee63eb28a, 0x3a28abd97527892f, 0xbd92fe58a1f19368, 0x3d951dbeae22a5c8, 0xbd94a4d54823e0fc, 0x3d91e432d674cfba, 0xbd8b001e26c6e764, 0x3d8328ce695259fe, 0xbdb4e492cf7d4f4c, 0x3d6aaa77d339dc00, 0x3e2366538db382e5, 0x3d4826ad7d581503, 0xbe8056e0810b14da ], [ 0x3feffffffffffffe, 0x3c759ab24e589a30, 0x3ce5982008db1304, 0xb981cf9bda64b38a, 0xbd0f610e8cde57ac, 0xb99884dcd86f98c8, 0x3d2df2dac2f2d47f, 0xb997f27bf279d988, 0xbd451b17f95fc0b4, 0xb9e063e04485c3e7, 0x3d576996ddc975d7, 0xb9e21489d6648428, 0xbd6546155a972b18, 0xb9b9d3fb518aa7c0, 0x3d70456ed89c4f24, 0x3a1eee772fc32c5e, 0xbd755d6295aa388a, 0x3d786ead99977388, 0xbd789b3d387efa6e, 0x3d76011e175e64f8, 0xbd70cd70515af47b, 0x3d69402199dfdde7, 0xbda806743bc32b08, 0x3d530e561550364a, 0x3e170093985e2c1b, 0x3d331999a27ace63, 0xbe735f54db0f4dbc ], [ 0x3ff0000000000000, 0xbc8a6d7d18831888, 0x3cc3e296303b2297, 0x39668cf648cfed1c, 0xbced8456ef97c744, 0x398fcded17005500, 0x3d0ccb92e6c24c8d, 0xb9aa704dc202cff2, 0xbd24c1aa8cf1229b, 0x39c652efa61e4ec2, 0x3d37918b6b83c0fb, 0x39b2fb01fb8836dc, 0xbd45f073659de44d, 0xb9e9ceb48a2d1931, 0x3d5134d070b5921e, 0x39d9af3038fcc184, 0xbd5730a2938c09dd, 0x3d5b4091041f5905, 0xbd5c3c44ab8c8421, 0x3d5a06b4f4c3044d, 0xbd5704f511555fe7, 0x3d4fe51fcfc1acba, 0x3d95e7229a07e7cd, 0x3d39f8121f6c3146, 0xbe0692b2f9b3f445, 0x3d1c8c34f73d3823, 0x3e6301e540260d52 ], ]; pxfm-0.1.23/src/err/erfc.rs000064400000000000000000000752021046102023000135330ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::dd_fmla; use crate::double_double::DoubleDouble; use crate::err::erf::{Erf, erf_accurate, erf_fast}; use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1, ldexp}; use std::hint::black_box; static ASYMPTOTIC_POLY: [[u64; 13]; 6] = [ [ 0x3fe20dd750429b6d, 0x3c61a1feb75a48a8, 0xbfd20dd750429b6c, 0x3fdb14c2f863e403, 0xbff0ecf9db3af35d, 0x400d9eb53ca6eeed, 0xc030a945830d95c8, 0x4056e8a963e2f1f5, 0xc0829b7ccc8f396f, 0x40b15e716e83c27e, 0xc0e1cfdcfbcaf22a, 0x4111986cc7a7e8fe, 0xc1371f7540590a91, ], [ 0x3fe20dd750429ae7, 0x3c863da89e801fd4, 0xbfd20dd750400795, 0x3fdb14c2f57c490c, 0xbff0ecf95c8c9014, 0x400d9e981f2321ef, 0xc030a81482de1506, 0x4056d662420a604b, 0xc08233c96fff7772, 0x40af5d62018d3e37, 0xc0d9ae55e9554450, 0x410052901e10d139, 0xc1166465df1385f0, ], [ 0x3fe20dd75041e3fc, 0xbc7c9b491c4920fc, 0xbfd20dd74e5f1526, 0x3fdb14c1d35a40e0, 0xbff0ecdecd30e86b, 0x400d9b4e7f725263, 0xc030958b5ca8fb39, 0x40563e3179bf609c, 0xc0806bbd1cd2d0fd, 0x40a7b66eb6d1d2f2, 0xc0cce5a4b1afab75, 0x40e8b5c6ae6f773c, 0xc0f5475860326f86, ], [ 0x3fe20dd75025cfe9, 0x3c55a92eef32fb20, 0xbfd20dd71eb9d4e7, 0x3fdb14af4c25db28, 0xbff0ebc78a22b3d8, 0x400d85287a0b3399, 0xc03045f751e5ca1d, 0x4054a0d87ddea589, 0xc07ac6a0981d1eee, 0x409f44822f567956, 0xc0bcba372de71349, 0x40d1a4a19f550ca4, 0xc0d52a580455ed79, ], [ 0x3fe20dd74eb31d84, 0xbc439c4054b7c090, 0xbfd20dd561af98c4, 0x3fdb1435165d9df1, 0xbff0e6b60308e940, 0x400d3ce30c140882, 0xc02f2083e404c299, 0x40520f113d89b42a, 0xc0741433ebd89f19, 0x4092f35b6a3154f6, 0xc0ab020a4313cf3b, 0x40b90f07e92da7ee, 0xc0b6565e1d7665c3, ], [ 0x3fe20dd744b3517b, 0xbc6f77ab25e01ab4, 0xbfd20dcc62ec4024, 0x3fdb125bfa4f66c1, 0xbff0d80e65381970, 0x400ca11fbcfa65b2, 0xc02cd9eaffb88315, 0x404e010db42e0da7, 0xc06c5c85250ef6a3, 0x4085e118d9c1eeaf, 0xc098d74be13d3d30, 0x40a211b1b2b5ac83, 0xc09900be759fc663, ], ]; static ASYMPTOTIC_POLY_ACCURATE: [[u64; 30]; 10] = [ [ 0x3fe20dd750429b6d, 0x3c61ae3a912b08f0, 0xbfd20dd750429b6d, 0xbc51ae34c0606d68, 0x3fdb14c2f863e924, 0xbc796c0f4c848fc8, 0xbff0ecf9db3e71b6, 0x3c645d756bd288b0, 0x400d9eb53fad4672, 0xbcac61629de9adf2, 0xc030a945f3d147ea, 0x3cb8fec5ad7ece20, 0x4056e8c02f27ca6d, 0xc0829d1c21c363e0, 0x40b17349b70be627, 0xc0e28a6bb4686182, 0x411602d1662523ca, 0xc14ccae7625c4111, 0x4184237d064f6e0d, 0xc1bb1e5466ca3a2f, 0x41e90ae06a0f6cc1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], [ 0x3fe20dd750429b6d, 0x3c61adaa62435c10, 0xbfd20dd750429b6d, 0xbc441516126827c8, 0x3fdb14c2f863e90b, 0x3c7a535780ba5ed4, 0xbff0ecf9db3e65d6, 0xbc9089edde27ad07, 0x400d9eb53fa52f20, 0xbcabc9737e9464ac, 0xc030a945f2cd7621, 0xbcc589f28b700332, 0x4056e8bffd7e194e, 0xc0829d18716876e2, 0x40b17312abe18250, 0xc0e287e73592805c, 0x4115ebf7394a39c1, 0xc14c2f14d46d0cf9, 0x4182af3d256f955e, 0xc1b7041659ebd7aa, 0x41e6039c232e2f71, 0xc2070ca15c5a07cb, 0, 0, 0, 0, 0, 0, 0, 0, ], [ 0x3fe20dd750429b6d, 0x3c5d3c35b5d37410, 0xbfd20dd750429b56, 0xbc7c028415f6f81b, 0x3fdb14c2f863c1cf, 0x3c51bb0de6470dbc, 0xbff0ecf9db33c363, 0x3c80f8068459eb16, 0x400d9eb53b9ce57b, 0x3ca20cce33e7d84a, 0xc030a945aa2ec4fa, 0xbcdf6e0fcd7c6030, 0x4056e8b824d2bfaa, 0xc0829cc372a6d0b0, 0x40b1703a99ddd429, 0xc0e2749f9a267cc6, 0x4115856a17271849, 0xc14a8bcb4ba9753f, 0x418035dcce882940, 0xc1b1e5d8c5e6e043, 0x41dfe3b4f365386e, 0xc20398fdef2b98fe, 0x42184234d4f4ea12, 0, 0, 0, 0, 0, 0, 0, ], [ 0x3fe20dd750429b6a, 0x3c8ae622b765e9fd, 0xbfd20dd750428f0e, 0x3c703c6c67d69513, 0x3fdb14c2f8563e8e, 0x3c6766a6bd7aa89c, 0xbff0ecf9d8dedd48, 0x3c90af52e90336e3, 0x400d9eb4aad086fe, 0x3ca640d371d54a19, 0xc030a93f1d01cfe0, 0xbcc68dbd8d9c522c, 0x4056e842e9fd5898, 0xc08299886ef1fb80, 0x40b15e0f0162c9a0, 0xc0e222dbc6b04cd8, 0x411460268db1ebdf, 0xc1474f53ce065fb3, 0x417961ca8553f870, 0xc1a8788395d13798, 0x41d35e37b25d0e81, 0xc1f707b7457c8f5e, 0x4211ff852df1c023, 0xc21b75d0ec56e2cd, 0, 0, 0, 0, 0, 0, ], [ 0x3fe20dd750429a8f, 0xbc766d8dda59bcea, 0xbfd20dd7503fdbab, 0x3c6707bdffc2b3fe, 0x3fdb14c2f6526025, 0xbc27fa4bb9541140, 0xbff0ecf99c417d45, 0xbc9748645ef7af94, 0x400d9eaa9c712a7d, 0x3ca79e478994ebb4, 0xc030a8ef11fbf141, 0x3cbb5c72d69f8954, 0x4056e4653e0455b1, 0xc08286909448e6cf, 0x40b113424ce76821, 0xc0e1346d859e76de, 0x4111f9f6cf2293bf, 0xc14258e6e3b337db, 0x41714029ecd465fb, 0xc19c530df5337a6f, 0x41c34bc4bbccd336, 0xc1e4a37c52641688, 0x420019707cec2974, 0xc21031fe736ea169, 0x420f6b3003de3ddf, 0, 0, 0, 0, 0, ], [ 0x3fe20dd75042756b, 0x3c84ad9178b56910, 0xbfd20dd74feda9e8, 0xbc78141c70bbc8d6, 0x3fdb14c2cb128467, 0xbc709aebaa106821, 0xbff0ecf603921a0b, 0x3c97d3cb5bceaf0b, 0x400d9e3e1751ca59, 0x3c76622ae5642670, 0xc030a686af57f547, 0x3cc083b320aff6b6, 0x4056cf0b6c027326, 0xc0823afcb69443d3, 0x40b03ab450d9f1b9, 0xc0de74cdb76bcab4, 0x410c671b60e607f1, 0xc138f1376d324ce4, 0x4163b64276234676, 0xc18aff0ce13c5a8e, 0x41aef20247251e87, 0xc1cc9f5662f721f6, 0x41e4687858e185e1, 0xc1f4fa507be073c2, 0x41fb99ac35ee4acc, 0xc1f16cb585ee3fa9, 0, 0, 0, 0, ], [ 0x3fe20dd7503e730d, 0x3c84e524a098a467, 0xbfd20dd7498fa6b2, 0x3c260a4e27751c80, 0x3fdb14c061bd2a0c, 0x3c695a8f847d2fc2, 0xbff0ecd0f11b8c7d, 0xbc94126deea76061, 0x400d9b1344463548, 0x3cafe09a4eca9b0e, 0xc030996ea52a87ed, 0xbca924f920db26c0, 0x40567a2264b556b0, 0xc0815dfc2c86b6b5, 0x40accc291b62efe4, 0xc0d81375a78e746a, 0x41033a6f15546329, 0xc12c1e9dc1216010, 0x4152397ea3d43fda, 0xc174661e5b2ea512, 0x4193412367ca5d45, 0xc1ade56b9d7f37c4, 0x41c2851d9722146d, 0xc1d19027baf0c3fe, 0x41d7e7b8b6ab58ac, 0xc1d4c446d56aaf22, 0x41c1492190400505, 0, 0, 0, ], [ 0x3fe20dd74ff10852, 0x3c8a32f26deff875, 0xbfd20dd6f06c491c, 0x3c770c16e1793358, 0x3fdb14a7d5e7fd4a, 0x3c7479998b54db5b, 0xbff0ebbdb3889c5f, 0xbc759b853e11369c, 0x400d89dd249d7ef8, 0xbc84b5edf0c8c314, 0xc0306526fb386114, 0xbc840d04eed7c7e0, 0x40557ff657e429ce, 0xc07ef63e90d38630, 0x40a6d4f34c4ea3da, 0xc0d04542b9e36a54, 0x40f577bf19097738, 0xc119702fe47c736d, 0x413a7ae12b54fdc6, 0xc157ca3f0f7c4fa9, 0x417225d983963cbf, 0xc1871a6eac612f9e, 0x4198086324225e1e, 0xc1a3de68670a7716, 0x41a91674de4dcbe9, 0xc1a6b44cc15b76c2, 0x419a36dae0f30d80, 0xc17cffc1747ea3dc, 0, 0, ], [ 0x3fe20dd74ba8f300, 0xbc59dd256871d210, 0xbfd20dd3593675bc, 0x3c7ec0e7ffa91ad9, 0x3fdb13eef86a077a, 0xbc74fb5d78d411b8, 0xbff0e5cf52a11f3a, 0xbc851f36c779dc8c, 0x400d4417a08b39d5, 0x3c91be9fb5956638, 0xc02f91b9f6ce80c3, 0xbccc9c99dd42829c, 0x405356439f45bb43, 0xc078c0ca12819b48, 0x409efcad2ecd6671, 0xc0c21b0af6fc1039, 0x40e327d215ee30c9, 0xc101fabda96167b0, 0x411d82e4373b315d, 0xc134ed9e2ff591e9, 0x41495c85dcd8eab5, 0xc159f016f0a3d62a, 0x41660e89d918b96f, 0xc16e97be202cba64, 0x4170d8a081619793, 0xc16c5422b4fcfc65, 0x4161131a9dc6aed1, 0xc14a457d9dced257, 0x4123605e980e8b86, 0, ], [ 0x3fe20dd7319d4d25, 0x3c82b02992c3b7ab, 0xbfd20dc29c13ab1b, 0xbc7d78d79b4ad767, 0x3fdb115a57b5ab13, 0xbc6aa8c45be0aa2e, 0xbff0d58ec437efd7, 0xbc5994f00a15e850, 0x400cb1742e229f23, 0xbca8000471d54399, 0xc02d99a5edf7b946, 0xbcbaf76ed7e35cde, 0x4050a8b71058eb28, 0xc072d88289da5bfc, 0x40943ddf24168edb, 0xc0b3e9dfc38b6d1a, 0x40d18d4df97ab3df, 0xc0eb550fc62dcab5, 0x41029cb71f116ed1, 0xc115fc9cc4e854e3, 0x41265915fd0567b1, 0xc1335eb5fca0e46d, 0x413c5261ecc0d789, 0xc14138932dc4eafc, 0x414117d4eb18facd, 0xc13af96163e35eca, 0x4130454a3a63c766, 0xc11c2ebc1d39b44a, 0x40ff3327698e0e6b, 0xc0d094febc3dff35, ], ]; // Approximation for the fast path of exp(z) for z=zh+zl, // with |z| < 0.000130273 < 2^-12.88 and |zl| < 2^-42.6 // (assuming x^y does not overflow or underflow) #[inline] fn q_1(z_dd: DoubleDouble) -> DoubleDouble { const C: [u64; 5] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555995d37, 0x3fa55555558489dc, ]; let z = z_dd.to_f64(); let mut q = dd_fmla(f64::from_bits(C[4]), z_dd.hi, f64::from_bits(C[3])); q = dd_fmla(q, z, f64::from_bits(C[2])); let mut v = DoubleDouble::from_exact_add(f64::from_bits(C[1]), q * z); v = DoubleDouble::quick_mult(z_dd, v); DoubleDouble::f64_add(f64::from_bits(C[0]), v) } #[inline] fn exp_1(x: DoubleDouble) -> DoubleDouble { const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); /* |INVLOG2-2^12/log(2)| < 2^-43.4 */ let k = (x.hi * INVLOG2).round_ties_even(); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3bbabc9e3b39803f), f64::from_bits(0x3f262e42fefa39ef), ); let k_dd = DoubleDouble::quick_f64_mult(k, LOG2_DD); let mut y_dd = DoubleDouble::from_exact_add(x.hi - k_dd.hi, x.lo); y_dd.lo -= k_dd.lo; let ki: i64 = k as i64; /* Note: k is an integer, this is just a conversion. */ let mi = (ki >> 12).wrapping_add(0x3ff); let i2: i64 = (ki >> 6) & 0x3f; let i1: i64 = ki & 0x3f; let t1 = DoubleDouble::new( f64::from_bits(EXP_REDUCE_T0[i2 as usize].0), f64::from_bits(EXP_REDUCE_T0[i2 as usize].1), ); let t2 = DoubleDouble::new( f64::from_bits(EXP_REDUCE_T1[i1 as usize].0), f64::from_bits(EXP_REDUCE_T1[i1 as usize].1), ); let mut v = DoubleDouble::quick_mult(t2, t1); let q = q_1(y_dd); v = DoubleDouble::quick_mult(v, q); let scale = f64::from_bits((mi as u64) << 52); v.hi *= scale; v.lo *= scale; v } struct Exp { e: i32, result: DoubleDouble, } fn exp_accurate(x_dd: DoubleDouble) -> Exp { static E2: [u64; 28] = [ 0x3ff0000000000000, 0xb960000000000000, 0x3ff0000000000000, 0xb9be200000000000, 0x3fe0000000000000, 0x3a03c00000000000, 0x3fc5555555555555, 0x3c655555555c78d9, 0x3fa5555555555555, 0x3c455555545616e2, 0x3f81111111111111, 0x3c011110121fc314, 0x3f56c16c16c16c17, 0xbbef49e06ee3a56e, 0x3f2a01a01a01a01a, 0x3b6b053e1eeab9c0, 0x3efa01a01a01a01a, 0x3ec71de3a556c733, 0x3e927e4fb7789f66, 0x3e5ae64567f54abe, 0x3e21eed8eff8958b, 0x3de6124613837216, 0x3da93974aaf26a57, 0x3d6ae7f4fd6d0bd9, 0x3d2ae7e982620b25, 0x3ce94e4ca59460d8, 0x3ca69a2a4b7ef36d, 0x3c6abfe1602308c9, ]; const LOG2INV: f64 = f64::from_bits(0x3ff71547652b82fe); let k: i32 = (x_dd.hi * LOG2INV).round_ties_even() as i32; const LOG2_H: f64 = f64::from_bits(0x3fe62e42fefa39ef); /* we approximate LOG2Lacc ~ log(2) - LOG2H with 38 bits, so that k*LOG2Lacc is exact (k has at most 11 bits) */ const LOG2_L: f64 = f64::from_bits(0x3c7abc9e3b398000); const LOG2_TINY: f64 = f64::from_bits(0x398f97b57a079a19); let yh = dd_fmla(-k as f64, LOG2_H, x_dd.hi); /* since |xh+xl| >= 2.92 we have |k| >= 4; (|k|-1/2)*log(2) <= |x| <= (|k|+1/2)*log(2) thus 1-1/(2|k|) <= |x/(k*log(2))| <= 1+1/(2|k|) thus by Sterbenz theorem yh is exact too */ let mut t = DoubleDouble::from_full_exact_add(-k as f64 * LOG2_L, x_dd.lo); let mut y_dd = DoubleDouble::from_exact_add(yh, t.hi); y_dd.lo = dd_fmla(-k as f64, LOG2_TINY, y_dd.lo + t.lo); /* now yh+yl approximates xh + xl - k*log(2), and we approximate p(yh+yl) in h + l */ /* Since |xh| <= 742, we assume |xl| <= ulp(742) = 2^-43. Then since |k| <= round(742/log(2)) = 1070, |yl| <= 1070*LOG2L + 2^-42 < 2^-42.7. Since |yh| <= log(2)/2, the contribution of yl is negligible as long as |i*p[i]*yh^(i-1)*yl| < 2^-104, which holds for i >= 16. Thus for coefficients of degree 16 or more, we don't take yl into account. */ let mut h = f64::from_bits(E2[19 + 8]); // degree 19 for a in (16..=18).rev() { h = dd_fmla(h, y_dd.hi, f64::from_bits(E2[a + 8])); // degree i } /* degree 15: h*(yh+yl)+E2[15 + 8] */ t = DoubleDouble::from_exact_mult(h, y_dd.hi); t.lo = dd_fmla(h, y_dd.lo, t.lo); let mut v = DoubleDouble::from_exact_add(f64::from_bits(E2[15 + 8]), t.hi); v.lo += t.lo; for a in (8..=14).rev() { /* degree i: (h+l)*(yh+yl)+E2[i+8] */ t = DoubleDouble::quick_mult(v, y_dd); v = DoubleDouble::from_exact_add(f64::from_bits(E2[a + 8]), t.hi); v.lo += t.lo; } for a in (0..=7).rev() { /* degree i: (h+l)*(yh+yl)+E2[2i]+E2[2i+1] */ t = DoubleDouble::quick_mult(v, y_dd); v = DoubleDouble::from_exact_add(f64::from_bits(E2[2 * a]), t.hi); v.lo += t.lo + f64::from_bits(E2[2 * a + 1]); } Exp { e: k, result: v } } #[cold] fn erfc_asympt_accurate(x: f64) -> f64 { /* subnormal exceptions */ if x == f64::from_bits(0x403a8f7bfbd15495) { return dd_fmla( f64::from_bits(0x0000000000000001), -0.25, f64::from_bits(0x000667bd620fd95b), ); } let u_dd = DoubleDouble::from_exact_mult(x, x); let exp_result = exp_accurate(DoubleDouble::new(-u_dd.lo, -u_dd.hi)); /* compute 1/x as double-double */ let yh = 1.0 / x; /* Newton's iteration for 1/x is y -> y + y*(1-x*y) */ let yl = yh * dd_fmla(-x, yh, 1.0); // yh+yl approximates 1/x static THRESHOLD: [u64; 10] = [ 0x3fb4500000000000, 0x3fbe000000000000, 0x3fc3f00000000000, 0x3fc9500000000000, 0x3fcf500000000000, 0x3fd3100000000000, 0x3fd7100000000000, 0x3fdbc00000000000, 0x3fe0b00000000000, 0x3fe3000000000000, ]; let mut i = 0usize; while i < THRESHOLD.len() && yh > f64::from_bits(THRESHOLD[i]) { i += 1; } let p = ASYMPTOTIC_POLY_ACCURATE[i]; let mut u_dd = DoubleDouble::from_exact_mult(yh, yh); u_dd.lo = dd_fmla(2.0 * yh, yl, u_dd.lo); /* the polynomial p has degree 29+2i, and its coefficient of largest degree is p[14+6+i] */ let mut z_dd = DoubleDouble::new(0., f64::from_bits(p[14 + 6 + i])); for a in (13..=27 + 2 * i).rev().step_by(2) { /* degree j: (zh+zl)*(uh+ul)+p[(j-1)/2+6]] */ let v = DoubleDouble::quick_mult(z_dd, u_dd); z_dd = DoubleDouble::from_full_exact_add(f64::from_bits(p[(a - 1) / 2 + 6]), v.hi); z_dd.lo += v.lo; } for a in (1..=11).rev().step_by(2) { let v = DoubleDouble::quick_mult(z_dd, u_dd); z_dd = DoubleDouble::from_full_exact_add(f64::from_bits(p[a - 1]), v.hi); z_dd.lo += v.lo + f64::from_bits(p[a]); } /* multiply by yh+yl */ u_dd = DoubleDouble::quick_mult(z_dd, DoubleDouble::new(yl, yh)); /* now uh+ul approximates p(1/x), i.e., erfc(x)*exp(x^2) */ /* now multiply (uh+ul)*(eh+el), after normalizing uh+ul to reduce the number of exceptional cases */ u_dd = DoubleDouble::from_exact_add(u_dd.hi, u_dd.lo); let v = DoubleDouble::quick_mult(u_dd, exp_result.result); /* multiply by 2^e */ /* multiply by 2^e */ let mut res = ldexp(v.to_f64(), exp_result.e); if res < f64::from_bits(0x0010000000000000) { /* for erfc(x) in the subnormal range, we have to perform a special rounding */ let mut corr = v.hi - ldexp(res, -exp_result.e); corr += v.lo; /* add corr*2^e */ res += ldexp(corr, exp_result.e); } res } #[cold] fn erfc_accurate(x: f64) -> f64 { if x < 0. { let mut v_dd = erf_accurate(-x); let t = DoubleDouble::from_exact_add(1.0, v_dd.hi); v_dd.hi = t.hi; v_dd.lo += t.lo; return v_dd.to_f64(); } else if x <= f64::from_bits(0x3ffb59ffb450828c) { // erfc(x) >= 2^-6 let mut v_dd = erf_accurate(x); let t = DoubleDouble::from_exact_add(1.0, -v_dd.hi); v_dd.hi = t.hi; v_dd.lo = t.lo - v_dd.lo; return v_dd.to_f64(); } // now 0x1.b59ffb450828cp+0 < x < 0x1.b39dc41e48bfdp+4 erfc_asympt_accurate(x) } /* Fast path for 0x1.713786d9c7c09p+1 < x < 0x1.b39dc41e48bfdp+4, using the asymptotic formula erfc(x) = exp(-x^2) * p(1/x)*/ fn erfc_asympt_fast(x: f64) -> Erf { /* for x >= 0x1.9db1bb14e15cap+4, erfc(x) < 2^-970, and we might encounter underflow issues in the computation of l, thus we delegate this case to the accurate path */ if x >= f64::from_bits(0x4039db1bb14e15ca) { return Erf { err: 1.0, result: DoubleDouble::default(), }; } let mut u = DoubleDouble::from_exact_mult(x, x); let e_dd = exp_1(DoubleDouble::new(-u.lo, -u.hi)); /* the assumptions from exp_1 are satisfied: * a_mul ensures |ul| <= ulp(uh), thus |ul/uh| <= 2^-52 * since |x| < 0x1.9db1bb14e15cap+4 we have |ul| < ulp(0x1.9db1bb14e15cap+4^2) = 2^-43 */ /* eh+el approximates exp(-x^2) with maximal relative error 2^-74.139 */ /* compute 1/x as double-double */ let yh = 1.0 / x; /* Assume 1 <= x < 2, then 0.5 <= yh <= 1, and yh = 1/x + eps with |eps| <= 2^-53. */ /* Newton's iteration for 1/x is y -> y + y*(1-x*y) */ let yl = yh * dd_fmla(-x, yh, 1.0); /* x*yh-1 = x*(1/x+eps)-1 = x*eps with |x*eps| <= 2^-52, thus the error on the FMA is bounded by ulp(2^-52.1) = 2^-105. Now |yl| <= |yh| * 2^-52 <= 2^-52, thus the rounding error on yh * __builtin_fma (-x, yh, 1.0) is bounded also by ulp(2^-52.1) = 2^-105. From [6], Lemma 3.7, if yl was computed exactly, then yh+yl would differ from 1/x by at most yh^2/theta^3*(1/x-yh)^2 for some theta in [yh,1/x] or [1/x,yh]. Since yh, 1/x <= 1, this gives eps^2 <= 2^-106. Adding the rounding errors, we have: |yh + yl - 1/x| <= 2^-105 + 2^-105 + 2^-106 < 2^-103.67. For the relative error, since |yh| >= 1/2, this gives: |yh + yl - 1/x| < 2^-102.67 * |yh+yl| */ const THRESHOLD: [u64; 6] = [ 0x3fbd500000000000, 0x3fc59da6ca291ba6, 0x3fcbc00000000000, 0x3fd0c00000000000, 0x3fd3800000000000, 0x3fd6300000000000, ]; let mut i = 0usize; while i < THRESHOLD.len() && yh > f64::from_bits(THRESHOLD[i]) { i += 1; } let p = ASYMPTOTIC_POLY[i]; u = DoubleDouble::from_exact_mult(yh, yh); /* Since |yh| <= 1, we have |uh| <= 1 and |ul| <= 2^-53. */ u.lo = dd_fmla(2.0 * yh, yl, u.lo); /* uh+ul approximates (yh+yl)^2, with absolute error bounded by ulp(ul) + yl^2, where ulp(ul) is the maximal rounding error in the FMA, and yl^2 is the neglected term. Since |ul| <= 2^-53, ulp(ul) <= 2^-105, and since |yl| <= 2^-52, this yields |uh + ul - yh^2| <= 2^-105 + 2^-104 < 2^-103.41. For the relative error, since |(yh+yl)^2| >= 1/4: |uh + ul - yh^2| < 2^-101.41 * |uh+ul|. And relatively to 1/x^2: yh + yl = 1/x * (1 + eps1) with |eps1| < 2^-102.67 uh + ul = (yh+yl)^2 * (1 + eps2) with |eps2| < 2^-101.41 This yields: |uh + ul - 1/x| < 2^-100.90 * |uh+ul|. */ /* evaluate p(uh+ul) */ let mut zh: f64 = f64::from_bits(p[12]); // degree 23 zh = dd_fmla(zh, u.hi, f64::from_bits(p[11])); // degree 21 zh = dd_fmla(zh, u.hi, f64::from_bits(p[10])); // degree 19 /* degree 17: zh*(uh+ul)+p[i] */ let mut v = DoubleDouble::quick_f64_mult(zh, u); let mut z_dd = DoubleDouble::from_exact_add(f64::from_bits(p[9]), v.hi); z_dd.lo += v.lo; for a in (3..=15).rev().step_by(2) { v = DoubleDouble::quick_mult(z_dd, u); z_dd = DoubleDouble::from_exact_add(f64::from_bits(p[((a + 1) / 2) as usize]), v.hi); z_dd.lo += v.lo; } /* degree 1: (zh+zl)*(uh+ul)+p[0]+p[1] */ v = DoubleDouble::quick_mult(z_dd, u); z_dd = DoubleDouble::from_exact_add(f64::from_bits(p[0]), v.hi); z_dd.lo += v.lo + f64::from_bits(p[1]); /* multiply by yh+yl */ u = DoubleDouble::quick_mult(z_dd, DoubleDouble::new(yl, yh)); /* now uh+ul approximates p(1/x) */ /* now multiply (uh+ul)*(eh+el) */ v = DoubleDouble::quick_mult(u, e_dd); /* Write y = 1/x. We have the following errors: * the maximal mathematical error is: |erfc(x)*exp(x^2) - p(y)| < 2^-71.804 * |p(y)| (for i=3) thus |erfc(x) - exp(-x^2)*p(y)| < 2^-71.804 * |exp(-x^2)*p(y)| * the error in approximating exp(-x^2) by eh+el: |eh + el - exp(-x^2)| < 2^-74.139 * |eh + el| * the fact that we evaluate p on yh+yl instead of 1/x this error is bounded by |p'| * |yh+yl - 1/x|, where |yh+yl - 1/x| < 2^-102.67 * |yh+yl|, and the relative error is bounded by |p'/p| * |yh+yl - 1/x|. Since the maximal value of |p'/p| is bounded by 27.2 (for i=0), this yields 27.2 * 2^-102.67 < 2^-97.9 * the rounding errors when evaluating p on yh+yl: this error is bounded (relatively) by 2^-67.184 (for i=5), see analyze_erfc_asympt_fast() in erfc.sage * the rounding error in (uh+ul)*(eh+el): we assume this error is bounded by 2^-80 (relatively) This yields a global relative bound of: (1+2^-71.804)*(1+2^-74.139)*(1+2^-97.9)*(1+2^-67.184)*(1+2^-80)-1 < 2^-67.115 */ if v.hi >= f64::from_bits(0x044151b9a3fdd5c9) { Erf { err: f64::from_bits(0x3bbd900000000000) * v.hi, result: v, } /* 2^-67.115 < 0x1.d9p-68 */ } else { Erf { result: v, err: f64::from_bits(0x0010000000000000), } // this overestimates 0x1.d9p-68 * h } } #[inline] fn erfc_fast(x: f64) -> Erf { if x < 0. // erfc(x) = 1 - erf(x) = 1 + erf(-x) { let res = erf_fast(-x); /* h+l approximates erf(-x), with relative error bounded by err, where err <= 0x1.78p-69 */ let err = res.err * res.result.hi; /* convert into absolute error */ let mut t = DoubleDouble::from_exact_add(1.0, res.result.hi); t.lo += res.result.lo; // since h <= 2, the fast_two_sum() error is bounded by 2^-105*h <= 2^-104 /* After the fast_two_sum() call, we have |t| <= ulp(h) <= ulp(2) = 2^-51 thus assuming |l| <= 2^-51 after the cr_erf_fast() call, we have |t| <= 2^-50 here, thus the rounding error on t -= *l is bounded by ulp(2^-50) = 2^-102. The absolute error is thus bounded by err + 2^-104 + 2^-102 = err + 0x1.4p-102. The maximal value of err here is for |x| < 0.0625, where cr_erf_fast() returns 0x1.78p-69, and h=1/2, yielding err = 0x1.78p-70 here. Adding 0x1.4p-102 is thus exact. */ return Erf { err: err + f64::from_bits(0x3994000000000000), result: t, }; } else if x <= f64::from_bits(0x400713786d9c7c09) { let res = erf_fast(x); /* h+l approximates erf(x), with relative error bounded by err, where err <= 0x1.78p-69 */ let err = res.err * res.result.hi; /* convert into absolute error */ let mut t = DoubleDouble::from_exact_add(1.0, -res.result.hi); t.lo -= res.result.lo; /* for x >= 0x1.e861fbb24c00ap-2, erf(x) >= 1/2, thus 1-h is exact by Sterbenz theorem, thus t = 0 in fast_two_sum(), and we have t = -l here, thus the absolute error is err */ if x >= f64::from_bits(0x3fde861fbb24c00a) { return Erf { err, result: t }; } /* for x < 0x1.e861fbb24c00ap-2, the error in fast_two_sum() is bounded by 2^-105*h, and since h <= 1/2, this yields 2^-106. After the fast_two_sum() call, we have |t| <= ulp(h) <= ulp(1/2) = 2^-53 thus assuming |l| <= 2^-53 after the cr_erf_fast() call, we have |t| <= 2^-52 here, thus the rounding error on t -= *l is bounded by ulp(2^-52) = 2^-104. The absolute error is thus bounded by err + 2^-106 + 2^-104 The maximal value of err here is for x < 0.0625, where cr_erf_fast() returns 0x1.78p-69, and h=1/2, yielding err = 0x1.78p-70 here. Adding 0x1.4p-104 is thus exact. */ return Erf { err: err + f64::from_bits(0x3974000000000000), result: t, }; } /* Now THRESHOLD1 < x < 0x1.b39dc41e48bfdp+4 thus erfc(x) < 0.000046. */ /* on a i7-8700 with gcc 12.2.0, for x in [THRESHOLD1,+5.0], the average reciprocal throughput is about 111 cycles (among which 20 cycles for exp_1) */ erfc_asympt_fast(x) } /// Complementary error function /// /// Max ulp 0.5 pub fn f_erfc(x: f64) -> f64 { let t: u64 = x.to_bits(); let at: u64 = t & 0x7fff_ffff_ffff_ffff; if t >= 0x8000000000000000u64 // x = -NaN or x <= 0 (excluding +0) { // for x <= -0x1.7744f8f74e94bp2, erfc(x) rounds to 2 (to nearest) if t >= 0xc017744f8f74e94bu64 // x = NaN or x <= -0x1.7744f8f74e94bp2 { if t >= 0xfff0000000000000u64 { // -Inf or NaN if t == 0xfff0000000000000u64 { return 2.0; } // -Inf return x + x; // NaN } return black_box(2.0) - black_box(f64::from_bits(0x3c90000000000000)); // rounds to 2 or below(2) } // for -9.8390953768041405e-17 <= x <= 0, erfc(x) rounds to 1 (to nearest) if f64::from_bits(0xbc9c5bf891b4ef6a) <= x { return dd_fmla(-x, f64::from_bits(0x3c90000000000000), 1.0); } } else // x = +NaN or x >= 0 (excluding -0) { // for x >= 0x1.b39dc41e48bfdp+4, erfc(x) < 2^-1075: rounds to 0 or 2^-1074 if at >= 0x403b39dc41e48bfdu64 // x = NaN or x >= 0x1.b39dc41e48bfdp+4 { if at >= 0x7ff0000000000000u64 { // +Inf or NaN if at == 0x7ff0000000000000u64 { return 0.0; } // +Inf return x + x; // NaN } return black_box(f64::from_bits(0x0000000000000001)) * black_box(0.25); // 0 or 2^-1074 wrt rounding } // for 0 <= x <= 0x1.c5bf891b4ef6ap-55, erfc(x) rounds to 1 (to nearest) if x <= f64::from_bits(0x3c8c5bf891b4ef6a) { return dd_fmla(-x, f64::from_bits(0x3c90000000000000), 1.0); } } /* now -0x1.7744f8f74e94bp+2 < x < -0x1.c5bf891b4ef6ap-54 or 0x1.c5bf891b4ef6ap-55 < x < 0x1.b39dc41e48bfdp+4 */ let result = erfc_fast(x); let left = result.result.hi + (result.result.lo - result.err); let right = result.result.hi + (result.result.lo + result.err); if left == right { return left; } erfc_accurate(x) } #[cfg(test)] mod tests { use super::*; #[test] fn test_erfc() { assert_eq!(f_erfc(1.0), 0.15729920705028513); assert_eq!(f_erfc(0.5), 0.4795001221869535); assert_eq!(f_erfc(0.000000005), 0.9999999943581042); assert_eq!(f_erfc(-0.00000000000065465465423305), 1.0000000000007387); } } pxfm-0.1.23/src/err/erfcx.rs000064400000000000000000000404541046102023000137240ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::pow_exec::exp_dd_fast; #[inline] fn core_erfcx(x: f64) -> DoubleDouble { if x <= 8. { // Rational approximant for erfcx generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // coeffs=CoefficientList[num,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // coeffs=CoefficientList[den,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 12] = [ (0xbc836faeb9a312bb, 0x3ff000000000ee8e), (0x3c91842f891bec6a, 0x4002ca20a78aaf8f), (0x3c7916e8a1c30681, 0x4005e955f70aed5b), (0x3cabad150d828d82, 0x4000646f5807ad07), (0xbc6f482680d66d9c, 0x3ff1449e03ed381c), (0xbc7188796156ae19, 0x3fdaa7e997e3b034), (0xbc5c8af0642761e3, 0x3fbe836282058d4a), (0xbc372829be2d072f, 0x3f99a2b2adc2ec05), (0x3c020cc8b96000ab, 0x3f6e6cc3d120a955), (0x3bdd138e6c136806, 0x3f3743d6735eaf13), (0xbb9fbd22f0675122, 0x3ef1c1d36ebe29a2), (0xb89093cc981c934c, 0xbc43c18bc6385c74), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = x2 * x2; let x8 = x4 * x4; let e0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[1]), x, DoubleDouble::from_bit_pair(P[0]), ); let e1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[3]), x, DoubleDouble::from_bit_pair(P[2]), ); let e2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[5]), x, DoubleDouble::from_bit_pair(P[4]), ); let e3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[7]), x, DoubleDouble::from_bit_pair(P[6]), ); let e4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[9]), x, DoubleDouble::from_bit_pair(P[8]), ); let e5 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[11]), x, DoubleDouble::from_bit_pair(P[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); const Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc95d65be031374e, 0x400bd10c4fb1dbe5), (0x3cb2d8f661db08a0, 0x4016a649ff973199), (0x3ca32cbcfdc0ea93, 0x4016daab399c1ffc), (0xbca2982868536578, 0x400fd61ab892d14c), (0xbca2e29199e17fd9, 0x40001f56c4d495a3), (0x3c412ce623a1790a, 0x3fe852b582135164), (0x3c61152eaf4b0dc5, 0x3fcb760564da7cde), (0xbc1b57ff91d81959, 0x3fa6e146988df835), (0x3c17183d8445f19a, 0x3f7b06599b5e912f), (0xbbd0ada61b85ff98, 0x3f449e39467b73d0), (0xbb658d84fc735e67, 0x3eff794442532b51), ]; let e0 = DoubleDouble::mul_f64_add_f64( DoubleDouble::from_bit_pair(Q[1]), x, f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[3]), x, DoubleDouble::from_bit_pair(Q[2]), ); let e2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[5]), x, DoubleDouble::from_bit_pair(Q[4]), ); let e3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[7]), x, DoubleDouble::from_bit_pair(Q[6]), ); let e4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[9]), x, DoubleDouble::from_bit_pair(Q[8]), ); let e5 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[11]), x, DoubleDouble::from_bit_pair(Q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); return DoubleDouble::div(p_num, p_den); } // for large x erfcx(x) ~ 1/sqrt(pi) / x * R(1/x) const ONE_OVER_SQRT_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3c61ae3a914fed80, 0x3fe20dd750429b6d)); let r = DoubleDouble::from_quick_recip(x); // Rational approximant generated by Wolfram: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[num,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // coeffs=CoefficientList[den,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 9] = [ (0xbb1d2ee37e46a4cd, 0x3ff0000000000000), (0x3ca2e575a4ce3d30, 0x4001303ab00c8bac), (0xbccf38381e5ee521, 0x4030a97aeed54c9f), (0xbcc3a2842df0dd3d, 0x4036f7733c9fd2f9), (0xbcfeaf46506f16ed, 0x4051c5f382750553), (0x3ccbb9f5e11d176a, 0x404ac0081e0749e0), (0xbcf374f8966ae2a5, 0x4052082526d99a5c), (0x3cbb5530b924f224, 0x402feabbf6571c29), (0xbcbcdd50a3ca4776, 0x40118726e1f2d204), ]; const Q: [(u64, u64); 9] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ca2e4613c9e0017, 0x4001303ab00c8bac), (0xbcce5f17cf14e51d, 0x4031297aeed54c9f), (0xbcdf7e0fed176f92, 0x40380a76e7a09bb2), (0x3cfc57b67a2797af, 0x4053bb22e04faf3e), (0xbcd3e63b7410b46b, 0x404ff46317ae9483), (0xbce122c15db2653f, 0x405925ef8a428c36), (0x3ce174ebe3e52c8e, 0x4040f49acfe692e1), (0xbcda0e267ce6e2e6, 0x40351a07878bfbd3), ]; let mut p_num = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[8]), r, DoubleDouble::from_bit_pair(P[7]), ); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_add(p_num, r, DoubleDouble::from_bit_pair(P[0])); let mut p_den = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[8]), r, DoubleDouble::from_bit_pair(Q[7]), ); p_den = DoubleDouble::mul_add(p_den, r, DoubleDouble::from_bit_pair(Q[6])); p_den = DoubleDouble::mul_add(p_den, r, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_add(p_den, r, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_add(p_den, r, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_add(p_den, r, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_add(p_den, r, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_add_f64(p_den, r, f64::from_bits(0x3ff0000000000000)); let v0 = DoubleDouble::quick_mult(ONE_OVER_SQRT_PI, r); let v1 = DoubleDouble::div(p_num, p_den); DoubleDouble::quick_mult(v0, v1) } /// Scaled complementary error function (exp(x^2)*erfc(x)) pub fn f_erfcx(x: f64) -> f64 { let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff; if !x.is_normal() { if x.is_nan() { return f64::NAN; } if x == 0. { return 1.; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f64::INFINITY }; } } if x.to_bits() >= 0xc03aa449ebc84dd6 { // x <= -sqrt(709.783) ~ -26.6417 return f64::INFINITY; } if ax < 0x3cb0000000000000u64 { // |x| <= f64::EPSILON use crate::common::f_fmla; const M_TWO_OVER_SQRT_PI: DoubleDouble = DoubleDouble::from_bit_pair((0xbc71ae3a914fed80, 0xbff20dd750429b6d)); return f_fmla( M_TWO_OVER_SQRT_PI.lo, x, f_fmla(M_TWO_OVER_SQRT_PI.hi, x, 1.), ); } if ax <= 0x3ff0000000000000u64 { // |x| <= 1 // Rational approximant generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[num,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // coeffs=CoefficientList[den,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 11] = [ (0xbb488611350b1950, 0x3ff0000000000000), (0xbc86ae482c7f2342, 0x3ff9c5d39e89602f), (0x3c6702d70b807254, 0x3ff5a4c406d6468b), (0x3c7fe41fc43cfed5, 0x3fe708e7f401bd0c), (0x3c73a4a355172c6d, 0x3fd0d9a0c1a7126c), (0x3c5f4c372faa270f, 0x3fb154722e30762e), (0xbc04c0227976379e, 0x3f88ecebb62ce646), (0xbbdc9ea151b9eb33, 0x3f580ea84143877b), (0xbb6dae7001a91491, 0x3f1c3c5f95579b0a), (0x3b6aca5e82c52897, 0x3ecea4db51968d9e), (0x3a41c4edd175d2af, 0x3dbc0dccea7fc8ed), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = x2 * x2; let x8 = x4 * x4; let q0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[1]), x, DoubleDouble::from_bit_pair(P[0]), ); let q1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[3]), x, DoubleDouble::from_bit_pair(P[2]), ); let q2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[5]), x, DoubleDouble::from_bit_pair(P[4]), ); let q3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[7]), x, DoubleDouble::from_bit_pair(P[6]), ); let q4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[9]), x, DoubleDouble::from_bit_pair(P[8]), ); let r0 = DoubleDouble::mul_add(x2, q1, q0); let r1 = DoubleDouble::mul_add(x2, q3, q2); let s0 = DoubleDouble::mul_add(x4, r1, r0); let s1 = DoubleDouble::mul_add(x2, DoubleDouble::from_bit_pair(P[10]), q4); let p_num = DoubleDouble::mul_add(x8, s1, s0); const Q: [(u64, u64); 11] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc7bae414cad99c8, 0x4005e9d57765fdce), (0x3c8fa553bed15758, 0x400b8c670b3fbcda), (0x3ca6c7ad610f1019, 0x4004f2ca59958153), (0x3c87787f336cc4e6, 0x3ff55c267090315a), (0xbc6ef55d4b2c4150, 0x3fde8b84b64b6f4e), (0x3c570d63c94be3a3, 0x3fbf0d5e36017482), (0x3c1882a745ef572e, 0x3f962f73633506c1), (0xbc0850bb6fc82764, 0x3f65593e0dc46acd), (0xbbb9dc0097d7d776, 0x3f290545603e2f94), (0xbb776e5781e3889d, 0x3edb29c49d18cf89), ]; let q0 = DoubleDouble::mul_f64_add_f64( DoubleDouble::from_bit_pair(Q[1]), x, f64::from_bits(0x3ff0000000000000), ); let q1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[3]), x, DoubleDouble::from_bit_pair(Q[2]), ); let q2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[5]), x, DoubleDouble::from_bit_pair(Q[4]), ); let q3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[7]), x, DoubleDouble::from_bit_pair(Q[6]), ); let q4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[9]), x, DoubleDouble::from_bit_pair(Q[8]), ); let r0 = DoubleDouble::mul_add(x2, q1, q0); let r1 = DoubleDouble::mul_add(x2, q3, q2); let s0 = DoubleDouble::mul_add(x4, r1, r0); let s1 = DoubleDouble::mul_add(x2, DoubleDouble::from_bit_pair(Q[10]), q4); let p_den = DoubleDouble::mul_add(x8, s1, s0); let v = DoubleDouble::div(p_num, p_den); return v.to_f64(); } let mut erfcx_abs_x = core_erfcx(f64::from_bits(ax)); if x < 0. { // exp(x^2)erfc(-x) = 2*exp(x^2) - erfcx(|x|) erfcx_abs_x = DoubleDouble::from_exact_add(erfcx_abs_x.hi, erfcx_abs_x.lo); let d2x = DoubleDouble::from_exact_mult(x, x); let expd2x = exp_dd_fast(d2x); return DoubleDouble::mul_f64_add(expd2x, 2., -erfcx_abs_x).to_f64(); } erfcx_abs_x.to_f64() } #[cfg(test)] mod tests { use crate::f_erfcx; #[test] fn test_erfcx() { assert_eq!(f_erfcx(-9.4324165432), 8.718049147018359e38); assert_eq!(f_erfcx(9.4324165432), 0.059483265496416374); assert_eq!(f_erfcx(-1.32432512125), 11.200579112797806); assert_eq!(f_erfcx(1.32432512125), 0.3528722004785406); assert_eq!(f_erfcx(-0.532431235), 2.0560589406595384); assert_eq!(f_erfcx(0.532431235), 0.5994337293294584); assert_eq!(f_erfcx(1e-26), 1.0); assert_eq!(f_erfcx(-173.), f64::INFINITY); assert_eq!(f_erfcx(-0.500000000023073), 1.952360489253639); assert_eq!(f_erfcx(-175.), f64::INFINITY); assert_eq!(f_erfcx(f64::INFINITY), 0.); assert_eq!(f_erfcx(f64::NEG_INFINITY), f64::INFINITY); assert!(f_erfcx(f64::NAN).is_nan()); } } pxfm-0.1.23/src/err/erfcxf.rs000064400000000000000000000216441046102023000140720ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::exponents::core_expdf; use crate::polyeval::{f_estrin_polyeval8, f_polyeval6}; #[inline] fn core_erfcx(x: f32) -> f64 { // x here is already always > 1 let dx = x as f64; if x < 8. { // Rational approximant generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // coeffs=CoefficientList[num,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // coeffs=CoefficientList[den,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval8( dx, f64::from_bits(0x3ff00000804c8f8f), f64::from_bits(0x3ffb7307ea8fdbeb), f64::from_bits(0x3ff7081ba7bc735c), f64::from_bits(0x3fe767338b33532a), f64::from_bits(0x3fce3c8288507fd6), f64::from_bits(0x3fa7ca2cb4ae697f), f64::from_bits(0x3f72b11b0dfb2348), f64::from_bits(0xbd9f64f0c15c479b), ); let p_den = f_estrin_polyeval8( dx, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4006c071e850132e), f64::from_bits(0x400d30326bc347ee), f64::from_bits(0x40060d8d56bada75), f64::from_bits(0x3ff56643fc4580eb), f64::from_bits(0x3fdb0e194e72a513), f64::from_bits(0x3fb5154759b61be3), f64::from_bits(0x3f8090b063cce524), ); return p_num / p_den; } // for large x erfcx(x) ~ 1/sqrt(pi) / x * R(1/x) const ONE_OVER_SQRT_PI: f64 = f64::from_bits(0x3fe20dd750429b6d); let r = 1. / dx; // Rational approximant generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[num,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // coeffs=CoefficientList[den,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval6( r, f64::from_bits(0x3ff0000000000002), f64::from_bits(0xbfd09caf2bb541c3), f64::from_bits(0x40132238367ae454), f64::from_bits(0xc0060bc62c3711b1), f64::from_bits(0x40024a90d229158d), f64::from_bits(0xc0013665d8ff3813), ); let p_den = f_polyeval6( r, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfd09caf2bb5101d), f64::from_bits(0x4015223836772f2c), f64::from_bits(0xc00715911b5f5f5c), f64::from_bits(0x4010b66411ec4e1f), f64::from_bits(0xc00b325c767ed436), ); (r * ONE_OVER_SQRT_PI) * (p_num / p_den) } /// Scaled complementary error function (exp(x^2)*erfc(x)) /// /// ulp 0.5 pub fn f_erfcxf(x: f32) -> f32 { let ax = x.to_bits() & 0x7fff_ffff; if !x.is_normal() { if x.is_nan() { return f32::NAN; } if x == 0. { return 1.; } if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f32::INFINITY }; } } if x <= -9.382415 { // x <= -9.382415 return f32::INFINITY; } if ax <= 0x34000000u32 { // |x| < ulp(1) we use taylor series at 0 // erfcx(x) ~ 1-(2 x)/Sqrt[\[Pi]]+x^2-(4 x^3)/(3 Sqrt[\[Pi]])+x^4/2-(8 x^5)/(15 Sqrt[\[Pi]])+O[x]^6 #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; const M_TWO_OVER_SQRT_PI: f32 = f32::from_bits(0xbf906ebb); return f_fmlaf(x, M_TWO_OVER_SQRT_PI, 1.); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::common::f_fmla; const M_TWO_OVER_SQRT_PI: f64 = f64::from_bits(0xbff20dd750429b6d); let dx = x as f64; return f_fmla(dx, M_TWO_OVER_SQRT_PI, 1.) as f32; } } if ax <= 0x3f800000u32 { // |x| <= 1 let dx = x as f64; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[num,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // coeffs=CoefficientList[den,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval8( dx, f64::from_bits(0x3feffffffffffff8), f64::from_bits(0x3ff26c328bd2dc5f), f64::from_bits(0x3fe6f91b9fa5f58c), f64::from_bits(0x3fd09edf3fcf5ee1), f64::from_bits(0x3faddb3bcedbff91), f64::from_bits(0x3f7e43b5dd4b7587), f64::from_bits(0x3f3baab6b3e61d7b), f64::from_bits(0xbe83e7d629825321), ); let p_den = f_estrin_polyeval8( dx, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x40023d04ee0abc28), f64::from_bits(0x400252b377263d61), f64::from_bits(0x3ff510af7f826479), f64::from_bits(0x3fddfc089c4731ed), f64::from_bits(0x3fba79b040e28b0a), f64::from_bits(0x3f8aea2f3579235a), f64::from_bits(0x3f485d2875b4f88c), ); return (p_num / p_den) as f32; } let erfcx_abs_x = core_erfcx(f32::from_bits(ax)); if x < 0. { // exp(x^2)erfc(-x) = 2*exp(x^2) - erfcx(|x|) let dx = x as f64; return f_fmla(2., core_expdf(dx * dx), -erfcx_abs_x) as f32; } erfcx_abs_x as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_erfcx() { assert_eq!(f_erfcxf(12.1), 0.046469606); assert_eq!(f_erfcxf(7.1), 0.07869752); assert_eq!(f_erfcxf(1.1), 0.40173045); assert_eq!(f_erfcxf(-0.23), 1.3232007); assert_eq!(f_erfcxf(-1.4325), 15.234794); assert_eq!(f_erfcxf(-10.), f32::INFINITY); assert_eq!(f_erfcxf(f32::INFINITY), 0.); assert_eq!(f_erfcxf(f32::NEG_INFINITY), f32::INFINITY); assert!(f_erfcxf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/err/erff.rs000064400000000000000000000253251046102023000135370ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; // Polynomials approximating erf(x)/x on ( k/8, (k + 1)/8 ) generated by Sollya // with: // > P = fpminimax(erf(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|D...|], // [k/8, (k + 1)/8]); // for k = 0..31. static COEFFS: [[u64; 8]; 32] = [ [ 0x3ff20dd750429b6d, 0xbfd812746b037753, 0x3fbce2f219e8596a, 0xbf9b82cdacb78fda, 0x3f756479297dfda5, 0xbf48b3ac5455ef02, 0xbf7126fcac367e3b, 0x3fb2d0bdb3ba4984, ], [ 0x3ff20dd750429b6d, 0xbfd812746b0379a8, 0x3fbce2f21a03cf2a, 0xbf9b82ce30de083e, 0x3f7565bcad3eb60f, 0xbf4c02c66f659256, 0x3f1f92f673385229, 0xbeedef402648ae90, ], [ 0x3ff20dd750429b34, 0xbfd812746b032dce, 0x3fbce2f219d84aae, 0xbf9b82ce22dcf139, 0x3f7565b9efcd4af1, 0xbf4c021f1af414bc, 0x3f1f7c6d177eff82, 0xbeec9e4410dcf865, ], [ 0x3ff20dd750426eab, 0xbfd812746ae592c7, 0x3fbce2f211525f14, 0xbf9b82ccc125e63f, 0x3f756596f261cfd3, 0xbf4bfde1ff8eeecf, 0x3f1f31a9d15dc5d8, 0xbeea5a4362844b3c, ], [ 0x3ff20dd75039c705, 0xbfd812746777e74d, 0x3fbce2f17af98a1b, 0xbf9b82be4b817cbe, 0x3f7564bec2e2962e, 0xbf4bee86f9da3558, 0x3f1e9443689dc0cc, 0xbee79c0f230805d8, ], [ 0x3ff20dd74f811211, 0xbfd81274371a3e8f, 0x3fbce2ec038262e5, 0xbf9b8265b82c5e1f, 0x3f75615a2e239267, 0xbf4bc63ae023dceb, 0x3f1d87c2102f7e06, 0xbee49584bea41d62, ], [ 0x3ff20dd746d063e3, 0xbfd812729a8a950f, 0x3fbce2cb0a2df232, 0xbf9b80eca1f51278, 0x3f75572e26c46815, 0xbf4b715e5638b65e, 0x3f1bfbb195484968, 0xbee177a565c15c52, ], [ 0x3ff20dd701b44486, 0xbfd812691145f237, 0x3fbce23a06b8cfd9, 0xbf9b7c1dc7245288, 0x3f753e92f7f397dd, 0xbf4ad97cc4acf0b2, 0x3f19f028b2b09b71, 0xbedcdc4da08da8c1, ], [ 0x3ff20dd5715ac332, 0xbfd8123e680bd0eb, 0x3fbce0457aded691, 0xbf9b6f52d52bed40, 0x3f750c291b84414c, 0xbf49ea246b1ad4a9, 0x3f177654674e0ca0, 0xbed737c11a1bcebb, ], [ 0x3ff20dce6593e114, 0xbfd811a59c02eadc, 0x3fbcdab53c7cd7d5, 0xbf9b526d2e321eed, 0x3f74b1d32cd8b994, 0xbf48963143ec0a1e, 0x3f14ad5700e4db91, 0xbed231e100e43ef2, ], [ 0x3ff20db48bfd5a62, 0xbfd80fdd84f9e308, 0x3fbccd340d462983, 0xbf9b196a29287680, 0x3f74210c2c13a0f7, 0xbf46dbdfb4ff71ae, 0x3f11bca2d17fbd71, 0xbecbca36f90c7cf5, ], [ 0x3ff20d64b2f8f508, 0xbfd80b4d4f19fa8b, 0x3fbcb088197262e3, 0xbf9ab51fd02e5b99, 0x3f734e1e5e81a632, 0xbf44c66377b502ce, 0x3f0d9ad25066213c, 0xbec4b0df7dd0cfa1, ], [ 0x3ff20c8fc1243576, 0xbfd8010cb2009e27, 0x3fbc7a47e9299315, 0xbf9a155be5683654, 0x3f7233502694997b, 0xbf426c94b7d81300, 0x3f08094f1de25fb9, 0xbebe0e3d776c6eef, ], [ 0x3ff20a9bd1611bc1, 0xbfd7ec7fbce83f90, 0x3fbc1d757d7317b7, 0xbf992c160cd589f0, 0x3f70d307269cc5c2, 0xbf3fda5b0d2d1879, 0x3f02fdd7b3b14a7f, 0xbeb54eed4a26af5a, ], [ 0x3ff20682834f943d, 0xbfd7c73f747bf5a9, 0x3fbb8c2db4a9ffd1, 0xbf97f0e4ffe989ec, 0x3f6e7061eae4166e, 0xbf3ad36e873fff2d, 0x3efd39222396128e, 0xbead83dacec5ea6b, ], [ 0x3ff1feb8d12676d7, 0xbfd7898347284afe, 0x3fbaba3466b34451, 0xbf9663adc573e2f9, 0x3f6ae99fb17c3e08, 0xbf3602f950ad5535, 0x3ef5e9717490609d, 0xbea3fca107bbc8d5, ], [ 0x3ff1f12fe3c536fa, 0xbfd72b1d1f22e6d3, 0x3fb99fc0eed4a896, 0xbf948db0a87bd8c6, 0x3f673e368895aa61, 0xbf319b35d5301fc8, 0x3ef007987e4bb033, 0xbe9a7edcd4c2dc70, ], [ 0x3ff1db7b0df84d5d, 0xbfd6a4e4a41cde02, 0x3fb83bbded16455d, 0xbf92809b3b36977e, 0x3f639c08bab44679, 0xbf2b7b45a70ed119, 0x3ee6e99b36410e7b, 0xbe913619bb7ebc0c, ], [ 0x3ff1bb1c85c4a527, 0xbfd5f23b99a249a3, 0x3fb694c91fa0d12c, 0xbf9053e1ce11c72d, 0x3f602bf72c50ea78, 0xbf24f478fb56cb02, 0x3ee005f80ecbe213, 0xbe85f2446bde7f5b, ], [ 0x3ff18dec3bd51f9d, 0xbfd5123f58346186, 0x3fb4b8a1ca536ab4, 0xbf8c4243015cc723, 0x3f5a1a8a01d351ef, 0xbf1f466b34f1d86b, 0x3ed5f835eea0bf6a, 0xbe7b83165b939234, ], [ 0x3ff152804c3369f4, 0xbfd4084cd4afd4bc, 0x3fb2ba2e836e47aa, 0xbf8800f2dfc6904b, 0x3f54a6daf0669c59, 0xbf16e326ab872317, 0x3ecd9761a6a755a5, 0xbe70fca33f9dd4b5, ], [ 0x3ff1087ad68356aa, 0xbfd2dbb044707459, 0x3fb0aea8ceaa0384, 0xbf840b516d52b3d2, 0x3f500c9e05f01d22, 0xbf1076afb0dc0ff7, 0x3ec39fadec400657, 0xbe64b5761352e7e3, ], [ 0x3ff0b0a7a8ba4a22, 0xbfd196990d22d4a1, 0x3fad5551e6ac0c4d, 0xbf807cce1770bd1a, 0x3f4890347b8848bf, 0xbf0757ec96750b6a, 0x3eb9b258a1e06bce, 0xbe58fc6d22da7572, ], [ 0x3ff04ce2be70fb47, 0xbfd0449e4b0b9cac, 0x3fa97f7424f4b0e7, 0xbf7ac825439c42f4, 0x3f428f5f65426dfb, 0xbf005b699a90f90f, 0x3eb0a888eecf4593, 0xbe4deace2b32bb31, ], [ 0x3fefbf9fb0e11cc8, 0xbfcde2640856545a, 0x3fa5f5b1f47f8510, 0xbf7588bc71eb41b9, 0x3f3bc6a0a772f56d, 0xbef6b9fad1f1657a, 0x3ea573204ba66504, 0xbe41d38065c94e44, ], [ 0x3feed8f18c99e031, 0xbfcb4cb6acd903b4, 0x3fa2c7f3dddd6fc1, 0xbf713052067df4e0, 0x3f34a5027444082f, 0xbeef672bab0e2554, 0x3e9b83c756348cc9, 0xbe3534f1a1079499, ], [ 0x3fedebd33044166d, 0xbfc8d7cd9053f7d8, 0x3f9ff9957fb3d6e7, 0xbf6b50be55de0f36, 0x3f2e92c8ec53a628, 0xbee5a4b88d508007, 0x3e91a27737559e26, 0xbe2942ae62cb2c14, ], [ 0x3fecfdbf0386f3bd, 0xbfc68e33d93b0dc4, 0x3f9b2683d58f53de, 0xbf65a9174e70d26f, 0x3f269ddd326d49cd, 0xbeddd8f397a8219c, 0x3e86a755016ad4dd, 0xbe1e366e0139187d, ], [ 0x3fec132adb8d7464, 0xbfc475a899f61b46, 0x3f970a431397a77c, 0xbf612e3d35beeee2, 0x3f20c16b05738333, 0xbed4a47f873e144e, 0x3e7d3d494c698c02, 0xbe12302c59547fe5, ], [ 0x3feb2f5fd05555e7, 0xbfc28feefbe03ec7, 0x3f93923acbb3a676, 0xbf5b4ff793cd6358, 0x3f18ea0eb8c913bc, 0xbeccb31ec2baceb1, 0x3e730011e7e80c04, 0xbe0617710635cb1d, ], [ 0x3fea54853cd9593e, 0xbfc0dbdbaea4dc8e, 0x3f90a93e2c20a0fd, 0xbf55c969ff401ea8, 0x3f129e0cc64fe627, 0xbec4160d8e9d3c2a, 0x3e68e7b67594624a, 0xbdfb1cf2c975b09b, ], [ 0x3fe983ceece09ff8, 0xbfbeacc78f7a2d00, 0x3f8c74418410655f, 0xbf51756a050e441e, 0x3f0bff3650f7f548, 0xbebc56c0217d3ada, 0x3e607b4918d0b489, 0xbdf0d4be8c1c50f8, ], ]; /// Error function /// /// Max ulp 0.5 #[inline] pub fn f_erff(x: f32) -> f32 { let x_u = x.to_bits(); let x_abs = x_u & 0x7fff_ffffu32; if x_abs >= 0x4080_0000u32 { static ONE: [f32; 2] = [1.0, -1.0]; static SMALL: [f32; 2] = [f32::from_bits(0xb3000000), f32::from_bits(0x33000000)]; let sign = x.is_sign_negative() as usize; if x_abs >= 0x7f80_0000u32 { return if x_abs > 0x7f80_0000 { x } else { ONE[sign] }; } return ONE[sign] + SMALL[sign]; } // Polynomial approximation: // erf(x) ~ x * (c0 + c1 * x^2 + c2 * x^4 + ... + c7 * x^14) let xd = x as f64; let xsq = xd * xd; const EIGHT: u32 = 3 << 23; let idx = f32::from_bits(x_abs.wrapping_add(EIGHT)) as usize; let c = COEFFS[idx]; let x4 = xsq * xsq; let c0 = f_fmla(xsq, f64::from_bits(c[1]), f64::from_bits(c[0])); let c1 = f_fmla(xsq, f64::from_bits(c[3]), f64::from_bits(c[2])); let c2 = f_fmla(xsq, f64::from_bits(c[5]), f64::from_bits(c[4])); let c3 = f_fmla(xsq, f64::from_bits(c[7]), f64::from_bits(c[6])); let x8 = x4 * x4; let p0 = f_fmla(x4, c1, c0); let p1 = f_fmla(x4, c3, c2); (xd * f_fmla(x8, p1, p0)) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_erff_test() { assert_eq!(f_erff(0.0), 0.0); assert_eq!(f_erff(1.0), 0.8427008); assert_eq!(f_erff(0.5), 0.5204999); } } pxfm-0.1.23/src/err/erffc.rs000064400000000000000000000244161046102023000137020ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use std::hint::black_box; static ERR0: [u64; 128] = [ 0x3ff0000000000000, 0x3ff0163da9fb3335, 0x3ff02c9a3e778061, 0x3ff04315e86e7f85, 0x3ff059b0d3158574, 0x3ff0706b29ddf6de, 0x3ff0874518759bc8, 0x3ff09e3ecac6f383, 0x3ff0b5586cf9890f, 0x3ff0cc922b7247f7, 0x3ff0e3ec32d3d1a2, 0x3ff0fb66affed31b, 0x3ff11301d0125b51, 0x3ff12abdc06c31cc, 0x3ff1429aaea92de0, 0x3ff15a98c8a58e51, 0x3ff172b83c7d517b, 0x3ff18af9388c8dea, 0x3ff1a35beb6fcb75, 0x3ff1bbe084045cd4, 0x3ff1d4873168b9aa, 0x3ff1ed5022fcd91d, 0x3ff2063b88628cd6, 0x3ff21f49917ddc96, 0x3ff2387a6e756238, 0x3ff251ce4fb2a63f, 0x3ff26b4565e27cdd, 0x3ff284dfe1f56381, 0x3ff29e9df51fdee1, 0x3ff2b87fd0dad990, 0x3ff2d285a6e4030b, 0x3ff2ecafa93e2f56, 0x3ff306fe0a31b715, 0x3ff32170fc4cd831, 0x3ff33c08b26416ff, 0x3ff356c55f929ff1, 0x3ff371a7373aa9cb, 0x3ff38cae6d05d866, 0x3ff3a7db34e59ff7, 0x3ff3c32dc313a8e5, 0x3ff3dea64c123422, 0x3ff3fa4504ac801c, 0x3ff4160a21f72e2a, 0x3ff431f5d950a897, 0x3ff44e086061892d, 0x3ff46a41ed1d0057, 0x3ff486a2b5c13cd0, 0x3ff4a32af0d7d3de, 0x3ff4bfdad5362a27, 0x3ff4dcb299fddd0d, 0x3ff4f9b2769d2ca7, 0x3ff516daa2cf6642, 0x3ff5342b569d4f82, 0x3ff551a4ca5d920f, 0x3ff56f4736b527da, 0x3ff58d12d497c7fd, 0x3ff5ab07dd485429, 0x3ff5c9268a5946b7, 0x3ff5e76f15ad2148, 0x3ff605e1b976dc09, 0x3ff6247eb03a5585, 0x3ff6434634ccc320, 0x3ff6623882552225, 0x3ff68155d44ca973, 0x3ff6a09e667f3bcd, 0x3ff6c012750bdabf, 0x3ff6dfb23c651a2f, 0x3ff6ff7df9519484, 0x3ff71f75e8ec5f74, 0x3ff73f9a48a58174, 0x3ff75feb564267c9, 0x3ff780694fde5d3f, 0x3ff7a11473eb0187, 0x3ff7c1ed0130c132, 0x3ff7e2f336cf4e62, 0x3ff80427543e1a12, 0x3ff82589994cce13, 0x3ff8471a4623c7ad, 0x3ff868d99b4492ed, 0x3ff88ac7d98a6699, 0x3ff8ace5422aa0db, 0x3ff8cf3216b5448c, 0x3ff8f1ae99157736, 0x3ff9145b0b91ffc6, 0x3ff93737b0cdc5e5, 0x3ff95a44cbc8520f, 0x3ff97d829fde4e50, 0x3ff9a0f170ca07ba, 0x3ff9c49182a3f090, 0x3ff9e86319e32323, 0x3ffa0c667b5de565, 0x3ffa309bec4a2d33, 0x3ffa5503b23e255d, 0x3ffa799e1330b358, 0x3ffa9e6b5579fdbf, 0x3ffac36bbfd3f37a, 0x3ffae89f995ad3ad, 0x3ffb0e07298db666, 0x3ffb33a2b84f15fb, 0x3ffb59728de5593a, 0x3ffb7f76f2fb5e47, 0x3ffba5b030a1064a, 0x3ffbcc1e904bc1d2, 0x3ffbf2c25bd71e09, 0x3ffc199bdd85529c, 0x3ffc40ab5fffd07a, 0x3ffc67f12e57d14b, 0x3ffc8f6d9406e7b5, 0x3ffcb720dcef9069, 0x3ffcdf0b555dc3fa, 0x3ffd072d4a07897c, 0x3ffd2f87080d89f2, 0x3ffd5818dcfba487, 0x3ffd80e316c98398, 0x3ffda9e603db3285, 0x3ffdd321f301b460, 0x3ffdfc97337b9b5f, 0x3ffe264614f5a129, 0x3ffe502ee78b3ff6, 0x3ffe7a51fbc74c83, 0x3ffea4afa2a490da, 0x3ffecf482d8e67f1, 0x3ffefa1bee615a27, 0x3fff252b376bba97, 0x3fff50765b6e4540, 0x3fff7bfdad9cbe14, 0x3fffa7c1819e90d8, 0x3fffd3c22b8f71f1, ]; static ERFC_COEFFS: [[u64; 16]; 2] = [ [ 0x3fec162355429b28, 0x400d99999999999a, 0x3fdda951cece2b85, 0xbff70ef6cff4bcc4, 0x4003d7f7b3d617de, 0xc009d0aa47537c51, 0x4009754ea9a3fcb1, 0xc0027a5453fcc015, 0x3ff1ef2e0531aeba, 0xbfceca090f5a1c06, 0xbfb7a3cd173a063c, 0x3fb30fa68a68fddd, 0x3f555ad9a326993a, 0xbf907e7b0bb39fbf, 0x3f52328706c0e950, 0x3f6d6aa0b7b19cfe, ], [ 0x401137c8983f8516, 0x400799999999999a, 0x3fc05b53aa241333, 0xbfca3f53872bf870, 0x3fbde4c30742c9d5, 0xbfacb24bfa591986, 0x3f9666aec059ca5f, 0xbf7a61250eb26b0b, 0x3f52b28b7924b34d, 0x3f041b13a9d45013, 0xbf16dd5e8a273613, 0x3ef09ce8ea5e8da5, 0x3ed33923b4102981, 0xbec1dfd161e3f984, 0xbe8c87618fcae3b3, 0x3e8e8a6ffa0ba2c7, ], ]; /// Complementary error function /// /// Max ULP 0.5 #[inline] pub fn f_erfcf(x: f32) -> f32 { let ax = f32::from_bits(x.to_bits() & 0x7fff_ffff); let axd = ax as f64; let x2 = axd * axd; let t = x.to_bits(); let at = t & 0x7fff_ffff; let sgn = t >> 31; let i: i64 = (at > 0x40051000) as i64; /* for x < -0x1.ea8f94p+1, erfc(x) rounds to 2 (to nearest) */ if t > 0xc07547cau32 { // x < -0x1.ea8f94p+1 if t >= 0xff800000u32 { // -Inf or NaN if t == 0xff800000u32 { return 2.0; } // -Inf return x + x; // NaN } return black_box(2.0) - black_box(f32::from_bits(0x33000000)); // rounds to 2 or nextbelow(2) } /* at is the absolute value of x for x >= 0x1.41bbf8p+3, erfc(x) < 2^-150, thus rounds to 0 or to 2^-149 depending on the rounding mode */ if at >= 0x4120ddfcu32 { // |x| >= 0x1.41bbf8p+3 if at >= 0x7f800000u32 { // +Inf or NaN if at == 0x7f800000u32 { return 0.0; } // +Inf return x + x; // NaN } // 0x1p-149f * 0.25f rounds to 0 or 2^-149 depending on rounding return black_box(f32::from_bits(0x00000001)) * black_box(0.25); } if at <= 0x3db80000u32 { // |x| <= 0x1.7p-4 if t == 0xb76c9f62u32 { // x = -0x1.d93ec4p-17 return black_box(f32::from_bits(0x3f800085)) + black_box(f32::from_bits(0x33000000)); // exceptional case } /* for |x| <= 0x1.c5bf88p-26. erfc(x) rounds to 1 (to nearest) */ if at <= 0x32e2dfc4u32 { // |x| <= 0x1.c5bf88p-26 if at == 0 { return 1.0; } static D: [f32; 2] = [f32::from_bits(0xb2800000), f32::from_bits(0x33000000)]; return 1.0 + D[sgn as usize]; } /* around 0, erfc(x) behaves as 1 - (odd polynomial) */ const C: [u64; 5] = [ 0x3ff20dd750429b6d, 0xbfd812746b03610b, 0x3fbce2f218831d2f, 0xbf9b82c609607dcb, 0x3f7553af09b8008e, ]; let fw0 = f_fmla(x2, f64::from_bits(C[4]), f64::from_bits(C[3])); let fw1 = f_fmla(x2, fw0, f64::from_bits(C[2])); let fw2 = f_fmla(x2, fw1, f64::from_bits(C[1])); let f0 = x as f64 * f_fmla(x2, fw2, f64::from_bits(C[0])); return (1.0 - f0) as f32; } /* now -0x1.ea8f94p+1 <= x <= 0x1.41bbf8p+3, with |x| > 0x1.7p-4 */ const ILN2: f64 = f64::from_bits(0x3ff71547652b82fe); const LN2H: f64 = f64::from_bits(0x3f762e42fefa0000); const LN2L: f64 = f64::from_bits(0x3d0cf79abd6f5dc8); let jt = dd_fmla(x2, ILN2, -(1024. + f64::from_bits(0x3f70000000000000))).to_bits(); let j: i64 = ((jt << 12) as i64) >> 48; let sf = ((j >> 7) as u64) .wrapping_add(0x3ffu64 | (sgn as u64) << 11) .wrapping_shl(52); const CH: [u64; 4] = [ 0xbfdffffffffff333, 0x3fc5555555556a14, 0xbfa55556666659b4, 0x3f81111074cc7b22, ]; let d = f_fmla(LN2L, j as f64, f_fmla(LN2H, j as f64, x2)); let d2 = d * d; let e0 = f64::from_bits(ERR0[(j & 127) as usize]); let fw0 = f_fmla(d, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let fw1 = f_fmla(d, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let fw2 = f_fmla(d2, fw0, fw1); let f = f_fmla(d2, fw2, d); let ct = ERFC_COEFFS[i as usize]; let z = (axd - f64::from_bits(ct[0])) / (axd + f64::from_bits(ct[1])); let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; let c = &ct[3..]; let sw0 = f_fmla(z, f64::from_bits(c[1]), f64::from_bits(c[0])); let sw1 = f_fmla(z, f64::from_bits(c[3]), f64::from_bits(c[2])); let sw2 = f_fmla(z, f64::from_bits(c[5]), f64::from_bits(c[4])); let sw3 = f_fmla(z, f64::from_bits(c[7]), f64::from_bits(c[6])); let zw0 = f_fmla(z2, sw1, sw0); let zw1 = f_fmla(z2, sw3, sw2); let sw4 = f_fmla(z, f64::from_bits(c[9]), f64::from_bits(c[8])); let sw5 = f_fmla(z, f64::from_bits(c[11]), f64::from_bits(c[10])); let zw2 = f_fmla(z4, zw1, zw0); let zw3 = f_fmla(z2, sw5, sw4); let zw4 = f_fmla(z4, f64::from_bits(c[12]), zw3); let mut s = f_fmla(z8, zw4, zw2); s = f_fmla(z, s, f64::from_bits(ct[2])); static OFF: [f64; 2] = [0., 2.]; let r = (f64::from_bits(sf) * f_fmla(-f, e0, e0)) * s; let y = OFF[sgn as usize] + r; y as f32 } #[cfg(test)] mod tests { use crate::f_erfcf; #[test] fn test_erfc() { assert_eq!(f_erfcf(0.0), 1.0); assert_eq!(f_erfcf(0.5), 0.47950011); assert_eq!(f_erfcf(1.0), 0.1572992); } } pxfm-0.1.23/src/err/inverf.rs000064400000000000000000000632531046102023000141100ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::fast_log_dd; use crate::polyeval::{f_polyeval4, f_polyeval5}; #[cold] fn inverf_0p06_to_0p75(x: f64) -> f64 { // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const P: [(u64, u64); 10] = [ (0xbc3e06eda42202a0, 0x3f93c2fc5d00e0c8), (0xbc6eb374406b33b4, 0xbfc76fcfd022e3ff), (0xbc857822d7ffd282, 0x3fe6f8443546010a), (0x3c68269c66dfb28a, 0xbff80996754ceb79), (0x3c543dce8990a9f9, 0x3ffcf778d5ef0504), (0xbc72fc55f73765f6, 0xbff433be821423d0), (0xbc66d05fb37c8592, 0x3fdf15f19e9d8da4), (0x3c56dfb85e83a2c5, 0xbfb770b6827e0829), (0x3bff1472ecdfa403, 0x3f7a98a2980282bb), (0x3baffb33d69d6276, 0xbf142a246fd2c07c), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let vz = DoubleDouble::full_add_f64(x2, -0.5625); let vx2 = vz * vz; let vx4 = vx2 * vx2; let vx8 = vx4 * vx4; let p0 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let p4 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let q0 = DoubleDouble::mul_add(vx2, p1, p0); let q1 = DoubleDouble::mul_add(vx2, p3, p2); let r0 = DoubleDouble::mul_add(vx4, q1, q0); let num = DoubleDouble::mul_add(vx8, p4, r0); // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const Q: [(u64, u64); 10] = [ (0xbc36337f24e57cb9, 0x3f92388d5d757e3a), (0xbc63dfae43d60e0b, 0xbfc6ca7da581358c), (0xbc77656389bd0e62, 0x3fe7c82ce417b4e0), (0xbc93679667bef2f0, 0xbffad58651fd1a51), (0x3ca2c6cb9eb17fb4, 0x4001bdb67e93a242), (0xbc9b58961ba253bc, 0xbffbdaeff6fbb81c), (0x3c7861f549c6aa61, 0x3fe91b12cf47da3a), (0xbc696dfd665b2f5e, 0xbfc7c5d0ffb7f1da), (0x3c1552b0ec0ba7b3, 0x3f939ada247f7609), (0xbbcaa226fb7b30a8, 0xbf41be65038ccfe6), ]; let p0 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[1]), DoubleDouble::from_bit_pair(Q[0]), ); let p1 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let p2 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let p3 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let p4 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let q0 = DoubleDouble::mul_add(vx2, p1, p0); let q1 = DoubleDouble::mul_add(vx2, p3, p2); let r0 = DoubleDouble::mul_add(vx4, q1, q0); let den = DoubleDouble::mul_add(vx8, p4, r0); let r = DoubleDouble::div(num, den); let k = DoubleDouble::quick_mult_f64(r, x); k.to_f64() } #[inline] fn inverf_asympt_small(z: DoubleDouble, zeta_sqrt: DoubleDouble, x: f64) -> f64 { // Generated in Wolfram Mathematica: // <90] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 11] = [ (0x3c936555853a8b2c, 0x3ff0001df06a2515), (0x3cea488e802db3c3, 0x404406ba373221da), (0xbce27d42419754e3, 0x407b0442e38a9597), (0xbd224a407624cbdf, 0x409c9277e31ef446), (0x3d4f16ce65d6fea0, 0x40aec3ec005b1d8a), (0x3d105bc37bc61b58, 0x40b46be8f860f4d9), (0x3d5ca133dcdecaa0, 0x40b3826e6a32dad7), (0x3d1d52013ba8aa38, 0x40aae93a603cf3ea), (0xbd07a75306df0fc3, 0x4098ab8357dc2e51), (0x3d1bb6770bb7a27e, 0x407ebead00879010), (0xbbfcbff4a9737936, 0x3f8936117ccbff83), ]; let z2 = DoubleDouble::quick_mult(z, z); let z4 = DoubleDouble::quick_mult(z2, z2); let z8 = DoubleDouble::quick_mult(z4, z4); let q0 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[1]), z, DoubleDouble::from_bit_pair(P[0]), ); let q1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[3]), z, DoubleDouble::from_bit_pair(P[2]), ); let q2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[5]), z, DoubleDouble::from_bit_pair(P[4]), ); let q3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[7]), z, DoubleDouble::from_bit_pair(P[6]), ); let q4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[9]), z, DoubleDouble::from_bit_pair(P[8]), ); let r0 = DoubleDouble::mul_add(z2, q1, q0); let r1 = DoubleDouble::mul_add(z2, q3, q2); let s0 = DoubleDouble::mul_add(z4, r1, r0); let s1 = DoubleDouble::mul_add(z2, DoubleDouble::from_bit_pair(P[10]), q4); let num = DoubleDouble::mul_add(z8, s1, s0); // See numerator generation above: // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const Q: [(u64, u64); 11] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc75b1109d4a3262, 0x40440782efaab17f), (0x3d1f7775b207d84f, 0x407b2da74b0d39f2), (0xbd3291fdbab49501, 0x409dac8d9e7c90b2), (0xbd58d8fdd27707a9, 0x40b178dfeffa3192), (0xbd57fc74ad705ce0, 0x40bad19b686f219f), (0x3d4075510031f2cd, 0x40be70a598208cea), (0xbd5442e109152efb, 0x40b9683ef36ae330), (0x3d5398192933962e, 0x40b04b7c4c3ca8ee), (0x3d2d04d03598e303, 0x409bd0080799fbf1), (0x3d2a988eb552ef44, 0x40815a46f12bafe3), ]; let q0 = DoubleDouble::mul_add_f64( DoubleDouble::from_bit_pair(Q[1]), z, f64::from_bits(0x3ff0000000000000), ); let q1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[3]), z, DoubleDouble::from_bit_pair(Q[2]), ); let q2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[5]), z, DoubleDouble::from_bit_pair(Q[4]), ); let q3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[7]), z, DoubleDouble::from_bit_pair(Q[6]), ); let q4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[9]), z, DoubleDouble::from_bit_pair(Q[8]), ); let r0 = DoubleDouble::mul_add(z2, q1, q0); let r1 = DoubleDouble::mul_add(z2, q3, q2); let s0 = DoubleDouble::mul_add(z4, r1, r0); let s1 = DoubleDouble::mul_add(z2, DoubleDouble::from_bit_pair(Q[10]), q4); let den = DoubleDouble::mul_add(z8, s1, s0); let r = DoubleDouble::div(num, den); let k = DoubleDouble::quick_mult(r, zeta_sqrt); f64::copysign(k.to_f64(), x) } // branch for |x| > 0.9999 for extreme tail #[cold] fn inverf_asympt_long(z: DoubleDouble, zeta_sqrt: DoubleDouble, x: f64) -> f64 { // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // Generated in Wolfram Mathematica: // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 14] = [ (0x3c97612f9b24a614, 0x3ff0000ba84cc7a5), (0xbcee8fe2da463412, 0x40515246546f5d88), (0x3d2fa4a2b891b526, 0x40956b6837159b11), (0x3d5d673ffad4f817, 0x40c5a1aa3be58652), (0x3d8867a1e5506f88, 0x40e65ebb1e1e7c75), (0xbd9bbc0764ed8f5b, 0x40fd2064a652e5c2), (0xbda78e569c0d237f, 0x410a385c627c461c), (0xbdab3123ebc465d7, 0x4110f05ca2b65fe5), (0x3d960def35955192, 0x4110bb079af2fe08), (0xbd97904816054836, 0x410911c24610c11c), (0xbd937745e9192593, 0x40fc603244adca35), (0xbd65fbc476d63050, 0x40e6399103188c21), (0xbd61016ef381cce6, 0x40c6482b44995b89), (0x3c326105c49e5a1a, 0xbfab44bd8b4e3138), ]; let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; let g0 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let g1 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let g2 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let g3 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let g4 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let g5 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let g6 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[13]), DoubleDouble::from_bit_pair(P[12]), ); let h0 = DoubleDouble::mul_add(z2, g1, g0); let h1 = DoubleDouble::mul_add(z2, g3, g2); let h2 = DoubleDouble::mul_add(z2, g5, g4); let q0 = DoubleDouble::mul_add(z4, h1, h0); let q1 = DoubleDouble::mul_add(z4, g6, h2); let num = DoubleDouble::mul_add(z8, q1, q0); // See numerator generation above: // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const Q: [(u64, u64); 14] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcfc7b886ee61417, 0x405152838f711f3c), (0xbd33f933c14e831a, 0x409576cb78cab36e), (0x3d33fb09e2c4898a, 0x40c5e8a2c7602ced), (0x3d7be430c664bf7e, 0x40e766fdc8c7638c), (0x3dac662e74cdfc0e, 0x4100276b5f47b5f1), (0x3da67d06e82a8495, 0x410f843887f8a24a), (0x3dbbf2e22fc2550a, 0x4116d04271703e08), (0xbdb2fb3aed100853, 0x4119aff4ed32b74b), (0x3dba75e7b7171c3c, 0x4116b5eb8bf386bd), (0x3dab2d8b8c1937eb, 0x410f71c38e84cb34), (0xbda4e2e8a50b7370, 0x4100ca04b0f36b94), (0xbd86ed6df34fdaf9, 0x40e9151ded4cf4b7), (0x3d6938ea702c0328, 0x40c923ee1ab270c4), ]; let g0 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[1]), DoubleDouble::from_bit_pair(Q[0]), ); let g1 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let g2 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let g3 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let g4 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let g5 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let g6 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[13]), DoubleDouble::from_bit_pair(Q[12]), ); let h0 = DoubleDouble::mul_add(z2, g1, g0); let h1 = DoubleDouble::mul_add(z2, g3, g2); let h2 = DoubleDouble::mul_add(z2, g5, g4); let q0 = DoubleDouble::mul_add(z4, h1, h0); let q1 = DoubleDouble::mul_add(z4, g6, h2); let den = DoubleDouble::mul_add(z8, q1, q0); let r = DoubleDouble::div(num, den); let k = DoubleDouble::quick_mult(r, zeta_sqrt); f64::copysign(k.to_f64(), x) } /// Inverse error function /// /// ulp 0.5 pub fn f_erfinv(x: f64) -> f64 { let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff; if !x.is_normal() { if x.is_nan() || x.is_infinite() { return f64::NAN; } if ax == 0 { return 0.; } } if ax >= 0x3ff0000000000000u64 { // |x| > 1 if ax == 0x3ff0000000000000u64 { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } return f64::NAN; } let z = f64::from_bits(ax); if ax <= 0x3f8374bc6a7ef9db { // 0.0095 // for small |x| using taylor series first 3 terms // Generated by SageMath: // from mpmath import mp, erf // // mp.prec = 100 // // def inverf_series(n_terms): // from mpmath import taylor // series_erf = taylor(mp.erfinv, 0, n_terms) // return series_erf // // ser = inverf_series(10) // for i in range(1, len(ser), 2): // k = ser[i] // print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),") let z2 = DoubleDouble::from_exact_mult(z, z); let p = f_fmla( z2.hi, f64::from_bits(0x3fb62847c47dda48), f64::from_bits(0x3fc053c2c0ab91c5), ); let mut r = DoubleDouble::mul_f64_add( z2, p, DoubleDouble::from_bit_pair((0xbc33ea2ef8dde075, 0x3fcdb29fb2fee5e4)), ); r = DoubleDouble::mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b)), ); // (rh + rl) * z = rh * z + rl*z let v = DoubleDouble::quick_mult_f64(r, z); return f64::copysign(v.to_f64(), x); } else if ax <= 0x3faeb851eb851eb8 { // 0.06 // for |x| < 0.06 using taylor series first 5 terms // Generated by SageMath: // from mpmath import mp, erf // // mp.prec = 100 // // def inverf_series(n_terms): // from mpmath import taylor // series_erf = taylor(mp.erfinv, 0, n_terms) // return series_erf // // ser = inverf_series(10) // for i in range(1, len(ser), 2): // k = ser[i] // print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),") let z2 = DoubleDouble::from_exact_mult(z, z); let p = f_polyeval4( z2.hi, f64::from_bits(0x3fb62847c47dda48), f64::from_bits(0x3fb0a13189c6ef7a), f64::from_bits(0x3faa7c85c89bb08b), f64::from_bits(0x3fa5eeb1d488e312), ); let mut r = DoubleDouble::mul_f64_add( z2, p, DoubleDouble::from_bit_pair((0x3c2cec68daff0d80, 0x3fc053c2c0ab91c5)), ); r = DoubleDouble::mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc33ea2ef8dde075, 0x3fcdb29fb2fee5e4)), ); r = DoubleDouble::mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b)), ); // (rh + rl) * z = rh * z + rl*z let v = DoubleDouble::quick_mult_f64(r, z); return f64::copysign(v.to_f64(), x); } if ax <= 0x3fe8000000000000u64 { // |x| < 0.75 // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const P: [(u64, u64); 5] = [ (0xbc3e06eda42202a0, 0x3f93c2fc5d00e0c8), (0xbc6eb374406b33b4, 0xbfc76fcfd022e3ff), (0xbc857822d7ffd282, 0x3fe6f8443546010a), (0x3c68269c66dfb28a, 0xbff80996754ceb79), (0x3c543dce8990a9f9, 0x3ffcf778d5ef0504), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let vz = DoubleDouble::full_add_f64(x2, -0.5625); let ps_num = f_polyeval5( vz.hi, f64::from_bits(0xbff433be821423d0), f64::from_bits(0x3fdf15f19e9d8da4), f64::from_bits(0xbfb770b6827e0829), f64::from_bits(0x3f7a98a2980282bb), f64::from_bits(0xbf142a246fd2c07c), ); let mut num = DoubleDouble::mul_f64_add(vz, ps_num, DoubleDouble::from_bit_pair(P[4])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[3])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[2])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[1])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[0])); // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const Q: [(u64, u64); 5] = [ (0xbc36337f24e57cb9, 0x3f92388d5d757e3a), (0xbc63dfae43d60e0b, 0xbfc6ca7da581358c), (0xbc77656389bd0e62, 0x3fe7c82ce417b4e0), (0xbc93679667bef2f0, 0xbffad58651fd1a51), (0x3ca2c6cb9eb17fb4, 0x4001bdb67e93a242), ]; let ps_den = f_polyeval5( vz.hi, f64::from_bits(0xbffbdaeff6fbb81c), f64::from_bits(0x3fe91b12cf47da3a), f64::from_bits(0xbfc7c5d0ffb7f1da), f64::from_bits(0x3f939ada247f7609), f64::from_bits(0xbf41be65038ccfe6), ); let mut den = DoubleDouble::mul_f64_add(vz, ps_den, DoubleDouble::from_bit_pair(Q[4])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[3])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[2])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[1])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[0])); let r = DoubleDouble::div(num, den); let k = DoubleDouble::quick_mult_f64(r, z); let err = f_fmla( k.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3c40000000000000), // 2^-59 ); let ub = k.hi + (k.lo + err); let lb = k.hi + (k.lo - err); if ub == lb { return f64::copysign(k.to_f64(), x); } return inverf_0p06_to_0p75(x); } let q = DoubleDouble::from_full_exact_add(1.0, -z); let mut zeta = fast_log_dd(q); zeta = DoubleDouble::from_exact_add(zeta.hi, zeta.lo); zeta = -zeta; let zeta_sqrt = zeta.fast_sqrt(); let rz = zeta_sqrt.recip(); if z < 0.9999 { inverf_asympt_small(rz, zeta_sqrt, x) } else { inverf_asympt_long(rz, zeta_sqrt, x) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_erfinv() { assert!(f_erfinv(f64::NEG_INFINITY).is_nan()); assert!(f_erfinv(f64::INFINITY).is_nan()); assert!(f_erfinv(f64::NAN).is_nan()); assert_eq!(f_erfinv(-0.5435340000000265), -0.5265673336010599); assert_eq!(f_erfinv(0.5435340000000265), 0.5265673336010599); assert_eq!(f_erfinv(0.001000000000084706), 0.0008862271575416209); assert_eq!(f_erfinv(-0.001000000000084706), -0.0008862271575416209); assert_eq!(f_erfinv(0.71), 0.7482049711849852); assert_eq!(f_erfinv(-0.71), -0.7482049711849852); assert_eq!(f_erfinv(0.41), 0.381014610957532); assert_eq!(f_erfinv(-0.41), -0.381014610957532); assert_eq!(f_erfinv(0.32), 0.29165547581744206); assert_eq!(f_erfinv(-0.32), -0.29165547581744206); assert_eq!(f_erfinv(0.82), 0.9480569762323499); assert_eq!(f_erfinv(-0.82), -0.9480569762323499); assert_eq!(f_erfinv(0.05), 0.044340387910005497); assert_eq!(f_erfinv(-0.05), -0.044340387910005497); assert_eq!(f_erfinv(0.99), 1.8213863677184494); assert_eq!(f_erfinv(-0.99), -1.8213863677184494); assert_eq!(f_erfinv(0.9900000000867389), 1.8213863698392927); assert_eq!(f_erfinv(-0.9900000000867389), -1.8213863698392927); assert_eq!(f_erfinv(0.99999), 3.123413274341571); assert_eq!(f_erfinv(-0.99999), -3.123413274341571); } } pxfm-0.1.23/src/err/inverfc.rs000064400000000000000000000631451046102023000142530ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::{fast_log_d_to_dd, fast_log_dd}; use crate::polyeval::{f_polyeval4, f_polyeval5}; #[cold] fn inverf_0p06_to_0p75(x: DoubleDouble) -> DoubleDouble { // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const P: [(u64, u64); 10] = [ (0xbc3e06eda42202a0, 0x3f93c2fc5d00e0c8), (0xbc6eb374406b33b4, 0xbfc76fcfd022e3ff), (0xbc857822d7ffd282, 0x3fe6f8443546010a), (0x3c68269c66dfb28a, 0xbff80996754ceb79), (0x3c543dce8990a9f9, 0x3ffcf778d5ef0504), (0xbc72fc55f73765f6, 0xbff433be821423d0), (0xbc66d05fb37c8592, 0x3fdf15f19e9d8da4), (0x3c56dfb85e83a2c5, 0xbfb770b6827e0829), (0x3bff1472ecdfa403, 0x3f7a98a2980282bb), (0x3baffb33d69d6276, 0xbf142a246fd2c07c), ]; let x2 = DoubleDouble::quick_mult(x, x); let vz = DoubleDouble::full_add_f64(x2, -0.5625); let vx2 = vz * vz; let vx4 = vx2 * vx2; let vx8 = vx4 * vx4; let p0 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let p4 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let q0 = DoubleDouble::mul_add(vx2, p1, p0); let q1 = DoubleDouble::mul_add(vx2, p3, p2); let r0 = DoubleDouble::mul_add(vx4, q1, q0); let num = DoubleDouble::mul_add(vx8, p4, r0); // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const Q: [(u64, u64); 10] = [ (0xbc36337f24e57cb9, 0x3f92388d5d757e3a), (0xbc63dfae43d60e0b, 0xbfc6ca7da581358c), (0xbc77656389bd0e62, 0x3fe7c82ce417b4e0), (0xbc93679667bef2f0, 0xbffad58651fd1a51), (0x3ca2c6cb9eb17fb4, 0x4001bdb67e93a242), (0xbc9b58961ba253bc, 0xbffbdaeff6fbb81c), (0x3c7861f549c6aa61, 0x3fe91b12cf47da3a), (0xbc696dfd665b2f5e, 0xbfc7c5d0ffb7f1da), (0x3c1552b0ec0ba7b3, 0x3f939ada247f7609), (0xbbcaa226fb7b30a8, 0xbf41be65038ccfe6), ]; let p0 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[1]), DoubleDouble::from_bit_pair(Q[0]), ); let p1 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let p2 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let p3 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let p4 = DoubleDouble::mul_add( vz, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let q0 = DoubleDouble::mul_add(vx2, p1, p0); let q1 = DoubleDouble::mul_add(vx2, p3, p2); let r0 = DoubleDouble::mul_add(vx4, q1, q0); let den = DoubleDouble::mul_add(vx8, p4, r0); let r = DoubleDouble::div(num, den); DoubleDouble::quick_mult(r, x) } #[inline] fn inverf_asympt_small(z: DoubleDouble, zeta_sqrt: DoubleDouble) -> DoubleDouble { // Generated in Wolfram Mathematica: // <90] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 11] = [ (0x3c936555853a8b2c, 0x3ff0001df06a2515), (0x3cea488e802db3c3, 0x404406ba373221da), (0xbce27d42419754e3, 0x407b0442e38a9597), (0xbd224a407624cbdf, 0x409c9277e31ef446), (0x3d4f16ce65d6fea0, 0x40aec3ec005b1d8a), (0x3d105bc37bc61b58, 0x40b46be8f860f4d9), (0x3d5ca133dcdecaa0, 0x40b3826e6a32dad7), (0x3d1d52013ba8aa38, 0x40aae93a603cf3ea), (0xbd07a75306df0fc3, 0x4098ab8357dc2e51), (0x3d1bb6770bb7a27e, 0x407ebead00879010), (0xbbfcbff4a9737936, 0x3f8936117ccbff83), ]; let z2 = DoubleDouble::quick_mult(z, z); let z4 = DoubleDouble::quick_mult(z2, z2); let z8 = DoubleDouble::quick_mult(z4, z4); let q0 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[1]), z, DoubleDouble::from_bit_pair(P[0]), ); let q1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[3]), z, DoubleDouble::from_bit_pair(P[2]), ); let q2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[5]), z, DoubleDouble::from_bit_pair(P[4]), ); let q3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[7]), z, DoubleDouble::from_bit_pair(P[6]), ); let q4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(P[9]), z, DoubleDouble::from_bit_pair(P[8]), ); let r0 = DoubleDouble::mul_add(z2, q1, q0); let r1 = DoubleDouble::mul_add(z2, q3, q2); let s0 = DoubleDouble::mul_add(z4, r1, r0); let s1 = DoubleDouble::mul_add(z2, DoubleDouble::from_bit_pair(P[10]), q4); let num = DoubleDouble::mul_add(z8, s1, s0); // See numerator generation above: // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const Q: [(u64, u64); 11] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc75b1109d4a3262, 0x40440782efaab17f), (0x3d1f7775b207d84f, 0x407b2da74b0d39f2), (0xbd3291fdbab49501, 0x409dac8d9e7c90b2), (0xbd58d8fdd27707a9, 0x40b178dfeffa3192), (0xbd57fc74ad705ce0, 0x40bad19b686f219f), (0x3d4075510031f2cd, 0x40be70a598208cea), (0xbd5442e109152efb, 0x40b9683ef36ae330), (0x3d5398192933962e, 0x40b04b7c4c3ca8ee), (0x3d2d04d03598e303, 0x409bd0080799fbf1), (0x3d2a988eb552ef44, 0x40815a46f12bafe3), ]; let q0 = DoubleDouble::mul_add_f64( DoubleDouble::from_bit_pair(Q[1]), z, f64::from_bits(0x3ff0000000000000), ); let q1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[3]), z, DoubleDouble::from_bit_pair(Q[2]), ); let q2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[5]), z, DoubleDouble::from_bit_pair(Q[4]), ); let q3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[7]), z, DoubleDouble::from_bit_pair(Q[6]), ); let q4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(Q[9]), z, DoubleDouble::from_bit_pair(Q[8]), ); let r0 = DoubleDouble::mul_add(z2, q1, q0); let r1 = DoubleDouble::mul_add(z2, q3, q2); let s0 = DoubleDouble::mul_add(z4, r1, r0); let s1 = DoubleDouble::mul_add(z2, DoubleDouble::from_bit_pair(Q[10]), q4); let den = DoubleDouble::mul_add(z8, s1, s0); let r = DoubleDouble::div(num, den); DoubleDouble::quick_mult(r, zeta_sqrt) } // branch for |x| > 0.9999 for extreme tail #[cold] fn inverf_asympt_long(z: DoubleDouble, zeta_sqrt: DoubleDouble) -> DoubleDouble { // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // Generated in Wolfram Mathematica: // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 14] = [ (0x3c97612f9b24a614, 0x3ff0000ba84cc7a5), (0xbcee8fe2da463412, 0x40515246546f5d88), (0x3d2fa4a2b891b526, 0x40956b6837159b11), (0x3d5d673ffad4f817, 0x40c5a1aa3be58652), (0x3d8867a1e5506f88, 0x40e65ebb1e1e7c75), (0xbd9bbc0764ed8f5b, 0x40fd2064a652e5c2), (0xbda78e569c0d237f, 0x410a385c627c461c), (0xbdab3123ebc465d7, 0x4110f05ca2b65fe5), (0x3d960def35955192, 0x4110bb079af2fe08), (0xbd97904816054836, 0x410911c24610c11c), (0xbd937745e9192593, 0x40fc603244adca35), (0xbd65fbc476d63050, 0x40e6399103188c21), (0xbd61016ef381cce6, 0x40c6482b44995b89), (0x3c326105c49e5a1a, 0xbfab44bd8b4e3138), ]; let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; let g0 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let g1 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let g2 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let g3 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let g4 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let g5 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[11]), DoubleDouble::from_bit_pair(P[10]), ); let g6 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(P[13]), DoubleDouble::from_bit_pair(P[12]), ); let h0 = DoubleDouble::mul_add(z2, g1, g0); let h1 = DoubleDouble::mul_add(z2, g3, g2); let h2 = DoubleDouble::mul_add(z2, g5, g4); let q0 = DoubleDouble::mul_add(z4, h1, h0); let q1 = DoubleDouble::mul_add(z4, g6, h2); let num = DoubleDouble::mul_add(z8, q1, q0); // See numerator generation above: // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const Q: [(u64, u64); 14] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcfc7b886ee61417, 0x405152838f711f3c), (0xbd33f933c14e831a, 0x409576cb78cab36e), (0x3d33fb09e2c4898a, 0x40c5e8a2c7602ced), (0x3d7be430c664bf7e, 0x40e766fdc8c7638c), (0x3dac662e74cdfc0e, 0x4100276b5f47b5f1), (0x3da67d06e82a8495, 0x410f843887f8a24a), (0x3dbbf2e22fc2550a, 0x4116d04271703e08), (0xbdb2fb3aed100853, 0x4119aff4ed32b74b), (0x3dba75e7b7171c3c, 0x4116b5eb8bf386bd), (0x3dab2d8b8c1937eb, 0x410f71c38e84cb34), (0xbda4e2e8a50b7370, 0x4100ca04b0f36b94), (0xbd86ed6df34fdaf9, 0x40e9151ded4cf4b7), (0x3d6938ea702c0328, 0x40c923ee1ab270c4), ]; let g0 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[1]), DoubleDouble::from_bit_pair(Q[0]), ); let g1 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let g2 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let g3 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let g4 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let g5 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[11]), DoubleDouble::from_bit_pair(Q[10]), ); let g6 = DoubleDouble::mul_add( z, DoubleDouble::from_bit_pair(Q[13]), DoubleDouble::from_bit_pair(Q[12]), ); let h0 = DoubleDouble::mul_add(z2, g1, g0); let h1 = DoubleDouble::mul_add(z2, g3, g2); let h2 = DoubleDouble::mul_add(z2, g5, g4); let q0 = DoubleDouble::mul_add(z4, h1, h0); let q1 = DoubleDouble::mul_add(z4, g6, h2); let den = DoubleDouble::mul_add(z8, q1, q0); let r = DoubleDouble::div(num, den); DoubleDouble::quick_mult(r, zeta_sqrt) } #[inline] fn erf_core(x: DoubleDouble) -> DoubleDouble { // x is always positive, here, should be filtered out before the call if x.hi <= 0.0095 { // 0.0095 // for small |x| using taylor series first 3 terms // Generated by SageMath: // from mpmath import mp, erf // // mp.prec = 100 // // def inverf_series(n_terms): // from mpmath import taylor // series_erf = taylor(mp.erfinv, 0, n_terms) // return series_erf // // ser = inverf_series(10) // for i in range(1, len(ser), 2): // k = ser[i] // print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),") let z2 = DoubleDouble::quick_mult(x, x); let p = f_fmla( z2.hi, f64::from_bits(0x3fb62847c47dda48), f64::from_bits(0x3fc053c2c0ab91c5), ); let mut r = DoubleDouble::mul_f64_add( z2, p, DoubleDouble::from_bit_pair((0xbc33ea2ef8dde075, 0x3fcdb29fb2fee5e4)), ); r = DoubleDouble::mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b)), ); // (rh + rl) * z = rh * z + rl*z let v = DoubleDouble::quick_mult(r, x); return v; } else if x.hi <= 0.06 { // 0.06 // for |x| < 0.06 using taylor series first 5 terms // Generated by SageMath: // from mpmath import mp, erf // // mp.prec = 100 // // def inverf_series(n_terms): // from mpmath import taylor // series_erf = taylor(mp.erfinv, 0, n_terms) // return series_erf // // ser = inverf_series(10) // for i in range(1, len(ser), 2): // k = ser[i] // print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),") let z2 = DoubleDouble::quick_mult(x, x); let p = f_polyeval4( z2.hi, f64::from_bits(0x3fb62847c47dda48), f64::from_bits(0x3fb0a13189c6ef7a), f64::from_bits(0x3faa7c85c89bb08b), f64::from_bits(0x3fa5eeb1d488e312), ); let mut r = DoubleDouble::mul_f64_add( z2, p, DoubleDouble::from_bit_pair((0x3c2cec68daff0d80, 0x3fc053c2c0ab91c5)), ); r = DoubleDouble::mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc33ea2ef8dde075, 0x3fcdb29fb2fee5e4)), ); r = DoubleDouble::mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b)), ); // (rh + rl) * z = rh * z + rl*z let v = DoubleDouble::quick_mult(r, x); return v; } if x.hi <= 0.75 { // |x| < 0.75 // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const P: [(u64, u64); 5] = [ (0xbc3e06eda42202a0, 0x3f93c2fc5d00e0c8), (0xbc6eb374406b33b4, 0xbfc76fcfd022e3ff), (0xbc857822d7ffd282, 0x3fe6f8443546010a), (0x3c68269c66dfb28a, 0xbff80996754ceb79), (0x3c543dce8990a9f9, 0x3ffcf778d5ef0504), ]; let x2 = DoubleDouble::quick_mult(x, x); let vz = DoubleDouble::full_add_f64(x2, -0.5625); let ps_num = f_polyeval5( vz.hi, f64::from_bits(0xbff433be821423d0), f64::from_bits(0x3fdf15f19e9d8da4), f64::from_bits(0xbfb770b6827e0829), f64::from_bits(0x3f7a98a2980282bb), f64::from_bits(0xbf142a246fd2c07c), ); let mut num = DoubleDouble::mul_f64_add(vz, ps_num, DoubleDouble::from_bit_pair(P[4])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[3])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[2])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[1])); num = DoubleDouble::mul_add(vz, num, DoubleDouble::from_bit_pair(P[0])); // Generated in Wolfram Mathematica: // <75, MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // x0=SetPrecision[0.5625,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]; const Q: [(u64, u64); 5] = [ (0xbc36337f24e57cb9, 0x3f92388d5d757e3a), (0xbc63dfae43d60e0b, 0xbfc6ca7da581358c), (0xbc77656389bd0e62, 0x3fe7c82ce417b4e0), (0xbc93679667bef2f0, 0xbffad58651fd1a51), (0x3ca2c6cb9eb17fb4, 0x4001bdb67e93a242), ]; let ps_den = f_polyeval5( vz.hi, f64::from_bits(0xbffbdaeff6fbb81c), f64::from_bits(0x3fe91b12cf47da3a), f64::from_bits(0xbfc7c5d0ffb7f1da), f64::from_bits(0x3f939ada247f7609), f64::from_bits(0xbf41be65038ccfe6), ); let mut den = DoubleDouble::mul_f64_add(vz, ps_den, DoubleDouble::from_bit_pair(Q[4])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[3])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[2])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[1])); den = DoubleDouble::mul_add(vz, den, DoubleDouble::from_bit_pair(Q[0])); let r = DoubleDouble::div(num, den); let k = DoubleDouble::quick_mult(r, x); let err = f_fmla( k.hi, f64::from_bits(0x3c70000000000000), // 2^-56 f64::from_bits(0x3c40000000000000), // 2^-59 ); let ub = k.hi + (k.lo + err); let lb = k.hi + (k.lo - err); if ub == lb { return k; } return inverf_0p06_to_0p75(x); } let q = DoubleDouble::full_add_f64(-x, 1.0); let mut zeta = fast_log_dd(q); zeta = DoubleDouble::from_exact_add(zeta.hi, zeta.lo); zeta = -zeta; let zeta_sqrt = zeta.fast_sqrt(); let rz = zeta_sqrt.recip(); if x.hi < 0.9999 { inverf_asympt_small(rz, zeta_sqrt) } else { inverf_asympt_long(rz, zeta_sqrt) } } #[cold] fn inverfc_extra_small(x: f64) -> DoubleDouble { // Reversed order for erfinv with direct identity without subtraction. let q = x; let mut zeta = fast_log_d_to_dd(q); zeta = DoubleDouble::from_exact_add(zeta.hi, zeta.lo); zeta = -zeta; let zeta_sqrt = zeta.fast_sqrt(); let rz = zeta_sqrt.recip(); if x >= 0.0001 { inverf_asympt_small(rz, zeta_sqrt) } else { inverf_asympt_long(rz, zeta_sqrt) } } /// Complementary inverse error function pub fn f_erfcinv(x: f64) -> f64 { if !x.is_normal() { if x.is_nan() || x.is_infinite() { return f64::NAN; } if x == 0. { return f64::INFINITY; } } if x < 0. { return f64::NAN; } if x >= 2. { if x == 2. { return f64::NEG_INFINITY; } return f64::NAN; } if x == 1. { return 0.; } // we compute erfcinv through identity // erfcinv(x) = -erfinv(1-x) static SIGN: [f64; 2] = [1.0, -1.0]; if x < 0.1 { return inverfc_extra_small(x).to_f64(); } let dx = if x > 1. { DoubleDouble::from_full_exact_sub(2., x) } else { DoubleDouble::new(0., x) }; let sign = SIGN[(x > 1.) as usize]; let mut dx = DoubleDouble::full_add_f64(-dx, 1.); dx = DoubleDouble::from_exact_add(dx.hi, dx.lo); erf_core(dx).to_f64() * sign } #[cfg(test)] mod tests { use super::*; #[test] fn test_inverfc() { assert_eq!(f_erfcinv(1.0000000000027623e-13), 5.261512368864527); assert_eq!(f_erfcinv(1.0001200000182189), -0.00010634724760131264); assert_eq!(f_erfcinv(0.7001200000182189), 0.2723481758403576); assert_eq!(f_erfcinv(1.5231200000182189), -0.502985998867995); assert_eq!(f_erfcinv(1.99545434324323243), -2.0064739778442213); assert!(f_erfcinv(2.05).is_nan()); assert!(f_erfcinv(-0.01).is_nan()); assert!(f_erfcinv(f64::NAN).is_nan()); assert!(f_erfcinv(f64::NEG_INFINITY).is_nan()); assert!(f_erfcinv(f64::INFINITY).is_nan()); } } pxfm-0.1.23/src/err/inverfcf.rs000064400000000000000000000057271046102023000144230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::err::inverff::erfinv_core; /// Complementary inverse error function /// /// Max ulp 0.5 pub fn f_erfcinvf(x: f32) -> f32 { if !x.is_normal() { if x.is_nan() || x.is_infinite() { return f32::INFINITY; } if x == 0. { return f32::INFINITY; } } if x < 0. { return f32::NAN; } if x >= 1. { if x == 1. { return 0.; } if x >= 2. { // x > 2 if x == 2. { return f32::NEG_INFINITY; } return f32::NAN; } } let z = x as f64; static SIGN: [f32; 2] = [1.0, -1.0]; // inferfc(x) = -inverf(1-x) // ax doesn't need to be extremely accurate, // it's just boundary detection so will do subtraction in f32 erfinv_core(1. - z, (1. - x).abs().to_bits(), SIGN[(x > 1.) as usize]) } #[cfg(test)] mod tests { use super::f_erfcinvf; #[test] fn m_test() { assert!(f_erfcinvf(-1.).is_nan()); assert_eq!(f_erfcinvf(0.), f32::INFINITY); assert_eq!(f_erfcinvf(2.), f32::NEG_INFINITY); assert!(f_erfcinvf(2.1).is_nan()); assert_eq!(f_erfcinvf(0.5), 0.47693628); assert_eq!(f_erfcinvf(1.5), -0.47693628); assert_eq!(f_erfcinvf(0.002), 2.1851242); assert_eq!(f_erfcinvf(1.002), -0.0017724329); } } pxfm-0.1.23/src/err/inverff.rs000064400000000000000000000355271046102023000142610ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::logs::simple_fast_log; use crate::polyeval::{ f_estrin_polyeval7, f_estrin_polyeval8, f_estrin_polyeval9, f_polyeval3, f_polyeval5, f_polyeval10, f_polyeval11, }; #[inline] pub(crate) fn erfinv_core(z: f64, ax: u32, sign: f32) -> f32 { if ax <= 0x3c1ba5e3u32 { // 0.0095 // for small |x| using taylor series first 3 terms let z2 = z * z; // Generated by SageMath: // from mpmath import mp, erf // // mp.prec = 100 // // def inverf_series(n_terms): // from mpmath import taylor // series_erf = taylor(mp.erfinv, 0, n_terms) // return series_erf // // ser = inverf_series(10) // for i in range(1, len(ser), 2): // k = ser[i] // print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),") let p = f_polyeval3( z2, f64::from_bits(0x3fec5bf891b4ef6b), f64::from_bits(0x3fcdb29fb2fee5e4), f64::from_bits(0x3fc053c2c0ab91c5), ) * z; return f32::copysign(p as f32, sign); } else if ax <= 0x3d75c28fu32 { // 0.06 // for |x| < 0.06 using taylor series first 5 terms let z2 = z * z; // Generated by SageMath: // from mpmath import mp, erf // // mp.prec = 100 // // def inverf_series(n_terms): // from mpmath import taylor // series_erf = taylor(mp.erfinv, 0, n_terms) // return series_erf // // ser = inverf_series(10) // for i in range(1, len(ser), 2): // k = ser[i] // print("f64::from_bits(" + double_to_hex(RealField(100)(k)) + "),") let p = f_polyeval5( z2, f64::from_bits(0x3fec5bf891b4ef6b), f64::from_bits(0x3fcdb29fb2fee5e4), f64::from_bits(0x3fc053c2c0ab91c5), f64::from_bits(0x3fb62847c47dda48), f64::from_bits(0x3fb0a13189c6ef7a), ) * z; return f32::copysign(p as f32, sign); } if ax <= 0x3f400000u32 { // |x| <= 0.75 let z2 = z * z; // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // // <70] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let r = z2 - 0.5625; // x0=SetPrecision[0.5625,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,8}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval9( r, f64::from_bits(0x3fa329348a73d9d4), f64::from_bits(0xbfd2cb089b644580), f64::from_bits(0x3fed229149f732d6), f64::from_bits(0xbff6a233d2028bff), f64::from_bits(0x3ff268adbfbb6023), f64::from_bits(0xbfddac401c7d70f4), f64::from_bits(0x3fb3b1bd759d5046), f64::from_bits(0xbf67aeb45bad547e), f64::from_bits(0xbf01ccc7434d381b), ); // x0=SetPrecision[0.5625,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,7}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_den = f_estrin_polyeval8( r, f64::from_bits(0x3fa1aac2ee4b1413), f64::from_bits(0xbfd279342e281c99), f64::from_bits(0x3feef89a353c6d1b), f64::from_bits(0xbffa8f1b7cd6d0a7), f64::from_bits(0x3ff89ce6289819a1), f64::from_bits(0xbfe7db5282a4a2e1), f64::from_bits(0x3fc543f9a928db4a), f64::from_bits(0xbf888fd2990e88db), ); let k = (p_num / p_den) * z; f32::copysign(k as f32, sign) } else if ax <= 0x3f580000u32 { // |x| <= 0.84375 let z2 = z * z; // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // // <70] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let r = z2 - 0.84375; // x0=SetPrecision[0.84375,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval10( r, f64::from_bits(0x3f116d07e62cbb74), f64::from_bits(0xbf5c38d390052412), f64::from_bits(0x3f92d6f96f84efe3), f64::from_bits(0xbfbac9189cae446b), f64::from_bits(0x3fd5dd124fb25677), f64::from_bits(0xbfe49845d46b80ab), f64::from_bits(0x3fe556c4913f60f8), f64::from_bits(0xbfd59e527704e33b), f64::from_bits(0x3fb07614a5e6c9f1), f64::from_bits(0xbf60ce54a2d8a789), ); // x0=SetPrecision[0.84375,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_den = f_polyeval10( r, f64::from_bits(0x3f09fbdd1c987d1e), f64::from_bits(0xbf5602ad17d419f4), f64::from_bits(0x3f8efe31ea5bc71d), f64::from_bits(0xbfb77e5f1bd26730), f64::from_bits(0x3fd4c3f03e4f5478), f64::from_bits(0xbfe5aa87dfc5e757), f64::from_bits(0x3fe9c6406f9abc0b), f64::from_bits(0xbfdff2f008b4db05), f64::from_bits(0x3fc1123be5319800), f64::from_bits(0xbf83be49c2d5cb9e), ); let k = (p_num / p_den) * z; f32::copysign(k as f32, sign) } else if ax <= 0x3f700000u32 { // |x| <= 0.9375 // First step rational approximant is generated, but it's ill-conditioned, thus // we're using taylor expansion to create Newton form at the point. // // <70] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let x2 = z * z; let r = x2 - 0.87890625; // x0=SetPrecision[0.87890625,75]; // NumberForm[Series[num[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval11( r, f64::from_bits(0x3ec70f1cbf8a758b), f64::from_bits(0xbf1c9dff87b698d0), f64::from_bits(0x3f5dfe7be00cc21c), f64::from_bits(0xbf913fd09c5a3682), f64::from_bits(0x3fb7ab0095693976), f64::from_bits(0xbfd3b3ca6a3c9919), f64::from_bits(0x3fe3533be6d1d8c8), f64::from_bits(0xbfe48208ef308ac7), f64::from_bits(0x3fd361a82dab69d1), f64::from_bits(0xbfa2401965a98195), f64::from_bits(0xbf54ba4d14ca54e3), ); // x0=SetPrecision[0.87890625,75]; // NumberForm[Series[den[x],{x,x0,50}], ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[den[x],{x,x0,k}],{k,0,9}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_den = f_polyeval10( r, f64::from_bits(0x3ec0699f391e2327), f64::from_bits(0xbf151ec184941078), f64::from_bits(0x3f5717bb379a3c6e), f64::from_bits(0xbf8beed3755c3484), f64::from_bits(0x3fb46148b4a431ef), f64::from_bits(0xbfd25690b7bc76fa), f64::from_bits(0x3fe3f1b2f4ee0d9d), f64::from_bits(0xbfe888a7a4511975), f64::from_bits(0x3fdd84db18f2a240), f64::from_bits(0xbfb844807521be56), ); let f = z * (p_num / p_den); f32::copysign(f as f32, sign) } else { // Rational approximation generated by Wolfram Mathematica: // for inverf(x) = sqrt(-log(1-x))*R(1/sqrt(-log(1-x))) // // <90] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let zeta = -simple_fast_log(1. - z); let zeta_sqrt = zeta.sqrt(); let rcp_zeta = (1. / zeta) * zeta_sqrt; let p_num = f_estrin_polyeval8( rcp_zeta, f64::from_bits(0x3ff00072876c578e), f64::from_bits(0x40314e00c10282da), f64::from_bits(0x404f4a1412af03f6), f64::from_bits(0x404c895cc0d9b1b3), f64::from_bits(0x404545794620bfaf), f64::from_bits(0x403264d21ea21354), f64::from_bits(0x3fc5a5141dd19237), f64::from_bits(0xbf8c2e49707c21ec), ); let p_den = f_estrin_polyeval7( rcp_zeta, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x403151312c313d77), f64::from_bits(0x405032345fa3d0cd), f64::from_bits(0x4053e0a81d4c5f09), f64::from_bits(0x4054fa20c5e0731c), f64::from_bits(0x404620d7f94d4804), f64::from_bits(0x4035d7400867b81f), ); let r = zeta_sqrt * (p_num / p_den); f32::copysign(r as f32, sign) } } /// Inverse error function /// /// Max ulp 0.5 pub fn f_erfinvf(x: f32) -> f32 { let ax = x.to_bits() & 0x7fff_ffff; if !x.is_normal() { if x.is_nan() || x.is_infinite() { return f32::NAN; } if ax == 0 { return 0.; } } if ax >= 0x3f800000u32 { // |x| > 1 if ax == 0x3f800000u32 { // |x| == 1 return if x.is_sign_negative() { f32::NEG_INFINITY } else { f32::INFINITY }; } return f32::NAN; } let z = f32::from_bits(ax) as f64; erfinv_core(z, ax, x) } #[cfg(test)] mod tests { use super::*; #[test] fn f_test_inv_erff() { assert!(f_erfinvf(f32::NEG_INFINITY).is_nan()); assert!(f_erfinvf(f32::INFINITY).is_nan()); assert!(f_erfinvf(-1.1).is_nan()); assert!(f_erfinvf(1.1).is_nan()); assert_eq!(f_erfinvf(-1.), f32::NEG_INFINITY); assert_eq!(f_erfinvf(1.), f32::INFINITY); assert_eq!(f_erfinvf(0.002), 0.0017724558); assert_eq!(f_erfinvf(-0.002), -0.0017724558); assert_eq!(f_erfinvf(0.02), 0.017726395); assert_eq!(f_erfinvf(-0.02), -0.017726395); assert_eq!(f_erfinvf(0.05), 0.044340387); assert_eq!(f_erfinvf(-0.05), -0.044340387); assert_eq!(f_erfinvf(0.5), 0.47693628); assert_eq!(f_erfinvf(-0.5), -0.47693628); assert_eq!(f_erfinvf(0.76), 0.8308411); assert_eq!(f_erfinvf(-0.76), -0.8308411); assert_eq!(f_erfinvf(0.92), 1.2379221); assert_eq!(f_erfinvf(-0.92), -1.2379221); assert_eq!(f_erfinvf(0.97), 1.5344859); assert_eq!(f_erfinvf(-0.97), -1.5344859); assert_eq!(f_erfinvf(0.99), 1.8213866); assert_eq!(f_erfinvf(-0.99), -1.8213866); assert_eq!(f_erfinvf(0.7560265), 0.82385886); } } pxfm-0.1.23/src/err/mod.rs000064400000000000000000000041341046102023000133670ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![deny(unreachable_pub)] mod erf; mod erf_poly; mod erfc; mod erfcx; mod erfcxf; mod erff; mod erffc; mod inverf; mod inverfc; mod inverfcf; mod inverff; mod rerf; mod rerf_poly; mod rerff; pub use erf::f_erf; pub use erfc::f_erfc; pub use erfcx::f_erfcx; pub use erfcxf::f_erfcxf; pub use erff::f_erff; pub use erffc::f_erfcf; pub use inverf::f_erfinv; pub use inverfc::f_erfcinv; pub use inverfcf::f_erfcinvf; pub use inverff::f_erfinvf; pub use rerf::f_rerf; pub use rerff::f_rerff; pxfm-0.1.23/src/err/rerf.rs000064400000000000000000000213031046102023000135430ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::err::rerf_poly::RERF_HARD; use crate::polyeval::f_polyeval7; #[cold] #[inline(never)] fn rerf_poly_tiny_hard(x: f64, z2: DoubleDouble) -> f64 { // Polynomial for x/erf(x) // Generated by Sollya. // d = [0, 1/16]; // f = x/erf(x); // Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|107...|], d); // See ./notes/r_erf_tiny_hard.sollya const C: [(u64, u64); 10] = [ (0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b), (0xbc6d7696fe4a7cd0, 0x3fd2e7fb0bcdf4f2), (0xbc0cb8b926064434, 0x3f842aa561ecc102), (0x3c1cd94c2f3e6f09, 0xbf75207c7ef80727), (0xbbb35c4effe3c87c, 0x3f2db4a8d7c32472), (0x3bbf1d1edd1e109a, 0x3f20faa7a99a4d3d), (0xbb9e05d21f4e1755, 0xbef3adb84631c39c), (0x3b6ee5dc31565280, 0xbec366647cacdcc9), (0x3b3698f8162c5fac, 0x3eaabb9db9f3b048), (0xbb026f5401fce891, 0xbe66cd40349520b6), ]; let mut p = DoubleDouble::mul_add( z2, DoubleDouble::from_bit_pair(C[9]), DoubleDouble::from_bit_pair(C[8]), ); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[7])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[6])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[5])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[4])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(C[0])); p = DoubleDouble::from_exact_add(p.hi, p.lo); let z = DoubleDouble::div_dd_f64(p, x); z.to_f64() } #[inline] fn rerf_poly_tiny(z: f64, x: f64) -> f64 { let z2 = DoubleDouble::from_exact_mult(z, z); // Polynomial for x/erf(x) // Generated by Sollya. // d = [0, 1/16]; // f = x/erf(x); // Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|107, 107, 107, D...|], d); // See ./notes/r_erf_tiny.sollya let p = f_polyeval7( z2.hi, f64::from_bits(0xbf75207c7ef80727), f64::from_bits(0x3f2db4a8d7c36a03), f64::from_bits(0x3f20faa7a8db7f27), f64::from_bits(0xbef3adae94983bb2), f64::from_bits(0xbec3b05fe5c49f32), f64::from_bits(0x3ed67902690892be), f64::from_bits(0xbf3090033375e5ee), ); let mut r = DoubleDouble::quick_mul_f64_add( z2, p, DoubleDouble::from_bit_pair((0xbc0cb29fd910c494, 0x3f842aa561ecc102)), ); r = DoubleDouble::quick_mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc6d7696ff4f712a, 0x3fd2e7fb0bcdf4f2)), ); r = DoubleDouble::quick_mul_add( z2, r, DoubleDouble::from_bit_pair((0xbc8618f13eb7ca11, 0x3fec5bf891b4ef6b)), ); r = DoubleDouble::from_exact_add(r.hi, r.lo); r = DoubleDouble::div_dd_f64(r, x); let err = f_fmla( r.hi, f64::from_bits(0x3c10000000000000), // 2^-62 f64::from_bits(0x3b90000000000000), // 2^-70 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } rerf_poly_tiny_hard(x, z2) } #[inline] fn rerf_poly_hard(x: f64, z2: DoubleDouble, idx: usize) -> f64 { let c = &RERF_HARD[idx]; let mut p = DoubleDouble::mul_add( z2, DoubleDouble::from_bit_pair(c[10]), DoubleDouble::from_bit_pair(c[9]), ); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[8])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[7])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[6])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[5])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[4])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[3])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[2])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[1])); p = DoubleDouble::mul_add(z2, p, DoubleDouble::from_bit_pair(c[0])); p = DoubleDouble::from_exact_add(p.hi, p.lo); let z = DoubleDouble::div_dd_f64(p, x); z.to_f64() } /// Computes 1/erf(x) /// /// Max ulp 0.5001 pub fn f_rerf(x: f64) -> f64 { let z = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); let t = z.to_bits(); let ux = t; /* 1/erf(x) rounds to +/-1 for RNDN for |x| > 0x4017afb48dc96626 */ if ux > 0x4017afb48dc96626 // |x| > 0x4017afb48dc96626 { let os = f64::copysign(1.0, x); const MASK: u64 = 0x7ff0000000000000u64; if ux > MASK { return x + x; /* NaN */ } if ux == MASK { return os; /* +/-Inf */ } return f_fmla(-f64::from_bits(0x3c90000000000000), os, os); } /* now |x| <= 0x4017afb48dc96626 */ if z < f64::from_bits(0x3c20000000000000) { // |x| < 0.0000000000000000004336808689942018 /* for x=-0 the code below returns +0 which is wrong */ if x == 0. { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } if z.to_bits() <= 0x38b7f12369dedu64 { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } /* double-double approximation of 2/sqrt(pi) to nearest */ const SQRT_PI_OVER_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc8618f13eb7ca89), f64::from_bits(0x3fec5bf891b4ef6b), ); /* tiny x is Taylor Series: 1/erf(x) ~ sqrt(pi)/(2 * x) + O(x^3), where the ratio of the O(x^3) term to the main term is in x^2/3, thus less than 2^-123 */ /* scale x by 2^106 to get out the subnormal range */ let sx = x * f64::from_bits(0x4690000000000000); let mut prod = DoubleDouble::div_dd_f64(SQRT_PI_OVER_2, sx); // scale back by 2^106, since we're performed the division prod = DoubleDouble::quick_mult_f64(prod, f64::from_bits(0x4690000000000000)); return prod.to_f64(); } if z.to_bits() < 0x3fb0000000000000u64 { return rerf_poly_tiny(z, x); } const SIXTEEN: u64 = 4 << 52; let idx = f64::from_bits(z.to_bits().wrapping_add(SIXTEEN)) as usize; let z2 = DoubleDouble::from_exact_mult(z, z); rerf_poly_hard(x, z2, idx) } #[cfg(test)] mod tests { use super::*; #[test] fn test_erf() { assert_eq!(f_rerf(65.), 1.0); assert_eq!(f_rerf(3.), 1.0000220909849995); assert_eq!(f_rerf(-3.), -1.0000220909849995); assert_eq!(f_rerf(-0.03723630312089732), -23.811078627277197); assert_eq!( f_rerf(0.0000000000000000002336808689942018), 3.7924667486354975e18 ); assert_eq!(f_rerf(2.000225067138672), 1.004695025872889); assert_eq!(f_rerf(0.), f64::INFINITY); assert_eq!(f_rerf(-0.), f64::NEG_INFINITY); } } pxfm-0.1.23/src/err/rerf_poly.rs000064400000000000000000001574641046102023000146300ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Poly for x/erf(x) generated by Sollya and SageMath: ```python def build_sollya_script(idx): return f""" d = [{idx}/16, {idx + 1}/16]; f = x/erf(x); Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20|], [|107...|], d); for i from 0 to degree(Q) by 2 do {{ write(coeff(Q, i)) >> "coefficients.txt"; write("\\n") >> "coefficients.txt"; }}; """ def load_coefficients(filename): with open(filename, "r") as f: return [RealField(500)(line.strip()) for line in f if line.strip()] def call_sollya_on_interval(idx): sollya_script = build_sollya_script(idx) with open("tmp_interval.sollya", "w") as f: f.write(sollya_script) import subprocess if os.path.exists("coefficients.txt"): os.remove("coefficients.txt") try: result = subprocess.run( ["sollya", "tmp_interval.sollya"], check=True, capture_output=True, text=True ) except subprocess.CalledProcessError as e: return def print_coeffs(poly): print("[") for i in range(len(poly)): coeff = poly[i] print_double_double("", coeff) print("],") print(f"pub(crate) static RERF_HARD: [[(u64, u64); 11]; 96] = [") for i in range(0, 96): call_sollya_on_interval(i) coeffs = load_coefficients(f"coefficients.txt") print_coeffs(coeffs) print("];") ``` **/ pub(crate) static RERF_HARD: [[(u64, u64); 11]; 96] = [ [ (0xbc8618f13eb7ca89, 0x3fec5bf891b4ef6b), (0xbc6d7696fe4a8276, 0x3fd2e7fb0bcdf4f2), (0xbc0cb8b8ee1a9698, 0x3f842aa561ecc102), (0x3c1cd7ccb69e95dd, 0xbf75207c7ef80727), (0xbbaa394a1107572c, 0x3f2db4a8d7c32477), (0x3b947772cadb5350, 0x3f20faa7a99a39f6), (0x3b82456978771f64, 0xbef3adb844cdd880), (0x3b37f7e102aeadc8, 0xbec366744e62af3d), (0xbb4abc03ab72db68, 0x3eaaf1daea64176d), (0xbb198547c9f8a468, 0xbeab1e39a7a0e2e7), (0x3b7f74a4a9ee36d8, 0x3f04a9e81d9c80b1), ], [ (0xbc8618f13eb7ca80, 0x3fec5bf891b4ef6b), (0xbc6d7696fe4b2b7e, 0x3fd2e7fb0bcdf4f2), (0xbc0cb8b91c2650c4, 0x3f842aa561ecc102), (0x3c1cdab546730682, 0xbf75207c7ef80727), (0x3bbb63455d753552, 0x3f2db4a8d7c3246e), (0xbbb424fd3813a0d0, 0x3f20faa7a99a56cc), (0xbb974ceb097ab454, 0xbef3adb846a857a7), (0x3b61d21be7b25ec5, 0xbec3666116b38c11), (0x3b3682e9db421864, 0x3eaab4cd09f0d085), (0x3aa5c983c010eade, 0x3e03700f5101836c), (0xbae41b274c7a5708, 0xbe5a9d21ba05e7ff), ], [ (0xbc8618f13eace57e, 0x3fec5bf891b4ef6b), (0xbc6d76974e25c204, 0x3fd2e7fb0bcdf4f2), (0xbc0ca83c7b5744b0, 0x3f842aa561ecc102), (0x3c18ce0252a1d68a, 0xbf75207c7ef80727), (0x3bce42420bd5d0b7, 0x3f2db4a8d7c32516), (0xbbb957874ae4a150, 0x3f20faa7a99a30ee), (0x3b8ddca7ef22dfae, 0xbef3adb8467833bb), (0xbb651d1f2d5b7a26, 0xbec3666141b05fd7), (0x3aeee8bd696a7e40, 0x3eaab4da0fa3f61f), (0xbaaea92dba36c4b8, 0x3e00fecb2644094c), (0x3ac784c24cdd6540, 0xbe5a2dbb95d32849), ], [ (0xbc8618f0f4f60562, 0x3fec5bf891b4ef6b), (0xbc6d77a534ca7ed6, 0x3fd2e7fb0bcdf4f2), (0xbbb70f4c473c9e00, 0x3f842aa561ecc102), (0xbc1a977c9db0b237, 0xbf75207c7ef80734), (0xbbc2d4a01ff162d0, 0x3f2db4a8d7c36d59), (0x3b9b8c9eea11c018, 0x3f20faa7a991fd98), (0xbb9b38ca273e4e60, 0xbef3adb841391777), (0xbb4cea6e9e663e28, 0xbec36663999cb0ce), (0x3b2c61386dab24b4, 0x3eaab533e624d8da), (0xba652f7751c8cde8, 0x3df1a4ff38724196), (0x3af4e3db417be62c, 0xbe597d9d709c8e08), ], [ (0xbc8618a3e2026a77, 0x3fec5bf891b4ef6b), (0xbc6e20944e2ac138, 0x3fd2e7fb0bcdf4f2), (0x3c2e12ce437042e0, 0x3f842aa561ecc10c), (0x3c12502cccbcf6b0, 0xbf75207c7ef80a4e), (0xbbcb4f065498051c, 0x3f2db4a8d7cd2219), (0x3bbf4b458bdec052, 0x3f20faa7a8e99ec9), (0x3b961dfc4148cd3a, 0xbef3adb801226409), (0x3b5a733630a550c8, 0xbec366748a484948), (0xbb4a24fac279758a, 0x3eaab6b15bf3135e), (0xba3e1e7b6682ff00, 0xbdf6bd63ad5e418d), (0xbafc10a24873a1e6, 0xbe5883474fe6d074), ], [ (0xbc85fe3dd629df7a, 0x3fec5bf891b4ef6b), (0x3c7db7a5dd1476d1, 0x3fd2e7fb0bcdf4f1), (0xbc2f10bd47f8beb3, 0x3f842aa561ecc2a2), (0xbc171085831fc822, 0xbf75207c7ef859cf), (0xbbad645d9fde8344, 0x3f2db4a8d8721804), (0x3bb7d0c1a80cb912, 0x3f20faa7a1860459), (0x3b8144a625fe24f0, 0xbef3adb626814084), (0xbb6d54a39e361631, 0xbec366c6f18511c4), (0x3b418b036802bd18, 0x3eaabb6edc1c9627), (0xbaa73c33c857a12e, 0xbe1a953fd40d7420), (0x3ad8027476e07af0, 0xbe573402996dd2c2), ], [ (0xbc81b66a7b5ccff1, 0x3fec5bf891b4ef6b), (0xbc79bd60b5b426c0, 0x3fd2e7fb0bcdf4e9), (0xbc0a204cd030c544, 0x3f842aa561ece3d6), (0xbbe49cde86af7e88, 0xbf75207c7efcfa9b), (0x3bb2554e3ad0acc8, 0x3f2db4a8df415e4a), (0x3bae907c3c53747c, 0x3f20faa76a3ce3dd), (0x3b576ef184d414a0, 0xbef3adac5933f5ab), (0xbb56367067dc7e24, 0xbec367fa0f7f75b1), (0xbb3995c8812c5cd2, 0x3eaac7daac27d5c7), (0x3acb5505cddd0ffc, 0xbe303e14c38cf6a0), (0xbafad790a7b16c40, 0xbe5585acf166b0ba), ], [ (0x3c85d1c9c211e918, 0x3fec5bf891b4ef6c), (0x3c7dc0f172d28f0b, 0x3fd2e7fb0bcdf448), (0xbc2cd8e027009eae, 0x3f842aa561eea354), (0xbc086a077cc659f6, 0xbf75207c7f2b7b51), (0x3bc0b8cda4fe6154, 0x3f2db4a91237a04d), (0x3ba9afd26de84c3c, 0x3f20faa63672fc62), (0x3b7fbd4c6465a488, 0xbef3ad83cf5114fe), (0x3b6a7dda1ef6dceb, 0xbec36ba8282105aa), (0xbb32111eb49ac7ac, 0x3eaae41105399da2), (0x3add98a71b27ea8a, 0xbe402d0a88af1d02), (0x3ae0a91f20394204, 0xbe5370d92bcc2a46), ], [ (0x3c803817d1372452, 0x3fec5bf891b4ef86), (0xbc50267f5364549c, 0x3fd2e7fb0bcdec86), (0xbc09a8c6f2bdfb78, 0x3f842aa561ff6c1f), (0xbc1481492e0d9a28, 0xbf75207c8084dac4), (0x3bcd3db423b0d83b, 0x3f2db4aa36bdbd16), (0xbbacf5bc5b2c622c, 0x3f20faa0e2396b76), (0x3b9659a867f69cff, 0xbef3acf933a983ac), (0x3b51d6f1b465e7fe, 0xbec3755a4ed1ff4c), (0xbaf686c63e3ebca0, 0x3eab1d46ecad9463), (0x3ad9001d67537478, 0xbe4cbb6369bcf991), (0xbac3dba508ae78c8, 0xbe50f32dbe9334db), ], [ (0x3c7e25fe9d726860, 0x3fec5bf891b4f0b1), (0xbc7ab06652d76f68, 0x3fd2e7fb0bcda52f), (0xbc279366f3014478, 0x3f842aa5627a5113), (0x3c191084f4962937, 0xbf75207c8861bf8f), (0x3bcc7278fec26fd4, 0x3f2db4af82fa6c34), (0x3b607855cfa9f9c0, 0x3f20fa8d3e0a083b), (0xbb9ad1bff06c0295, 0xbef3ab635e1ce916), (0xbb52ac297a882c52, 0xbec38be316fa087e), (0x3b3566206093fe92, 0x3eab86bb787edab1), (0x3ad927375753f59c, 0xbe57893e809642e0), (0x3adec7fd7dac2bae, 0xbe4c238076f40165), ], [ (0xbc7450f4e5a34d6a, 0x3fec5bf891b4faf9), (0x3c6070254f6c97c2, 0x3fd2e7fb0bcba54d), (0x3c1f8f97820f81aa, 0x3f842aa56548d807), (0x3bc2d77ef02fd540, 0xbf75207cadd38a6f), (0x3bc008d39e65c4c1, 0x3f2db4c40d23ef77), (0x3bcdc5ae5472cba9, 0x3f20fa4f4740e11c), (0xbb75e14939f85e6c, 0xbef3a7522154b882), (0xbb60f6b3a1eb8a9a, 0xbec3bae123763846), (0x3b491b16febd3218, 0x3eac395e796a3137), (0xbb0bab30884bdbf8, 0xbe6212bc42b9a2e0), (0xbab8eccd2fe224e0, 0xbe45b61fe119ad92), ], [ (0x3c76cf1bebd8f6be, 0x3fec5bf891b542d1), (0xbc733582099fcc3e, 0x3fd2e7fb0bc009ee), (0x3c0b172518bbd9b8, 0x3f842aa572cff422), (0x3bdd3ab1da49a7e0, 0xbf75207d439ef930), (0xbbbf954393296a6c, 0x3f2db5083a0025ae), (0xbbc233ee942ade70, 0x3f20f9a4b3181e2c), (0xbb9431141736d564, 0xbef39e09cd205f73), (0x3b5c0416708c428a, 0xbec413c0641365e8), (0x3b311ec7c02434ac, 0x3ead513298bd2dd3), (0xbb0076afa010fc38, 0xbe6a400d6bbe9756), (0x3ab039de17d27b28, 0xbe3da0ada3cb2927), ], [ (0xbc80961ba80fa981, 0x3fec5bf891b6dccf), (0xbc27d2093e9c3580, 0x3fd2e7fb0b8828f0), (0xbc1b60797c0d2948, 0x3f842aa5a9bda8d4), (0x3c08a71b89c8f1ae, 0xbf75207f44782913), (0x3bbc75fe3c50b94c, 0x3f2db5ccf9b43f81), (0xbba70122edae31f0, 0x3f20f805df1b6c19), (0x3b92da280ec6be23, 0xbef38b05a18fa724), (0x3b6e03aa9603e78a, 0xbec4ad11ca8a9f23), (0xbb207645aa426dd4, 0x3eaee794c191d1e9), (0xbb1277f7834b907b, 0xbe721f2390f45efb), (0xbac2bab97552f26b, 0xbe2ee44166bd4092), ], [ (0xbc86412a39a97d22, 0x3fec5bf891be76b4), (0x3c6bce7a45dd0c50, 0x3fd2e7fb0aa56f36), (0x3c2557e7253abfae, 0x3f842aa6683a6171), (0x3c1559b4aafa5f9c, 0xbf7520853439abe3), (0xbb931b56d2d59ec0, 0x3f2db7bf11a6dcfd), (0x3bb30078186be24c, 0x3f20f484e99876bd), (0xbb94ca3a5181c4ee, 0xbef367e9a00dd18a), (0x3b622de077c887c0, 0xbec59eb568b2aedc), (0x3b5b0c17a3645969, 0x3eb08516c078c57d), (0x3b0b158910694e5a, 0xbe77daf6997136dd), (0xba909415002bf356, 0xbdf90b2f8adaf43d), ], [ (0x3c8eebcc5fdc47b3, 0x3fec5bf891dcc345), (0xbc7bdeb76ca780cf, 0x3fd2e7fb0797f73d), (0x3c10bf8295c1d6f2, 0x3f842aa89fda59cf), (0x3bf71f4b638009f4, 0xbf7520947eb352dd), (0x3bc81c2b39c7cfa7, 0x3f2dbc13cf992042), (0xbbcd2ae351951d22, 0x3f20edc7c5c2c729), (0x3b715d146b0c26a8, 0xbef32d944e41faf6), (0xbb6803167e74aae4, 0xbec6f973a7c3b9d4), (0xbb5698b55b8efe74, 0x3eb1d7b8c937b349), (0x3b1b643c9a997ac0, 0xbe7dfd096f4a5fa7), (0xba8fb6dd2d7a7030, 0x3e267fb86eba06c2), ], [ (0x3c86dc4ce01692a8, 0x3fec5bf892422403), (0x3c6e1211450bce0e, 0x3fd2e7fafeac6014), (0xbbfac1ba719423a8, 0x3f842aae4848982d), (0x3bf7686d089e7c08, 0xbf7520b68fd53c70), (0xbbbfc998753b244c, 0x3f2dc4802e8aeb22), (0xbba4c102da8c2be4, 0x3f20e25750bd0372), (0xbb62a950af6d7a38, 0xbef2d72aa1889a4a), (0xbb5d08f83a362a90, 0xbec8b99e783f6f6c), (0xbb5a15ec3de1bc4b, 0x3eb35589957ab913), (0x3b238126ff764adf, 0xbe8202891efeec09), (0xbace98afae47d9fe, 0x3e363d29bdcd0d91), ], [ (0x3c87e39a19b3d0c6, 0x3fec5bf89359d0b8), (0xbc74ed6ab85ab940, 0x3fd2e7fae8fcf8a7), (0x3c236cc1abf3c943, 0x3f842aba66ba4606), (0xbc175eb282d39023, 0xbf7520f6d89f5b09), (0x3bc0d4196881a655, 0x3f2dd28079e0bef9), (0x3bc21692d4ce8e46, 0x3f20d1982ee796d5), (0x3b677efb5a2869f0, 0xbef267c3cd8ec55d), (0x3b61b3a6e7d66719, 0xbecab655d18fe460), (0xbb5c2fcc91af77b1, 0x3eb4d3150ddbaa9c), (0x3b23a75514e0479a, 0xbe84a998a5fc1c26), (0x3ad030148c0b6a26, 0x3e3ebef94909972c), ], [ (0xbc885896855a57a0, 0x3fec5bf895afed62), (0xbc7f2cb90899316b, 0x3fd2e7fabfc54d4d), (0xbc1101eb755b3912, 0x3f842acedf24073a), (0x3c1d800e32be466e, 0xbf75215754e511d7), (0xbbbd7331487b23d4, 0x3f2de52c38f47908), (0x3bc0f459fff1ce70, 0x3f20bdc1658e0283), (0xbb3e9c5de054df00, 0xbef1f28a151cbecb), (0x3b646ea1f49d631e, 0xbecc91c3df6254c0), (0x3b3f922df375d0bc, 0x3eb60fbb57ac269e), (0xbb2adf22ce6fd8d8, 0xbe869dfb539fe8e7), (0x3ae7ff8ad5344063, 0x3e4227d4022456f1), ], [ (0xbc8ae090bfd1cee8, 0x3fec5bf898aa52a7), (0x3c62380fa44cbb08, 0x3fd2e7fa9085783d), (0xbc2bb2a4c308cd8c, 0x3f842ae3f8e02952), (0xbc1a80c30380f9a9, 0xbf7521b0bf608ac3), (0xbbcc1f24fab1d546, 0x3f2df4b9f3f226b4), (0xbbbe2b985bc87e80, 0x3f20aee6ee37d5fe), (0xbb956ef789bc02ec, 0xbef1a3ac85b7c6fa), (0x3b64f04fb6389bef, 0xbecdb12073729082), (0xbb5c530a33a8d714, 0x3eb6bba58e548b6b), (0xbb28aa08bba90045, 0xbe8791f4b89ddd8a), (0x3add8797a6eed87e, 0x3e435face41bc747), ], [ (0x3c76800e5118cba2, 0x3fec5bf8955c5890), (0xbc66b79aa48d850a, 0x3fd2e7fabdaeecb1), (0xbc1d060b60882aea, 0x3f842ad29f1d0d93), (0xbc0b7f7e1852d7de, 0xbf75217193e7b656), (0xbbb1dfda43c4090c, 0x3f2deb4c771372b5), (0x3bc2e3b7bf2030ec, 0x3f20b69da01bfa8a), (0xbb74d03bd81ad920, 0xbef1c6b6437d4791), (0x3b578508c016669e, 0xbecd44137495d835), (0x3b33cb45437e37c4, 0x3eb68402b52f1038), (0x3b1be6ce572b06ec, 0xbe874ebcad44d73b), (0x3ab4e75545af6170, 0x3e4316a8f4237932), ], [ (0x3c8936981c457407, 0x3fec5bf86fa67e7e), (0x3c5d1fc5562f5e74, 0x3fd2e7fc9a6db835), (0x3c2f4b2630af6de9, 0x3f842a290204d06b), (0x3c1a6b67044328aa, 0xbf751f35151a87ad), (0x3bca01fb3f4b9119, 0x3f2d9bfe8abb12df), (0x3ba530023186fc68, 0x3f20f2eaaebdb0aa), (0xbb85c5b20b084330, 0xbef2c599ff9e90f6), (0x3b6259424427f91e, 0xbeca60d00700323e), (0xbb529d2845b8c334, 0x3eb52404388a56a8), (0xbaf9bbc47316c558, 0xbe85c134d3d72756), (0xbae4bd922e473c2e, 0x3e418254e80c1fe1), ], [ (0x3c77b49c8708d95e, 0x3fec5bf7d439ccf3), (0xbc695b6d321a65b0, 0x3fd2e803977ec913), (0xbc2b99b73f650bb7, 0x3f8427e578b0c50f), (0xbbba4050af501080, 0xbf7518400f97e451), (0x3bc8b775372d0f1d, 0x3f2cbb5d411da776), (0x3bc0be4772912425, 0x3f218e6db0bf59c7), (0x3b777ca8e20895b4, 0xbef51c15be0f3a57), (0xbb6e2f3c48e85db8, 0xbec434774a0a089a), (0xbb3c765ffe5eadec, 0x3eb276f3778acc12), (0xbb0e4efe64d76c5c, 0xbe8300d68f0489e4), (0xbac93f2262acf544, 0x3e3dec41980b63a9), ], [ (0xbc8e50b3604c6456, 0x3fec5bf5f9905958), (0x3c73af2096783c36, 0x3fd2e8171399b082), (0x3c26b66b5099742e, 0x3f8422226134cb30), (0xbbf2cecc14e6c1fc, 0xbf750815c60e91f8), (0x3bcdb6c9be6c6293, 0x3f2adeea8a272502), (0xbbb73d5d9ccadd56, 0x3f22bb838b4d286e), (0x3b7ab2b233005e94, 0xbef93dba1ccdcc99), (0xbb298d7a22372b18, 0xbeb47ed03a750fd0), (0xbb3c07e8e0e06602, 0x3ead0ce153b552f1), (0x3b00cfb58d5874fc, 0xbe7e9cfd756ceaaf), (0x3abaa30adaab76ec, 0x3e37acea6cf7ffff), ], [ (0x3c30ec78f45292a0, 0x3fec5bf143d22204), (0xbc65249f97c5b9fc, 0x3fd2e8446c72543a), (0x3c201cc14aa2fa0b, 0x3f8415d93f136226), (0x3c0b56c2e9770fae, 0xbf74e8827285303e), (0xbbb6e48066484c1c, 0x3f278a5f412a35b2), (0xbbbbbb0c95d58fe4, 0x3f24a9089131326b), (0x3b7a0d70ba412e64, 0xbeff71b80a68e993), (0xbb11a7a28f6d7794, 0x3e9b91b885fa211a), (0xbb42339bfc23dfbc, 0x3ea32030cab757da), (0xbb1cda1488302a7e, 0xbe76157aada72026), (0xbadf9a0d5ca2457c, 0x3e31131ffd0ba6ca), ], [ (0xbc7ece76656bab74, 0x3fec5be6e950c0b7), (0x3c63bb57e740537e, 0x3fd2e8a012e0fa7b), (0x3c0575dc0334f2f4, 0x3f83ff0526acf1d1), (0x3c044dc560ec8f12, 0xbf74b291f390e4df), (0xbba350c48d6165b4, 0x3f224f839f50e0d8), (0xbbcf4d7854c8f79d, 0x3f277180d211eb44), (0x3ba94de841c700c9, 0xbf03d68928731504), (0xbb5b205425b9350c, 0x3ec426773f6ea48b), (0xbb1144f74a129450, 0x3e8ffe1e219179b5), (0xbabc5212976e4640, 0xbe6a9699317cdb6b), (0xbab5cec1a7ad7650, 0x3e25a54cb77230ab), ], [ (0x3c7d3f135943435e, 0x3fec5bd2eb61db6c), (0xbc61a1b9a1340f02, 0x3fd2e94353bc742e), (0x3c19472444a43534, 0x3f83d9826b0583dd), (0xbbf12099cc113f3c, 0xbf7460d083cf2916), (0x3bb25fb6f0143753, 0x3f15ff639d8c7e95), (0x3bcede86c1446be7, 0x3f2b084187ccc491), (0x3b9a4dd307e02614, 0xbf08bbc0c1452f04), (0xbb3417e35857f4d0, 0x3ed33caa76ba5931), (0x3b1f52eb65326bfc, 0xbe7a134a03fb3e51), (0x3ad82ac5fbd7ed1c, 0xbe545f84b2d562ea), (0xbaa952213eabb426, 0x3e15c65f270ddf3a), ], [ (0x3c61314e0f36eae0, 0x3fec5bb0fabf7432), (0x3c4a7c9c8f10f7f0, 0x3fd2ea43cf632902), (0xbc2bb7ae41d5a847, 0x3f83a2f96236fd49), (0xbbe33588677f3160, 0xbf73f2d3185d3b37), (0xbb893c2f894e5ec9, 0x3eee57818d9bc48d), (0xbbcfddea70d9e657, 0x3f2f2a9378e5af2f), (0xbb63ef176f255500, 0xbf0df3787dbe8741), (0x3b655f1aa127557e, 0x3edc459e3ece2d4d), (0xbb1e1661ae65e8e0, 0xbe9b0fc5cfefa97b), (0xbad66f3fc66c8a1e, 0x3e3d44dc6438f8b4), (0x3a8d0e6f53fcebaa, 0x3df3e3080e36d5ab), ], [ (0xbc83c010ea9374dc, 0x3fec5b7f0b87a9f9), (0x3c6a6947b642049a, 0x3fd2eba2164b914b), (0x3c2634e3ab1d746a, 0x3f835dd772e0ef48), (0x3bf0782b17d77b30, 0xbf737167e3a38e85), (0xbbb40bdd48addf07, 0xbf1016d6fb297d24), (0x3bcf4fce5e515ae2, 0x3f31adaaa086b765), (0xbb8667e90e887a10, 0xbf116e09c64e2aad), (0x3b733b8f1b2232c6, 0x3ee2148b515bbd2b), (0xbb3bb2c4ed26a2da, 0xbea5da89dcd96f7f), (0xbafdf9fe30fc648c, 0x3e5c23c03edd43fc), (0x3a68ee4c14603a48, 0xbdfb0412417cab57), ], [ (0xbc773b1b718353b8, 0x3fec5b423b9914bf), (0xbc7f621dd963a3cd, 0x3fd2ed2f4cdcf43d), (0x3c1377fcfefe24aa, 0x3f8314d842c3c294), (0x3be8e3cbd7aeb3f0, 0xbf72f22b0bee15ab), (0x3bc496dcb0a74226, 0xbf2124f7dd94863f), (0xbbc478f070fc4cca, 0x3f3376cd8b422ad4), (0x3bb72b86098b27ca, 0xbf13609490beb9b4), (0xbb8a94963c37f01f, 0x3ee4fe73c72cd39c), (0x3b4eb88aba09a145, 0xbeab93d2727633c8), (0x3ada9fc93c355918, 0x3e64bc38f4bdd701), (0x3aacb4db95da1717, 0xbe0b7c042bc74acf), ], [ (0x3c7468673688468e, 0x3fec5b0e0b4ba59c), (0x3c63faba1ee6b95a, 0x3fd2ee6e13906790), (0x3c25d66fa927da0f, 0x3f82de1072840d12), (0x3c049a24d8185b76, 0xbf7298e1fdd2f328), (0xbbcb7522c6abdf2b, 0xbf271d739ebb595c), (0x3b781acdc996cf00, 0x3f348f3e4ad28bed), (0xbbb072bf3c89d176, 0xbf147e86a40b207b), (0xbb7326b6cefec84a, 0x3ee68e6da7092266), (0xbb4ab0ed312c8bf6, 0xbeae725d99148642), (0x3ae0aa816b363984, 0x3e67dbdaa9091ad7), (0xbab2ce220dadff17, 0xbe10cdaf22c2927b), ], [ (0x3c59b93c25ba7460, 0x3fec5b0cbe5e774e), (0x3c76bace4b68f17f, 0x3fd2ee7808bb5f14), (0x3c23621dcf18db27, 0x3f82dc0fb77c520e), (0xbc02d3c316b92c3a, 0xbf729538f26e0dcd), (0xbbb5af2640454844, 0xbf2761ad24928630), (0xbbbf891c477ebd78, 0x3f349c95434125d0), (0xbba67df7fbd6d762, 0xbf148cc92ace3e89), (0xbb8134dd93b8d72a, 0x3ee6a3128d6f907c), (0xbb480c96baa85bb3, 0xbeae99327a49a987), (0xbb010257aa03b053, 0x3e6806c7c36a2043), (0x3a8d675538737ba0, 0xbe10f818a58178e7), ], [ (0x3c4a20c2ffd8c330, 0x3fec5b8650dc1b3c), (0x3c62ceb5ea6912b2, 0x3fd2ebf4d4343027), (0x3c16415358b3f530, 0x3f833bcb9ed1448b), (0xbba8e783f7cfa180, 0xbf731c5b9abc5061), (0xbbaae1179ef013fc, 0xbf1f1c82ab22093f), (0x3bd7061ebab8bd73, 0x3f335e45d67f5aad), (0xbbb3588d8714539f, 0xbf1373beb7a74ded), (0x3b7fb635c236f1be, 0x3ee54eaf0a4c3c7d), (0x3b4b413e2552f1f8, 0xbeac7bf3734a2753), (0x3ad1966368233040, 0x3e6608a4dfca5ed0), (0xbaabd52ab1c1dbd7, 0xbe0e8e7eadc45948), ], [ (0xbc86c6b99854f4ba, 0x3fec5ce2559d0e27), (0xbc4a9e39820df128, 0x3fd2e52f5edc3a75), (0x3c27e98d97a9a153, 0x3f842eb29566ca99), (0x3c11cc01d593a0ec, 0xbf745f29c9e85745), (0x3b89afdb819cd2f2, 0x3ef05af782dbcf48), (0x3bd94f533f217e09, 0x3f30bc4a31a29779), (0xbbbfbe37dbbc71f8, 0xbf11437d0d41d892), (0xbb67d7e84495e1e8, 0x3ee2cfcf4d336454), (0x3b3d0270024aa634, 0xbea8bf815c6422e7), (0xbb05654d572091fa, 0x3e62b7e50b8b90f7), (0xba85f715ca71b7dc, 0xbe094267189abccb), ], [ (0xbc8b568ee19f600b, 0x3fec5fa0fcc15e00), (0xbc64ae1ca196be12, 0x3fd2d850584e3d92), (0x3c0a1c38b8779b7c, 0x3f85e1633267448c), (0xbc13b2df368daa76, 0xbf767f05f772e0a9), (0xbba0052ee0bdb2ec, 0x3f2df5e6488ca6b4), (0xbbc5d74cdcf0270c, 0x3f299bbf35dee9e2), (0x3b96ad64b65e89ec, 0xbf0c5fcccc6c2660), (0xbb7ddbaa4fd30031, 0x3edf04a61deebc6f), (0xbb4641f56fdb0c8d, 0xbea417ec3b158cd4), (0x3af812e2551e8ff5, 0x3e5da8ee1deb57d9), (0xba9c21a62c8f20b2, 0xbe036932312c05a8), ], [ (0xbc47652f2b249250, 0x3fec6448d67cfe05), (0x3c5afdb8fb1ae7ac, 0x3fd2c3bb4abd265f), (0x3bf6ea0e9295baa8, 0x3f8870b03cea9b85), (0x3c16e6edb6eaa9ce, 0xbf7983ef9ac59092), (0xbbd53706eee79aa0, 0x3f40d717aff12a16), (0x3b976cca73ed1ac4, 0x3f1f5b3b385c1df1), (0xbba92870918744ca, 0xbf050c70db59e05d), (0xbb68ce6bbed5291e, 0x3ed79ad9cab6b863), (0x3b25baf1eee468b0, 0xbe9e56911c6c7a65), (0x3acd5d9a83435b80, 0x3e55e780d4a0464c), (0x3a8a364d35d45748, 0xbdfbd379eb2ab90c), ], [ (0xbc86c14b725ebb7e, 0x3fec6b4995c9de08), (0x3c7fb4771aa6f28f, 0x3fd2a6801486dfd3), (0xbc1ddfd7f1a153ba, 0x3f8bdf67d031f37d), (0xbc1586107ba99f80, 0xbf7d567e256e9203), (0xbbd112a73c31475e, 0x3f4c04519837759b), (0x3ba970117820cdb0, 0x3f01e26fbfb35d5e), (0x3b917088f90c92fd, 0xbefa7c64efae669b), (0x3b65bd710079150c, 0x3ed025b4f44232c3), (0xbb3f4dc2dd3bca5a, 0xbe94fbfe22e2526d), (0xbad2bf7e2a4b5574, 0x3e4de68ff4d747db), (0xba66c7d262b0b8a0, 0xbdf284a620b476c7), ], [ (0xbc84f871309252ee, 0x3fec74d76f950dde), (0x3c73834d4a6e7629, 0x3fd280c9b1a7e591), (0x3c3fa12d907a2b1e, 0x3f9007b78ba255a7), (0x3c16d44c8e8e4772, 0xbf80dfb353df5a7b), (0x3bfb84839bc97e6c, 0x3f541ace9d6f0acb), (0xbb9f14a16e84e7e6, 0xbf0c5b9486ce16f6), (0xbb624dbbbdce6efc, 0xbee6845e8710cd70), (0x3b6b59eb1f7dce35, 0x3ec289bd217664a3), (0xbb1a89e7d7c9c484, 0xbe89a757f8976281), (0x3acb4ae14dab0160, 0x3e426e9030e70fe7), (0x3a66a0ff13406f8c, 0xbde685814eb9c1cd), ], [ (0x3c809dc339e7995b, 0x3fec80c5a9555a89), (0xbc7ac33f6b3ca912, 0x3fd25430220cdd40), (0xbc1d4879d501b850, 0x3f92600eb46b8925), (0xbc2356327e3c25bb, 0xbf8336697f13a6f5), (0x3bda184d42970a70, 0x3f5a3a7bf90daf85), (0xbbcf8a4f720606fa, 0xbf2216381ceaccf0), (0xbb5d74978d8f4ff4, 0x3ec3acc294571d2d), (0x3b40f758a5d05eff, 0x3eab35536442f032), (0xbb1ec9e02f4c63ac, 0xbe78f2289217918e), (0xbabce0fe6cf01f98, 0x3e3350c3425bfb87), (0xba4f5a4d99818b90, 0xbdd8030b1ab1d204), ], [ (0xbc8d02acc1cc01da, 0x3fec8e6875ca6326), (0x3c68a17807900ab2, 0x3fd223d750e2a6ce), (0x3c3163ca3d33dbaf, 0x3f94c9473e76f76e), (0xbc098c145f9a6988, 0xbf857e3609470780), (0x3be47f0b24ee33a0, 0x3f5fe44219ffd11d), (0xbbc84789e8a20cf6, 0xbf2bbb7875215acb), (0x3b826e3c4224937a, 0x3eebbd791e5dd7a0), (0xbb3acd5f8da0e7f8, 0xbe93a6327ea04bd4), (0xbae90714b4795a94, 0xbe54e507e484f249), (0xbab1e85380873c6b, 0x3e1b7573e2bacf04), (0xba3301dce6665228, 0xbdc3b8ad84d29515), ], [ (0x3c8d598cc241ff55, 0x3fec9c85c70ba99b), (0xbc65e89f36890f9c, 0x3fd1f44f0f0625b4), (0x3c367cbc3334c914, 0x3f9709a35c721473), (0xbc23c533c2439634, 0xbf8783fdd8cab2f6), (0x3bff4430c6d372ec, 0x3f6254c211749b8b), (0x3bd7b84698e1faad, 0xbf31b9854d15a252), (0xbb8cd24e4e9b2656, 0x3ef68a7163ed7349), (0x3aee567652b74700, 0xbeb24689d2fed6d7), (0xbaaf24ed7d5f8040, 0x3e6096c6454ced2d), (0x3a94b5bb048a5dc6, 0xbdf3d8ad529aec47), (0x3a352f915f1c25ab, 0xbd91ca14681e58d4), ], [ (0xbc74394db20486d4, 0x3feca95a4f0eb301), (0x3c4a618c39437380, 0x3fd1cb356c162992), (0xbbd69159680e11c0, 0x3f98e3b24dd576a4), (0x3bb8f7d83288ce80, 0xbf891917845064d2), (0xbbf78d9838298862, 0x3f641b308822fb3e), (0xbbc321121160c9d8, 0xbf3474c17c3e0cfb), (0x3b9671925655ca8f, 0x3efc6107868e72b2), (0x3b46dc53b07e8e38, 0xbebad58367e4fcc3), (0x3b0b188021c3c3b6, 0x3e7087856ee75ad1), (0xbaad266b1a1b870e, 0xbe17bf1e1306c8f8), (0x3a4abb0faac45373, 0x3dadad8d29b6235a), ], [ (0xbc7b6735f38dcae0, 0x3fecb2b42a201841), (0xbc71582a96911b64, 0x3fd1aea941ad3474), (0xbc1a5e42a8fa5814, 0x3f9a1d7ee70c5812), (0xbc2046c34fb353f0, 0xbf8a18a3b401e573), (0x3bf7ffd5734be186, 0x3f652c60953fad12), (0x3bdd67e65789eb7f, 0xbf360556f51f1a8d), (0x3b9c078fde66a698, 0x3eff90fa5f587ec6), (0xbb3b345af7af1394, 0xbebf495ae99135f7), (0x3b1ef4298de4a753, 0x3e749ca3314eb91b), (0x3ac0bc479cb04d48, 0xbe204f74fb426011), (0x3a540203e5d5fe1e, 0x3db78557e884da1f), ], [ (0x3c7b9948887e3e30, 0x3fecb620c520b78a), (0xbc5cab423bfd4cb4, 0x3fd1a4a30f1a92da), (0x3c2937d3e12e5ef0, 0x3f9a8725b90119cc), (0x3c2a939091181278, 0xbf8a6b215fafec97), (0x3b842353662cd800, 0x3f6580eb53280d97), (0x3bd5dbe311f5e11e, 0xbf367c2d0446d766), (0x3ba105d1260b0e81, 0x3f003c7ffe8bc37c), (0xbb5bdc4485e10110, 0xbec04002440fd45b), (0xbaf45c45a6300d6c, 0x3e75ada1d2518cd8), (0x3a9e8e805aba9430, 0xbe216bcc91193d8a), (0xba49ad660ab34b8e, 0x3db99a7a2668e27b), ], [ (0xbc2947bf41bc9e00, 0x3fecb126f017035d), (0xbc7899059f5b8bb1, 0x3fd1b25105f6bdf3), (0xbc0895d0113bfb18, 0x3f99ffbf6823d4f5), (0xbc0f10a553f5d368, 0xbf8a07d8fb6fb3de), (0xbc0c7ec3a21f454e, 0x3f65215c13d9b6ff), (0x3bd1b601cf9453e4, 0xbf35fe063a62e384), (0x3b8827981ea2380a, 0x3eff91aca599febb), (0xbb2fc16dac065cc8, 0xbebf5d1e288c9e5c), (0xbaeef186161095a0, 0x3e74bd8a1c9555bc), (0xbacc403521f2eaf1, 0xbe2080eb36ed965e), (0xba3f86e752c89df8, 0x3db7fcd3a5bdb4d8), ], [ (0x3c8bcee7c8181d39, 0x3feca18848848e82), (0x3c69fc813308a73c, 0x3fd1db84d997da00), (0x3c3c53850ba9a712, 0x3f98786cc1d7bdc5), (0xbc2ca52fc8e5b866, 0xbf88f4811c08cd00), (0x3bff40da3a5c6bdc, 0x3f64230b2277791f), (0xbbca96457825fbbc, 0xbf34bbd65de2655f), (0xbb8f50c40c736b46, 0x3efd5ab0bde82aa8), (0xbb50eafc87b58e98, 0xbebcb0d4a3c5aff1), (0x3b089e7298344bb0, 0x3e729f7e0e19e149), (0xba7bdb04058a0820, 0xbe1d07eae288fa78), (0xba4b0253c12941ea, 0x3db4a07f49c5130b), ], [ (0xbc89edfc54aa2483, 0x3fec857c1cd41af6), (0xbc5a659387945ca0, 0x3fd2225424e8bcf6), (0x3c377fc2e3bc7889, 0x3f95f4c4f8ed59c3), (0x3c2c4286b497cf7c, 0xbf87430db00b9afa), (0x3c073f64e00247cb, 0x3f62a3e0f44a96a2), (0xbbbd945716fa0818, 0xbf32eb40cc8f3c79), (0xbb89740359a8ca0e, 0x3efa4c36e442171d), (0xbb15318efd8f9b50, 0xbeb9290343025508), (0x3b0452efb2ecf7c8, 0x3e6fe4933deba02f), (0x3abe6d64af899514, 0xbe183869735ef3a0), (0x3a34e4c2dbab070c, 0x3db0bc589c565cf5), ], [ (0xbc79fbf2f033ddfa, 0x3fec5be1ae114ebf), (0x3c62fd50833dbe24, 0x3fd286e5752eafab), (0xbbd5a1098dc5b600, 0x3f92897c1dc47bc3), (0x3c1904c95a070666, 0xbf850eaed8497ba0), (0xbbd04ac48084a568, 0x3f60c6331075f2b6), (0x3bbf3f5b46bed4bc, 0xbf30c0b464b7bc75), (0xbb98f7dad74f10c4, 0x3ef6cdf21e81cb9a), (0x3b44e287afdd458a, 0xbeb54c027ef829be), (0xbb0e9493b04030bd, 0x3e6a48ce7c9a8f3a), (0x3ab2e43f966ce1b5, 0xbe136513318f7913), (0x3a1693d5d1266bc0, 0x3da9ff3e55e5505b), ], [ (0x3c194781c55e3f00, 0x3fec24612d8075f9), (0x3c42c7b224a571e8, 0x3fd3077421970e7e), (0x3c2f8a4e5c0c1a72, 0x3f8cb2bb0e6bd65c), (0x3c26ce9b18985937, 0xbf82784bfab50a33), (0xbbf575cf19a4e653, 0x3f5d5a00e338fbc3), (0x3bb58b5f972663f2, 0xbf2cd6470bd0df26), (0xbb9d14973ed1a406, 0x3ef3329bb4ddacb9), (0xbb594a948357e8a2, 0xbeb17992005b48da), (0xbae1a67f3edd9b50, 0x3e64f7cb2aa0a2a1), (0x3aa41767e302bcd7, 0xbe0e0619d8c4b803), (0x3a42aa74db3d3d98, 0x3da37e072fc79210), ], [ (0x3c8d85ecbc120409, 0x3febdf79b3f36264), (0x3c4ae0e5eb5f4e28, 0x3fd3a081ec9e8dc3), (0x3c263a71c416c207, 0x3f8322a212289954), (0x3be52b87741ca630, 0xbf7f4624e1cf93c2), (0x3beb1990f8049eec, 0x3f58f1f394dd9af0), (0xbbc35bb151b25d75, 0xbf2822f4710adeee), (0xbb887c15268e3c40, 0x3eef6e32a041feb1), (0xbb4c7bc7c59ec68c, 0xbeabdf462f9e52f8), (0x3b054e47e872ed22, 0x3e603f5ed0b63b43), (0xba8c028decc6d7ec, 0xbe068f73246295da), (0xba3dbbf54cb0eec2, 0x3d9c5cdde2869e86), ], [ (0xbc5b64600e93c3c0, 0x3feb8e7bcdfa2551), (0xbc5edb222388a5a4, 0x3fd44d2c26cbf7ab), (0x3c150066d9ee763d, 0x3f718ffba24f3952), (0x3c09a588d15d0ddc, 0xbf7962e4ef5c450f), (0xbbfea7fbc24ad3bd, 0x3f548ce8089a5348), (0xbbbb19fd9ed05e78, 0xbf23a326550eca65), (0x3b4883cab8f6a4d0, 0x3ee908398ae19492), (0xbb3dae34b83d0a7e, 0xbea5a1d18b74c1ad), (0x3af6481f3bef8e86, 0x3e5881b400db6b43), (0x3a9febede716e6a0, 0xbe007fd85744e496), (0xba3e753baebb1cb9, 0x3d94159b20d20045), ], [ (0xbc8e0384101b69ae, 0x3feb3372978b846c), (0x3c7b389bd1e1869a, 0x3fd507973f33deca), (0x3be2e93210bce21a, 0xbf4f4d350dde3443), (0x3c1dbbd2ec26225d, 0xbf738585a37ac336), (0x3be34b6c09c314de, 0x3f50587dfefd189d), (0x3bacacf0dbcad6b4, 0xbf1f014a3f2c06fd), (0xbb8fcbc2dcbf78a5, 0x3ee362604eb5e17c), (0xbb454b555003d9a0, 0xbea0576c9981626c), (0xbaf474992319e3e5, 0x3e5200504cc51756), (0xba9a6909449d2d57, 0xbdf7846656305e2c), (0xba2cc3f7de9c46f8, 0x3d8bbadfc202f815), ], [ (0xbc8a3a50aa1d0747, 0x3fead0ff0244e221), (0xbc7a4fcbad89546e, 0x3fd5c9637406d596), (0x3c19bbcf5493a8bd, 0xbf795f996b9bda39), (0x3c0b49da59645f55, 0xbf6bc68547b5094f), (0xbbdb42f1472d8fc6, 0x3f48ed03525fcc78), (0x3b773bee95e6a5c0, 0xbf17aa1e224a084b), (0xbb7dce71fb3e3715, 0x3edd215cc70f90bc), (0xbb2a0ef6b971411c, 0xbe980113baf025cd), (0x3aee70cf25ebaad4, 0x3e49be8d01e22c7d), (0xba94bf3997882434, 0xbdf054d1d63dc91a), (0x3a20f0241013c27d, 0x3d82ab14512ab887), ], [ (0xbc8f9b01fd279096, 0x3fea6a29d58c33b7), (0xbc674dce8d0d0f3c, 0x3fd68c1eb8e2979d), (0x3c1bfcc8cbb07d48, 0xbf870f223a0c0167), (0xbbfb9ab59aae5a80, 0xbf614c2e57681df0), (0xbbd2b24814ac2946, 0x3f41faa38f77e2dd), (0xbbb53e8ed6013a54, 0xbf1158f6fd950634), (0x3b682bf413594436, 0x3ed526b8cc5a388b), (0xbb2f4bc0688a4900, 0xbe9117b230bc51cb), (0xbae98263a8ee88cd, 0x3e41e2b3a3f437f8), (0x3a78e8eb32b2b25c, 0xbde61231934d9184), (0xba1a8267a0ec97a6, 0x3d787cedf94e959b), ], [ (0x3c77d79c50a3711c, 0x3fea0231475ff3ae), (0xbc76363fa4e751ce, 0x3fd749aa5223f7e6), (0xbc3ba545d09d93bf, 0xbf9063ae7ef70c82), (0x3bd3d8a5dcae02b8, 0xbf4f618f89fa450f), (0xbbd20ab97faf56c8, 0x3f37e458b1e356d2), (0xbb86ee12886504d4, 0xbf0821cfdc163182), (0x3b2399e77fb2aac0, 0x3ecd75466a96fffa), (0xbb2ba6075e89c324, 0xbe87796133348897), (0x3ade02e57201493d, 0x3e380bfa3749564d), (0xba46d184faf9c670, 0xbddcee3600927b2c), (0x39f3dd4c231ece36, 0x3d6f362ec2a3967b), ], [ (0x3c735b83158e076c, 0x3fe99c56d0c67edb), (0xbc7a0b939d383a3d, 0x3fd7fc8d884ba6f2), (0xbc258d70b80083a0, 0xbf94cedb0ec61a6e), (0x3ba17e34a4e241e3, 0x3f0bcb4f74b08e2f), (0xbbbd6ec88c065d10, 0x3f2b6b788359e8dd), (0xbb940711b6ddbb99, 0xbeff16fca1811824), (0x3b664cd0d6355e5b, 0x3ec3660dc6b130e1), (0xbb1e6e3b0d706c32, 0xbe7ec91c367ea244), (0x3ace61b5d0d8a422, 0x3e2f0cc3ffc61fb0), (0xba4afae6d7bdc6e0, 0xbdd2476a6857058d), (0x3a00d53a0573b0fc, 0x3d633a7716320ae7), ], [ (0xbc79381c4b156290, 0x3fe93bb13b9992ac), (0x3c7970515413bd0e, 0x3fd8a031c4b5878f), (0x3c2031b5b4ec6b42, 0xbf98b46c9b7757e1), (0xbbc736951053a998, 0x3f4de4c5bf840851), (0x3ba8c149b58a4e02, 0x3f15754d3047c4dd), (0xbb949f7b0a34b5b6, 0xbef18508262de66c), (0xbb45552c936dac08, 0x3eb778e548c6b669), (0xbb1a6048f183d296, 0xbe72eab94b8e28a2), (0x3ac7391c2bf764c2, 0x3e22fc01dac54242), (0xba57caf213001686, 0xbdc6050b8d7ebfb9), (0x39ec1d99f5c2d0ac, 0x3d56b075f6914b50), ], [ (0xbc6bef6c010a9dc8, 0x3fe8e305fd2cb54e), (0x3c57932d301d71e4, 0x3fd9310711c87531), (0x3c386a44ecd2809e, 0xbf9c0829c8db1297), (0x3befcbf5dbe22972, 0x3f5a8ae87061dead), (0xbb7c9eb3c41756f8, 0xbef44394ab78a55e), (0xbb7a0c67c82446cc, 0xbedc78b9f90cda78), (0xbb420fd732d8f516, 0x3ea847cae47a2a7b), (0x3afb56e020c7a39e, 0xbe64e6bb322f4510), (0xbab3903c2be6b225, 0x3e155d1a9adaec94), (0x3a44a03f19abf2cc, 0xbdb8bcefe707e8fc), (0xb9d2417a35fd5cf8, 0x3d492f55542093f8), ], [ (0xbc862c4896b0b83d, 0x3fe894abe4a5b9dc), (0x3c7fe5c1c461460b, 0x3fd9ac922ad51dca), (0xbc33c291e0f24f05, 0xbf9ec58118c16c40), (0x3c0cf0b67c87e94e, 0x3f61e13d56b8940f), (0x3b6a790492e66540, 0xbf196af8349e4224), (0x3b31fa44d2bbd27e, 0x3ea2c42b70c9face), (0x3b2da20edbf59d2a, 0x3e9026f15ff2ee68), (0x3ae76f3d337ed97c, 0xbe526e097fd57d38), (0x3a9b983a79d51a18, 0x3e049a10a6c5b670), (0x3a3dc119a1c2f37a, 0xbda8a67c2aff9c17), (0xb9b2a4fe2b205130, 0x3d394c38265362bb), ], [ (0x3c77751441c8d3b4, 0x3fe8527813695aa2), (0x3c684eaa21e959ac, 0x3fda1166ea70106b), (0xbbdf4a6612c53b00, 0xbfa07734e6653b74), (0x3c0c7623498c8faa, 0x3f6563a6d917beff), (0xbbbd20a58a820126, 0xbf2431a6af0bf8de), (0x3b7d336f20d13d06, 0x3ed83dd6dda34654), (0xbb0b79b53e2c9b8a, 0xbe785be48d0ea29c), (0xbabeae4dddf12aee, 0xbe277cc09aefafd0), (0x3a59b67c103ee0d0, 0x3de9bcf4059586a2), (0x3a36708298b1f001, 0xbd92977be7d90308), (0xb9995f674b559478, 0x3d24a39363573224), ], [ (0x3c88059266015c63, 0x3fe81db53af85c81), (0x3c789ce0c91db2ea, 0x3fda5f12f3ca50da), (0x3c4fff4eb90f91b4, 0xbfa1450b1759f5fd), (0xbc0a5bae5f820112, 0x3f67ea33ae8225ad), (0x3bab3e1e966adef4, 0xbf296683eed1efcc), (0x3b558fbcb75a4300, 0x3ee37b35afee8bcf), (0x3b378b11a48054f7, 0xbe948b0f763cdd6e), (0xbadc68d151c5bcb6, 0x3e3b2ec7f8804690), (0x3a7a42b7c2cfda06, 0xbdd15431166629c5), (0x39c2cae40190fb38, 0xbd4254e40504074e), (0xb99f9b3ffd3df550, 0x3cfd32cfd9ee6824), ], [ (0x3c87852e7149316e, 0x3fe7f7244909eafb), (0x3c7d8b1870b59b84, 0x3fda95fcf538479f), (0xbc2dd434dbc26fe4, 0xbfa1d1cca085a602), (0x3c0f3d9182229bc7, 0x3f6995d566fe00f2), (0xbbce4c25eba9cee0, 0xbf2cbb2cd72dbf60), (0xbb6230a87de521a4, 0x3ee8091a0ed3ca17), (0xbb335f025a60c368, 0xbe9d316349e5762a), (0x3aed896b5a4d66cf, 0x3e48db6f436655ec), (0xba8d11019695e34c, 0xbdebeca2e7bfe62e), (0x3a13d9003f78f398, 0x3d825e2abee6700c), (0xb990404712f30786, 0xbd04fd8e7f84648d), ], [ (0xbc7d8fda24c8dc12, 0x3fe7df050ce33e3b), (0x3c74e2e804ecc588, 0x3fdab73cea883ea5), (0xbc2f5e041ad627c8, 0xbfa2244d670961da), (0x3c084c14e3d4348d, 0x3f6a887a1549f65c), (0xbbad4fb99d51b250, 0xbf2e8f85a842c421), (0xbb6484129b1a6f58, 0x3eea7507df06e1f0), (0xbb28afff859217ec, 0xbea0d29386ae890a), (0xbad0e96cc5515e0e, 0x3e4e7874a63969fb), (0xba9457f9482630cf, 0xbdf29b66626d984b), (0x3a061faa1b0f8ae4, 0x3d8b7a97aa5e6073), (0x39b8132f149882ca, 0xbd1289bc81c39d03), ], [ (0x3c7858d5859b0790, 0x3fe7d524fa022593), (0x3c7ab8681f9b2dda, 0x3fdac471728a6e5c), (0xbc392a31bd2c45e0, 0xbfa24416aa73c1ed), (0x3c0d03e98625a176, 0x3f6ae329e0be0f25), (0x3bb3ba40a20c6278, 0xbf2f39530a88b387), (0x3b683affc9a4f36c, 0x3eeb4f0eff41c408), (0x3b4b93014e8d4280, 0xbea194ff496f4fa6), (0x3affa9cc8e999f15, 0x3e502a0196d40303), (0x3a87d9e18ef0015c, 0xbdf4191a6c0fa6f9), (0x3a016447bf89fbf8, 0x3d8e50d97a2071b0), (0x39a41134a604833c, 0xbd14f7987074c37a), ], [ (0xbc8849b77320b1d6, 0x3fe7d8f21fcc2d5c), (0x3c6e500d1903dbf0, 0x3fdabf9588f99816), (0xbc41e8febc95a3f6, 0xbfa238e8af85956a), (0x3bf7cb20d4422e6c, 0x3f6ac4adc7f7de78), (0x3bcc4e80d908858a, 0xbf2f02c60cfb5d78), (0x3b8e622bcfcd200d, 0x3eeb0c1f999348b0), (0x3b38a070b3ab8ed8, 0xbea15bf677ada740), (0x3abb3aa525a7aa40, 0x3e4fceb78e014b78), (0xba88b19b0e21f96c, 0xbdf3b2e2d550cf5f), (0xb9c60dd540ad3700, 0x3d8d970d5bc2a4c6), (0xb9be83c8c31b4a6b, 0xbd145fa013479421), ], [ (0x3c79295ebf3ef4c4, 0x3fe7e9900e8c4c05), (0x3c717516935a5da6, 0x3fdaaad9baaf12a4), (0x3c4c9b35ae24337b, 0xbfa20a56ed057c52), (0x3c044bdda20e1933, 0x3f6a48b3b812e527), (0x3ba9b9db34d0c628, 0xbf2e2a29e903ce84), (0xbb8eca303b9b0d7d, 0x3eea0897d78deb13), (0x3b2024794b273684, 0xbea08401e50fb51f), (0xbae524c48f70dcb6, 0x3e4de1cd5f227b76), (0x3a93df2981146671, 0xbdf241b2a7dd10b3), (0x3a20275bd58bf3a8, 0x3d8b078eda0da34e), (0xb975173cc6f8cdc0, 0xbd1253ddd72c126b), ], [ (0x3c62ceb50bd97224, 0x3fe805ed671a8ed0), (0x3c7b6351621a7e0a, 0x3fda888206fd30ef), (0xbc4584aecef194b1, 0xbfa1bf7d67de3096), (0xbc08df5dab1e3e31, 0x3f69875818cc1132), (0xbb95e8f170b42d00, 0xbf2ce258acfa7ad8), (0xbb7ce9c19cd3375a, 0x3ee88b766706b93c), (0x3b3b55602543baa8, 0xbe9ea08995007a03), (0xbad3cfda551ad0a4, 0x3e4b3836accb970b), (0x3a7ce45c5bf4a770, 0xbdf052539f32ed36), (0x3a0d7e61158a35fc, 0x3d87b2188a7de05d), (0x39aab32ffc3fe31c, 0xbd0f7c473b9d736f), ], [ (0xbc76c7483e675afc, 0x3fe82cd81ce66983), (0xbc5ef5d3caaba448, 0x3fda5aca2a9e1224), (0xbc4a4d027a0a8332, 0xbfa15ecf0dfd892e), (0x3be2c1d3462002d8, 0x3f689503837e3442), (0xbbc509f8a68e8ca2, 0xbf2b53b6f662cf45), (0xbb60f335fd78f46c, 0x3ee6c9c7668886b1), (0xbb3a5a0cabb87303, 0xbe9bdff1f2d05298), (0xbae3d6fb4768ef6f, 0x3e484322f27254ec), (0xba5cfbb17d2ed970, 0xbdec78e7274dd815), (0x3a0fae6fdd22043c, 0x3d8435a56ec10a68), (0x398a0afc8fdd84cc, 0xbd0a3d84b2a469ec), ], [ (0x3c85275019a63bb1, 0x3fe85d0f9ead23a9), (0xbc7974d5f2d0ab34, 0x3fda23d053d2b1f9), (0x3c25be352012ca48, 0xbfa0edf91eeb8a5a), (0xbbfa726a80174ca0, 0x3f678284e4bab95d), (0xbbcceccff8d62cba, 0xbf299d7803f58699), (0x3b20eb35873a9940, 0x3ee4e9f7283f6640), (0x3b3641fc5b936877, 0xbe9906486da98e29), (0x3aea438a4fcdd9f2, 0x3e454a362a3889a6), (0xba82ae66c2606eaf, 0xbde867553e123f52), (0xba231385b8b89c0f, 0x3d80e8b863b8cec3), (0x399dbb221e9dfdb4, 0xbd056bb50a6179c5), ], [ (0xbc8345a68bce03f8, 0x3fe895541a035cf4), (0x3c6a9a13b818bbe8, 0x3fd9e58630317028), (0x3c3e5e56ece03e20, 0xbfa071d825df20c5), (0xbc043060f7b87f82, 0x3f665d556fbb2b9e), (0x3bbb55c0244c2894, 0xbf27d6fef71eedec), (0x3b806a3db3cffa6e, 0x3ee306dbc230ea08), (0xbb2fcb3bd608fa04, 0xbe963cfb5eb7dc39), (0x3ad8bdca1f8849c6, 0x3e4277fcbf00c0f2), (0x3a79b5a7f6701dda, 0xbde4a77f1e97bc2a), (0x39ee8bc647b19098, 0x3d7be97fa139ec70), (0x39a742e93993d7e6, 0xbd013be949b0c1df), ], [ (0x3c85a304157923b2, 0x3fe8d4728500ffee), (0xbc71876145eae8b8, 0x3fd9a1a7b920519b), (0xbc3d2ec62d32922e, 0xbf9fdcf4fe2e6866), (0xbbcb05a4e91bc710, 0x3f652ff5c4a490a2), (0xbbc9fb86475d7c78, 0xbf26113d24d89dd2), (0x3b6e06275e8ce9b4, 0x3ee1325b7e36d29e), (0x3b2e12813f06a494, 0xbe939d1a60ad6f51), (0xbad3005982fa855a, 0x3e3fc676f4a347ee), (0xba85afc3d21b71be, 0xbde152903c9bc0b8), (0xba1be795cc3bb4cd, 0x3d76d08684fc4f40), (0xb99979de162142b7, 0xbcfb72c9bdfebf2e), ], [ (0xbc87e105ec9ca5f4, 0x3fe9194d6629e509), (0xbc79c00221836f35, 0x3fd959b6e47cc1cb), (0xbc26c9c009d62078, 0xbf9ece59214cf137), (0xbbfe20f5fddc5310, 0x3f64025702ca8fc4), (0xbba84afb784aa07c, 0xbf2457f85b9b3831), (0x3b54ea926ad5167c, 0x3edeef4e272f250a), (0xbb023defeec5e0a0, 0xbe913432dc663e67), (0x3aae60197d5217c8, 0x3e3b2b72ce97aa39), (0x3a63141e2e6f5022, 0xbddcde4ddf08d4ea), (0x39eca6549fac9060, 0x3d72854850b02948), (0xb939a6cb39aa2600, 0xbcf5b3efba807911), ], [ (0xbc24d27ad1e68c80, 0x3fe962e2905556ed), (0x3c69998b03a75cee, 0x3fd90efb3eca9aba), (0x3c3c5ac4bdd68696, 0xbf9dbd168f65fb7e), (0x3be519a7a0660ba4, 0x3f62da45c6e72103), (0xbbc8b81ea1bc7080, 0xbf22b2ecd5924135), (0x3b5e56067f09a9d4, 0x3edbba1394728855), (0x3b28207c17005b80, 0xbe8e0ffed775f6e9), (0xbadbacdffd118992, 0x3e372225c30c46fa), (0x3a68218e8f652ab4, 0xbdd7f276a6d4d262), (0x3a0144bf6c21cae7, 0x3d6dedf685adbda0), (0xb99078cdaa8ca380, 0xbcf113f00b9fe725), ], [ (0xbc712c24f9d2f218, 0x3fe9b04e3301ca38), (0x3c7193d913e4e618, 0x3fd8c28470534676), (0xbc3677a730753df1, 0xbf9cad33f35e2755), (0x3bc11212e8675ef0, 0x3f61bbd0172a316b), (0xbb93d13eee592c20, 0xbf2126c548b5619a), (0xbb7f0f63eeeee01d, 0x3ed8cab1036d4dec), (0xbb289ac10a4baa55, 0xbe8a32410f19bdd5), (0x3ac451ab8a7a47d0, 0x3e33a420595d0d3a), (0xba603784d0bf66a6, 0xbdd3ce7c43e80e82), (0x39fe2bb244cfded2, 0x3d681c69081d1b37), (0x395917e555865c68, 0xbceacbdfedaea1f7), ], [ (0x3c8f0fa86a56e6ba, 0x3fea00cbb7e2c1e2), (0xbc63acefc8cc1c66, 0x3fd8752ebfc07ba7), (0x3c3e999a1b70ea47, 0xbf9ba1b2cc9437f4), (0x3be3a460fc6ec980, 0x3f60a9a1d27c214e), (0x3bb37b03b766db48, 0xbf1f6bd0acca9dd1), (0xbb713d37e0e4001a, 0x3ed6221851224bca), (0xbb207e1b7175b01f, 0xbe86ca231706849e), (0x3ad2bf8297bed558, 0x3e30a5c736124de1), (0xba727489396341d5, 0xbdd05a979295fac9), (0x39f1756e19c37c9a, 0x3d6364167eb132f4), (0x3983bb2d132598e9, 0xbce4fd25b8623a10), ], [ (0x3c84f280c7337943, 0x3fea53b4eef9f5a5), (0xbc69118e2061c5da, 0x3fd827a8c3a5cc4b), (0x3c3ed707936633ac, 0xbf9a9cbc621418be), (0x3bbc9603743be350, 0x3f5f4aaa94ee28c7), (0xbbb7a8e3165c93dc, 0xbf1cc23b919438f8), (0xbb7920595035541d, 0x3ed3be2ada53954c), (0x3b24880c577104dd, 0xbe83cf0de829e720), (0xbac9bba9b94d4f97, 0x3e2c32789bf32b44), (0x3a6a7d6fb4480815, 0xbdcafc517db4919d), (0x39ff848c09f51077, 0x3d5f2b62427707c6), (0x398e7d47b82a2483, 0xbce06e6c75ffb9d2), ], [ (0x3c874be4e30f55fd, 0x3feaa8800692a548), (0xbc7983ddaa23edda, 0x3fd7da799a85a3a1), (0x3c29fd6ca97884f0, 0xbf999fcb692e46c2), (0x3bf0a8fd72f30686, 0x3f5d5f6e7ebe838d), (0xbbb41d28e076799c, 0xbf1a501fd07cd87f), (0x3b5a4d8bed2ad3cc, 0x3ed19aee4bf149cb), (0x3b286b20ed1ac9b8, 0xbe8136b705548435), (0xbaa2b95c9c1a2fd4, 0x3e27e05b60054049), (0xba45b18e400c714c, 0xbdc643aab819d20d), (0xb9f127bc1b8ba61b, 0x3d590e09ca6a23af), (0xb97b1e2097b4cdce, 0xbcd9bc2e12b23103), ], [ (0x3c7f2f0799382490, 0x3feafebcbfb3a5a6), (0x3c727a6f0626ebe1, 0x3fd78e0728cbc72f), (0xbc0989b2c393e360, 0xbf98abd10da484bf), (0xbbf1c8cbe9077ebf, 0x3f5b91fd1b5e71f1), (0x3bb2dddefa74558b, 0xbf18135c2255aff9), (0x3b69dc72be6abee5, 0x3ecf66cede9d9f9f), (0x3afb52ef032713c0, 0xbe7decaae15f192a), (0xba9db8b3a1526ca8, 0x3e2439c768f9f33b), (0xba6bcb4e3ca70c74, 0xbdc261268dbd2e9a), (0x39f22f54fe950e34, 0x3d5427b26d8593fa), (0xb96523c3104ba290, 0xbcd42c447ec0cc74), ], [ (0x3c80f855a5653f06, 0x3feb56113d9e9fc0), (0x3c7901a7f01610ff, 0x3fd7429c0204c3ba), (0xbc2879c1b3ea956c, 0xbf97c154c2349766), (0xbbd2c40ca2762fb4, 0x3f59e1f11efd1eec), (0xbbaad9436855a79e, 0xbf1608ebbb454bde), (0x3b5d9d26778908c0, 0x3ecc04604ee7154d), (0x3b1604c163265ec0, 0xbe7a06c1e1593471), (0x3ac14ff60c7c6164, 0x3e21259f614c0715), (0xba22d4163461b648, 0xbdbe602ef33d6637), (0x39fbfef523aa8104, 0x3d503bc5a16de542), (0xb96ef0efa7439614, 0xbccfac1400ac6db2), ], [ (0x3c817e5fae67811b, 0x3febae36bac7427c), (0x3c416ec3c6a31ff8, 0x3fd6f86cc3b7fc0a), (0x3be68b8723641480, 0xbf96e08ec82e7973), (0x3bdb9567557c5bac, 0x3f584e572bac1437), (0x3bbf4c36068c245d, 0xbf142d4fd9685b5f), (0x3b6fd00e8a412202, 0x3ec903b46ab16552), (0x3b1a26353b11a93a, 0xbe76a7ffb613d977), (0x3a83fcc3e211ffd0, 0x3e1d1b24e667426f), (0xba431eb4941eb958, 0xbdb9227627e5f349), (0xb9e5b1fb0b09d692, 0x3d4a30f8c120e1fc), (0x396256e383967df9, 0xbcc8e8aa37bc61f0), ], [ (0xbc6af2a3b8a6417c, 0x3fec06f659b4d0a2), (0x3c72c912d943a127, 0x3fd6af9cc36509a8), (0x3c346b1c71fd9485, 0xbf96097db8eb9798), (0xbbd6098a353eaa68, 0x3f56d5e207087908), (0x3ba7ef357dae1da2, 0xbf127cd98a6a5063), (0x3b59d23dfa50e50a, 0x3ec65a59b3e87f89), (0xbb1b2a7ac925c26a, 0xbe73be7c669b60c4), (0x3abf7a6f9aa49d38, 0x3e18bc66c4d33d25), (0x3a598bd8cb8e83be, 0xbdb4d4aee38b7aa0), (0x39e8c05a738afb6a, 0x3d452ae72a594d04), (0xb9581feb7fc372c8, 0xbcc3a189a1f1d088), ], [ (0xbc8b94a3f11b0b1b, 0x3fec6026362273c0), (0x3c7a9433928985a8, 0x3fd6684205e2cfa8), (0xbc316c22e2ee8975, 0xbf953bf793a414a0), (0x3b8eaa45bca8e100, 0x3f5577111d8e7869), (0x3bb37d8f271623f3, 0xbf10f3db4ed954fd), (0xbb5cffa19b715950, 0x3ec3fe9093dddaa2), (0x3b1fcf0f684df6f8, 0xbe713a42e1480d90), (0x3abfa83b47f916ac, 0x3e150dad8bd02d20), (0x3a59abbe7813943f, 0xbdb14b5382d39865), (0xb9efe1edf8eeca76, 0x3d41245f6e4996be), (0x3949af3eecb215a2, 0xbcbf03908246b7c6), ], [ (0xbc80c31a8863f9d6, 0x3fecb9a6cb682a24), (0x3c7fed51d74bff86, 0x3fd622688518051f), (0xbc1591ef749caee4, 0xbf9477b6ed4c398b), (0xbbce137d55208958, 0x3f54304c2141eeee), (0xbbab7a179e1ae7dd, 0xbf0f1d91c60481ce), (0x3b55449a00736a6e, 0x3ec1e76e7622605d), (0xbaccb03dd24f7810, 0xbe6e1a99fac954a8), (0xbab80ff44fecc168, 0x3e11f2a815bce70a), (0xba3ce823a0233bd6, 0xbdacc51da262d834), (0x397750c051a75c00, 0x3d3bd2e2e3a657bb), (0xb95134cc93e44584, 0xbcb88ed08e872b27), ], [ (0x3c78ddf4513624a6, 0x3fed1360b92664d6), (0xbc6c375ce17d0080, 0x3fd5de14d2825f87), (0x3c2f9ef6b2759e44, 0xbf93bc64e699f695), (0xbbf5442d5bca96e1, 0x3f52fff6380176c4), (0xbb949c6dfb89070a, 0xbf0c9494574d2471), (0xbb65ac54bdb2df7f, 0x3ec00ce94926b534), (0x3b07c40ed8f854a0, 0xbe6a56ccff5f9038), (0xbaa6ab98e2498c16, 0x3e0ea6ea534c6311), (0xba4cece43020bd1a, 0xbda7fa106c3a3ead), (0xb9c623e1759261aa, 0x3d36a181cda3fbde), (0xb957aa56acc34690, 0xbcb37e8b3f1b09f6), ], [ (0xbc62a747ca07d630, 0x3fed6d42e652ce9a), (0xbc789f5a03143863, 0x3fd59b462a4134b2), (0xbc36139452148f43, 0xbf9309a084e7d879), (0xbbede9bf011d0122, 0x3f51e47ac9c4c1e3), (0x3bae3a191b4e3711, 0xbf0a468a447d21ea), (0x3b516b9dbf20d3a0, 0x3ebccfa848c16ecb), (0xbaf45f67850622dc, 0xbe671406d6247e7e), (0xba9afce70816748e, 0x3e0a3815485d6074), (0x3a4365c1867e0cf7, 0xbda405987f7f2f4b), (0x39d30563667171d7, 0x3d3272e30e95ed90), (0xb91280c86c884580, 0xbcaf073402f44315), ], [ (0x3c8f60a249f7c00e, 0x3fedc740fcccedd7), (0x3c53f9df06bc8f9c, 0x3fd559f80c631fe7), (0xbc31921248d74572, 0xbf925f03faf7b7d2), (0x3bdfe8b708962ff8, 0x3f50dc559c122c5c), (0xbba1d03d8e55ebc1, 0xbf082dc34fb7663d), (0x3b587dd0630cd995, 0x3eb9e3a65f1e1ccc), (0xbad1b315f72bea20, 0xbe644022ea43612d), (0x3a92aa9f91588038, 0x3e06774a0eae4e26), (0x3a2dde6ed80a8ad4, 0xbda0c0b1b147b2e0), (0x39b72f1e01edcf12, 0x3d2e25bd83b43837), (0xb915c51aee817f28, 0xbca8c18518a470b6), ], [ (0x3c6066aa803f0eb0, 0x3fee21523413f6d4), (0x3c701a65181dd95a, 0x3fd51a2372016c24), (0x3becd2eeb19f4fa0, 0xbf91bc285adfbae2), (0x3bd585c64e7b0238, 0x3f4fcc2f1ab1d691), (0xbb937747d5ec3df8, 0xbf064512bf089bca), (0x3b5b3a729384d857, 0x3eb74a95ddbb9ed7), (0xbb04bce0c7a6c35e, 0xbe61cb92c772ae76), (0xba9bc777b30f579a, 0x3e03488a2c937069), (0x3a2eef4771938cfe, 0xbd9c17387c41e64a), (0xb9ba789ead7c145e, 0x3d28b025d52dcbff), (0xb9471fb6ef94b8de, 0xbca3cd451511437b), ], [ (0x3c6fdcfd2ad6b2cc, 0x3fee7b70600bc584), (0xbc216caa13b9e460, 0x3fd4dbbfb210e2e8), (0x3c339b6e95789745, 0xbf9120a815b6c918), (0x3b956397b544cce0, 0x3f4e00d1e8922c76), (0x3ba4c65063f6319c, 0xbf0487ca2ab8e00b), (0x3b5b594e90f0637d, 0x3eb4fa9b5402f99a), (0xbabb01e0da08d320, 0xbe5f520c220f27b0), (0xbaa38014f8475a9c, 0x3e00947b1d1c07d5), (0xba3a70f466ff0512, 0xbd979905fceffdcd), (0x39aec257742e626c, 0x3d24434adc2f738f), (0xb92109b402248df6, 0xbc9fc2116c6f4f4c), ], [ (0xbc8ed7b55bc9a299, 0x3feed5973870ea62), (0x3c7068e6a0c0c082, 0x3fd49ec32763cc12), (0xbc3079ab6b76d441, 0xbf908c2099da4782), (0xbbeea4f5224b5d84, 0x3f4c5414cbe78b75), (0x3bac8ba9ee3c50e7, 0xbf02f1b182c9dcaf), (0xbb594f6e7ccb3656, 0x3eb2eb11438a7ca9), (0xbacdeb584cff4340, 0xbe5b9a34dc857c26), (0xba805fa93f84a21c, 0x3dfc8f43f4c51beb), (0xba3ae305c497455f, 0xbd93dcbcbc79e194), (0x39c91204c96816ba, 0x3d20aaf5b3fed175), (0x3931bf2dad1b074d, 0xbc9987b162a8d125), ], [ (0xbc8708c57fc49fa0, 0x3fef2fc3ce35d863), (0x3c6b3c877a15c102, 0x3fd46323a69e9f48), (0xbc27369c4763b491, 0xbf8ffc669e0ee421), (0x3bef1f26de28a2cd, 0x3f4ac3a8e2298377), (0xbba1cae3482f37ad, 0xbf017efdb93d4bc3), (0x3b53791a286e42a2, 0x3eb114642afe2ad3), (0xbafcada319b6cbb6, 0xbe585c28eac84be9), (0x3a4204182a290740, 0x3df8a37a4be247cb), (0x3a1aec8200b2b59c, 0xbd90c016dbd0389b), (0xb9bcbc705e49bce8, 0x3d1b7b30ce88ec83), (0xb90e04b1b0d7a938, 0xbc9492d96e10325b), ], [ (0xbc5a1c7d0cbb1620, 0x3fef89f42525e2f5), (0xbc6820327b9fb348, 0x3fd428d6d02b7336), (0xbc2028945818c390, 0xbf8eed0c4104b3e1), (0xbbeb1e19744aaa74, 0x3f494d6d68346b7e), (0xbb8648aa3d83ead0, 0xbf002c46ff7034db), (0x3b45bd818ecdcdba, 0x3eaedfe28b22d4e0), (0xbacb470408632410, 0xbe5587433a8ae1af), (0xba84cce387f694ea, 0x3df54a716368ebb1), (0xba16fd37fa555ba4, 0xbd8c4e3a86a2428b), (0xb9b5bae13524103e, 0x3d16b4243fb6f92d), (0x391f2bc487b07970, 0xbc909e8be69a15eb), ], [ (0x3c86cbe5e98a98ab, 0x3fefe426e98d02ad), (0xbc7374332a339b7b, 0x3fd3efd247baee74), (0x3c1e64f9511446c0, 0xbf8de98772761246), (0x3bebc8cddaed336e, 0x3f47ef6d292b758c), (0x3b890892e5c34bdc, 0xbefdecfe560cf884), (0x3b46edd1273601a7, 0x3eabefd0f34b6491), (0xbafabe6880484076, 0xbe530d455c33b91b), (0x3a87b53325d0c678, 0x3df26d73fda0c451), (0xba2145ca4055c756, 0xbd87f5ea8424c217), (0x3970bcc9a5266510, 0x3d12cbd951992e7f), (0xb92875f59f8743e5, 0xbc8ae9d6bb861ef8), ], [ (0x3c8e56531a4c0964, 0x3ff01f2d9d896b96), (0x3c69dd28e00eeaea, 0x3fd3b80bd8b693ad), (0x3c2112b49c2d929d, 0xbf8cf13718435314), (0xbbd3e3f549a6c02a, 0x3f46a7db8fd4d886), (0xbb9cfaf7080719dc, 0xbefbb5d132483335), (0x3b129df2d8378b30, 0x3ea94e632358a780), (0x3af34f526a85aadc, 0xbe50e1fbc80213d2), (0x3a85db7b76383a49, 0x3deff2fc81c56fd6), (0x3a1b4963ac2d4f62, 0xbd8451d234f7b2ee), (0x3985ca3f55e40518, 0x3d0f2fe7398a45f0), (0x392021e0641a748a, 0xbc85d7a01c5f7eb1), ], [ (0x3c8d688d52eeb63c, 0x3ff04c4843a795cb), (0x3c2e29d7b8b68640, 0x3fd381798d3b7124), (0x3c113b1fae95b222, 0xbf8c038376b558a7), (0x3bed5a3bd9d8951c, 0x3f457511992ea31d), (0x3b7acaf014e5fd04, 0xbef9ae1b7af2711a), (0x3b38fcf24e4c4314, 0x3ea6f2a944764535), (0xbab02dd93f02bfe0, 0xbe4df5df7475d1b8), (0x3a7be4558e764b58, 0x3debbd3b73f426e4), (0x39f60932f017fc58, 0xbd814340b64a12fa), (0x39962f7e531d98b0, 0x3d09ecf0c3cdff1f), (0xb92d928723f3b280, 0xbc81c44f3088b25e), ], [ (0x3c75eee764574b40, 0x3ff0796337eb156b), (0xbc75feae40a1a90b, 0x3fd34c11bbbceb70), (0x3c178be5b54d01d6, 0xbf8b1fddd6af094f), (0x3bd64edc5974df88, 0x3f44558acfb2b08c), (0x3b946505515a12bb, 0xbef7d172dfd1900f), (0x3b287c83bbb858b0, 0x3ea4d4cac4417e94), (0xbae9e442fc4b2618, 0xbe4a9e49b7c94308), (0xba566f889cc2e640, 0x3de81eda24ccecac), (0xba05ed5e30af5d38, 0xbd7d61fb394a66ad), (0xb9a9d5b973f44a13, 0x3d05982d519e12cc), (0xb906ddcc141d26be, 0xbc7cf7be237827b9), ], [ (0xbc81b90566f6f908, 0x3ff0a67e5c3c200c), (0xbc7d5212fc82f031, 0x3fd317cb0e502e4c), (0x3c200bb08e842505, 0xbf8a45c0157745d2), (0xbbebf591fc8f8179, 0x3f4347e266dfc96f), (0xbb86d2b6b1fc969e, 0xbef61bdff626f11b), (0xbb4b30acc251a2d5, 0x3ea2ede2579e5ca9), (0xbabdf54fda20eff0, 0xbe47adc218497f29), (0x3a64b88f981d6108, 0x3de5014d76da32ed), (0xba0cf8965161f6a2, 0xbd790c89e7a51571), (0x397940e2585c8c10, 0x3d020598950e90e1), (0xb8fe7525e1f6db28, 0xbc77aa994d491ad0), ], [ (0x3c8c4c890adae8f4, 0x3ff0d3999da52293), (0xbc6b205b14d29e54, 0x3fd2e49c85c0476f), (0xbc1fef66c53ee65e, 0xbf8974ac29e86d4f), (0xbbc62f38b0b4df28, 0x3f424ad083d71fe1), (0xbb945e74cd665950, 0xbef489d1c88dc8ce), (0x3b4aa3a0566b6933, 0x3ea137deb7d59680), (0x3ae507d700308bfb, 0xbe4516f993433b0f), (0x3a63c8fe3c89e8ac, 0x3de2519519e74a92), (0xba130f708fc4a0b1, 0xbd7563ea5df792c4), (0xb976d5e23edcbf48, 0x3cfe234f6246180b), (0xb8f27fdcff9e8dc4, 0xbc73605c0a952524), ], ]; pxfm-0.1.23/src/err/rerff.rs000064400000000000000000000304331046102023000137150ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; // Polynomials approximating x/erf(x) on ( k/8, (k + 1)/8 ) generated by Sollya and SageMath // ```text // def build_sollya_script(idx): // return f""" // d = [{idx}/8, {idx + 1}/8]; // // f = x/erf(x); // Q = fpminimax(f, [|0, 2, 4, 6, 8, 10, 12, 14|], [|D...|], d); // // for i from 0 to degree(Q) by 2 do {{ // write(coeff(Q, i)) >> "coefficients.txt"; // write("\\n") >> "coefficients.txt"; // }}; // """ // // def load_coefficients(filename): // with open(filename, "r") as f: // return [RealField(500)(line.strip()) for line in f if line.strip()] // // def call_sollya_on_interval(idx): // sollya_script = build_sollya_script(idx) // with open("tmp_interval.sollya", "w") as f: // f.write(sollya_script) // import subprocess // if os.path.exists("coefficients.txt"): // os.remove("coefficients.txt") // try: // result = subprocess.run( // ["sollya", "tmp_interval.sollya"], // check=True, // capture_output=True, // text=True // ) // except subprocess.CalledProcessError as e: // return // // def print_coeffs(poly): // print("[") // for i in range(len(poly)): // coeff = poly[i] // print(double_to_hex(coeff), ",") // print("],") // // print(f"static COEFFS: [[u64; 8]; 32] = [") // for i in range(0, 32): // call_sollya_on_interval(i) // coeffs = load_coefficients(f"coefficients.txt") // print_coeffs(coeffs) // print("];") // ``` static COEFFS: [[u64; 8]; 32] = [ [ 0x3fec5bf891b4ef6b, 0x3fd2e7fb0bcdee7f, 0x3f842aa5641a200a, 0xbf752081ae81d16e, 0x3f2e1a191fb85592, 0xbf203a20ad500043, 0x3f861a864f719e76, 0xbfc79f68bad20bd1, ], [ 0x3fec5bf891b4ef6b, 0x3fd2e7fb0bcdf45b, 0x3f842aa561f35512, 0xbf75207c8167ac1d, 0x3f2db4b119b4ce20, 0x3f20fa28737c4219, 0xbef38e74cca2219a, 0xbec5d70713fc621e, ], [ 0x3fec5bf891b4ef30, 0x3fd2e7fb0bce1c0f, 0x3f842aa56138541f, 0xbf75207c6197eb7c, 0x3f2db4799120e074, 0x3f20fc28d915a6e9, 0xbef3ea5b479dc053, 0xbebbffe6df8ec372, ], [ 0x3fec5bf891b4bf18, 0x3fd2e7fb0bde166f, 0x3f842aa53c721766, 0xbf7520796733bbec, 0x3f2db21eebf4144f, 0x3f210545cc78d0f0, 0xbef48ad7e4aa2d10, 0xbeb24a043ad31907, ], [ 0x3fec5bf891ab16e9, 0x3fd2e7fb0dc7b919, 0x3f842aa29d8381e7, 0xbf7520592585d601, 0x3f2da30df1566e43, 0x3f212780ff325aa6, 0xbef5e98ea9819e42, 0xbe9849d52099dcb9, ], [ 0x3fec5bf890ddfa8d, 0x3fd2e7fb28aab312, 0x3f842a8a461f0eb7, 0xbf751f93b2d27114, 0x3f2d66789eed5f95, 0x3f21818ff1832f50, 0xbef84264724049ef, 0x3e9df12b02e82a5a, ], [ 0x3fec5bf887f64fa4, 0x3fd2e7fbfcc05f75, 0x3f842a02323e2099, 0xbf751c86d291ced6, 0x3f2cbd5653cde433, 0x3f223299b32b8583, 0xbefb7fc6e286cd94, 0x3eb49676cb3da393, ], [ 0x3fec5bf84f8e2488, 0x3fd2e7ffe83d2974, 0x3f842821c5cc659c, 0xbf7514805a6196e3, 0x3f2b723680f64bb5, 0x3f233416dcfcd366, 0xbefefe55300afaa7, 0x3ebf0c475fb71e7a, ], [ 0x3fec5bf7999e6afe, 0x3fd2e809c6d4caa7, 0x3f84247256be4a56, 0xbf750838db0c0cf5, 0x3f29e7e867267388, 0x3f24226adee5ce74, 0xbf00c0830af2bf01, 0x3ec26fb6b18e628b, ], [ 0x3fec5bf801fc5ad5, 0x3fd2e80618e8941e, 0x3f84254c04b0b234, 0xbf7509d7cf351201, 0x3f2a01829944820c, 0x3f241d7bb0c7e2de, 0xbf00c2d844916d26, 0x3ec2817d39abc26b, ], [ 0x3fec5c0938a12f13, 0x3fd2e7706c510d79, 0x3f8448392db86aae, 0xbf75526e9c6046f0, 0x3f2facd0bc0e7862, 0x3f21fc4093e1e6b7, 0xbefdf54af68ba968, 0x3ebfe348fc246c15, ], [ 0x3fec5c6dcdadc5d8, 0x3fd2e495072afff3, 0x3f84d6f390564d4d, 0xbf764a7e85749c85, 0x3f37effb62caee80, 0x3f19cb39bc236ae6, 0xbef6d7035785e8f3, 0x3eb755aa2e58fc52, ], [ 0x3fec5dd74381acff, 0x3fd2dbe68140f116, 0x3f86459e1acfda0f, 0xbf7865203923a03d, 0x3f43665053a48049, 0x3f0409e353b761ea, 0xbeeb0b00f567c9f8, 0x3eabc33000611b25, ], [ 0x3fec6175431226d1, 0x3fd2c8dcbb0babcc, 0x3f88f5bfd61e5d2e, 0xbf7bc60de8dff620, 0x3f4d9b7076c7767c, 0xbf0106584fac3547, 0xbed0a56cd1030deb, 0x3e970ee11e7beb48, ], [ 0x3fec68445d99a8e9, 0x3fd2a9d608dbfea2, 0x3f8cc072ddf22cb6, 0xbf7fe5f2efdc5f5c, 0x3f5431d1deff38bc, 0xbf197220e4a1dda8, 0x3ec9e2469e6c1c67, 0x3e4be72535d53d7b, ], [ 0x3fec713c415bf088, 0x3fd28610e83aa38c, 0x3f9049ee1942f46b, 0xbf81c513d165d6fd, 0x3f585bc13e0fcaba, 0xbf22715362e30768, 0x3ede6bfa3c69e8e3, 0xbe852cd85f8dea5b, ], [ 0x3fec770e08b47107, 0x3fd2716324b22047, 0x3f91460d403e6b9c, 0xbf829ab46375f10d, 0x3f5a0e7f00c76fb5, 0xbf2484890f2d7eeb, 0x3ee207b21bbd8496, 0xbe8bbee036671b6a, ], [ 0x3fec6f4a2d01088d, 0x3fd288e494bc89b7, 0x3f905203788a2821, 0xbf81eab2727ce365, 0x3f58ddba75a3c100, 0xbf2347c9a317a175, 0x3ee099c93ce5f44f, 0xbe88e9f9c064f833, ], [ 0x3fec4c9bbce50c7d, 0x3fd2e8175b0e1837, 0x3f89a2d1518c7a4c, 0xbf7f3fa91859127e, 0x3f55431c495b1077, 0xbf1fc1af665bb1f8, 0x3eda0f1d735195cb, 0xbe827b8d6fa224ed, ], [ 0x3fec03cce39d7213, 0x3fd39c2316e290bf, 0x3f7b674438899313, 0xbf783644c88c71fb, 0x3f5047a3da485180, 0xbf1748b54f823d57, 0x3ed20c86d3302f22, 0xbe77f94cafe045a8, ], [ 0x3feb913f0adf6c4b, 0x3fd49c4cedae09fc, 0xbf4a6dea9778f474, 0xbf7006dc4e6c8125, 0x3f461483c254fa5f, 0xbf0e75052760bf18, 0x3ec65425869bc096, 0xbe6bc2df9fbc0f82, ], [ 0x3feafbeda3b7d400, 0x3fd5cb900ee1fb5e, 0xbf8228d16e87de3d, 0xbf6011d44e155bf5, 0x3f3993b736442257, 0xbf017c7ee5efa6ad, 0x3eb886e337d2e3c2, 0xbe5cba4b79e90043, ], [ 0x3fea54849d309eba, 0x3fd701afa55e3d21, 0xbf90c72bb2e2799f, 0xbf33c92573294e34, 0x3f265284f7a6d53a, 0xbef09f09298ed1e8, 0x3ea7153a46cb2e27, 0xbe49ef6ec79265fd, ], [ 0x3fe9b128df667870, 0x3fd816d295a867cb, 0xbf9713f11ea84a26, 0x3f4edcbdd63903bb, 0x3ef44f54fc7a6024, 0xbed45da547d2fcb8, 0x3e9049754d57a9a7, 0xbe32aba05ca26a69, ], [ 0x3fe927f49edf4ace, 0x3fd8ecd207c6a7d1, 0xbf9b8cd215124008, 0x3f5cbab209dd389d, 0xbf12a8920ea6230f, 0x3eb442dfce60b0e2, 0x3e52494e415c7728, 0xbe09a1b1bbb9cee4, ], [ 0x3fe8ca3d7437d06f, 0x3fd973c08b6d33fb, 0xbf9e272ca1fccc06, 0x3f61efd00e2016b6, 0xbf1e6dab18e9d45a, 0x3ed0b446e3469be1, 0xbe7503c584488bed, 0x3e069968660290a4, ], [ 0x3fe8a1f4b154f663, 0x3fd9a9a8b81692d4, 0xbf9f1e9312dd4501, 0x3f632b4d20599404, 0xbf2119c1b5e43b24, 0x3ed42b9874284d56, 0xbe7c17cc1eef4b9d, 0x3e117f0a9057a689, ], [ 0x3fe8b15bfcf78f33, 0x3fd99720c884ab33, 0xbf9ed2265979f5a6, 0x3f62d3c30432692b, 0xbf20a17346c37362, 0x3ed36538f2d21c31, 0xbe7aac6bb10f8b90, 0x3e1061d3a1737044, ], [ 0x3fe8f479e98cb825, 0x3fd94ab3f8d0c80c, 0xbf9da7afe85abf94, 0x3f618fe28f71a3d4, 0xbf1df723b2a63e38, 0x3ed0d190252a7f7c, 0xbe7631fdd49272b0, 0x3e0a17567cab4a94, ], [ 0x3fe9636d647b61c0, 0x3fd8d4aaba0e0212, 0xbf9bf904574e56ea, 0x3f5fb68684d8555d, 0xbf19d06f9cf17bbf, 0x3ecb92b9f0b8acf3, 0xbe7145bde0c499ae, 0x3e033cf1cb08ce4c, ], [ 0x3fe9f4c3301b6d33, 0x3fd844100b4598b3, 0xbf9a0b94e19be990, 0x3f5c0ed55c70532f, 0xbf15a786c9e62b23, 0x3ec5e3f05a04f5c6, 0xbe69ea9db2e37883, 0x3dfb3e5ad2cd0fb2, ], [ 0x3fea9f469c75536c, 0x3fd7a51b3d9eda10, 0xbf980f63a2cb486c, 0x3f5887f72a9f07e0, 0xbf11e4d454f2f994, 0x3ec113d0aed8bdef, 0xbe6311f84083acf4, 0x3df2e4dc2e50e3fa, ], ]; /// Computes 1/erf(x) /// /// Max ulp 0.5 #[inline] pub fn f_rerff(x: f32) -> f32 { let x_u = x.to_bits(); let x_abs = x_u & 0x7fff_ffffu32; if x == 0. { return if x.is_sign_negative() { f32::NEG_INFINITY } else { f32::INFINITY }; } if x_abs >= 0x4080_0000u32 { static ONE: [f32; 2] = [1.0, -1.0]; static SMALL: [f32; 2] = [f32::from_bits(0xb3000000), f32::from_bits(0x33000000)]; let sign = x.is_sign_negative() as usize; if x_abs >= 0x7f80_0000u32 { return if x_abs > 0x7f80_0000 { x } else { ONE[sign] }; } return ONE[sign] + SMALL[sign]; } // Polynomial approximation see [COEFFS] for generation: // 1/erf(x) ~ (c0 + c1 * x^2 + c2 * x^4 + ... + c7 * x^14) / x let xd = x as f64; let xsq = xd * xd; const EIGHT: u32 = 3 << 23; let idx = f32::from_bits(x_abs.wrapping_add(EIGHT)) as usize; let c = COEFFS[idx]; let x4 = xsq * xsq; let c0 = f_fmla(xsq, f64::from_bits(c[1]), f64::from_bits(c[0])); let c1 = f_fmla(xsq, f64::from_bits(c[3]), f64::from_bits(c[2])); let c2 = f_fmla(xsq, f64::from_bits(c[5]), f64::from_bits(c[4])); let c3 = f_fmla(xsq, f64::from_bits(c[7]), f64::from_bits(c[6])); let x8 = x4 * x4; let p0 = f_fmla(x4, c1, c0); let p1 = f_fmla(x4, c3, c2); ((f_fmla(x8, p1, p0)) / xd) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_erff_test() { assert_eq!(f_rerff(0.0), f32::INFINITY); assert_eq!(f_rerff(-0.0), f32::NEG_INFINITY); assert_eq!(f_rerff(0.015255669), 58.096153); assert_eq!(f_rerff(1.0), 1.1866608); assert_eq!(f_rerff(0.5), 1.9212301); } } pxfm-0.1.23/src/exponents/auxiliary.rs000064400000000000000000000065371046102023000160630ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicSign, f64_from_parts}; #[inline] pub(crate) fn ldexp(d: f64, i: i32) -> f64 { let mut n = i; let exp_max = 1023; let exp_min = -1022; const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) let f_exp_max = f64_from_parts(DyadicSign::Pos, EXP_BIAS << 1, 0); // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) let f_exp_min = f64_from_parts(DyadicSign::Pos, 1, 0); let mut x = d; if n < exp_min { // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) let f_pow_subnorm = f64_from_parts(DyadicSign::Pos, 52 + EXP_BIAS, 0); let mul = f_exp_min * f_pow_subnorm; let add = -exp_min - 52i32; // 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 + 52i32 + 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 if n > exp_max { 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; } } } let scale = f64_from_parts(DyadicSign::Pos, (EXP_BIAS as i32 + n) as u64, 0); x * scale } #[inline] pub(crate) fn fast_ldexp(d: f64, i: i32) -> f64 { let mut u = d.to_bits(); u = u.wrapping_add((i as u64).wrapping_shl(52)); f64::from_bits(u) } pxfm-0.1.23/src/exponents/exp.rs000064400000000000000000000371301046102023000146410ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, fmla, pow2i, rintk}; use crate::double_double::DoubleDouble; use crate::exponents::auxiliary::fast_ldexp; /// Exp for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn exp(d: f64) -> f64 { const EXP_POLY_1_D: f64 = 2f64; const EXP_POLY_2_D: f64 = 0.16666666666666674f64; const EXP_POLY_3_D: f64 = -0.0027777777777777614f64; const EXP_POLY_4_D: f64 = 6.613756613755705e-5f64; const EXP_POLY_5_D: f64 = -1.6534391534392554e-6f64; const EXP_POLY_6_D: f64 = 4.17535139757361979584e-8f64; const L2_U: f64 = 0.693_147_180_559_662_956_511_601_805_686_950_683_593_75; const L2_L: f64 = 0.282_352_905_630_315_771_225_884_481_750_134_360_255_254_120_68_e-12; const R_LN2: f64 = 1.442_695_040_888_963_407_359_924_681_001_892_137_426_645_954_152_985_934_135_449_406_931; let qf = rintk(d * R_LN2); let q = qf as i32; let mut r = fmla(qf, -L2_U, d); r = fmla(qf, -L2_L, r); let f = r * r; // Poly for u = r*(exp(r)+1)/(exp(r)-1) let mut u = EXP_POLY_6_D; u = fmla(u, f, EXP_POLY_5_D); u = fmla(u, f, EXP_POLY_4_D); u = fmla(u, f, EXP_POLY_3_D); u = fmla(u, f, EXP_POLY_2_D); u = fmla(u, f, EXP_POLY_1_D); let u = 1f64 + 2f64 * r / (u - r); let i2 = pow2i(q); u * i2 // if d < -964f64 { // r = 0f64; // } // if d > 709f64 { // r = f64::INFINITY; // } } pub(crate) static EXP_REDUCE_T0: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc719083535b085e, 0x3ff02c9a3e778061), (0x3c8d73e2a475b466, 0x3ff059b0d3158574), (0x3c6186be4bb28500, 0x3ff0874518759bc8), (0x3c98a62e4adc610a, 0x3ff0b5586cf9890f), (0x3c403a1727c57b52, 0x3ff0e3ec32d3d1a2), (0xbc96c51039449b3a, 0x3ff11301d0125b51), (0xbc932fbf9af1369e, 0x3ff1429aaea92de0), (0xbc819041b9d78a76, 0x3ff172b83c7d517b), (0x3c8e5b4c7b4968e4, 0x3ff1a35beb6fcb75), (0x3c9e016e00a2643c, 0x3ff1d4873168b9aa), (0x3c8dc775814a8494, 0x3ff2063b88628cd6), (0x3c99b07eb6c70572, 0x3ff2387a6e756238), (0x3c82bd339940e9da, 0x3ff26b4565e27cdd), (0x3c8612e8afad1256, 0x3ff29e9df51fdee1), (0x3c90024754db41d4, 0x3ff2d285a6e4030b), (0x3c86f46ad23182e4, 0x3ff306fe0a31b715), (0x3c932721843659a6, 0x3ff33c08b26416ff), (0xbc963aeabf42eae2, 0x3ff371a7373aa9cb), (0xbc75e436d661f5e2, 0x3ff3a7db34e59ff7), (0x3c8ada0911f09ebc, 0x3ff3dea64c123422), (0xbc5ef3691c309278, 0x3ff4160a21f72e2a), (0x3c489b7a04ef80d0, 0x3ff44e086061892d), (0x3c73c1a3b69062f0, 0x3ff486a2b5c13cd0), (0x3c7d4397afec42e2, 0x3ff4bfdad5362a27), (0xbc94b309d25957e4, 0x3ff4f9b2769d2ca7), (0xbc807abe1db13cac, 0x3ff5342b569d4f82), (0x3c99bb2c011d93ac, 0x3ff56f4736b527da), (0x3c96324c054647ac, 0x3ff5ab07dd485429), (0x3c9ba6f93080e65e, 0x3ff5e76f15ad2148), (0xbc9383c17e40b496, 0x3ff6247eb03a5585), (0xbc9bb60987591c34, 0x3ff6623882552225), (0xbc9bdd3413b26456, 0x3ff6a09e667f3bcd), (0xbc6bbe3a683c88aa, 0x3ff6dfb23c651a2f), (0xbc816e4786887a9a, 0x3ff71f75e8ec5f74), (0xbc90245957316dd4, 0x3ff75feb564267c9), (0xbc841577ee049930, 0x3ff7a11473eb0187), (0x3c705d02ba15797e, 0x3ff7e2f336cf4e62), (0xbc9d4c1dd41532d8, 0x3ff82589994cce13), (0xbc9fc6f89bd4f6ba, 0x3ff868d99b4492ed), (0x3c96e9f156864b26, 0x3ff8ace5422aa0db), (0x3c85cc13a2e3976c, 0x3ff8f1ae99157736), (0xbc675fc781b57ebc, 0x3ff93737b0cdc5e5), (0xbc9d185b7c1b85d0, 0x3ff97d829fde4e50), (0x3c7c7c46b071f2be, 0x3ff9c49182a3f090), (0xbc9359495d1cd532, 0x3ffa0c667b5de565), (0xbc9d2f6edb8d41e2, 0x3ffa5503b23e255d), (0x3c90fac90ef7fd32, 0x3ffa9e6b5579fdbf), (0x3c97a1cd345dcc82, 0x3ffae89f995ad3ad), (0xbc62805e3084d708, 0x3ffb33a2b84f15fb), (0xbc75584f7e54ac3a, 0x3ffb7f76f2fb5e47), (0x3c823dd07a2d9e84, 0x3ffbcc1e904bc1d2), (0x3c811065895048de, 0x3ffc199bdd85529c), (0x3c92884dff483cac, 0x3ffc67f12e57d14b), (0x3c7503cbd1e949dc, 0x3ffcb720dcef9069), (0xbc9cbc3743797a9c, 0x3ffd072d4a07897c), (0x3c82ed02d75b3706, 0x3ffd5818dcfba487), (0x3c9c2300696db532, 0x3ffda9e603db3285), (0xbc91a5cd4f184b5c, 0x3ffdfc97337b9b5f), (0x3c839e8980a9cc90, 0x3ffe502ee78b3ff6), (0xbc9e9c23179c2894, 0x3ffea4afa2a490da), (0x3c9dc7f486a4b6b0, 0x3ffefa1bee615a27), (0x3c99d3e12dd8a18a, 0x3fff50765b6e4540), (0x3c874853f3a5931e, 0x3fffa7c1819e90d8), ]; pub(crate) static EXP_REDUCE_T1: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c9ae8e38c59c72a, 0x3ff000b175effdc7), (0xbc57b5d0d58ea8f4, 0x3ff00162f3904052), (0x3c94115cb6b16a8e, 0x3ff0021478e11ce6), (0xbc8d7c96f201bb2e, 0x3ff002c605e2e8cf), (0x3c984711d4c35ea0, 0x3ff003779a95f959), (0xbc80484245243778, 0x3ff0042936faa3d8), (0xbc94b237da2025fa, 0x3ff004dadb113da0), (0xbc75e00e62d6b30e, 0x3ff0058c86da1c0a), (0x3c9a1d6cedbb9480, 0x3ff0063e3a559473), (0xbc94acf197a00142, 0x3ff006eff583fc3d), (0xbc6eaf2ea42391a6, 0x3ff007a1b865a8ca), (0x3c7da93f90835f76, 0x3ff0085382faef83), (0xbc86a79084ab093c, 0x3ff00905554425d4), (0x3c986364f8fbe8f8, 0x3ff009b72f41a12b), (0xbc882e8e14e3110e, 0x3ff00a6910f3b6fd), (0xbc84f6b2a7609f72, 0x3ff00b1afa5abcbf), (0xbc7e1a258ea8f71a, 0x3ff00bcceb7707ec), (0x3c74362ca5bc26f2, 0x3ff00c7ee448ee02), (0x3c9095a56c919d02, 0x3ff00d30e4d0c483), (0xbc6406ac4e81a646, 0x3ff00de2ed0ee0f5), (0x3c9b5a6902767e08, 0x3ff00e94fd0398e0), (0xbc991b2060859320, 0x3ff00f4714af41d3), (0x3c8427068ab22306, 0x3ff00ff93412315c), (0x3c9c1d0660524e08, 0x3ff010ab5b2cbd11), (0xbc9e7bdfb3204be8, 0x3ff0115d89ff3a8b), (0x3c8843aa8b9cbbc6, 0x3ff0120fc089ff63), (0xbc734104ee7edae8, 0x3ff012c1fecd613b), (0xbc72b6aeb6176892, 0x3ff0137444c9b5b5), (0x3c7a8cd33b8a1bb2, 0x3ff01426927f5278), (0x3c72edc08e5da99a, 0x3ff014d8e7ee8d2f), (0x3c857ba2dc7e0c72, 0x3ff0158b4517bb88), (0x3c9b61299ab8cdb8, 0x3ff0163da9fb3335), (0xbc990565902c5f44, 0x3ff016f0169949ed), (0x3c870fc41c5c2d54, 0x3ff017a28af25567), (0x3c94b9a6e145d76c, 0x3ff018550706ab62), (0xbc7008eff5142bfa, 0x3ff019078ad6a19f), (0xbc977669f033c7de, 0x3ff019ba16628de2), (0xbc909bb78eeead0a, 0x3ff01a6ca9aac5f3), (0x3c9371231477ece6, 0x3ff01b1f44af9f9e), (0x3c75e7626621eb5a, 0x3ff01bd1e77170b4), (0xbc9bc72b100828a4, 0x3ff01c8491f08f08), (0xbc6ce39cbbab8bbe, 0x3ff01d37442d5070), (0x3c816996709da2e2, 0x3ff01de9fe280ac8), (0xbc8c11f5239bf536, 0x3ff01e9cbfe113ef), (0x3c8e1d4eb5edc6b4, 0x3ff01f4f8958c1c6), (0xbc9afb99946ee3f0, 0x3ff020025a8f6a35), (0xbc98f06d8a148a32, 0x3ff020b533856324), (0xbc82bf310fc54eb6, 0x3ff02168143b0281), (0xbc9c95a035eb4176, 0x3ff0221afcb09e3e), (0xbc9491793e46834c, 0x3ff022cdece68c4f), (0xbc73e8d0d9c49090, 0x3ff02380e4dd22ad), (0xbc9314aa16278aa4, 0x3ff02433e494b755), (0x3c848daf888e9650, 0x3ff024e6ec0da046), (0x3c856dc8046821f4, 0x3ff02599fb483385), (0x3c945b42356b9d46, 0x3ff0264d1244c719), (0xbc7082ef51b61d7e, 0x3ff027003103b10e), (0x3c72106ed0920a34, 0x3ff027b357854772), (0xbc9fd4cf26ea5d0e, 0x3ff0286685c9e059), (0xbc909f8775e78084, 0x3ff02919bbd1d1d8), (0x3c564cbba902ca28, 0x3ff029ccf99d720a), (0x3c94383ef231d206, 0x3ff02a803f2d170d), (0x3c94a47a505b3a46, 0x3ff02b338c811703), (0x3c9e471202234680, 0x3ff02be6e199c811), ]; // sets the exponent of a binary64 number to 0 (subnormal range) #[inline] pub(crate) fn to_denormal(x: f64) -> f64 { let mut ix = x.to_bits(); ix &= 0x000fffffffffffff; f64::from_bits(ix) } #[inline] fn exp_poly_dd(z: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 7] = [ (0x0000000000000000, 0x3ff0000000000000), (0x39c712f72ecec2cf, 0x3fe0000000000000), (0x3c65555555554d07, 0x3fc5555555555555), (0x3c455194d28275da, 0x3fa5555555555555), (0x3c012faa0e1c0f7b, 0x3f81111111111111), (0xbbf4ba45ab25d2a3, 0x3f56c16c16da6973), (0xbbc9091d845ecd36, 0x3f2a01a019eb7f31), ]; let mut r = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[6]), z, DoubleDouble::from_bit_pair(C[5]), ); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[4])); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[3])); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[2])); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[1])); DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[0])) } #[cold] fn as_exp_accurate(x: f64, t: f64, tz: DoubleDouble, ie: i64) -> f64 { let mut ix = x.to_bits(); if ((ix >> 52) & 0x7ff) < 0x3c9 { return 1. + x; } /* Use Cody-Waite argument reduction: since |x| < 745, we have |t| < 2^23, thus since l2h is exactly representable on 29 bits, l2h*t is exact. */ const L2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3d0718432a1b0e26), f64::from_bits(0x3f262e42ff000000), ); const L2LL: f64 = f64::from_bits(0x3999ff0342542fc3); let dx = f_fmla(-L2.hi, t, x); let dx_dd = DoubleDouble::quick_mult_f64(DoubleDouble::new(L2LL, L2.lo), t); let dz = DoubleDouble::full_add_f64(dx_dd, dx); let mut f = exp_poly_dd(dz); f = DoubleDouble::quick_mult(dz, f); if ix > 0xc086232bdd7abcd2u64 { // x < -708.396 ix = 1i64.wrapping_sub(ie).wrapping_shl(52) as u64; f = DoubleDouble::quick_mult(f, tz); f = DoubleDouble::add(tz, f); let new_f = DoubleDouble::from_exact_add(f64::from_bits(ix), f.hi); f.lo += new_f.lo; f.hi = to_denormal(f.hi + f.lo); } else { if tz.hi == 1.0 { let fhe = DoubleDouble::from_exact_add(tz.hi, f.hi); let fhl = DoubleDouble::from_exact_add(fhe.lo, f.lo); f.hi = fhe.hi; f.lo = fhl.hi; ix = f.lo.to_bits(); if (ix & 0x000fffffffffffff) == 0 { let v = fhl.lo.to_bits(); let d: i64 = (((((ix as i64) >> 63) ^ ((v as i64) >> 63)) as u64).wrapping_shl(1) as i64) .wrapping_add(1); ix = ix.wrapping_add(d as u64); f.lo = f64::from_bits(ix); } } else { f = DoubleDouble::quick_mult(f, tz); f = DoubleDouble::add(tz, f); } f = DoubleDouble::from_exact_add(f.hi, f.lo); f.hi = fast_ldexp(f.hi, ie as i32); } f.hi } /// Computes exponent /// /// Max found ULP 0.5 pub fn f_exp(x: f64) -> f64 { let mut ix = x.to_bits(); let aix = ix & 0x7fffffffffffffff; // exp(x) rounds to 1 to nearest for |x| <= 5.55112e-17 if aix <= 0x3c90000000000000u64 { // |x| <= 5.55112e-17 return 1.0 + x; } if aix >= 0x40862e42fefa39f0u64 { // |x| >= 709.783 if aix > 0x7ff0000000000000u64 { return x + x; } // nan if aix == 0x7ff0000000000000u64 { // |x| = inf return if (ix >> 63) != 0 { 0.0 // x = -inf } else { x // x = inf }; } if (ix >> 63) == 0 { // x >= 709.783 let z = f64::from_bits(0x7fe0000000000000); return z * z; } if aix >= 0x40874910d52d3052u64 { // x <= -745.133 return f64::from_bits(0x18000000000000) * f64::from_bits(0x3c80000000000000); } } const S: f64 = f64::from_bits(0x40b71547652b82fe); let t = (x * S).round(); let jt: i64 = t as i64; let i0: i64 = (jt >> 6) & 0x3f; let i1 = jt & 0x3f; let ie: i64 = jt >> 12; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i0 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let tz = DoubleDouble::quick_mult(t0, t1); const L2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3d0718432a1b0e26), f64::from_bits(0x3f262e42ff000000), ); /* Use Cody-Waite argument reduction: since |x| < 745, we have |t| < 2^23, thus since l2h is exactly representable on 29 bits, l2h*t is exact. */ let dx = f_fmla(L2.lo, t, f_fmla(-L2.hi, t, x)); let dx2 = dx * dx; const CH: [u64; 4] = [ 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc55555557e54ff, 0x3fa55555553a12f4, ]; let pw0 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pw1 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let p = f_fmla(dx2, pw0, pw1); let mut f = DoubleDouble::new(f_fmla(tz.hi * dx, p, tz.lo), tz.hi); const EPS: f64 = f64::from_bits(0x3c0833beace2b6fe); if ix > 0xc086232bdd7abcd2u64 { // subnormal case: x < -708.396 ix = 1u64.wrapping_sub(ie as u64).wrapping_shl(52); let sums = DoubleDouble::from_exact_add(f64::from_bits(ix), f.hi); f.hi = sums.hi; f.lo += sums.lo; let ub = f.hi + (f.lo + EPS); let lb = f.hi + (f.lo - EPS); if ub != lb { return as_exp_accurate(x, t, tz, ie); } f.hi = to_denormal(lb); } else { let ub = f.hi + (f.lo + EPS); let lb = f.hi + (f.lo - EPS); if ub != lb { return as_exp_accurate(x, t, tz, ie); } f.hi = fast_ldexp(lb, ie as i32); } f.hi } #[cfg(test)] mod tests { use super::*; #[test] fn exp_test() { assert!( (exp(0f64) - 1f64).abs() < 1e-8, "Invalid result {}", exp(0f64) ); assert!( (exp(5f64) - 148.4131591025766034211155800405522796f64).abs() < 1e-8, "Invalid result {}", exp(5f64) ); } #[test] fn f_exp_test() { assert_eq!(f_exp(0.000000014901161193847656), 1.0000000149011614); assert_eq!(f_exp(0.), 1.); assert_eq!(f_exp(5f64), 148.4131591025766034211155800405522796f64); assert_eq!(f_exp(f64::INFINITY), f64::INFINITY); assert_eq!(f_exp(f64::NEG_INFINITY), 0.); assert!(f_exp(f64::NAN).is_nan()); } } pxfm-0.1.23/src/exponents/exp10.rs000064400000000000000000000203241046102023000147770ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::exponents::auxiliary::fast_ldexp; use crate::exponents::exp::{EXP_REDUCE_T0, EXP_REDUCE_T1, to_denormal}; use std::hint::black_box; #[inline] fn exp10_poly_dd(z: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 6] = [ (0xbcaf48ad494ea102, 0x40026bb1bbb55516), (0xbcae2bfab318d399, 0x40053524c73cea69), (0x3ca81f50779e162b, 0x4000470591de2ca4), (0x3c931a5cc5d3d313, 0x3ff2bd7609fd98c4), (0x3c8910de8c68a0c2, 0x3fe1429ffd336aa3), (0xbc605e703d496537, 0x3fca7ed7086882b4), ]; let mut r = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[5]), z, DoubleDouble::from_bit_pair(C[4]), ); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[3])); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[2])); r = DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[1])); DoubleDouble::quick_mul_add(r, z, DoubleDouble::from_bit_pair(C[0])) } #[cold] fn as_exp10_accurate(x: f64) -> f64 { let mut ix = x.to_bits(); let t = (f64::from_bits(0x40ca934f0979a371) * x).round_ties_even(); let jt: i64 = t as i64; let i1 = jt & 0x3f; let i0 = (jt >> 6) & 0x3f; let ie = jt >> 12; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i0 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let dt = DoubleDouble::quick_mult(t0, t1); const L0: f64 = f64::from_bits(0x3f13441350800000); const L1: f64 = f64::from_bits(0xbd1f79fef311f12b); const L2: f64 = f64::from_bits(0xb9aac0b7c917826b); let dx = x - L0 * t; let dx_dd = DoubleDouble::quick_mult_f64(DoubleDouble::new(L2, L1), t); let dz = DoubleDouble::full_add_f64(dx_dd, dx); let mut f = exp10_poly_dd(dz); f = DoubleDouble::quick_mult(dz, f); let mut zfh: f64; if ix < 0xc0733a7146f72a42u64 { if (jt & 0xfff) == 0 { f = DoubleDouble::from_exact_add(f.hi, f.lo); let zt = DoubleDouble::from_exact_add(dt.hi, f.hi); f.hi = zt.lo; f = DoubleDouble::from_exact_add(f.hi, f.lo); ix = f.hi.to_bits(); if (ix.wrapping_shl(12)) == 0 { let l = f.lo.to_bits(); let sfh: i64 = ((ix as i64) >> 63) ^ ((l as i64) >> 63); ix = ix.wrapping_add(((1i64 << 51) ^ sfh) as u64); } zfh = zt.hi + f64::from_bits(ix); } else { f = DoubleDouble::quick_mult(f, dt); f = DoubleDouble::add(dt, f); f = DoubleDouble::from_exact_add(f.hi, f.lo); zfh = f.hi; } zfh = fast_ldexp(zfh, ie as i32); } else { ix = (1u64.wrapping_sub(ie as u64)) << 52; f = DoubleDouble::quick_mult(f, dt); f = DoubleDouble::add(dt, f); let zt = DoubleDouble::from_exact_add(f64::from_bits(ix), f.hi); f.hi = zt.hi; f.lo += zt.lo; zfh = to_denormal(f.to_f64()); } zfh } /// Computes exp10 /// /// Max found ULP 0.5 pub fn f_exp10(x: f64) -> f64 { let mut ix = x.to_bits(); let aix = ix & 0x7fff_ffff_ffff_ffff; if aix > 0x40734413509f79feu64 { // |x| > 0x40734413509f79fe if aix > 0x7ff0000000000000u64 { return x + x; } // nan if aix == 0x7ff0000000000000u64 { return if (ix >> 63) != 0 { 0.0 } else { x }; } if (ix >> 63) == 0 { return f64::from_bits(0x7fe0000000000000) * 2.0; // x > 308.255 } if aix > 0x407439b746e36b52u64 { // x < -323.607 return black_box(f64::from_bits(0x0018000000000000)) * black_box(f64::from_bits(0x3c80000000000000)); } } // check x integer to avoid a spurious inexact exception if ix.wrapping_shl(16) == 0 && (aix >> 48) <= 0x4036 { let kx = x.round_ties_even(); if kx == x { let k = kx as i64; if k >= 0 { let mut r = 1.0; for _ in 0..k { r *= 10.0; } return r; } } } /* avoid spurious underflow: for |x| <= 2.41082e-17 exp10(x) rounds to 1 to nearest */ if aix <= 0x3c7bcb7b1526e50eu64 { return 1.0 + x; // |x| <= 2.41082e-17 } let t = (f64::from_bits(0x40ca934f0979a371) * x).round_ties_even(); let jt = t as i64; let i1 = jt & 0x3f; let i0 = (jt >> 6) & 0x3f; let ie = jt >> 12; let t00 = EXP_REDUCE_T0[i0 as usize]; let t01 = EXP_REDUCE_T1[i1 as usize]; let t0 = DoubleDouble::from_bit_pair(t00); let t1 = DoubleDouble::from_bit_pair(t01); let mut tz = DoubleDouble::quick_mult(t0, t1); const L0: f64 = f64::from_bits(0x3f13441350800000); const L1: f64 = f64::from_bits(0x3d1f79fef311f12b); let dx = f_fmla(-L1, t, f_fmla(-L0, t, x)); let dx2 = dx * dx; const CH: [u64; 4] = [ 0x40026bb1bbb55516, 0x40053524c73cea69, 0x4000470591fd74e1, 0x3ff2bd760a1f32a5, ]; let p0 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let p1 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let p = f_fmla(dx2, p1, p0); let mut fh = tz.hi; let fx = tz.hi * dx; let mut fl = f_fmla(fx, p, tz.lo); const EPS: f64 = 1.63e-19; if ix < 0xc0733a7146f72a42u64 { // x > -307.653 // x > -0x1.33a7146f72a42p+8 let ub = fh + (fl + EPS); let lb = fh + (fl - EPS); if lb != ub { return as_exp10_accurate(x); } fh = fast_ldexp(fh + fl, ie as i32); } else { // x <= -307.653: exp10(x) < 2^-1022 ix = 1u64.wrapping_sub(ie as u64).wrapping_shl(52); tz = DoubleDouble::from_exact_add(f64::from_bits(ix), fh); fl += tz.lo; let ub = fh + (fl + EPS); let lb = fh + (fl - EPS); if lb != ub { return as_exp10_accurate(x); } fh = to_denormal(fh + fl); } fh } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp10f() { assert_eq!(f_exp10(-3.370739843267434), 0.00042585343701025656); assert_eq!(f_exp10(1.), 10.0); assert_eq!(f_exp10(2.), 100.0); assert_eq!(f_exp10(3.), 1000.0); assert_eq!(f_exp10(4.), 10000.0); assert_eq!(f_exp10(5.), 100000.0); assert_eq!(f_exp10(6.), 1000000.0); assert_eq!(f_exp10(7.), 10000000.0); assert_eq!(f_exp10(f64::INFINITY), f64::INFINITY); assert_eq!(f_exp10(f64::NEG_INFINITY), 0.); assert!(f_exp10(f64::NAN).is_nan()); } } pxfm-0.1.23/src/exponents/exp10f.rs000064400000000000000000000163231046102023000151510ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf}; use crate::polyeval::f_polyeval7; pub(crate) struct ExpBReduc { pub(crate) hi: f64, pub(crate) lo: f64, } const MID_BITS: u32 = 5; const MID_MASK: usize = (1 << MID_BITS) - 1; const LOG2_B: f64 = f64::from_bits(0x400a934f0979a371) * (1 << MID_BITS) as f64; const M_LOGB_2_HI: f64 = f64::from_bits(0xbfd34413509f8000) / (1 << MID_BITS) as f64; const M_LOGB_2_LO: f64 = f64::from_bits(0x3d380433b83b532a) / (1 << MID_BITS) as f64; const EXP_2_MID: [u64; 32] = [ 0x3ff0000000000000, 0x3ff059b0d3158574, 0x3ff0b5586cf9890f, 0x3ff11301d0125b51, 0x3ff172b83c7d517b, 0x3ff1d4873168b9aa, 0x3ff2387a6e756238, 0x3ff29e9df51fdee1, 0x3ff306fe0a31b715, 0x3ff371a7373aa9cb, 0x3ff3dea64c123422, 0x3ff44e086061892d, 0x3ff4bfdad5362a27, 0x3ff5342b569d4f82, 0x3ff5ab07dd485429, 0x3ff6247eb03a5585, 0x3ff6a09e667f3bcd, 0x3ff71f75e8ec5f74, 0x3ff7a11473eb0187, 0x3ff82589994cce13, 0x3ff8ace5422aa0db, 0x3ff93737b0cdc5e5, 0x3ff9c49182a3f090, 0x3ffa5503b23e255d, 0x3ffae89f995ad3ad, 0x3ffb7f76f2fb5e47, 0x3ffc199bdd85529c, 0x3ffcb720dcef9069, 0x3ffd5818dcfba487, 0x3ffdfc97337b9b5f, 0x3ffea4afa2a490da, 0x3fff50765b6e4540, ]; // Approximating 10^dx with degree-5 minimax polynomial generated by Sollya: // > Q = fpminimax((10^x - 1)/x, 4, [|D...|], [-log10(2)/2^6, log10(2)/2^6]); // Then: // 10^dx ~ P(dx) = 1 + COEFFS[0] * dx + ... + COEFFS[4] * dx^5. pub(crate) const EXP10F_COEFFS: [u64; 5] = [ 0x40026bb1bbb55515, 0x40053524c73bd3ea, 0x4000470591dff149, 0x3ff2bd7c0a9fbc4d, 0x3fe1429e74a98f43, ]; /// Range reduction function equivalent to exp_b_range_reduc #[inline] pub(crate) fn exp_b_range_reduc(x: f32) -> ExpBReduc { let xd = x as f64; // kd = round(log2(b) * x) let kd = (LOG2_B * xd).round(); let k = kd as i32; // hi = floor(kd / 2^MID_BITS) let exp_hi = (k.wrapping_shr(MID_BITS) as u64).wrapping_shl(52); // 52 = fraction bits in f64 // mh = 2^hi * 2^mid let mid_index = (k as usize) & MID_MASK; let mh_bits = EXP_2_MID[mid_index].wrapping_add(exp_hi); let mh = f64::from_bits(mh_bits); // dx = x - (hi + mid) * log(2) let z0 = f_fmla(kd, M_LOGB_2_HI, xd); let dx = f_fmla(kd, M_LOGB_2_LO, z0); ExpBReduc { lo: dx, hi: mh } } /// Computes exp10 /// /// Max found ULP 0.49999508 #[inline] pub fn f_exp10f(x: f32) -> f32 { let x_u = x.to_bits(); let x_abs = x_u & 0x7fffffff; // When |x| >= log10(2^128), or x is nan if x_abs >= 0x421a209bu32 { // When x < log10(2^-150) or nan if x_u > 0xc2349e35u32 { // exp(-Inf) = 0 if x.is_infinite() { return 0.0; } // exp(nan) = nan if x.is_nan() { return x; } return 0.0; } // x >= log10(2^128) or nan if x > 0. && (x_u >= 0x421a209bu32) { // x is +inf or nan return x + f32::INFINITY; } } if x_abs <= 0x3d000000u32 { // |x| < 1/32 if x_abs <= 0x3b9a209bu32 { if x_u == 0xb25e5bd9u32 { // x = -1.2943e-08 return 1.; } // |x| < 2^-25 // 10^x ~ 1 + log(10) * x if x_abs <= 0x32800000u32 { return f_fmlaf(x, f32::from_bits(0x40135da2), 1.0); } } let xd = x as f64; // Special polynomial for small x. // Generated by Sollya: // d = [-1/32, 1/32]; // f_exp10f = (10^y - 1)/y; // Q = fpminimax(f_exp10f, 6, [|D...|], d, relative, floating); // See ./notes/exp10f_small.sollya let p = f_polyeval7( xd, f64::from_bits(0x40026bb1bbb55516), f64::from_bits(0x40053524c73cfbf6), f64::from_bits(0x4000470591de0b07), f64::from_bits(0x3ff2bd760599f3a5), f64::from_bits(0x3fe142a001511a6f), f64::from_bits(0x3fca7feffa781d53), f64::from_bits(0x3fb16e53492c0f0e), ); return f_fmla(p, xd, 1.) as f32; } // Range reduction: 10^x = 2^(mid + hi) * 10^lo // rr = (2^(mid + hi), lo) let rr = exp_b_range_reduc(x); // The low part is approximated by a degree-5 minimax polynomial. // 10^lo ~ 1 + COEFFS[0] * lo + ... + COEFFS[4] * lo^5 let lo2 = rr.lo * rr.lo; // c0 = 1 + COEFFS[0] * lo let c0 = f_fmla(rr.lo, f64::from_bits(EXP10F_COEFFS[0]), 1.0); // c1 = COEFFS[1] + COEFFS[2] * lo let c1 = f_fmla( rr.lo, f64::from_bits(EXP10F_COEFFS[2]), f64::from_bits(EXP10F_COEFFS[1]), ); // c2 = COEFFS[3] + COEFFS[4] * lo let c2 = f_fmla( rr.lo, f64::from_bits(EXP10F_COEFFS[4]), f64::from_bits(EXP10F_COEFFS[3]), ); // p = c1 + c2 * lo^2 // = COEFFS[1] + COEFFS[2] * lo + COEFFS[3] * lo^2 + COEFFS[4] * lo^3 let p = f_fmla(lo2, c2, c1); // 10^lo ~ c0 + p * lo^2 // 10^x = 2^(mid + hi) * 10^lo // ~ mh * (c0 + p * lo^2) // = (mh * c0) + p * (mh * lo^2) f_fmla(p, lo2 * rr.hi, c0 * rr.hi) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp10f() { assert_eq!(f_exp10f(-1. / 64.), 0.9646616); assert_eq!(f_exp10f(1. / 64.), 1.0366329); assert_eq!(f_exp10f(1.), 10.0); assert_eq!(f_exp10f(2.), 100.0); assert_eq!(f_exp10f(3.), 1000.0); assert_eq!(f_exp10f(f32::INFINITY), f32::INFINITY); assert_eq!(f_exp10f(f32::NEG_INFINITY), 0.); assert!(f_exp10f(f32::NAN).is_nan()); } } pxfm-0.1.23/src/exponents/exp10m1.rs000064400000000000000000000523561046102023000152470ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::exp2m1::{EXP_M1_2_TABLE1, EXP_M1_2_TABLE2}; const LN10H: f64 = f64::from_bits(0x40026bb1bbb55516); const LN10L: f64 = f64::from_bits(0xbcaf48ad494ea3e9); struct Exp10m1 { exp: DoubleDouble, err: f64, } // Approximation for the fast path of exp(z) for z=zh+zl, // with |z| < 0.000130273 < 2^-12.88 and |zl| < 2^-42.6 // (assuming x^y does not overflow or underflow) #[inline] fn q_1(dz: DoubleDouble) -> DoubleDouble { const Q_1: [u64; 5] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555995d37, 0x3fa55555558489dc, ]; let z = dz.to_f64(); let mut q = f_fmla(f64::from_bits(Q_1[4]), dz.hi, f64::from_bits(Q_1[3])); q = f_fmla(q, z, f64::from_bits(Q_1[2])); let mut p0 = DoubleDouble::from_exact_add(f64::from_bits(Q_1[1]), q * z); p0 = DoubleDouble::quick_mult(dz, p0); p0 = DoubleDouble::f64_add(f64::from_bits(Q_1[0]), p0); p0 } #[inline] fn exp1(x: DoubleDouble) -> DoubleDouble { const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); /* |INVLOG2-2^12/log(2)| < 2^-43.4 */ let k = (x.hi * INVLOG2).round_ties_even(); const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); let mut zk = DoubleDouble::from_exact_mult(LOG2H, k); zk.lo = f_fmla(k, LOG2L, zk.lo); let mut yz = DoubleDouble::from_exact_add(x.hi - zk.hi, x.lo); yz.lo -= zk.lo; let ik: i64 = k as i64; /* Note: k is an integer, this is just a conversion. */ let im: i64 = (ik >> 12).wrapping_add(0x3ff); let i2: i64 = (ik >> 6) & 0x3f; let i1: i64 = ik & 0x3f; let t1 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE1[i2 as usize]); let t2 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE2[i1 as usize]); let p0 = DoubleDouble::quick_mult(t2, t1); let mut q = q_1(yz); q = DoubleDouble::quick_mult(p0, q); /* Scale by 2^k. Warning: for x near 1024, we can have k=2^22, thus M = 2047, which encodes Inf */ let mut du = (im as u64).wrapping_shl(52); if im == 0x7ff { q.hi *= 2.0; q.lo *= 2.0; du = (im.wrapping_sub(1) as u64).wrapping_shl(52); } q.hi *= f64::from_bits(du); q.lo *= f64::from_bits(du); q } #[inline] fn exp10m1_fast(x: f64, tiny: bool) -> Exp10m1 { if tiny { return exp10m1_fast_tiny(x); } /* now -54 < x < -0.125 or 0.125 < x < 1024: we approximate exp(x*log(2)) and subtract 1 */ let v = DoubleDouble::quick_mult_f64(DoubleDouble::new(LN10L, LN10H), x); /* The a_mul() call is exact, and the error of the fma() is bounded by ulp(l). We have |t| <= ulp(h) <= ulp(LN2H*1024) = 2^-43, |t+x*LN2L| <= 2^-43 * 1024*LN2L < 2^-42.7, thus |l| <= |t| + |x*LN2L| + ulp(t+x*LN2L) <= 2^-42.7 + 2^-95 <= 2^-42.6, and ulp(l) <= 2^-95. Thus: |h + l - x*log(2)| <= |h + l - x*(LN2H+LN2L)| + |x|*|LN2H+LN2L-log(2)| <= 2^-95 + 1024*2^-110.4 < 2^-94.9 */ let mut p = exp1(v); let zf: DoubleDouble = if x >= 0. { // implies h >= 1 and the fast_two_sum pre-condition holds DoubleDouble::from_exact_add(p.hi, -1.0) } else { DoubleDouble::from_exact_add(-1.0, p.hi) }; p.lo += zf.lo; p.hi = zf.hi; /* The error in the above fast_two_sum is bounded by 2^-105*|h|, with the new value of h, thus the total absolute error is bounded by eps1*|h_in|+2^-105*|h|. Relatively to h this yields eps1*|h_in/h| + 2^-105, where the maximum of |h_in/h| is obtained for x near -0.125, with |2^x/(2^x-1)| < 11.05. We get a relative error bound of 2^-74.138*11.05 + 2^-105 < 2^-70.67. */ Exp10m1 { exp: p, err: f64::from_bits(0x3b77a00000000000) * p.hi, /* 2^-70.67 < 0x1.42p-71 */ } } // Approximation for the accurate path of exp(z) for z=zh+zl, // with |z| < 0.000130273 < 2^-12.88 and |zl| < 2^-42.6 // (assuming x^y does not overflow or underflow) #[inline] fn q_2(dz: DoubleDouble) -> DoubleDouble { /* Let q[0]..q[7] be the coefficients of degree 0..7 of Q_2. The ulp of q[7]*z^7 is at most 2^-155, thus we can compute q[7]*z^7 in double precision only. The ulp of q[6]*z^6 is at most 2^-139, thus we can compute q[6]*z^6 in double precision only. The ulp of q[5]*z^5 is at most 2^-124, thus we can compute q[5]*z^5 in double precision only. */ /* The following is a degree-7 polynomial generated by Sollya for exp(z) over [-0.000130273,0.000130273] with absolute error < 2^-113.218 (see file exp_accurate.sollya). Since we use this code only for |x| > 0.125 in exp2m1(x), the corresponding relative error for exp2m1 is about 2^-113.218/|exp2m1(-0.125)| which is about 2^-110. */ const Q_2: [u64; 9] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555555555, 0x3c655555555c4d26, 0x3fa5555555555555, 0x3f81111111111111, 0x3f56c16c3fbb4213, 0x3f2a01a023ede0d7, ]; let z = dz.to_f64(); let mut q = dd_fmla(f64::from_bits(Q_2[8]), dz.hi, f64::from_bits(Q_2[7])); q = dd_fmla(q, z, f64::from_bits(Q_2[6])); q = dd_fmla(q, z, f64::from_bits(Q_2[5])); // multiply q by z and add Q_2[3] + Q_2[4] let mut p = DoubleDouble::from_exact_mult(q, z); let r0 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[3]), p.hi); p.hi = r0.hi; p.lo += r0.lo + f64::from_bits(Q_2[4]); // multiply hi+lo by zh+zl and add Q_2[2] p = DoubleDouble::quick_mult(p, dz); let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[2]), p.hi); p.hi = r1.hi; p.lo += r1.lo; // multiply hi+lo by zh+zl and add Q_2[1] p = DoubleDouble::quick_mult(p, dz); let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[1]), p.hi); p.hi = r1.hi; p.lo += r1.lo; // multiply hi+lo by zh+zl and add Q_2[0] p = DoubleDouble::quick_mult(p, dz); let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[0]), p.hi); p.hi = r1.hi; p.lo += r1.lo; p } // returns a double-double approximation hi+lo of exp(x*log(10)) // assumes -0x1.041704c068efp+4 < x <= 0x1.34413509f79fep+8 #[inline] fn exp_2(x: f64) -> DoubleDouble { let mut k = (x * f64::from_bits(0x40ca934f0979a371)).round_ties_even(); if k == 4194304. { k = 4194303.; // ensures M < 2047 below } // since |x| <= 745 we have k <= 3051520 const LOG2_10H: f64 = f64::from_bits(0x3f134413509f79ff); const LOG2_10M: f64 = f64::from_bits(0xbb89dc1da9800000); const LOG2_10L: f64 = f64::from_bits(0xb984fd20dba1f655); let yhh = dd_fmla(-k, LOG2_10H, x); // exact, |yh| <= 2^-13 let mut ky0 = DoubleDouble::from_exact_add(yhh, -k * LOG2_10M); ky0.lo = dd_fmla(-k, LOG2_10L, ky0.lo); /* now x = k + yh, thus 2^x = 2^k * 2^yh, and we multiply yh by log(10) to use the accurate path of exp() */ let ky = DoubleDouble::quick_mult(ky0, DoubleDouble::new(LN10L, LN10H)); let ik = k as i64; let im = (ik >> 12).wrapping_add(0x3ff); let i2 = (ik >> 6) & 0x3f; let i1 = ik & 0x3f; let t1 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE1[i2 as usize]); let t2 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE2[i1 as usize]); let p = DoubleDouble::quick_mult(t2, t1); let mut q = q_2(ky); q = DoubleDouble::quick_mult(p, q); let mut ud: u64 = (im as u64).wrapping_shl(52); if im == 0x7ff { q.hi *= 2.0; q.lo *= 2.0; ud = (im.wrapping_sub(1) as u64).wrapping_shl(52); } q.hi *= f64::from_bits(ud); q.lo *= f64::from_bits(ud); q } #[cold] fn exp10m1_accurate_tiny(x: f64) -> f64 { let x2 = x * x; let x4 = x2 * x2; /* The following is a degree-17 polynomial generated by Sollya (file exp10m1_accurate.sollya), which approximates exp10m1(x) with relative error bounded by 2^-107.506 for |x| <= 0.0625. */ const Q: [u64; 25] = [ 0x40026bb1bbb55516, 0xbcaf48ad494ea3e9, 0x40053524c73cea69, 0xbcae2bfab318d696, 0x4000470591de2ca4, 0x3ca823527cebf918, 0x3ff2bd7609fd98c4, 0x3c931ea51f6641df, 0x3fe1429ffd1d4d76, 0x3c7117195be7f232, 0x3fca7ed70847c8b6, 0xbc54260c5e23d0c8, 0x3fb16e4dfc333a87, 0xbc533fd284110905, 0x3f94116b05fdaa5d, 0xbc20721de44d79a8, 0x3f74897c45d93d43, 0x3f52ea52b2d182ac, 0x3f2facfd5d905b22, 0x3f084fe12df8bde3, 0x3ee1398ad75d01bf, 0x3eb6a9e96fbf6be7, 0x3e8bd456a29007c2, 0x3e6006cf8378cf9b, 0x3e368862b132b6e2, ]; let mut c13 = dd_fmla(f64::from_bits(Q[23]), x, f64::from_bits(Q[22])); // degree 15 let c11 = dd_fmla(f64::from_bits(Q[21]), x, f64::from_bits(Q[20])); // degree 14 c13 = dd_fmla(f64::from_bits(Q[24]), x2, c13); // degree 15 // add Q[19]*x+c13*x2+c15*x4 to Q[18] (degree 11) let mut p = DoubleDouble::from_exact_add( f64::from_bits(Q[18]), f_fmla(f64::from_bits(Q[19]), x, f_fmla(c11, x2, c13 * x4)), ); // multiply h+l by x and add Q[17] (degree 10) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[17]), p.hi); p.lo += p0.lo; p.hi = p0.hi; // multiply h+l by x and add Q[16] (degree 9) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[16]), p.hi); p.lo += p0.lo; p.hi = p0.hi; // multiply h+l by x and add Q[14]+Q[15] (degree 8) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[14]), p.hi); p.lo += p0.lo + f64::from_bits(Q[15]); p.hi = p0.hi; // multiply h+l by x and add Q[12]+Q[13] (degree 7) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[12]), p.hi); p.lo += p0.lo + f64::from_bits(Q[13]); p.hi = p0.hi; // multiply h+l by x and add Q[10]+Q[11] (degree 6) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[10]), p.hi); p.lo += p0.lo + f64::from_bits(Q[11]); p.hi = p0.hi; // multiply h+l by x and add Q[8]+Q[9] (degree 5) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[8]), p.hi); p.lo += p0.lo + f64::from_bits(Q[9]); p.hi = p0.hi; // multiply h+l by x and add Q[6]+Q[7] (degree 4) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[6]), p.hi); p.lo += p0.lo + f64::from_bits(Q[7]); p.hi = p0.hi; // multiply h+l by x and add Q[4]+Q[5] (degree 3) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[4]), p.hi); p.lo += p0.lo + f64::from_bits(Q[5]); p.hi = p0.hi; // multiply h+l by x and add Q[2]+Q[3] (degree 2) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[2]), p.hi); p.lo += p0.lo + f64::from_bits(Q[3]); p.hi = p0.hi; // multiply h+l by x and add Q[0]+Q[1] (degree 2) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[0]), p.hi); p.lo += p0.lo + f64::from_bits(Q[1]); p.hi = p0.hi; // multiply h+l by x p = DoubleDouble::quick_f64_mult(x, p); p.to_f64() } #[cold] fn exp10m1_accurate(x: f64) -> f64 { let t = x.to_bits(); let ux = t; let ax = ux & 0x7fffffffffffffffu64; if ax <= 0x3fc0000000000000u64 { // |x| <= 0.125 return exp10m1_accurate_tiny(x); } let mut p = exp_2(x); let zf: DoubleDouble = DoubleDouble::from_full_exact_add(p.hi, -1.0); p.lo += zf.lo; p.hi = zf.hi; p.to_f64() } /* |x| <= 0.125, put in h + l a double-double approximation of exp2m1(x), and return the maximal corresponding absolute error. We also have |x| > 0x1.0527dbd87e24dp-51. With xmin=RR("0x1.0527dbd87e24dp-51",16), the routine exp2m1_fast_tiny_all(xmin,0.125,2^-65.73) in exp2m1.sage returns 1.63414352331297e-20 < 2^-65.73, and exp2m1_fast_tiny_all(-0.125,-xmin,2^-65.62) returns 1.76283772822891e-20 < 2^-65.62, which proves the relative error is bounded by 2^-65.62. */ #[inline] fn exp10m1_fast_tiny(x: f64) -> Exp10m1 { /* The following is a degree-11 polynomial generated by Sollya (file exp10m1_fast.sollya), which approximates exp10m1(x) with relative error bounded by 2^-69.58 for |x| <= 0.0625. */ const P: [u64; 14] = [ 0x40026bb1bbb55516, 0xbcaf48abcf79e094, 0x40053524c73cea69, 0xbcae1badf796d704, 0x4000470591de2ca4, 0x3ca7db8caacb2cea, 0x3ff2bd7609fd98ba, 0x3fe1429ffd1d4d98, 0x3fca7ed7084998e1, 0x3fb16e4dfc30944b, 0x3f94116ae4b57526, 0x3f74897c6a90f61c, 0x3f52ec689c32b3a0, 0x3f2faced20d698fe, ]; let x2 = x * x; let x4 = x2 * x2; let mut c9 = dd_fmla(f64::from_bits(P[12]), x, f64::from_bits(P[11])); // degree 9 let c7 = dd_fmla(f64::from_bits(P[10]), x, f64::from_bits(P[9])); // degree 7 let mut c5 = dd_fmla(f64::from_bits(P[8]), x, f64::from_bits(P[7])); // degree 5 c9 = dd_fmla(f64::from_bits(P[13]), x2, c9); // degree 9 c5 = dd_fmla(c7, x2, c5); // degree 5 c5 = dd_fmla(c9, x4, c5); // degree 5 let mut p = DoubleDouble::from_exact_mult(c5, x); let p0 = DoubleDouble::from_exact_add(f64::from_bits(P[6]), p.hi); p.lo += p0.lo; p.hi = p0.hi; p = DoubleDouble::quick_f64_mult(x, p); let p1 = DoubleDouble::from_exact_add(f64::from_bits(P[4]), p.hi); p.lo += p1.lo + f64::from_bits(P[5]); p.hi = p1.hi; p = DoubleDouble::quick_f64_mult(x, p); let p2 = DoubleDouble::from_exact_add(f64::from_bits(P[2]), p.hi); p.lo += p2.lo + f64::from_bits(P[3]); p.hi = p2.hi; p = DoubleDouble::quick_f64_mult(x, p); let p2 = DoubleDouble::from_exact_add(f64::from_bits(P[0]), p.hi); p.lo += p2.lo + f64::from_bits(P[1]); p.hi = p2.hi; p = DoubleDouble::quick_f64_mult(x, p); Exp10m1 { exp: p, err: f64::from_bits(0x3bb0a00000000000) * p.hi, // 2^-65.62 < 0x1.4ep-66 } } /// Computes 10^x - 1 /// /// Max found ULP 0.5 pub fn f_exp10m1(d: f64) -> f64 { let mut x = d; let t = x.to_bits(); let ux = t; let ax = ux & 0x7fffffffffffffffu64; if ux >= 0xc03041704c068ef0u64 { // x = -NaN or x <= -0x1.041704c068efp+4 if (ux >> 52) == 0xfff { // -NaN or -Inf return if ux > 0xfff0000000000000u64 { x + x } else { -1.0 }; } // for x <= -0x1.041704c068efp+4, exp10m1(x) rounds to -1 to nearest return -1.0 + f64::from_bits(0x3c90000000000000); } else if ax > 0x40734413509f79feu64 { // x = +NaN or x >= 1024 if (ux >> 52) == 0x7ff { // +NaN return x + x; } return f64::from_bits(0x7fefffffffffffff) * x; } else if ax <= 0x3c90000000000000u64 // |x| <= 0x1.0527dbd87e24dp-51 /* then the second term of the Taylor expansion of 2^x-1 at x=0 is smaller in absolute value than 1/2 ulp(first term): log(2)*x + log(2)^2*x^2/2 + ... */ { /* we use special code when log(2)*|x| is very small, in which case the double-double approximation h+l has its lower part l "truncated" */ return if ax <= 0x3970000000000000u64 // |x| <= 2^-104 { // special case for 0 if x == 0. { return x; } if x.abs() == f64::from_bits(0x000086c73059343c) { return dd_fmla( -f64::copysign(f64::from_bits(0x1e60010000000000), x), f64::from_bits(0x1e50000000000000), f64::copysign(f64::from_bits(0x000136568740cb56), x), ); } if x.abs() == f64::from_bits(0x00013a7b70d0248c) { return dd_fmla( f64::copysign(f64::from_bits(0x1e5ffe0000000000), x), f64::from_bits(0x1e50000000000000), f64::copysign(f64::from_bits(0x0002d41f3b972fc7), x), ); } // scale x by 2^106 x *= f64::from_bits(0x4690000000000000); let mut z = DoubleDouble::from_exact_mult(LN10H, x); z.lo = dd_fmla(LN10L, x, z.lo); let mut h2 = z.to_f64(); // round to 53-bit precision // scale back, hoping to avoid double rounding h2 *= f64::from_bits(0x3950000000000000); // now subtract back h2 * 2^106 from h to get the correction term let mut h = dd_fmla(-h2, f64::from_bits(0x4690000000000000), z.hi); // add l h += z.lo; /* add h2 + h * 2^-106. Warning: when h=0, 2^-106*h2 might be exact, thus no underflow will be raised. We have underflow for 0 < x <= 0x1.71547652b82fep-1022 for RNDZ, and for 0 < x <= 0x1.71547652b82fdp-1022 for RNDN/RNDU. */ dyad_fmla(h, f64::from_bits(0x3950000000000000), h2) } else { const C2: f64 = f64::from_bits(0x40053524c73cea69); // log(2)^2/2 let mut z = DoubleDouble::quick_mult_f64(DoubleDouble::new(LN10L, LN10H), x); /* h+l approximates the first term x*log(2) */ /* we add C2*x^2 last, so that in case there is a cancellation in LN10L*x+l, it will contribute more bits */ z.lo = dd_fmla(C2 * x, x, z.lo); z.to_f64() }; } /* now -0x1.041704c068efp+4 < x < -2^-54 or 2^-54 < x <= 0x1.34413509f79fep+8 */ /* 10^x-1 is exact for x integer, 1 <= x <= 15 */ if ux << 15 == 0 { let i = x.floor() as i32; if x == i as f64 && 1 <= i && i <= 15 { static EXP10_1_15: [u64; 16] = [ 0x0000000000000000, 0x4022000000000000, 0x4058c00000000000, 0x408f380000000000, 0x40c3878000000000, 0x40f869f000000000, 0x412e847e00000000, 0x416312cfe0000000, 0x4197d783fc000000, 0x41cdcd64ff800000, 0x4202a05f1ff80000, 0x42374876e7ff0000, 0x426d1a94a1ffe000, 0x42a2309ce53ffe00, 0x42d6bcc41e8fffc0, 0x430c6bf52633fff8, ]; return f64::from_bits(EXP10_1_15[i as usize]); } } let result = exp10m1_fast(x, ax <= 0x3fb0000000000000u64); let left = result.exp.hi + (result.exp.lo - result.err); let right = result.exp.hi + (result.exp.lo + result.err); if left != right { return exp10m1_accurate(x); } left } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp10m1() { assert_eq!(f_exp10m1(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002364140972981833), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005443635762124408); assert_eq!(99., f_exp10m1(2.0)); assert_eq!(315.22776601683796, f_exp10m1(2.5)); assert_eq!(-0.7056827241416722, f_exp10m1(-0.5311842449009418)); } } pxfm-0.1.23/src/exponents/exp10m1f.rs000064400000000000000000000117231046102023000154060ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::exponents::exp10f::EXP10F_COEFFS; use crate::polyeval::f_polyeval3; #[cold] fn exp10m1f_small(x: f32) -> f32 { let dx = x as f64; let dx_sq = dx * dx; let c0 = dx * f64::from_bits(EXP10F_COEFFS[0]); let c1 = f_fmla( dx, f64::from_bits(EXP10F_COEFFS[2]), f64::from_bits(EXP10F_COEFFS[1]), ); let c2 = f_fmla( dx, f64::from_bits(EXP10F_COEFFS[4]), f64::from_bits(EXP10F_COEFFS[3]), ); // 10^dx - 1 ~ (1 + COEFFS[0] * dx + ... + COEFFS[4] * dx^5) - 1 // = COEFFS[0] * dx + ... + COEFFS[4] * dx^5 f_polyeval3(dx_sq, c0, c1, c2) as f32 } /// Computes 10^x - 1 /// /// Max ULP 0.5 #[inline] pub fn f_exp10m1f(x: f32) -> f32 { let x_u = x.to_bits(); let x_abs = x_u & 0x7fff_ffffu32; // When x >= log10(2^128), or x is nan if x.is_sign_positive() && x_u >= 0x421a_209bu32 { // x >= log10(2^128) and 10^x - 1 rounds to +inf, or x is +inf or nan return x + f32::INFINITY; } if x_abs <= 0x3b9a_209bu32 { // |x| <= 0.004703594 return exp10m1f_small(x); } // When x <= log10(2^-25), or x is nan if x_u >= 0xc0f0d2f1 { // exp10m1(-inf) = -1 if x.is_infinite() { return -1.0; } // exp10m1(nan) = nan if x.is_nan() { return x; } if x_u == 0xc0f0d2f1 { return f32::from_bits(0xbf7fffff); // -1.0f + 0x1.0p-24f } return -1.0; } // Exact outputs when x = 1, 2, ..., 10. // Quick check mask: 0x800f'ffffU = ~(bits of 1.0f | ... | bits of 10.0f) if x_u & 0x800f_ffffu32 == 0 { match x_u { 0x3f800000u32 => return 9.0, // x = 1.0f 0x40000000u32 => return 99.0, // x = 2.0f 0x40400000u32 => return 999.0, // x = 3.0f 0x40800000u32 => return 9_999.0, // x = 4.0f 0x40a00000u32 => return 99_999.0, // x = 5.0f 0x40c00000u32 => return 999_999.0, // x = 6.0f 0x40e00000u32 => return 9_999_999.0, // x = 7.0f 0x41000000u32 => return 99_999_999.0, // x = 8.0f 0x41100000u32 => return 999_999_999.0, // x = 9.0f 0x41200000u32 => return 9_999_999_999.0, // x = 10.0f _ => {} } } // Range reduction: 10^x = 2^(mid + hi) * 10^lo // rr = (2^(mid + hi), lo) let rr = crate::exponents::exp10f::exp_b_range_reduc(x); // The low part is approximated by a degree-5 minimax polynomial. // 10^lo ~ 1 + COEFFS[0] * lo + ... + COEFFS[4] * lo^5 let lo_sq = rr.lo * rr.lo; let c0 = f_fmla(rr.lo, f64::from_bits(EXP10F_COEFFS[0]), 1.0); let c1 = f_fmla( rr.lo, f64::from_bits(EXP10F_COEFFS[2]), f64::from_bits(EXP10F_COEFFS[1]), ); let c2 = f_fmla( rr.lo, f64::from_bits(EXP10F_COEFFS[4]), f64::from_bits(EXP10F_COEFFS[3]), ); let exp10_lo = f_polyeval3(lo_sq, c0, c1, c2); // 10^x - 1 = 2^(mid + hi) * 10^lo - 1 // ~ mh * exp10_lo - 1 f_fmla(exp10_lo, rr.hi, -1.0) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp10m1f() { assert_eq!(f_exp10m1f(0.0), 0.0); assert_eq!(f_exp10m1f(1.0), 9.0); assert_eq!(f_exp10m1f(1.5), 30.622776); } } pxfm-0.1.23/src/exponents/exp2.rs000064400000000000000000000177721046102023000147350ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::auxiliary::fast_ldexp; use crate::exponents::exp::{EXP_REDUCE_T0, EXP_REDUCE_T1, to_denormal}; #[inline] fn exp2_poly_dd(z: f64) -> DoubleDouble { const C: [(u64, u64); 6] = [ (0x3bbabc9e3b39873e, 0x3f262e42fefa39ef), (0xbae5e43a53e44950, 0x3e4ebfbdff82c58f), (0xba0d3a15710d3d83, 0x3d6c6b08d704a0c0), (0x3914dd5d2a5e025a, 0x3c83b2ab6fba4e77), (0xb83dc47e47beb9dd, 0x3b95d87fe7a66459), (0xb744fcd51fcb7640, 0x3aa430912f9fb79d), ]; let mut r = DoubleDouble::quick_mul_f64_add( DoubleDouble::from_bit_pair(C[5]), z, DoubleDouble::from_bit_pair(C[4]), ); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[3])); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[2])); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[1])); DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(C[0])) } #[cold] fn exp2_accurate(x: f64) -> f64 { let mut ix = x.to_bits(); let sx = 4096.0 * x; let fx = sx.round_ties_even(); let z = sx - fx; let k: i64 = fx as i64; let i1 = k & 0x3f; let i0 = (k >> 6) & 0x3f; let ie = k >> 12; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i0 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let dt = DoubleDouble::quick_mult(t0, t1); let mut f = exp2_poly_dd(z); f = DoubleDouble::quick_mult_f64(f, z); if ix <= 0xc08ff00000000000u64 { // x >= -1022 // for -0x1.71547652b82fep-54 <= x <= 0x1.71547652b82fdp-53, // exp2(x) round to x to nearest if f64::from_bits(0xbc971547652b82fe) <= x && x <= f64::from_bits(0x3ca71547652b82fd) { return dd_fmla(x, 0.5, 1.0); } else if (k & 0xfff) == 0 { // 4096*x rounds to 4096*integer let zf = DoubleDouble::from_exact_add(dt.hi, f.hi); let zfl = DoubleDouble::from_exact_add(zf.lo, f.lo); f.hi = zf.hi; f.lo = zfl.hi; ix = zfl.hi.to_bits(); if ix & 0x000fffffffffffff == 0 { // fl is a power of 2 if ((ix >> 52) & 0x7ff) != 0 { // |fl| is Inf let v = zfl.lo.to_bits(); let d: i64 = ((((ix as i64) >> 63) ^ ((v as i64) >> 63)) as u64) .wrapping_shl(1) .wrapping_add(1) as i64; ix = ix.wrapping_add(d as u64); f.lo = f64::from_bits(ix); } } } else { f = DoubleDouble::quick_mult(f, dt); f = DoubleDouble::add(dt, f); } let hf = DoubleDouble::from_exact_add(f.hi, f.lo); fast_ldexp(hf.hi, ie as i32) } else { ix = 1u64.wrapping_sub(ie as u64).wrapping_shl(52); f = DoubleDouble::quick_mult(f, dt); f = DoubleDouble::add(dt, f); let zve = DoubleDouble::from_exact_add(f64::from_bits(ix), f.hi); f.hi = zve.hi; f.lo += zve.lo; to_denormal(f.to_f64()) } } /// Computes exp2 /// /// Max found ULP 0.5 pub fn f_exp2(x: f64) -> f64 { let mut ix = x.to_bits(); let ax = ix.wrapping_shl(1); if ax == 0 { return 1.0; } if ax >= 0x8120000000000000u64 { // |x| >= 1024 if ax > 0xffe0000000000000u64 { return x + x; // nan } if ax == 0xffe0000000000000u64 { return if (ix >> 63) != 0 { 0.0 } else { x }; } // +/-inf if (ix >> 63) != 0 { // x <= -1024 if ix >= 0xc090cc0000000000u64 { // x <= -1075 const Z: f64 = f64::from_bits(0x0010000000000000); return Z * Z; } } else { // x >= 1024 return f64::from_bits(0x7fe0000000000000) * x; } } // for |x| <= 0x1.71547652b82fep-54, 2^x rounds to 1 to nearest // this avoids a spurious underflow in z*z below if ax <= 0x792e2a8eca5705fcu64 { return 1.0 + f64::copysign(f64::from_bits(0x3c90000000000000), x); } let m = ix.wrapping_shl(12); let ex = (ax >> 53).wrapping_sub(0x3ff); let frac = ex >> 63 | m << (ex & 63); let sx = 4096.0 * x; let fx = sx.round_ties_even(); let z = sx - fx; let z2 = z * z; let k = fx as i64; let i1 = k & 0x3f; let i0 = (k >> 6) & 0x3f; let ie = k >> 12; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i0 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let ti0 = DoubleDouble::quick_mult(t0, t1); const C: [u64; 4] = [ 0x3f262e42fefa39ef, 0x3e4ebfbdff82c58f, 0x3d6c6b08d73b3e01, 0x3c83b2ab6fdda001, ]; let tz = ti0.hi * z; let mut fh = ti0.hi; let p0 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let p1 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let p2 = f_fmla(z2, p1, p0); let mut fl = f_fmla(tz, p2, ti0.lo); const EPS: f64 = f64::from_bits(0x3c0833beace2b6fe); if ix <= 0xc08ff00000000000u64 { // x >= -1022 if frac != 0 { let ub = fh + (fl + EPS); fh += fl - EPS; if ub != fh { return exp2_accurate(x); } } fh = fast_ldexp(fh, ie as i32); } else { // subnormal case ix = 1u64.wrapping_sub(ie as u64).wrapping_shl(52); let rs = DoubleDouble::from_exact_add(f64::from_bits(ix), fh); fl += rs.lo; fh = rs.hi; if frac != 0 { let ub = fh + (fl + EPS); fh += fl - EPS; if ub != fh { return exp2_accurate(x); } } // when 2^x is exact, no underflow should be raised fh = to_denormal(fh); } fh } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp2d() { assert_eq!(f_exp2(2.0), 4.0); assert_eq!(f_exp2(3.0), 8.0); assert_eq!(f_exp2(4.0), 16.0); assert!((f_exp2(0.35f64) - 0.35f64.exp2()).abs() < 1e-8); assert!((f_exp2(-0.6f64) - (-0.6f64).exp2()).abs() < 1e-8); assert_eq!(f_exp2(f64::INFINITY), f64::INFINITY); assert_eq!(f_exp2(f64::NEG_INFINITY), 0.); assert!(f_exp2(f64::NAN).is_nan()); } } pxfm-0.1.23/src/exponents/exp2f.rs000064400000000000000000000266371046102023000151030ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf, pow2if}; use crate::polyeval::f_polyeval6; use std::hint::black_box; const TBLSIZE: usize = 64; #[repr(align(64))] struct Exp2Table([(u32, u32); TBLSIZE]); #[rustfmt::skip] static EXP2FT: Exp2Table = Exp2Table([(0x3F3504F3, 0xB2D4175E),(0x3F36FD92, 0x3268D5EF),(0x3F38FBAF, 0xB30E8719),(0x3F3AFF5B, 0x3319E7DA),(0x3F3D08A4, 0x333CD82F),(0x3F3F179A, 0x330E1902),(0x3F412C4D, 0x32CCF4D7),(0x3F4346CD, 0x328F330E),(0x3F45672A, 0xB201B5B7),(0x3F478D75, 0x32CCCE34),(0x3F49B9BE, 0x335E937C),(0x3F4BEC15, 0x2FF41909),(0x3F4E248C, 0xB21760EA),(0x3F506334, 0x3283628B),(0x3F52A81E, 0x3340F500),(0x3F54F35B, 0x331202BD),(0x3F5744FD, 0x32B66A3E),(0x3F599D16, 0x32D0D9B1),(0x3F5BFBB8, 0x332ED93F),(0x3F5E60F5, 0x3350A709),(0x3F60CCDF, 0x32025744),(0x3F633F89, 0xB33A7C4D),(0x3F65B907, 0x321DA4E9),(0x3F68396A, 0xB2FF36A7),(0x3F6AC0C7, 0x3217E40E),(0x3F6D4F30, 0xB2400CBB),(0x3F6FE4BA, 0x331A2ACC),(0x3F728177, 0xB2B7D3E5),(0x3F75257D, 0xB1FED2BE),(0x3F77D0DF, 0xB32B73BA),(0x3F7A83B3, 0x32579081),(0x3F7D3E0C, 0xB19726B5),(0x3F800000, 0x00000000),(0x3F8164D2, 0x320C09FB),(0x3F82CD87, 0x3391E031),(0x3F843A29, 0x33287EEF),(0x3F85AAC3, 0xB38F6665),(0x3F871F62, 0x339004AB),(0x3F88980F, 0x33AC4561),(0x3F8A14D5, 0xB39CDAEA),(0x3F8B95C2, 0x32949D5C),(0x3F8D1ADF, 0xB36F79FA),(0x3F8EA43A, 0x33971DC2),(0x3F9031DC, 0xB32BD022),(0x3F91C3D3, 0xB3928952),(0x3F935A2B, 0xB2EBFECF),(0x3F94F4F0, 0x3357B8BB),(0x3F96942D, 0xB307353B),(0x3F9837F0, 0xB345DFE9),(0x3F99E046, 0x3382A804),(0x3F9B8D3A, 0x3326993E),(0x3F9D3EDA, 0x3350A029),(0x3F9EF532, 0xB3605F62),(0x3FA0B051, 0xB210909B),(0x3FA27043, 0xB0DDC369),(0x3FA43516, 0x33385844),(0x3FA5FED7, 0x33400757),(0x3FA7CD94, 0x3325446E),(0x3FA9A15B, 0x33237A50),(0x3FAB7A3A, 0x33201CA4),(0x3FAD583F, 0x32394687),(0x3FAF3B79, 0x332E1225),(0x3FB123F6, 0x33838969),(0x3FB311C4, 0xB219F2BA)]); /** Generated by SageMath: ```python print("[") for k in range(64): k = RealField(150)(2)**(RealField(150)(k) / RealField(150)(64)) print(double_to_hex(k) + ",") print("];") ``` **/ static EXP2F_TABLE: [u64; 64] = [ 0x3ff0000000000000, 0x3ff02c9a3e778061, 0x3ff059b0d3158574, 0x3ff0874518759bc8, 0x3ff0b5586cf9890f, 0x3ff0e3ec32d3d1a2, 0x3ff11301d0125b51, 0x3ff1429aaea92de0, 0x3ff172b83c7d517b, 0x3ff1a35beb6fcb75, 0x3ff1d4873168b9aa, 0x3ff2063b88628cd6, 0x3ff2387a6e756238, 0x3ff26b4565e27cdd, 0x3ff29e9df51fdee1, 0x3ff2d285a6e4030b, 0x3ff306fe0a31b715, 0x3ff33c08b26416ff, 0x3ff371a7373aa9cb, 0x3ff3a7db34e59ff7, 0x3ff3dea64c123422, 0x3ff4160a21f72e2a, 0x3ff44e086061892d, 0x3ff486a2b5c13cd0, 0x3ff4bfdad5362a27, 0x3ff4f9b2769d2ca7, 0x3ff5342b569d4f82, 0x3ff56f4736b527da, 0x3ff5ab07dd485429, 0x3ff5e76f15ad2148, 0x3ff6247eb03a5585, 0x3ff6623882552225, 0x3ff6a09e667f3bcd, 0x3ff6dfb23c651a2f, 0x3ff71f75e8ec5f74, 0x3ff75feb564267c9, 0x3ff7a11473eb0187, 0x3ff7e2f336cf4e62, 0x3ff82589994cce13, 0x3ff868d99b4492ed, 0x3ff8ace5422aa0db, 0x3ff8f1ae99157736, 0x3ff93737b0cdc5e5, 0x3ff97d829fde4e50, 0x3ff9c49182a3f090, 0x3ffa0c667b5de565, 0x3ffa5503b23e255d, 0x3ffa9e6b5579fdbf, 0x3ffae89f995ad3ad, 0x3ffb33a2b84f15fb, 0x3ffb7f76f2fb5e47, 0x3ffbcc1e904bc1d2, 0x3ffc199bdd85529c, 0x3ffc67f12e57d14b, 0x3ffcb720dcef9069, 0x3ffd072d4a07897c, 0x3ffd5818dcfba487, 0x3ffda9e603db3285, 0x3ffdfc97337b9b5f, 0x3ffe502ee78b3ff6, 0x3ffea4afa2a490da, 0x3ffefa1bee615a27, 0x3fff50765b6e4540, 0x3fffa7c1819e90d8, ]; /* ULP 0.508 method let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; let ui = f32::to_bits(d + redux); let mut i0 = ui; i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let k = i0 / TBLSIZE as u32; i0 &= TBLSIZE as u32 - 1; let mut uf = f32::from_bits(ui); uf -= redux; let item = EXP2FT.0[i0 as usize]; let z0: f32 = f32::from_bits(item.0); let z1: f32 = f32::from_bits(item.1); let f: f32 = d - uf - z1; let mut u = 0.055504108664458832; u = f_fmlaf(u, f, 0.24022650695908768); u = f_fmlaf(u, f, 0.69314718055994973); u *= f; let i2 = pow2if(k as i32); f_fmlaf(u, z0, z0) * i2 */ /// Computing exp2f /// /// ULP 0.4999994 #[inline] pub fn f_exp2f(x: f32) -> f32 { let mut t = x.to_bits(); if (t & 0xffff) == 0 { // x maybe integer let k: i32 = (((t >> 23) & 0xff) as i32).wrapping_sub(127); // 2^k <= |x| < 2^(k+1) if k >= 0 && k < 9 && (t << (9i32.wrapping_add(k))) == 0 { // x integer, with 1 <= |x| < 2^9 let msk = (t as i32) >> 31; let mut m: i32 = (((t & 0x7fffff) | (1 << 23)) >> (23 - k)) as i32; m = (m ^ msk).wrapping_sub(msk).wrapping_add(127); if m > 0 && m < 255 { t = (m as u32).wrapping_shl(23); return f32::from_bits(t); } else if m <= 0 && m > -23 { t = 1i32.wrapping_shl(22i32.wrapping_add(m) as u32) as u32; return f32::from_bits(t); } } } let ux = t.wrapping_shl(1); if ux >= 0x86000000u32 || ux < 0x65000000u32 { // |x| >= 128 or x=nan or |x| < 0x1p-26 if ux < 0x65000000u32 { return 1.0 + x; } // |x| < 0x1p-26 // if x < -149 or 128 <= x is special if !(t >= 0xc3000000u32 && t < 0xc3150000u32) { if ux >= 0xffu32 << 24 { // x is inf or nan if ux > (0xffu32 << 24) { return x + x; } // x = nan static IR: [f32; 2] = [f32::INFINITY, 0.]; return IR[(t >> 31) as usize]; // x = +-inf } if t >= 0xc3150000u32 { // x < -149 let z = x; let mut y = f_fmla( z as f64 + 149., f64::from_bits(0x3690000000000000), f64::from_bits(0x36a0000000000000), ); y = y.max(f64::from_bits(0x3680000000000000)); return y as f32; } // now x >= 128 let r = black_box(f64::from_bits(0x47e0000000000000)) * black_box(f64::from_bits(0x47e0000000000000)); return r as f32; } } if ux <= 0x7a000000u32 { // |x| < 1/32 // Generated by Sollya exp2 on range [-1/32;1/32]: // d = [-1/32, 1/32]; // f_exp2f = (2^y - 1)/y; // Q = fpminimax(f_exp2f, 5, [|D...|], d, relative, floating); // See ./notes/exp2f_small.sollya const C: [u64; 6] = [ 0x3fe62e42fefa39f3, 0x3fcebfbdff82c57b, 0x3fac6b08d6f2d7aa, 0x3f83b2ab6fc92f5d, 0x3f55d897cfe27125, 0x3f243090e61e6af1, ]; let xd = x as f64; let p = f_polyeval6( xd, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), ); return f_fmla(p, xd, 1.) as f32; } let x_d = x as f64; let kf = (x_d * 64.).round(); let k = kf as i32; // dx = lo = x - (hi + mid) = x - kf * 2^(-6) let dx = f_fmla(f64::from_bits(0xbf90000000000000), kf, x_d); const TABLE_BITS: u32 = 6; const TABLE_MASK: u64 = (1u64 << TABLE_BITS) - 1; // hi = floor(kf * 2^(-5)) // exp_hi = shift hi to the exponent field of double precision. let exp_hi: i64 = ((k >> TABLE_BITS) as i64).wrapping_shl(52); // mh = 2^hi * 2^mid // mh_bits = bit field of mh let mh_bits = (EXP2F_TABLE[((k as u64) & TABLE_MASK) as usize] as i64).wrapping_add(exp_hi); let mh = f64::from_bits(mh_bits as u64); // Degree-4 polynomial approximating (2^x - 1)/x generated by Sollya with: // > P = fpminimax((2^y - 1)/y, 4, [|D...|], [-1/64. 1/64]); // see ./notes/exp2f.sollya const C: [u64; 5] = [ 0x3fe62e42fefa39ef, 0x3fcebfbdff8131c4, 0x3fac6b08d7061695, 0x3f83b2b1bee74b2a, 0x3f55d88091198529, ]; let dx_sq = dx * dx; let c1 = f_fmla(dx, f64::from_bits(C[0]), 1.0); let c2 = f_fmla(dx, f64::from_bits(C[2]), f64::from_bits(C[1])); let c3 = f_fmla(dx, f64::from_bits(C[4]), f64::from_bits(C[3])); let p = f_fmla(dx_sq, c3, c2); // 2^x = 2^(hi + mid + lo) // = 2^(hi + mid) * 2^lo // ~ mh * (1 + lo * P(lo)) // = mh + (mh*lo) * P(lo) f_fmla(p, dx_sq * mh, c1 * mh) as f32 } #[inline] pub(crate) fn dirty_exp2f(d: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; let ui = f32::to_bits(d + redux); let mut i0 = ui; i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let k = i0 / TBLSIZE as u32; i0 &= TBLSIZE as u32 - 1; let mut uf = f32::from_bits(ui); uf -= redux; let item = EXP2FT.0[i0 as usize]; let z0: f32 = f32::from_bits(item.0); let f: f32 = d - uf; let mut u = 0.24022650695908768; u = f_fmlaf(u, f, 0.69314718055994973); u *= f; let i2 = pow2if(k as i32); f_fmlaf(u, z0, z0) * i2 } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp2f() { assert_eq!(f_exp2f(1. / 64.), 1.0108893); assert_eq!(f_exp2f(2.0), 4.0); assert_eq!(f_exp2f(3.0), 8.0); assert_eq!(f_exp2f(4.0), 16.0); assert_eq!(f_exp2f(10.0), 1024.0); assert_eq!(f_exp2f(-10.0), 0.0009765625); assert!(f_exp2f(f32::NAN).is_nan()); assert_eq!(f_exp2f(-0.35), 0.7845841); assert_eq!(f_exp2f(0.35), 1.2745606); assert!(f_exp2f(f32::INFINITY).is_infinite()); assert_eq!(f_exp2f(f32::NEG_INFINITY), 0.0); } #[test] fn test_dirty_exp2f() { assert!((dirty_exp2f(0.35f32) - 0.35f32.exp2()).abs() < 1e-5); assert!((dirty_exp2f(-0.6f32) - (-0.6f32).exp2()).abs() < 1e-5); } } pxfm-0.1.23/src/exponents/exp2m1.rs000064400000000000000000000622771046102023000151730ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::fast_ldexp; const LN2H: f64 = f64::from_bits(0x3fe62e42fefa39ef); const LN2L: f64 = f64::from_bits(0x3c7abc9e3b39803f); struct Exp2m1 { exp: DoubleDouble, err: f64, } /* For 0 <= i < 64, T1[i] = (h,l) such that h+l is the best double-double approximation of 2^(i/64). The approximation error is bounded as follows: |h + l - 2^(i/64)| < 2^-107. */ pub(crate) static EXP_M1_2_TABLE1: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc719083535b085d, 0x3ff02c9a3e778061), (0x3c8d73e2a475b465, 0x3ff059b0d3158574), (0x3c6186be4bb284ff, 0x3ff0874518759bc8), (0x3c98a62e4adc610b, 0x3ff0b5586cf9890f), (0x3c403a1727c57b53, 0x3ff0e3ec32d3d1a2), (0xbc96c51039449b3a, 0x3ff11301d0125b51), (0xbc932fbf9af1369e, 0x3ff1429aaea92de0), (0xbc819041b9d78a76, 0x3ff172b83c7d517b), (0x3c8e5b4c7b4968e4, 0x3ff1a35beb6fcb75), (0x3c9e016e00a2643c, 0x3ff1d4873168b9aa), (0x3c8dc775814a8495, 0x3ff2063b88628cd6), (0x3c99b07eb6c70573, 0x3ff2387a6e756238), (0x3c82bd339940e9d9, 0x3ff26b4565e27cdd), (0x3c8612e8afad1255, 0x3ff29e9df51fdee1), (0x3c90024754db41d5, 0x3ff2d285a6e4030b), (0x3c86f46ad23182e4, 0x3ff306fe0a31b715), (0x3c932721843659a6, 0x3ff33c08b26416ff), (0xbc963aeabf42eae2, 0x3ff371a7373aa9cb), (0xbc75e436d661f5e3, 0x3ff3a7db34e59ff7), (0x3c8ada0911f09ebc, 0x3ff3dea64c123422), (0xbc5ef3691c309278, 0x3ff4160a21f72e2a), (0x3c489b7a04ef80d0, 0x3ff44e086061892d), (0x3c73c1a3b69062f0, 0x3ff486a2b5c13cd0), (0x3c7d4397afec42e2, 0x3ff4bfdad5362a27), (0xbc94b309d25957e3, 0x3ff4f9b2769d2ca7), (0xbc807abe1db13cad, 0x3ff5342b569d4f82), (0x3c99bb2c011d93ad, 0x3ff56f4736b527da), (0x3c96324c054647ad, 0x3ff5ab07dd485429), (0x3c9ba6f93080e65e, 0x3ff5e76f15ad2148), (0xbc9383c17e40b497, 0x3ff6247eb03a5585), (0xbc9bb60987591c34, 0x3ff6623882552225), (0xbc9bdd3413b26456, 0x3ff6a09e667f3bcd), (0xbc6bbe3a683c88ab, 0x3ff6dfb23c651a2f), (0xbc816e4786887a99, 0x3ff71f75e8ec5f74), (0xbc90245957316dd3, 0x3ff75feb564267c9), (0xbc841577ee04992f, 0x3ff7a11473eb0187), (0x3c705d02ba15797e, 0x3ff7e2f336cf4e62), (0xbc9d4c1dd41532d8, 0x3ff82589994cce13), (0xbc9fc6f89bd4f6ba, 0x3ff868d99b4492ed), (0x3c96e9f156864b27, 0x3ff8ace5422aa0db), (0x3c85cc13a2e3976c, 0x3ff8f1ae99157736), (0xbc675fc781b57ebc, 0x3ff93737b0cdc5e5), (0xbc9d185b7c1b85d1, 0x3ff97d829fde4e50), (0x3c7c7c46b071f2be, 0x3ff9c49182a3f090), (0xbc9359495d1cd533, 0x3ffa0c667b5de565), (0xbc9d2f6edb8d41e1, 0x3ffa5503b23e255d), (0x3c90fac90ef7fd31, 0x3ffa9e6b5579fdbf), (0x3c97a1cd345dcc81, 0x3ffae89f995ad3ad), (0xbc62805e3084d708, 0x3ffb33a2b84f15fb), (0xbc75584f7e54ac3b, 0x3ffb7f76f2fb5e47), (0x3c823dd07a2d9e84, 0x3ffbcc1e904bc1d2), (0x3c811065895048dd, 0x3ffc199bdd85529c), (0x3c92884dff483cad, 0x3ffc67f12e57d14b), (0x3c7503cbd1e949db, 0x3ffcb720dcef9069), (0xbc9cbc3743797a9c, 0x3ffd072d4a07897c), (0x3c82ed02d75b3707, 0x3ffd5818dcfba487), (0x3c9c2300696db532, 0x3ffda9e603db3285), (0xbc91a5cd4f184b5c, 0x3ffdfc97337b9b5f), (0x3c839e8980a9cc8f, 0x3ffe502ee78b3ff6), (0xbc9e9c23179c2893, 0x3ffea4afa2a490da), (0x3c9dc7f486a4b6b0, 0x3ffefa1bee615a27), (0x3c99d3e12dd8a18b, 0x3fff50765b6e4540), (0x3c874853f3a5931e, 0x3fffa7c1819e90d8), ]; /* For 0 <= i < 64, T2[i] = (h,l) such that h+l is the best double-double approximation of 2^(i/2^12). The approximation error is bounded as follows: |h + l - 2^(i/2^12)| < 2^-107. */ pub(crate) static EXP_M1_2_TABLE2: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c9ae8e38c59c72a, 0x3ff000b175effdc7), (0xbc57b5d0d58ea8f4, 0x3ff00162f3904052), (0x3c94115cb6b16a8e, 0x3ff0021478e11ce6), (0xbc8d7c96f201bb2f, 0x3ff002c605e2e8cf), (0x3c984711d4c35e9f, 0x3ff003779a95f959), (0xbc80484245243777, 0x3ff0042936faa3d8), (0xbc94b237da2025f9, 0x3ff004dadb113da0), (0xbc75e00e62d6b30d, 0x3ff0058c86da1c0a), (0x3c9a1d6cedbb9481, 0x3ff0063e3a559473), (0xbc94acf197a00142, 0x3ff006eff583fc3d), (0xbc6eaf2ea42391a5, 0x3ff007a1b865a8ca), (0x3c7da93f90835f75, 0x3ff0085382faef83), (0xbc86a79084ab093c, 0x3ff00905554425d4), (0x3c986364f8fbe8f8, 0x3ff009b72f41a12b), (0xbc882e8e14e3110e, 0x3ff00a6910f3b6fd), (0xbc84f6b2a7609f71, 0x3ff00b1afa5abcbf), (0xbc7e1a258ea8f71b, 0x3ff00bcceb7707ec), (0x3c74362ca5bc26f1, 0x3ff00c7ee448ee02), (0x3c9095a56c919d02, 0x3ff00d30e4d0c483), (0xbc6406ac4e81a645, 0x3ff00de2ed0ee0f5), (0x3c9b5a6902767e09, 0x3ff00e94fd0398e0), (0xbc991b2060859321, 0x3ff00f4714af41d3), (0x3c8427068ab22306, 0x3ff00ff93412315c), (0x3c9c1d0660524e08, 0x3ff010ab5b2cbd11), (0xbc9e7bdfb3204be8, 0x3ff0115d89ff3a8b), (0x3c8843aa8b9cbbc6, 0x3ff0120fc089ff63), (0xbc734104ee7edae9, 0x3ff012c1fecd613b), (0xbc72b6aeb6176892, 0x3ff0137444c9b5b5), (0x3c7a8cd33b8a1bb3, 0x3ff01426927f5278), (0x3c72edc08e5da99a, 0x3ff014d8e7ee8d2f), (0x3c857ba2dc7e0c73, 0x3ff0158b4517bb88), (0x3c9b61299ab8cdb7, 0x3ff0163da9fb3335), (0xbc990565902c5f44, 0x3ff016f0169949ed), (0x3c870fc41c5c2d53, 0x3ff017a28af25567), (0x3c94b9a6e145d76c, 0x3ff018550706ab62), (0xbc7008eff5142bf9, 0x3ff019078ad6a19f), (0xbc977669f033c7de, 0x3ff019ba16628de2), (0xbc909bb78eeead0a, 0x3ff01a6ca9aac5f3), (0x3c9371231477ece5, 0x3ff01b1f44af9f9e), (0x3c75e7626621eb5b, 0x3ff01bd1e77170b4), (0xbc9bc72b100828a5, 0x3ff01c8491f08f08), (0xbc6ce39cbbab8bbe, 0x3ff01d37442d5070), (0x3c816996709da2e2, 0x3ff01de9fe280ac8), (0xbc8c11f5239bf535, 0x3ff01e9cbfe113ef), (0x3c8e1d4eb5edc6b3, 0x3ff01f4f8958c1c6), (0xbc9afb99946ee3f0, 0x3ff020025a8f6a35), (0xbc98f06d8a148a32, 0x3ff020b533856324), (0xbc82bf310fc54eb6, 0x3ff02168143b0281), (0xbc9c95a035eb4175, 0x3ff0221afcb09e3e), (0xbc9491793e46834d, 0x3ff022cdece68c4f), (0xbc73e8d0d9c49091, 0x3ff02380e4dd22ad), (0xbc9314aa16278aa3, 0x3ff02433e494b755), (0x3c848daf888e9651, 0x3ff024e6ec0da046), (0x3c856dc8046821f4, 0x3ff02599fb483385), (0x3c945b42356b9d47, 0x3ff0264d1244c719), (0xbc7082ef51b61d7e, 0x3ff027003103b10e), (0x3c72106ed0920a34, 0x3ff027b357854772), (0xbc9fd4cf26ea5d0f, 0x3ff0286685c9e059), (0xbc909f8775e78084, 0x3ff02919bbd1d1d8), (0x3c564cbba902ca27, 0x3ff029ccf99d720a), (0x3c94383ef231d207, 0x3ff02a803f2d170d), (0x3c94a47a505b3a47, 0x3ff02b338c811703), (0x3c9e47120223467f, 0x3ff02be6e199c811), ]; // Approximation for the fast path of exp(z) for z=zh+zl, // with |z| < 0.000130273 < 2^-12.88 and |zl| < 2^-42.6 // (assuming x^y does not overflow or underflow) #[inline] fn q_1(dz: DoubleDouble) -> DoubleDouble { const Q_1: [u64; 5] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555995d37, 0x3fa55555558489dc, ]; let z = dz.to_f64(); let mut q = f_fmla(f64::from_bits(Q_1[4]), dz.hi, f64::from_bits(Q_1[3])); q = f_fmla(q, z, f64::from_bits(Q_1[2])); let mut p0 = DoubleDouble::from_exact_add(f64::from_bits(Q_1[1]), q * z); p0 = DoubleDouble::quick_mult(dz, p0); p0 = DoubleDouble::f64_add(f64::from_bits(Q_1[0]), p0); p0 } #[inline] fn exp1(x: DoubleDouble) -> DoubleDouble { const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); /* |INVLOG2-2^12/log(2)| < 2^-43.4 */ let k = (x.hi * INVLOG2).round_ties_even(); const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); const LOG2DD: DoubleDouble = DoubleDouble::new(LOG2L, LOG2H); let zk = DoubleDouble::quick_mult_f64(LOG2DD, k); let mut yz = DoubleDouble::from_exact_add(x.hi - zk.hi, x.lo); yz.lo -= zk.lo; let ik: i64 = k as i64; /* Note: k is an integer, this is just a conversion. */ let im: i64 = (ik >> 12).wrapping_add(0x3ff); let i2: i64 = (ik >> 6) & 0x3f; let i1: i64 = ik & 0x3f; let t1 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE1[i2 as usize]); let t2 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE2[i1 as usize]); let p0 = DoubleDouble::quick_mult(t2, t1); let mut q = q_1(yz); q = DoubleDouble::quick_mult(p0, q); /* Scale by 2^k. Warning: for x near 1024, we can have k=2^22, thus M = 2047, which encodes Inf */ let mut du = (im as u64).wrapping_shl(52); if im == 0x7ff { q.hi *= 2.0; q.lo *= 2.0; du = (im.wrapping_sub(1) as u64).wrapping_shl(52); } q.hi *= f64::from_bits(du); q.lo *= f64::from_bits(du); q } #[inline] fn exp2m1_fast(x: f64, tiny: bool) -> Exp2m1 { if tiny { return exp2m1_fast_tiny(x); } /* now -54 < x < -0.125 or 0.125 < x < 1024: we approximate exp(x*log(2)) and subtract 1 */ let mut v = DoubleDouble::from_exact_mult(LN2H, x); v.lo = f_fmla(x, LN2L, v.lo); /* The a_mul() call is exact, and the error of the fma() is bounded by ulp(l). We have |t| <= ulp(h) <= ulp(LN2H*1024) = 2^-43, |t+x*LN2L| <= 2^-43 * 1024*LN2L < 2^-42.7, thus |l| <= |t| + |x*LN2L| + ulp(t+x*LN2L) <= 2^-42.7 + 2^-95 <= 2^-42.6, and ulp(l) <= 2^-95. Thus: |h + l - x*log(2)| <= |h + l - x*(LN2H+LN2L)| + |x|*|LN2H+LN2L-log(2)| <= 2^-95 + 1024*2^-110.4 < 2^-94.9 */ let mut p = exp1(v); let zf: DoubleDouble = if x >= 0. { // implies h >= 1 and the fast_two_sum pre-condition holds DoubleDouble::from_exact_add(p.hi, -1.0) } else { DoubleDouble::from_exact_add(-1.0, p.hi) }; p.lo += zf.lo; p.hi = zf.hi; /* The error in the above fast_two_sum is bounded by 2^-105*|h|, with the new value of h, thus the total absolute error is bounded by eps1*|h_in|+2^-105*|h|. Relatively to h this yields eps1*|h_in/h| + 2^-105, where the maximum of |h_in/h| is obtained for x near -0.125, with |2^x/(2^x-1)| < 11.05. We get a relative error bound of 2^-74.138*11.05 + 2^-105 < 2^-70.67. */ Exp2m1 { exp: p, err: f64::from_bits(0x3b84200000000000) * p.hi, /* 2^-70.67 < 0x1.42p-71 */ } } // Approximation for the accurate path of exp(z) for z=zh+zl, // with |z| < 0.000130273 < 2^-12.88 and |zl| < 2^-42.6 // (assuming x^y does not overflow or underflow) #[inline] fn q_2(dz: DoubleDouble) -> DoubleDouble { /* Let q[0]..q[7] be the coefficients of degree 0..7 of Q_2. The ulp of q[7]*z^7 is at most 2^-155, thus we can compute q[7]*z^7 in double precision only. The ulp of q[6]*z^6 is at most 2^-139, thus we can compute q[6]*z^6 in double precision only. The ulp of q[5]*z^5 is at most 2^-124, thus we can compute q[5]*z^5 in double precision only. */ /* The following is a degree-7 polynomial generated by Sollya for exp(z) over [-0.000130273,0.000130273] with absolute error < 2^-113.218 (see file exp_accurate.sollya). Since we use this code only for |x| > 0.125 in exp2m1(x), the corresponding relative error for exp2m1 is about 2^-113.218/|exp2m1(-0.125)| which is about 2^-110. */ const Q_2: [u64; 9] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555555555, 0x3c655555555c4d26, 0x3fa5555555555555, 0x3f81111111111111, 0x3f56c16c3fbb4213, 0x3f2a01a023ede0d7, ]; let z = dz.to_f64(); let mut q = dd_fmla(f64::from_bits(Q_2[8]), dz.hi, f64::from_bits(Q_2[7])); q = dd_fmla(q, z, f64::from_bits(Q_2[6])); q = dd_fmla(q, z, f64::from_bits(Q_2[5])); // multiply q by z and add Q_2[3] + Q_2[4] let mut p = DoubleDouble::from_exact_mult(q, z); let r0 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[3]), p.hi); p.hi = r0.hi; p.lo += r0.lo + f64::from_bits(Q_2[4]); // multiply hi+lo by zh+zl and add Q_2[2] p = DoubleDouble::quick_mult(p, dz); let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[2]), p.hi); p.hi = r1.hi; p.lo += r1.lo; // multiply hi+lo by zh+zl and add Q_2[1] p = DoubleDouble::quick_mult(p, dz); let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[1]), p.hi); p.hi = r1.hi; p.lo += r1.lo; // multiply hi+lo by zh+zl and add Q_2[0] p = DoubleDouble::quick_mult(p, dz); let r1 = DoubleDouble::from_exact_add(f64::from_bits(Q_2[0]), p.hi); p.hi = r1.hi; p.lo += r1.lo; p } // returns a double-double approximation hi+lo of exp(x*log(2)) for |x| < 745 #[inline] fn exp_2(x: f64) -> DoubleDouble { let k = (x * f64::from_bits(0x40b0000000000000)).round_ties_even(); // since |x| <= 745 we have k <= 3051520 let yhh = f_fmla(-k, f64::from_bits(0x3f30000000000000), x); // exact, |yh| <= 2^-13 /* now x = k + yh, thus 2^x = 2^k * 2^yh, and we multiply yh by log(2) to use the accurate path of exp() */ let ky = DoubleDouble::quick_f64_mult(yhh, DoubleDouble::new(LN2L, LN2H)); let ik = k as i64; let im = (ik >> 12).wrapping_add(0x3ff); let i2 = (ik >> 6) & 0x3f; let i1 = ik & 0x3f; let t1 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE1[i2 as usize]); let t2 = DoubleDouble::from_bit_pair(EXP_M1_2_TABLE2[i1 as usize]); let p = DoubleDouble::quick_mult(t2, t1); let mut q = q_2(ky); q = DoubleDouble::quick_mult(p, q); let mut ud: u64 = (im as u64).wrapping_shl(52); if im == 0x7ff { q.hi *= 2.0; q.lo *= 2.0; ud = (im.wrapping_sub(1) as u64).wrapping_shl(52); } q.hi *= f64::from_bits(ud); q.lo *= f64::from_bits(ud); q } #[cold] pub(crate) fn exp2m1_accurate_tiny(x: f64) -> f64 { let x2 = x * x; let x4 = x2 * x2; const Q: [u64; 22] = [ 0x3fe62e42fefa39ef, 0x3c7abc9e3b398040, 0x3fcebfbdff82c58f, 0xbc65e43a53e44dcf, 0x3fac6b08d704a0c0, 0xbc4d331627517168, 0x3f83b2ab6fba4e77, 0x3c14e65df0779f8c, 0x3f55d87fe78a6731, 0x3bd0717fbf4bd050, 0x3f2430912f86c787, 0x3bcbd2bdec9bcd42, 0x3eeffcbfc588b0c7, 0xbb8e60aa6d5e4aa9, 0x3eb62c0223a5c824, 0x3e7b5253d395e7d4, 0x3e3e4cf5158b9160, 0x3dfe8cac734c6058, 0x3dbc3bd64f17199d, 0x3d78161a17e05651, 0x3d33150b3d792231, 0x3cec184260bfad7e, ]; let mut c13 = dd_fmla(f64::from_bits(Q[20]), x, f64::from_bits(Q[19])); // degree 13 let c11 = dd_fmla(f64::from_bits(Q[18]), x, f64::from_bits(Q[17])); // degree 11 c13 = dd_fmla(f64::from_bits(Q[21]), x2, c13); // degree 13 // add Q[16]*x+c11*x2+c13*x4 to Q[15] (degree 9) let mut p = DoubleDouble::from_exact_add( f64::from_bits(Q[15]), f_fmla(f64::from_bits(Q[16]), x, f_fmla(c11, x2, c13 * x4)), ); // multiply h+l by x and add Q[14] (degree 8) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[14]), p.hi); p.lo += p0.lo; p.hi = p0.hi; // multiply h+l by x and add Q[12]+Q[13] (degree 7) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[12]), p.hi); p.lo += p0.lo + f64::from_bits(Q[13]); p.hi = p0.hi; // multiply h+l by x and add Q[10]+Q[11] (degree 6) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[10]), p.hi); p.lo += p0.lo + f64::from_bits(Q[11]); p.hi = p0.hi; // multiply h+l by x and add Q[8]+Q[9] (degree 5) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[8]), p.hi); p.lo += p0.lo + f64::from_bits(Q[9]); p.hi = p0.hi; // multiply h+l by x and add Q[6]+Q[7] (degree 4) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[6]), p.hi); p.lo += p0.lo + f64::from_bits(Q[7]); p.hi = p0.hi; // multiply h+l by x and add Q[4]+Q[5] (degree 3) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[4]), p.hi); p.lo += p0.lo + f64::from_bits(Q[5]); p.hi = p0.hi; // multiply h+l by x and add Q[2]+Q[3] (degree 2) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[2]), p.hi); p.lo += p0.lo + f64::from_bits(Q[3]); p.hi = p0.hi; // multiply h+l by x and add Q[0]+Q[1] (degree 2) p = DoubleDouble::quick_f64_mult(x, p); let p0 = DoubleDouble::from_exact_add(f64::from_bits(Q[0]), p.hi); p.lo += p0.lo + f64::from_bits(Q[1]); p.hi = p0.hi; // multiply h+l by x p = DoubleDouble::quick_f64_mult(x, p); p.to_f64() } #[cold] fn exp2m1_accurate(x: f64) -> f64 { let t = x.to_bits(); let ux = t; let ax = ux & 0x7fffffffffffffffu64; if ax <= 0x3fc0000000000000u64 { // |x| <= 0.125 return exp2m1_accurate_tiny(x); } let mut p = exp_2(x); let zf: DoubleDouble = DoubleDouble::from_full_exact_add(p.hi, -1.0); p.lo += zf.lo; p.hi = zf.hi; p.to_f64() } /* |x| <= 0.125, put in h + l a double-double approximation of exp2m1(x), and return the maximal corresponding absolute error. We also have |x| > 0x1.0527dbd87e24dp-51. With xmin=RR("0x1.0527dbd87e24dp-51",16), the routine exp2m1_fast_tiny_all(xmin,0.125,2^-65.73) in exp2m1.sage returns 1.63414352331297e-20 < 2^-65.73, and exp2m1_fast_tiny_all(-0.125,-xmin,2^-65.62) returns 1.76283772822891e-20 < 2^-65.62, which proves the relative error is bounded by 2^-65.62. */ #[inline] fn exp2m1_fast_tiny(x: f64) -> Exp2m1 { /* The maximal value of |c4*x^4/exp2m1(x)| over [-0.125,0.125] is less than 2^-15.109, where c4 is the degree-4 coefficient, thus we can compute the coefficients of degree 4 or higher using double precision only. */ const P: [u64; 12] = [ 0x3fe62e42fefa39ef, 0x3c7abd1697afcaf8, 0x3fcebfbdff82c58f, 0xbc65e5a1d09e1599, 0x3fac6b08d704a0bf, 0x3f83b2ab6fba4e78, 0x3f55d87fe78a84e6, 0x3f2430912f86a480, 0x3eeffcbfbc1f2b36, 0x3eb62c0226c7f6d1, 0x3e7b539529819e63, 0x3e3e4d552bed5b9c, ]; let x2 = x * x; let x4 = x2 * x2; let mut c8 = dd_fmla(f64::from_bits(P[10]), x, f64::from_bits(P[9])); // degree 8 let c6 = dd_fmla(f64::from_bits(P[8]), x, f64::from_bits(P[7])); // degree 6 let mut c4 = dd_fmla(f64::from_bits(P[6]), x, f64::from_bits(P[5])); // degree 4 c8 = dd_fmla(f64::from_bits(P[11]), x2, c8); // degree 8 c4 = dd_fmla(c6, x2, c4); // degree 4 c4 = dd_fmla(c8, x4, c4); // degree 4 let mut p = DoubleDouble::from_exact_mult(c4, x); let p0 = DoubleDouble::from_exact_add(f64::from_bits(P[4]), p.hi); p.lo += p0.lo; p.hi = p0.hi; p = DoubleDouble::quick_f64_mult(x, p); let p1 = DoubleDouble::from_exact_add(f64::from_bits(P[2]), p.hi); p.lo += p1.lo + f64::from_bits(P[3]); p.hi = p1.hi; p = DoubleDouble::quick_f64_mult(x, p); let p2 = DoubleDouble::from_exact_add(f64::from_bits(P[0]), p.hi); p.lo += p2.lo + f64::from_bits(P[1]); p.hi = p2.hi; p = DoubleDouble::quick_f64_mult(x, p); Exp2m1 { exp: p, err: f64::from_bits(0x3bd4e00000000000) * p.hi, // 2^-65.62 < 0x1.4ep-66 } } /// Computes 2^x - 1 /// /// Max found ULP 0.5 pub fn f_exp2m1(d: f64) -> f64 { let mut x = d; let t = x.to_bits(); let ux = t; let ax = ux & 0x7fffffffffffffffu64; if ux >= 0xc04b000000000000u64 { // x = -NaN or x <= -54 if (ux >> 52) == 0xfff { // -NaN or -Inf return if ux > 0xfff0000000000000u64 { x + x } else { -1.0 }; } // for x <= -54, exp2m1(x) rounds to -1 to nearest return -1.0 + f64::from_bits(0x3c90000000000000); } else if ax >= 0x4090000000000000u64 { // x = +NaN or x >= 1024 if (ux >> 52) == 0x7ff { // +NaN return x + x; } /* for x >= 1024, exp2m1(x) rounds to +Inf to nearest, but for RNDZ/RNDD, we should have no overflow for x=1024 */ return f_fmla( x, f64::from_bits(0x7bffffffffffffff), f64::from_bits(0x7fefffffffffffff), ); } else if ax <= 0x3cc0527dbd87e24du64 // |x| <= 0x1.0527dbd87e24dp-51 /* then the second term of the Taylor expansion of 2^x-1 at x=0 is smaller in absolute value than 1/2 ulp(first term): log(2)*x + log(2)^2*x^2/2 + ... */ { /* we use special code when log(2)*|x| is very small, in which case the double-double approximation h+l has its lower part l "truncated" */ return if ax <= 0x3970000000000000u64 // |x| <= 2^-104 { // special case for 0 if x == 0. { return x; } // scale x by 2^106 x *= f64::from_bits(0x4690000000000000); let z = DoubleDouble::quick_mult_f64(DoubleDouble::new(LN2L, LN2H), x); let mut h2 = z.to_f64(); // round to 53-bit precision // scale back, hoping to avoid double rounding h2 *= f64::from_bits(0x3950000000000000); // now subtract back h2 * 2^106 from h to get the correction term let mut h = dd_fmla(-h2, f64::from_bits(0x4690000000000000), z.hi); // add l h += z.lo; /* add h2 + h * 2^-106. Warning: when h=0, 2^-106*h2 might be exact, thus no underflow will be raised. We have underflow for 0 < x <= 0x1.71547652b82fep-1022 for RNDZ, and for 0 < x <= 0x1.71547652b82fdp-1022 for RNDN/RNDU. */ dyad_fmla(h, f64::from_bits(0x3950000000000000), h2) } else { const C2: f64 = f64::from_bits(0x3fcebfbdff82c58f); // log(2)^2/2 let mut z = DoubleDouble::from_exact_mult(LN2H, x); z.lo = dyad_fmla(LN2L, x, z.lo); /* h+l approximates the first term x*log(2) */ /* we add C2*x^2 last, so that in case there is a cancellation in LN2L*x+l, it will contribute more bits */ z.lo += C2 * x * x; z.to_f64() }; } /* now -54 < x < -0x1.0527dbd87e24dp-51 or 0x1.0527dbd87e24dp-51 < x < 1024 */ /* 2^x-1 is exact for x integer, -53 <= x <= 53 */ if ux.wrapping_shl(17) == 0 { let i = x.floor() as i32; if x == i as f64 && -53 <= i && i <= 53 { return if i >= 0 { ((1u64 << i) - 1) as f64 } else { -1.0 + fast_ldexp(1.0, i) }; } } let result = exp2m1_fast(x, ax <= 0x3fc0000000000000u64); let left = result.exp.hi + (result.exp.lo - result.err); let right = result.exp.hi + (result.exp.lo + result.err); if left != right { return exp2m1_accurate(x); } left } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp2m1() { assert_eq!(f_exp2m1(5.4172231599824623E-312), 3.75493295981e-312); assert_eq!(f_exp2m1( 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017800593653177087), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012338431302992956); assert_eq!(3., f_exp2m1(2.0)); assert_eq!(4.656854249492381, f_exp2m1(2.5)); assert_eq!(-0.30801352040368324, f_exp2m1(-0.5311842449009418)); } } pxfm-0.1.23/src/exponents/exp2m1f.rs000064400000000000000000000245001046102023000153240ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use std::hint::black_box; static Q: [(u32, u32); 3] = [ (0x7f7fffff, 0x7f7fffff), (0x7f7fffff, 0x73000000), (0xbf800000, 0x32800000), ]; static TB: [u64; 16] = [ 0x3ff0000000000000, 0x3ff0b5586cf9890f, 0x3ff172b83c7d517b, 0x3ff2387a6e756238, 0x3ff306fe0a31b715, 0x3ff3dea64c123422, 0x3ff4bfdad5362a27, 0x3ff5ab07dd485429, 0x3ff6a09e667f3bcd, 0x3ff7a11473eb0187, 0x3ff8ace5422aa0da, 0x3ff9c49182a3f090, 0x3ffae89f995ad3ad, 0x3ffc199bdd85529c, 0x3ffd5818dcfba487, 0x3ffea4afa2a490da, ]; // |x| < 8.44e-2/log(2) #[cold] fn exp2mf_small(ax: u32, z: f64, ux: u32) -> f32 { let z2: f64 = z * z; let mut r: f64; if ax < 0x3d67a4ccu32 { // |x| < 3.92e-2/log(2) if ax < 0x3caa2feeu32 { // |x| < 1.44e-2/log(2) if ax < 0x3bac1405u32 { // |x| < 3.64e-3/log(2) if ax < 0x3a358876u32 { // |x| < 4.8e-4/log(2) if ax < 0x37d32ef6u32 { // |x| < 1.745e-5/log(2) if ax < 0x331fdd82u32 { // |x| < 2.58e-8/log(2) if ax < 0x2538aa3bu32 { // |x| < 0x1.715476p-53 r = f64::from_bits(0x3fe62e42fefa39ef); } else { r = f_fmla( z, f64::from_bits(0x3fcebfbdff82c58f), f64::from_bits(0x3fe62e42fefa39f0), ); } } else { if ux == 0xb3d85005u32 { return (black_box(f64::from_bits(0xbe72bdf760000000)) - black_box(f64::from_bits(0x3b28000000000000))) as f32; } if ux == 0x3338428du32 { return (black_box(f64::from_bits(0x3e5fee08a0000000)) + black_box(f64::from_bits(0x3af0000000000000))) as f32; } const C: [u64; 3] = [0x3fe62e42fefa39ef, 0x3fcebfbdff8548fd, 0x3fac6b08d704a06d]; let r0 = f_fmla(z, f64::from_bits(C[2]), f64::from_bits(C[1])); r = f_fmla(z, r0, f64::from_bits(C[0])); } } else { if ux == 0x388bca4fu32 { return (black_box(f64::from_bits(0x3f08397020000000)) - black_box(f64::from_bits(0x3bb8000000000000))) as f32; } const C: [u64; 4] = [ 0x3fe62e42fefa39ef, 0x3fcebfbdff82c58f, 0x3fac6b08dc82b347, 0x3f83b2ab6fbad172, ]; let r0 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let r1 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); r = f_fmla(z2, r0, r1); } } else { const C: [u64; 5] = [ 0x3fe62e42fefa39ef, 0x3fcebfbdff82c068, 0x3fac6b08d704a6dc, 0x3f83b2ac262c3eed, 0x3f55d87fe7af779a, ]; let r0 = f_fmla(z, f64::from_bits(C[4]), f64::from_bits(C[3])); let r1 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let w0 = f_fmla(z, r0, f64::from_bits(C[2])); r = f_fmla(z2, w0, r1); } } else { const C: [u64; 6] = [ 0x3fe62e42fefa39f0, 0x3fcebfbdff82c58d, 0x3fac6b08d7011d13, 0x3f83b2ab6fbd267d, 0x3f55d88a81cea49e, 0x3f2430912ea9b963, ]; let r0 = f_fmla(z, f64::from_bits(C[5]), f64::from_bits(C[4])); let r1 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let r2 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); r = r2 + z2 * f_fmla(z2, r0, r1); } } else { const C: [u64; 7] = [ 0x3fe62e42fefa39ef, 0x3fcebfbdff82c639, 0x3fac6b08d7049f1c, 0x3f83b2ab6f5243bd, 0x3f55d87fe80a9e6c, 0x3f2430d0b9257fa8, 0x3eeffcbfc4cf0952, ]; let r0 = f_fmla(z, f64::from_bits(C[6]), f64::from_bits(C[5])); let r1 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let r2 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let z0 = f_fmla(z, r0, f64::from_bits(C[4])); r = f_fmla(z2, f_fmla(z2, z0, r1), r2); } } else { const C: [u64; 8] = [ 0x3fe62e42fefa39ef, 0x3fcebfbdff82c591, 0x3fac6b08d704cf6b, 0x3f83b2ab6fba00ce, 0x3f55d87fdfdaadb4, 0x3f24309137333066, 0x3eeffe5e90daf7dd, 0x3eb62c0220eed731, ]; let r0 = f_fmla(z, f64::from_bits(C[7]), f64::from_bits(C[6])); let r1 = f_fmla(z, f64::from_bits(C[5]), f64::from_bits(C[4])); let r2 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let r3 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let w0 = f_fmla(z2, r0, r1); let w1 = f_fmla(z2, r2, r3); r = w1 + (z2 * z2) * w0; } r *= z; r as f32 } /// Computes 2^x-1 /// /// Max found ULP 0.5 #[inline] pub fn f_exp2m1f(x: f32) -> f32 { let t = x.to_bits(); let z = x as f64; let ux = t; let ax = ux & 0x7fff_ffff; if ux >= 0xc1c80000u32 { // x <= -25 if ax > (0xffu32 << 23) { return x + x; } // nan // avoid spurious inexact exception for -Inf if ux == 0xff800000 { f32::from_bits(Q[2].0) } else { let zq = Q[2]; black_box(f32::from_bits(zq.0)) + black_box(f32::from_bits(zq.1)) } } else if ax >= 0x43000000u32 { // x >= 128 if ax > (0xffu32 << 23) { return x + x; } // nan // for x=128 and rounding downward or to zero, there is no overflow let special = if x == 128.0 && (f32::from_bits(Q[1].0) + f32::from_bits(Q[1].1) == f32::from_bits(Q[1].0)) { 1 } else { 0 }; // avoid spurious inexact exception for +Inf if ux == 0x7f800000u32 { x } else { f32::from_bits(Q[special].0) + f32::from_bits(Q[special].1) } } else if ax < 0x3df95f1fu32 { // |x| < 8.44e-2/log(2) exp2mf_small(ax, z, ux) } else { const C: [u64; 6] = [ 0x3fa62e42fefa398b, 0x3f4ebfbdff84555a, 0x3eec6b08d4ad86d3, 0x3e83b2ad1b1716a2, 0x3e15d7472718ce9d, 0x3da4a1d7f457ac56, ]; let a = 16.0 * z; let ia = a.floor(); let h = a - ia; let h2 = h * h; let i: i64 = ia as i64; let j = i & 0xf; let mut e = i.wrapping_sub(j); e >>= 4; let mut s = f64::from_bits(TB[j as usize]); let su = ((e as u64).wrapping_add(0x3ffu64)) << 52; s *= f64::from_bits(su); let mut c0 = f_fmla(h, f64::from_bits(C[1]), f64::from_bits(C[0])); let c2 = f_fmla(h, f64::from_bits(C[3]), f64::from_bits(C[2])); let c4 = f_fmla(h, f64::from_bits(C[5]), f64::from_bits(C[4])); c0 += h2 * f_fmla(h2, c4, c2); let w = s * h; f_fmla(w, c0, s - 1.0) as f32 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_exp2m1f() { assert_eq!(f_exp2m1f(0.432423), 0.34949815); assert_eq!(f_exp2m1f(-4.), -0.9375); assert_eq!(f_exp2m1f(5.43122), 42.14795); assert_eq!(f_exp2m1f(4.), 15.0); assert_eq!(f_exp2m1f(3.), 7.); assert_eq!(f_exp2m1f(0.1), 0.07177346); assert_eq!(f_exp2m1f(0.0543432432), 0.038386293); assert!(f_exp2m1f(f32::NAN).is_nan()); assert_eq!(f_exp2m1f(f32::INFINITY), f32::INFINITY); assert_eq!(f_exp2m1f(f32::NEG_INFINITY), -1.0); } } pxfm-0.1.23/src/exponents/exp_f128.rs000064400000000000000000000336761046102023000154140ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; #[inline] fn poly_exp_f128(x: DyadicFloat128) -> DyadicFloat128 { static COEFFS_128: [DyadicFloat128; 8] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 1.0 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 1.0 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 0.5 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, // 1/6 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, // 1/24 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x88888888_88888888_88888888_88888889_u128, }, // 1/120 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xb60b60b6_0b60b60b_60b60b60_b60b60b6_u128, }, // 1/720 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0xd00d00d0_0d00d00d_00d00d00_d00d00d0_u128, }, // 1/5040 ]; let mut z = COEFFS_128[7]; for i in (0..7).rev() { z = x * z + COEFFS_128[i]; } z } #[cold] #[inline(never)] pub(crate) fn rational128_exp(x: f64) -> DyadicFloat128 { const LOG2_E: f64 = f64::from_bits(0x3ff71547652b82fe); let tmp = f_fmla(x, LOG2_E, f64::from_bits(0x4148000000040000)); let k = (tmp.to_bits() >> 19) as i32; let kd = k as f64; let idx1: usize = ((k >> 6) & 0x3f) as usize; let idx2 = (k & 0x3f) as usize; const MLOG_2_EXP2_M12_HI: f64 = f64::from_bits(0xbf262e42ff000000); const MLOG_2_EXP2_M12_MID_30: f64 = f64::from_bits(0x3d0718432a000000); const MLOG_2_EXP2_M12_LO: f64 = f64::from_bits(0x3b0b0e2633fe0685); let t1 = f_fmla(kd, MLOG_2_EXP2_M12_HI, x); // exact let t2 = kd * MLOG_2_EXP2_M12_MID_30; // exact let t3 = kd * MLOG_2_EXP2_M12_LO; // Error < 2^-133 let dx = DyadicFloat128::new_from_f64(t1) + (DyadicFloat128::new_from_f64(t2) + DyadicFloat128::new_from_f64(t3)); let exp_mid1 = DyadicFloat128::new_from_f64(f64::from_bits(TD_EXP2_MID1[idx1].2)) + (DyadicFloat128::new_from_f64(f64::from_bits(TD_EXP2_MID1[idx1].1)) + DyadicFloat128::new_from_f64(f64::from_bits(TD_EXP2_MID1[idx1].0))); let exp_mid2 = DyadicFloat128::new_from_f64(f64::from_bits(TD_EXP2_MID2[idx2].2)) + (DyadicFloat128::new_from_f64(f64::from_bits(TD_EXP2_MID2[idx2].1)) + DyadicFloat128::new_from_f64(f64::from_bits(TD_EXP2_MID2[idx2].0))); let exp_mid = exp_mid1 * exp_mid2; let p = poly_exp_f128(dx); let mut r = exp_mid * p; r.exponent += (kd as i64 >> 12) as i16; r } // Lookup table for 2^(k * 2^-6) with k = 0..63. // Generated by Sollya with: // > display=hexadecimal; // > prec = 500; // > for i from 0 to 63 do { // a = 2^(i * 2^-6); // b = round(a, D, RN); // c = round(a - b, D, RN); // d = round(a - b - c, D, RN); // print("{", d, ",", c, ",", b, "},"); // }; static TD_EXP2_MID1: [(u64, u64, u64); 64] = [ (0x0000000000000000, 0x0000000000000000, 0x3ff0000000000000), (0xb919085b0a3d74d5, 0xbc719083535b085d, 0x3ff02c9a3e778061), (0x39105ff94f8d257e, 0x3c8d73e2a475b465, 0x3ff059b0d3158574), (0x39015820d96b414f, 0x3c6186be4bb284ff, 0x3ff0874518759bc8), (0xb9367c9bd6ebf74c, 0x3c98a62e4adc610b, 0x3ff0b5586cf9890f), (0xb8e5aa76994e9ddb, 0x3c403a1727c57b53, 0x3ff0e3ec32d3d1a2), (0x3929d58b988f562d, 0xbc96c51039449b3a, 0x3ff11301d0125b51), (0xb932fe7bb4c76416, 0xbc932fbf9af1369e, 0x3ff1429aaea92de0), (0x3924f2406aa13ff0, 0xbc819041b9d78a76, 0x3ff172b83c7d517b), (0x390ad36183926ae8, 0x3c8e5b4c7b4968e4, 0x3ff1a35beb6fcb75), (0x391ea62d0881b918, 0x3c9e016e00a2643c, 0x3ff1d4873168b9aa), (0xb90781dbc16f1ea4, 0x3c8dc775814a8495, 0x3ff2063b88628cd6), (0xb924d89f9af532e0, 0x3c99b07eb6c70573, 0x3ff2387a6e756238), (0x391277393a461b77, 0x3c82bd339940e9d9, 0x3ff26b4565e27cdd), (0x390de54485604690, 0x3c8612e8afad1255, 0x3ff29e9df51fdee1), (0xb91ee9d8f8cb9307, 0x3c90024754db41d5, 0x3ff2d285a6e4030b), (0x3917b7b2f09cd0d9, 0x3c86f46ad23182e4, 0x3ff306fe0a31b715), (0xb93406a2ea6cfc6b, 0x3c932721843659a6, 0x3ff33c08b26416ff), (0x39387e3e12516bfa, 0xbc963aeabf42eae2, 0x3ff371a7373aa9cb), (0x3909b0b1ff17c296, 0xbc75e436d661f5e3, 0x3ff3a7db34e59ff7), (0xb92808ba68fa8fb7, 0x3c8ada0911f09ebc, 0x3ff3dea64c123422), (0xb8d32b43eafc6518, 0xbc5ef3691c309278, 0x3ff4160a21f72e2a), (0xb8d0ac312de3d922, 0x3c489b7a04ef80d0, 0x3ff44e086061892d), (0x390e1eebae743ac0, 0x3c73c1a3b69062f0, 0x3ff486a2b5c13cd0), (0x38ec06c7745c2b39, 0x3c7d4397afec42e2, 0x3ff4bfdad5362a27), (0xb8f1aa1fd7b685cd, 0xbc94b309d25957e3, 0x3ff4f9b2769d2ca7), (0x390fa733951f214c, 0xbc807abe1db13cad, 0x3ff5342b569d4f82), (0xb90ff86852a613ff, 0x3c99bb2c011d93ad, 0x3ff56f4736b527da), (0xb92744ee506fdafe, 0x3c96324c054647ad, 0x3ff5ab07dd485429), (0xb9395f9ab75fa7d6, 0x3c9ba6f93080e65e, 0x3ff5e76f15ad2148), (0x3905d8e757cfb991, 0xbc9383c17e40b497, 0x3ff6247eb03a5585), (0x3934a337f4dc0a3b, 0xbc9bb60987591c34, 0x3ff6623882552225), (0x39357d3e3adec175, 0xbc9bdd3413b26456, 0x3ff6a09e667f3bcd), (0x38ca59f88abbe778, 0xbc6bbe3a683c88ab, 0x3ff6dfb23c651a2f), (0xb92269796953a4c3, 0xbc816e4786887a99, 0x3ff71f75e8ec5f74), (0xb938f8e7fa19e5e8, 0xbc90245957316dd3, 0x3ff75feb564267c9), (0xb8e4217a932d10d4, 0xbc841577ee04992f, 0x3ff7a11473eb0187), (0x38f70a1427f8fcdf, 0x3c705d02ba15797e, 0x3ff7e2f336cf4e62), (0x38f0f6ad65cbbac1, 0xbc9d4c1dd41532d8, 0x3ff82589994cce13), (0xb92f16f65181d921, 0xbc9fc6f89bd4f6ba, 0x3ff868d99b4492ed), (0xb9130644a7836333, 0x3c96e9f156864b27, 0x3ff8ace5422aa0db), (0x38d3bf26d2b85163, 0x3c85cc13a2e3976c, 0x3ff8f1ae99157736), (0x390697e257ac0db2, 0xbc675fc781b57ebc, 0x3ff93737b0cdc5e5), (0x3937edb9d7144b6f, 0xbc9d185b7c1b85d1, 0x3ff97d829fde4e50), (0x3916376b7943085c, 0x3c7c7c46b071f2be, 0x3ff9c49182a3f090), (0x392354084551b4fb, 0xbc9359495d1cd533, 0x3ffa0c667b5de565), (0xb90bfd7adfd63f48, 0xbc9d2f6edb8d41e1, 0x3ffa5503b23e255d), (0x3928b16ae39e8cb9, 0x3c90fac90ef7fd31, 0x3ffa9e6b5579fdbf), (0x393a7fbc3ae675ea, 0x3c97a1cd345dcc81, 0x3ffae89f995ad3ad), (0x3902babc0edda4d9, 0xbc62805e3084d708, 0x3ffb33a2b84f15fb), (0x390aa64481e1ab72, 0xbc75584f7e54ac3b, 0x3ffb7f76f2fb5e47), (0x3929a164050e1258, 0x3c823dd07a2d9e84, 0x3ffbcc1e904bc1d2), (0x39199e51125928da, 0x3c811065895048dd, 0x3ffc199bdd85529c), (0xb92fc44c329d5cb2, 0x3c92884dff483cad, 0x3ffc67f12e57d14b), (0x391d8765566b032e, 0x3c7503cbd1e949db, 0x3ffcb720dcef9069), (0xb93e7044039da0f6, 0xbc9cbc3743797a9c, 0x3ffd072d4a07897c), (0xb90ab053b05531fc, 0x3c82ed02d75b3707, 0x3ffd5818dcfba487), (0x3937f6246f0ec615, 0x3c9c2300696db532, 0x3ffda9e603db3285), (0x393b7225a944efd6, 0xbc91a5cd4f184b5c, 0x3ffdfc97337b9b5f), (0x3921e92cb3c2d278, 0x3c839e8980a9cc8f, 0x3ffe502ee78b3ff6), (0xb92fc0f242bbf3de, 0xbc9e9c23179c2893, 0x3ffea4afa2a490da), (0x393f6dd5d229ff69, 0x3c9dc7f486a4b6b0, 0x3ffefa1bee615a27), (0xb914019bffc80ef3, 0x3c99d3e12dd8a18b, 0x3fff50765b6e4540), (0x38fdc060c36f7651, 0x3c874853f3a5931e, 0x3fffa7c1819e90d8), ]; // Lookup table for 2^(k * 2^-12) with k = 0..63. // Generated by Sollya with: // > display=hexadecimal; // > prec = 500; // > for i from 0 to 63 do { // a = 2^(i * 2^-12); // b = round(a, D, RN); // c = round(a - b, D, RN); // d = round(a - b - c, D, RN); // print("{", d, ",", c, ",", b, "},"); // }; static TD_EXP2_MID2: [(u64, u64, u64); 64] = [ (0x0000000000000000, 0x0000000000000000, 0x3ff0000000000000), (0x39339726694630e3, 0x3c9ae8e38c59c72a, 0x3ff000b175effdc7), (0x38fe5e06ddd31156, 0xbc57b5d0d58ea8f4, 0x3ff00162f3904052), (0x3905a0768b51f609, 0x3c94115cb6b16a8e, 0x3ff0021478e11ce6), (0x390d008403605217, 0xbc8d7c96f201bb2f, 0x3ff002c605e2e8cf), (0x39289bc16f765708, 0x3c984711d4c35e9f, 0x3ff003779a95f959), (0xb924535b7f8c1e2d, 0xbc80484245243777, 0x3ff0042936faa3d8), (0xb938ba92f6b25456, 0xbc94b237da2025f9, 0x3ff004dadb113da0), (0xb8e30c72e81f4294, 0xbc75e00e62d6b30d, 0x3ff0058c86da1c0a), (0xb9134a5384e6f0b9, 0x3c9a1d6cedbb9481, 0x3ff0063e3a559473), (0x393f8d0580865d2e, 0xbc94acf197a00142, 0x3ff006eff583fc3d), (0xb90002bcb3ae9a99, 0xbc6eaf2ea42391a5, 0x3ff007a1b865a8ca), (0x390c3c5aedee9851, 0x3c7da93f90835f75, 0x3ff0085382faef83), (0x3927217851d1ec6e, 0xbc86a79084ab093c, 0x3ff00905554425d4), (0xb9180cbca335a7c3, 0x3c986364f8fbe8f8, 0x3ff009b72f41a12b), (0xb91706bd4eb22595, 0xbc882e8e14e3110e, 0x3ff00a6910f3b6fd), (0xb90b55dd523f3c08, 0xbc84f6b2a7609f71, 0x3ff00b1afa5abcbf), (0x39190a1e207cced1, 0xbc7e1a258ea8f71b, 0x3ff00bcceb7707ec), (0x39178d0472db37c5, 0x3c74362ca5bc26f1, 0x3ff00c7ee448ee02), (0xb92bcd4db3cb52fe, 0x3c9095a56c919d02, 0x3ff00d30e4d0c483), (0xb8fcf1b131575ec2, 0xbc6406ac4e81a645, 0x3ff00de2ed0ee0f5), (0xb8f6aaa1fa7ff913, 0x3c9b5a6902767e09, 0x3ff00e94fd0398e0), (0x39168f236dff3218, 0xbc991b2060859321, 0x3ff00f4714af41d3), (0xb92e8bb58067e60a, 0x3c8427068ab22306, 0x3ff00ff93412315c), (0x393d4cd5e1d71fdf, 0x3c9c1d0660524e08, 0x3ff010ab5b2cbd11), (0x393e4ecf350ebe88, 0xbc9e7bdfb3204be8, 0x3ff0115d89ff3a8b), (0x3926a2aa2c89c4f8, 0x3c8843aa8b9cbbc6, 0x3ff0120fc089ff63), (0x3911ca368a20ed05, 0xbc734104ee7edae9, 0x3ff012c1fecd613b), (0x38dedb1095d925cf, 0xbc72b6aeb6176892, 0x3ff0137444c9b5b5), (0xb90488c78eded75f, 0x3c7a8cd33b8a1bb3, 0x3ff01426927f5278), (0xb8e7480f5ea1b3c9, 0x3c72edc08e5da99a, 0x3ff014d8e7ee8d2f), (0xb90ae45989a04dd5, 0x3c857ba2dc7e0c73, 0x3ff0158b4517bb88), (0x392bf48007d80987, 0x3c9b61299ab8cdb7, 0x3ff0163da9fb3335), (0x3921aa91a059292c, 0xbc990565902c5f44, 0x3ff016f0169949ed), (0x391b6663292855f5, 0x3c870fc41c5c2d53, 0x3ff017a28af25567), (0x393e7fbca6793d94, 0x3c94b9a6e145d76c, 0x3ff018550706ab62), (0xb915b9f5c7de3b93, 0xbc7008eff5142bf9, 0x3ff019078ad6a19f), (0x3914638bf2f6acab, 0xbc977669f033c7de, 0x3ff019ba16628de2), (0xb92ab237b9a069c5, 0xbc909bb78eeead0a, 0x3ff01a6ca9aac5f3), (0x3933ab358be97cef, 0x3c9371231477ece5, 0x3ff01b1f44af9f9e), (0xb914027b2294bb64, 0x3c75e7626621eb5b, 0x3ff01bd1e77170b4), (0x390656394426c990, 0xbc9bc72b100828a5, 0x3ff01c8491f08f08), (0x390bf9785189bdd8, 0xbc6ce39cbbab8bbe, 0x3ff01d37442d5070), (0x3927c12f86114fe3, 0x3c816996709da2e2, 0x3ff01de9fe280ac8), (0xb92653d5d24b5d28, 0xbc8c11f5239bf535, 0x3ff01e9cbfe113ef), (0x39204a0cdc1d86d7, 0x3c8e1d4eb5edc6b3, 0x3ff01f4f8958c1c6), (0x392c678c46149782, 0xbc9afb99946ee3f0, 0x3ff020025a8f6a35), (0x39348524e1e9df70, 0xbc98f06d8a148a32, 0x3ff020b533856324), (0x3929953ea727ff0b, 0xbc82bf310fc54eb6, 0x3ff02168143b0281), (0xb93ccfbbec22d28e, 0xbc9c95a035eb4175, 0x3ff0221afcb09e3e), (0x3939e2bb6e181de1, 0xbc9491793e46834d, 0x3ff022cdece68c4f), (0x391f17609ae29308, 0xbc73e8d0d9c49091, 0x3ff02380e4dd22ad), (0xb91c7dc2c476bfb8, 0xbc9314aa16278aa3, 0x3ff02433e494b755), (0xb92fab994971d4a3, 0x3c848daf888e9651, 0x3ff024e6ec0da046), (0x392848b62cbdd0af, 0x3c856dc8046821f4, 0x3ff02599fb483385), (0xb92bf603ba715d0c, 0x3c945b42356b9d47, 0x3ff0264d1244c719), (0x39189434e751e1aa, 0xbc7082ef51b61d7e, 0x3ff027003103b10e), (0xb9103b54fd64e8ac, 0x3c72106ed0920a34, 0x3ff027b357854772), (0x3927785ea0acc486, 0xbc9fd4cf26ea5d0f, 0x3ff0286685c9e059), (0xb92ce447fdb35ff9, 0xbc909f8775e78084, 0x3ff02919bbd1d1d8), (0x38f5b884aab5642a, 0x3c564cbba902ca27, 0x3ff029ccf99d720a), (0xb93cfb3e46d7c1c0, 0x3c94383ef231d207, 0x3ff02a803f2d170d), (0xb8f0d40cee4b81af, 0x3c94a47a505b3a47, 0x3ff02b338c811703), (0x3926ae7d36d7c1f7, 0x3c9e47120223467f, 0x3ff02be6e199c811), ]; #[cfg(test)] mod tests { use crate::exponents::exp_f128::rational128_exp; #[test] fn test_exp() { assert_eq!(rational128_exp(2.).fast_as_f64(), 7.38905609893065); } } pxfm-0.1.23/src/exponents/expf.rs000064400000000000000000000377231046102023000150170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf, fmlaf, pow2if, rintfk}; use crate::polyeval::f_polyeval5; const L2U_F: f32 = 0.693_145_751_953_125; const L2L_F: f32 = 1.428_606_765_330_187_045_e-6; const R_LN2_F: f32 = std::f32::consts::LOG2_E; /// Exp for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn expf(d: f32) -> f32 { const EXP_POLY_1_S: f32 = 2f32; const EXP_POLY_2_S: f32 = 0.16666707f32; const EXP_POLY_3_S: f32 = -0.002775669f32; let qf = rintfk(d * R_LN2_F); let q = qf as i32; let r = fmlaf(qf, -L2U_F, d); let r = fmlaf(qf, -L2L_F, r); let f = r * r; // Poly for u = r*(exp(r)+1)/(exp(r)-1) let mut u = EXP_POLY_3_S; u = fmlaf(u, f, EXP_POLY_2_S); u = fmlaf(u, f, EXP_POLY_1_S); let u = 1f32 + 2f32 * r / (u - r); let i2 = pow2if(q); u * i2 // if d < -87f32 { // r = 0f32; // } // if d > 88f32 { // r = f32::INFINITY; // } } // Lookup table for exp(m) with m = -104, ..., 102. // -104 = floor(log(single precision's min denormal)) // 102 = ceil(log(single precision's max bessel K(n) that will be used)) // Table is generated with SageMath as follows: // for r in range(-104, 102): // print(double_to_hex(RealField(180)(r).exp()) + ",") static EXP_M1: [u64; 206] = [ 0x368f1e6b68529e33, 0x36a525be4e4e601d, 0x36bcbe0a45f75eb1, 0x36d3884e838aea68, 0x36ea8c1f14e2af5d, 0x37020a717e64a9bd, 0x3718851d84118908, 0x3730a9bdfb02d240, 0x3746a5bea046b42e, 0x375ec7f3b269efa8, 0x3774eafb87eab0f2, 0x378c6e2d05bbc000, 0x37a35208867c2683, 0x37ba425b317eeacd, 0x37d1d8508fa8246a, 0x37e840fbc08fdc8a, 0x38007b7112bc1ffe, 0x381666d0dad2961d, 0x382e726c3f64d0fe, 0x3844b0dc07cabf98, 0x385c1f2daf3b6a46, 0x38731c5957a47de2, 0x3889f96445648b9f, 0x38a1a6baeadb4fd1, 0x38b7fd974d372e45, 0x38d04da4d1452919, 0x38e62891f06b3450, 0x38fe1dd273aa8a4a, 0x3914775e0840bfdd, 0x392bd109d9d94bda, 0x3942e73f53fba844, 0x3959b138170d6bfe, 0x397175af0cf60ec5, 0x3987baee1bffa80b, 0x39a02057d1245ceb, 0x39b5eafffb34ba31, 0x39cdca23bae16424, 0x39e43e7fc88b8056, 0x39fb83bf23a9a9eb, 0x3a12b2b8dd05b318, 0x3a2969d47321e4cc, 0x3a41452b7723aed2, 0x3a5778fe2497184c, 0x3a6fe7116182e9cc, 0x3a85ae191a99585a, 0x3a9d775d87da854d, 0x3ab4063f8cc8bb98, 0x3acb374b315f87c1, 0x3ae27ec458c65e3c, 0x3af923372c67a074, 0x3b11152eaeb73c08, 0x3b2737c5645114b5, 0x3b3f8e6c24b5592e, 0x3b5571db733a9d61, 0x3b6d257d547e083f, 0x3b83ce9b9de78f85, 0x3b9aebabae3a41b5, 0x3bb24b6031b49bda, 0x3bc8dd5e1bb09d7e, 0x3be0e5b73d1ff53d, 0x3bf6f741de1748ec, 0x3c0f36bd37f42f3e, 0x3c2536452ee2f75c, 0x3c3cd480a1b74820, 0x3c539792499b1a24, 0x3c6aa0de4bf35b38, 0x3c82188ad6ae3303, 0x3c9898471fca6055, 0x3cb0b6c3afdde064, 0x3cc6b7719a59f0e0, 0x3cdee001eed62aa0, 0x3cf4fb547c775da8, 0x3d0c8464f7616468, 0x3d236121e24d3bba, 0x3d3a56e0c2ac7f75, 0x3d51e642baeb84a0, 0x3d6853f01d6d53ba, 0x3d80885298767e9a, 0x3d967852a7007e42, 0x3dae8a37a45fc32e, 0x3dc4c1078fe9228a, 0x3ddc3527e433fab1, 0x3df32b48bf117da2, 0x3e0a0db0d0ddb3ec, 0x3e21b48655f37267, 0x3e381056ff2c5772, 0x3e505a628c699fa1, 0x3e6639e3175a689d, 0x3e7e355bbaee85cb, 0x3e94875ca227ec38, 0x3eabe6c6fdb01612, 0x3ec2f6053b981d98, 0x3ed9c54c3b43bc8b, 0x3ef18354238f6764, 0x3f07cd79b5647c9b, 0x3f202cf22526545a, 0x3f35fc21041027ad, 0x3f4de16b9c24a98f, 0x3f644e51f113d4d6, 0x3f7b993fe00d5376, 0x3f92c155b8213cf4, 0x3fa97db0ccceb0af, 0x3fc152aaa3bf81cc, 0x3fd78b56362cef38, 0x3ff0000000000000, 0x4005bf0a8b145769, 0x401d8e64b8d4ddae, 0x403415e5bf6fb106, 0x404b4c902e273a58, 0x40628d389970338f, 0x407936dc5690c08f, 0x409122885aaeddaa, 0x40a749ea7d470c6e, 0x40bfa7157c470f82, 0x40d5829dcf950560, 0x40ed3c4488ee4f7f, 0x4103de1654d37c9a, 0x411b00b5916ac955, 0x413259ac48bf05d7, 0x4148f0ccafad2a87, 0x4160f2ebd0a80020, 0x417709348c0ea4f9, 0x418f4f22091940bd, 0x41a546d8f9ed26e1, 0x41bceb088b68e804, 0x41d3a6e1fd9eecfd, 0x41eab5adb9c43600, 0x420226af33b1fdc1, 0x4218ab7fb5475fb7, 0x4230c3d3920962c9, 0x4246c932696a6b5d, 0x425ef822f7f6731d, 0x42750bba3796379a, 0x428c9aae4631c056, 0x42a370470aec28ed, 0x42ba6b765d8cdf6d, 0x42d1f43fcc4b662c, 0x42e866f34a725782, 0x4300953e2f3a1ef7, 0x431689e221bc8d5b, 0x432ea215a1d20d76, 0x4344d13fbb1a001a, 0x435c4b334617cc67, 0x43733a43d282a519, 0x438a220d397972eb, 0x43a1c25c88df6862, 0x43b8232558201159, 0x43d0672a3c9eb871, 0x43e64b41c6d37832, 0x43fe4cf766fe49be, 0x44149767bc0483e3, 0x442bfc951eb8bb76, 0x444304d6aeca254b, 0x4459d97010884251, 0x44719103e4080b45, 0x4487e013cd114461, 0x44a03996528e074c, 0x44b60d4f6fdac731, 0x44cdf8c5af17ba3b, 0x44e45e3076d61699, 0x44fbaed16a6e0da7, 0x4512cffdfebde1a1, 0x4529919cabefcb69, 0x454160345c9953e3, 0x45579dbc9dc53c66, 0x45700c810d464097, 0x4585d009394c5c27, 0x459da57de8f107a8, 0x45b425982cf597cd, 0x45cb61e5ca3a5e31, 0x45e29bb825dfcf87, 0x45f94a90db0d6fe2, 0x46112fec759586fd, 0x46275c1dc469e3af, 0x463fbfd219c43b04, 0x4655936d44e1a146, 0x466d531d8a7ee79c, 0x4683ed9d24a2d51b, 0x469b15cfe5b6e17b, 0x46b268038c2c0e00, 0x46c9044a73545d48, 0x46e1002ab6218b38, 0x46f71b3540cbf921, 0x470f6799ea9c414a, 0x47255779b984f3eb, 0x473d01a210c44aa4, 0x4753b63da8e91210, 0x476aca8d6b0116b8, 0x478234de9e0c74e9, 0x4798bec7503ca477, 0x47b0d0eda9796b90, 0x47c6db0118477245, 0x47df1056dc7bf22d, 0x47f51c2cc3433801, 0x480cb108ffbec164, 0x48237f780991b584, 0x483a801c0ea8ac4d, 0x48520247cc4c46c1, 0x48687a0553328015, 0x4880a233dee4f9bb, 0x48969b7f55b808ba, 0x48aeba064644060a, 0x48c4e184933d9364, 0x48dc614fe2531841, 0x48f3494a9b171bf5, 0x490a36798b9d969b, ]; // Lookup table for exp(m * 2^(-7)) with m = 0, ..., 127. // Table is generated with Sollya as follows: // > display = hexadecimal; // > for i from 0 to 127 do { D(exp(i / 128)); }; static EXP_M2: [u64; 128] = [ 0x3ff0000000000000, 0x3ff0202015600446, 0x3ff04080ab55de39, 0x3ff06122436410dd, 0x3ff08205601127ed, 0x3ff0a32a84e9c1f6, 0x3ff0c49236829e8c, 0x3ff0e63cfa7ab09d, 0x3ff1082b577d34ed, 0x3ff12a5dd543ccc5, 0x3ff14cd4fc989cd6, 0x3ff16f9157587069, 0x3ff192937074e0cd, 0x3ff1b5dbd3f68122, 0x3ff1d96b0eff0e79, 0x3ff1fd41afcba45e, 0x3ff2216045b6f5cd, 0x3ff245c7613b8a9b, 0x3ff26a7793f60164, 0x3ff28f7170a755fd, 0x3ff2b4b58b372c79, 0x3ff2da4478b620c7, 0x3ff3001ecf601af7, 0x3ff32645269ea829, 0x3ff34cb8170b5835, 0x3ff373783a722012, 0x3ff39a862bd3c106, 0x3ff3c1e2876834aa, 0x3ff3e98deaa11dcc, 0x3ff41188f42c3e32, 0x3ff439d443f5f159, 0x3ff462707b2bac21, 0x3ff48b5e3c3e8186, 0x3ff4b49e2ae5ac67, 0x3ff4de30ec211e60, 0x3ff50817263c13cd, 0x3ff5325180cfacf7, 0x3ff55ce0a4c58c7c, 0x3ff587c53c5a7af0, 0x3ff5b2fff3210fd9, 0x3ff5de9176045ff5, 0x3ff60a7a734ab0e8, 0x3ff636bb9a983258, 0x3ff663559cf1bc7c, 0x3ff690492cbf9433, 0x3ff6bd96fdd034a2, 0x3ff6eb3fc55b1e76, 0x3ff719443a03acb9, 0x3ff747a513dbef6a, 0x3ff776630c678bc1, 0x3ff7a57ede9ea23e, 0x3ff7d4f946f0ba8d, 0x3ff804d30347b546, 0x3ff8350cd30ac390, 0x3ff865a7772164c5, 0x3ff896a3b1f66a0e, 0x3ff8c802477b0010, 0x3ff8f9c3fd29beaf, 0x3ff92be99a09bf00, 0x3ff95e73e6b1b75e, 0x3ff99163ad4b1dcc, 0x3ff9c4b9b995509b, 0x3ff9f876d8e8c566, 0x3ffa2c9bda3a3e78, 0x3ffa61298e1e069c, 0x3ffa9620c6cb3374, 0x3ffacb82581eee54, 0x3ffb014f179fc3b8, 0x3ffb3787dc80f95f, 0x3ffb6e2d7fa5eb18, 0x3ffba540dba56e56, 0x3ffbdcc2cccd3c85, 0x3ffc14b431256446, 0x3ffc4d15e873c193, 0x3ffc85e8d43f7cd0, 0x3ffcbf2dd7d490f2, 0x3ffcf8e5d84758a9, 0x3ffd3311bc7822b4, 0x3ffd6db26d16cd67, 0x3ffda8c8d4a66969, 0x3ffde455df80e3c0, 0x3ffe205a7bdab73e, 0x3ffe5cd799c6a54e, 0x3ffe99ce2b397649, 0x3ffed73f240dc142, 0x3fff152b7a07bb76, 0x3fff539424d90f5e, 0x3fff927a1e24bb76, 0x3fffd1de6182f8c9, 0x400008e0f64294ab, 0x40002912df5ce72a, 0x400049856cd84339, 0x40006a39207f0a09, 0x40008b2e7d2035cf, 0x4000ac6606916501, 0x4000cde041b0e9ae, 0x4000ef9db467dcf8, 0x4001119ee5ac36b6, 0x400133e45d82e952, 0x4001566ea50201d7, 0x4001793e4652cc50, 0x40019c53ccb3fc6b, 0x4001bfafc47bda73, 0x4001e352bb1a74ad, 0x4002073d3f1bd518, 0x40022b6fe02a3b9c, 0x40024feb2f105cb8, 0x400274afbdbba4a6, 0x400299be1f3e7f1c, 0x4002bf16e7d2a38c, 0x4002e4baacdb6614, 0x40030aaa04e80d05, 0x400330e587b62b28, 0x4003576dce33fead, 0x40037e437282d4ee, 0x4003a5670ff972ed, 0x4003ccd9432682b4, 0x4003f49aa9d30590, 0x40041cabe304cb34, 0x4004450d8f00edd4, 0x40046dc04f4e5338, 0x400496c4c6b832da, 0x4004c01b9950a111, 0x4004e9c56c731f5d, 0x400513c2e6c731d7, 0x40053e14b042f9ca, 0x400568bb722dd593, 0x400593b7d72305bb, ]; /// Computes exp /// /// Max found ULP 0.5 #[inline] pub fn f_expf(x: f32) -> f32 { let x_u = x.to_bits(); let x_abs = x_u & 0x7fff_ffffu32; if x_abs >= 0x42b2_0000u32 || x_abs <= 0x3280_0000u32 { let exp = ((x_u >> 23) & 0xFF) as i32; // |x| < 2^-25 if exp <= 101i32 { return 1.0 + x; } // When x < log(2^-150) or nan if x_u >= 0xc2cf_f1b5u32 { // exp(-Inf) = 0 if x.is_infinite() { return 0.0; } // exp(nan) = nan if x.is_nan() { return x; } return 0.0; } // x >= 89 or nan if x.is_sign_positive() && (x_u >= 0x42b2_0000) { // x is +inf or nan return x + f32::INFINITY; } } // For -104 < x < 89, to compute exp(x), we perform the following range // reduction: find hi, mid, lo such that: // x = hi + mid + lo, in which // hi is an integer, // mid * 2^7 is an integer // -2^(-8) <= lo < 2^-8. // In particular, // hi + mid = round(x * 2^7) * 2^(-7). // Then, // exp(x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo). // We store exp(hi) and exp(mid) in the lookup tables EXP_M1 and EXP_M2 // respectively. exp(lo) is computed using a degree-4 minimax polynomial // generated by Sollya. // x_hi = (hi + mid) * 2^7 = round(x * 2^7). let kf = (x * 128.).round(); // Subtract (hi + mid) from x to get lo. let xd = f_fmlaf(kf, -0.0078125 /* - 1/128 */, x) as f64; let mut x_hi = kf as i32; x_hi += 104 << 7; // hi = x_hi >> 7 let exp_hi = f64::from_bits(EXP_M1[(x_hi >> 7) as usize]); // mid * 2^7 = x_hi & 0x0000'007fU; let exp_mid = f64::from_bits(EXP_M2[(x_hi & 0x7f) as usize]); // Degree-4 minimax polynomial generated by Sollya with the following // commands: // d = [-2^-8, 2^-8]; // f_exp = expm1(x)/x; // Q = fpminimax(f_exp, 3, [|D...|], [-2^-8, 2^-8]); let p = f_polyeval5( xd, 1., f64::from_bits(0x3feffffffffff777), f64::from_bits(0x3fe000000000071c), f64::from_bits(0x3fc555566668e5e7), f64::from_bits(0x3fa55555555ef243), ); (p * exp_hi * exp_mid) as f32 } #[inline] pub(crate) fn core_expf(x: f32) -> f64 { // x_hi = (hi + mid) * 2^7 = round(x * 2^7). let kf = (x * 128.).round(); // Subtract (hi + mid) from x to get lo. let xd = f_fmlaf(kf, -0.0078125 /* - 1/128 */, x) as f64; let mut x_hi = kf as i32; x_hi += 104 << 7; // hi = x_hi >> 7 let exp_hi = f64::from_bits(EXP_M1[(x_hi >> 7) as usize]); // mid * 2^7 = x_hi & 0x0000'007fU; let exp_mid = f64::from_bits(EXP_M2[(x_hi & 0x7f) as usize]); // Degree-4 minimax polynomial generated by Sollya with the following // commands: // d = [-2^-8, 2^-8]; // f_exp = expm1(x)/x; // Q = fpminimax(f_exp, 3, [|D...|], [-2^-8, 2^-8]); let p = f_polyeval5( xd, 1., f64::from_bits(0x3feffffffffff777), f64::from_bits(0x3fe000000000071c), f64::from_bits(0x3fc555566668e5e7), f64::from_bits(0x3fa55555555ef243), ); p * exp_hi * exp_mid } #[inline] pub(crate) fn core_expdf(x: f64) -> f64 { // x_hi = (hi + mid) * 2^7 = round(x * 2^7). let kf = (x * 128.).round(); // Subtract (hi + mid) from x to get lo. let xd = f_fmla(kf, -0.0078125 /* - 1/128 */, x); let mut x_hi = kf as i32; x_hi += 104 << 7; // hi = x_hi >> 7 let exp_hi = f64::from_bits(EXP_M1[(x_hi >> 7) as usize]); // mid * 2^7 = x_hi & 0x0000'007fU; let exp_mid = f64::from_bits(EXP_M2[(x_hi & 0x7f) as usize]); // Degree-4 minimax polynomial generated by Sollya with the following // commands: // d = [-2^-8, 2^-8]; // f_exp = expm1(x)/x; // Q = fpminimax(f_exp, 3, [|D...|], [-2^-8, 2^-8]); let p = f_polyeval5( xd, 1., f64::from_bits(0x3feffffffffff777), f64::from_bits(0x3fe000000000071c), f64::from_bits(0x3fc555566668e5e7), f64::from_bits(0x3fa55555555ef243), ); p * exp_hi * exp_mid } #[cfg(test)] mod tests { use super::*; #[test] fn expf_test() { assert!( (expf(0f32) - 1f32).abs() < 1e-6, "Invalid result {}", expf(0f32) ); assert!( (expf(5f32) - 148.4131591025766f32).abs() < 1e-6, "Invalid result {}", expf(5f32) ); } #[test] fn f_expf_test() { assert_eq!(f_expf(-103.971596), 1e-45); assert!( (f_expf(0f32) - 1f32).abs() < 1e-6, "Invalid result {}", f_expf(0f32) ); assert!( (f_expf(5f32) - 148.4131591025766f32).abs() < 1e-6, "Invalid result {}", f_expf(5f32) ); assert_eq!(f_expf(f32::INFINITY), f32::INFINITY); assert_eq!(f_expf(f32::NEG_INFINITY), 0.); assert!(f_expf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/exponents/expm1.rs000064400000000000000000000506421046102023000151020ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::fast_ldexp; use crate::shared_eval::poly_dekker_generic; use std::hint::black_box; static TZ: [(u64, u64); 65] = [ (0xbc6797d4686c5393, 0xbfcc5041854df7d4), (0xbc8ea1cb9d163339, 0xbfcb881a23aebb48), (0x3c8f483a3e8cd60f, 0xbfcabe60e1f21838), (0x3c7dffd920f493db, 0xbfc9f3129931fab0), (0xbc851bfdbb129094, 0xbfc9262c1c3430a0), (0x3c8cd3e5225e2206, 0xbfc857aa375db4e4), (0x3c5e3a6bdaece8f9, 0xbfc78789b0a5e0c0), (0xbc8daf2ae0c2d3d4, 0xbfc6b5c7478983d8), (0xbc7fd36226fadd44, 0xbfc5e25fb4fde210), (0x3c7d887cd0341ab0, 0xbfc50d4fab639758), (0xbc8676a52a1a618b, 0xbfc43693d679612c), (0x3c79776b420ad283, 0xbfc35e28db4ecd9c), (0x3c73d5fd7d70a5ed, 0xbfc2840b5836cf68), (0x3c5a94ad2c8fa0bf, 0xbfc1a837e4ba3760), (0x3c26ad4c353465b0, 0xbfc0caab118a1278), (0xbc78bba170e59b65, 0xbfbfd6c2d0e3d910), (0xbc8e1e0a76cb0685, 0xbfbe14aed893eef0), (0x3c8fe131f55e75f8, 0xbfbc4f1331d22d40), (0xbc8b5beee8bcee31, 0xbfba85e8c62d9c10), (0xbc77fe9b02c25e9b, 0xbfb8b92870fa2b58), (0xbc832ae7bdaf1116, 0xbfb6e8caff341fe8), (0x3c7a6cfe58cbd73b, 0xbfb514c92f634788), (0x3c68798de3138a56, 0xbfb33d1bb17df2e8), (0xbc3589321a7ef10b, 0xbfb161bb26cbb590), (0xbc78d0e700fcfb65, 0xbfaf0540438fd5c0), (0x3c8473ef07d5dd3b, 0xbfab3f864c080000), (0xbc838e62149c16e2, 0xbfa7723950130400), (0xbc508bb6309bd394, 0xbfa39d4a1a77e050), (0xbc8bad3fd501a227, 0xbf9f8152aee94500), (0x3c63d27ac39ed253, 0xbf97b88f290230e0), (0xbc8b60bbd08aac55, 0xbf8fc055004416c0), (0xbc4a00d03b3359de, 0xbf7fe0154aaeed80), (0x0000000000000000, 0x0000000000000000), (0x3c8861931c15e39b, 0x3f80100ab00222c0), (0x3c77ab864b3e9045, 0x3f90202ad5778e40), (0x3c74e5659d75e95b, 0x3f984890d9043740), (0x3c78e0bd083aba81, 0x3fa040ac0224fd90), (0x3c345cc1cf959b1b, 0x3fa465509d383eb0), (0xbc8eb6980ce14da7, 0x3fa89246d053d180), (0x3c77324137d6c342, 0x3facc79f4f5613a0), (0xbc45272ff30eed1b, 0x3fb082b577d34ed8), (0xbc81280f19dace1c, 0x3fb2a5dd543ccc50), (0xbc8d550af31c8ec3, 0x3fb4cd4fc989cd68), (0x3c87923b72aa582d, 0x3fb6f91575870690), (0xbc776c2e732457f1, 0x3fb92937074e0cd8), (0x3c881f5c92a5200f, 0x3fbb5dbd3f681220), (0x3c8e8ac7a4d3206c, 0x3fbd96b0eff0e790), (0xbc712db6f4bbe33b, 0x3fbfd41afcba45e8), (0xbc58c4a5df1ec7e5, 0x3fc10b022db7ae68), (0xbc6bd4b1c37ea8a2, 0x3fc22e3b09dc54d8), (0x3c85aeb9860044d0, 0x3fc353bc9fb00b20), (0xbc64c26602c63fda, 0x3fc47b8b853aafec), (0xbc87f644c1f9d314, 0x3fc5a5ac59b963cc), (0x3c8f5aa8ec61fc2d, 0x3fc6d223c5b10638), (0x3c27ab912c69ffeb, 0x3fc800f67b00d7b8), (0xbc5b3564bc0ec9cd, 0x3fc9322934f54148), (0x3c86a7062465be33, 0x3fca65c0b85ac1a8), (0xbc885718d2ff1bf4, 0x3fcb9bc1d3910094), (0xbc8045cb0c685e08, 0x3fccd4315e9e0834), (0xbc16e7fb859d5055, 0x3fce0f143b41a554), (0x3c851bbdee020603, 0x3fcf4c6f5508ee5c), (0x3c6e17611afc42c5, 0x3fd04623d0b0f8c8), (0xbc71c5b2e8735a43, 0x3fd0e7510fd7c564), (0xbc825fe139c4cffd, 0x3fd189c1ecaeb084), (0xbc789843c4964554, 0x3fd22d78f0fa061a), ]; pub(crate) static EXPM1_T0: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc719083535b085e, 0x3ff02c9a3e778061), (0x3c8d73e2a475b466, 0x3ff059b0d3158574), (0x3c6186be4bb28500, 0x3ff0874518759bc8), (0x3c98a62e4adc610a, 0x3ff0b5586cf9890f), (0x3c403a1727c57b52, 0x3ff0e3ec32d3d1a2), (0xbc96c51039449b3a, 0x3ff11301d0125b51), (0xbc932fbf9af1369e, 0x3ff1429aaea92de0), (0xbc819041b9d78a76, 0x3ff172b83c7d517b), (0x3c8e5b4c7b4968e4, 0x3ff1a35beb6fcb75), (0x3c9e016e00a2643c, 0x3ff1d4873168b9aa), (0x3c8dc775814a8494, 0x3ff2063b88628cd6), (0x3c99b07eb6c70572, 0x3ff2387a6e756238), (0x3c82bd339940e9da, 0x3ff26b4565e27cdd), (0x3c8612e8afad1256, 0x3ff29e9df51fdee1), (0x3c90024754db41d4, 0x3ff2d285a6e4030b), (0x3c86f46ad23182e4, 0x3ff306fe0a31b715), (0x3c932721843659a6, 0x3ff33c08b26416ff), (0xbc963aeabf42eae2, 0x3ff371a7373aa9cb), (0xbc75e436d661f5e2, 0x3ff3a7db34e59ff7), (0x3c8ada0911f09ebc, 0x3ff3dea64c123422), (0xbc5ef3691c309278, 0x3ff4160a21f72e2a), (0x3c489b7a04ef80d0, 0x3ff44e086061892d), (0x3c73c1a3b69062f0, 0x3ff486a2b5c13cd0), (0x3c7d4397afec42e2, 0x3ff4bfdad5362a27), (0xbc94b309d25957e4, 0x3ff4f9b2769d2ca7), (0xbc807abe1db13cac, 0x3ff5342b569d4f82), (0x3c99bb2c011d93ac, 0x3ff56f4736b527da), (0x3c96324c054647ac, 0x3ff5ab07dd485429), (0x3c9ba6f93080e65e, 0x3ff5e76f15ad2148), (0xbc9383c17e40b496, 0x3ff6247eb03a5585), (0xbc9bb60987591c34, 0x3ff6623882552225), (0xbc9bdd3413b26456, 0x3ff6a09e667f3bcd), (0xbc6bbe3a683c88aa, 0x3ff6dfb23c651a2f), (0xbc816e4786887a9a, 0x3ff71f75e8ec5f74), (0xbc90245957316dd4, 0x3ff75feb564267c9), (0xbc841577ee049930, 0x3ff7a11473eb0187), (0x3c705d02ba15797e, 0x3ff7e2f336cf4e62), (0xbc9d4c1dd41532d8, 0x3ff82589994cce13), (0xbc9fc6f89bd4f6ba, 0x3ff868d99b4492ed), (0x3c96e9f156864b26, 0x3ff8ace5422aa0db), (0x3c85cc13a2e3976c, 0x3ff8f1ae99157736), (0xbc675fc781b57ebc, 0x3ff93737b0cdc5e5), (0xbc9d185b7c1b85d0, 0x3ff97d829fde4e50), (0x3c7c7c46b071f2be, 0x3ff9c49182a3f090), (0xbc9359495d1cd532, 0x3ffa0c667b5de565), (0xbc9d2f6edb8d41e2, 0x3ffa5503b23e255d), (0x3c90fac90ef7fd32, 0x3ffa9e6b5579fdbf), (0x3c97a1cd345dcc82, 0x3ffae89f995ad3ad), (0xbc62805e3084d708, 0x3ffb33a2b84f15fb), (0xbc75584f7e54ac3a, 0x3ffb7f76f2fb5e47), (0x3c823dd07a2d9e84, 0x3ffbcc1e904bc1d2), (0x3c811065895048de, 0x3ffc199bdd85529c), (0x3c92884dff483cac, 0x3ffc67f12e57d14b), (0x3c7503cbd1e949dc, 0x3ffcb720dcef9069), (0xbc9cbc3743797a9c, 0x3ffd072d4a07897c), (0x3c82ed02d75b3706, 0x3ffd5818dcfba487), (0x3c9c2300696db532, 0x3ffda9e603db3285), (0xbc91a5cd4f184b5c, 0x3ffdfc97337b9b5f), (0x3c839e8980a9cc90, 0x3ffe502ee78b3ff6), (0xbc9e9c23179c2894, 0x3ffea4afa2a490da), (0x3c9dc7f486a4b6b0, 0x3ffefa1bee615a27), (0x3c99d3e12dd8a18a, 0x3fff50765b6e4540), (0x3c874853f3a5931e, 0x3fffa7c1819e90d8), ]; pub(crate) static EXPM1_T1: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c9ae8e38c59c72a, 0x3ff000b175effdc7), (0xbc57b5d0d58ea8f4, 0x3ff00162f3904052), (0x3c94115cb6b16a8e, 0x3ff0021478e11ce6), (0xbc8d7c96f201bb2e, 0x3ff002c605e2e8cf), (0x3c984711d4c35ea0, 0x3ff003779a95f959), (0xbc80484245243778, 0x3ff0042936faa3d8), (0xbc94b237da2025fa, 0x3ff004dadb113da0), (0xbc75e00e62d6b30e, 0x3ff0058c86da1c0a), (0x3c9a1d6cedbb9480, 0x3ff0063e3a559473), (0xbc94acf197a00142, 0x3ff006eff583fc3d), (0xbc6eaf2ea42391a6, 0x3ff007a1b865a8ca), (0x3c7da93f90835f76, 0x3ff0085382faef83), (0xbc86a79084ab093c, 0x3ff00905554425d4), (0x3c986364f8fbe8f8, 0x3ff009b72f41a12b), (0xbc882e8e14e3110e, 0x3ff00a6910f3b6fd), (0xbc84f6b2a7609f72, 0x3ff00b1afa5abcbf), (0xbc7e1a258ea8f71a, 0x3ff00bcceb7707ec), (0x3c74362ca5bc26f2, 0x3ff00c7ee448ee02), (0x3c9095a56c919d02, 0x3ff00d30e4d0c483), (0xbc6406ac4e81a646, 0x3ff00de2ed0ee0f5), (0x3c9b5a6902767e08, 0x3ff00e94fd0398e0), (0xbc991b2060859320, 0x3ff00f4714af41d3), (0x3c8427068ab22306, 0x3ff00ff93412315c), (0x3c9c1d0660524e08, 0x3ff010ab5b2cbd11), (0xbc9e7bdfb3204be8, 0x3ff0115d89ff3a8b), (0x3c8843aa8b9cbbc6, 0x3ff0120fc089ff63), (0xbc734104ee7edae8, 0x3ff012c1fecd613b), (0xbc72b6aeb6176892, 0x3ff0137444c9b5b5), (0x3c7a8cd33b8a1bb2, 0x3ff01426927f5278), (0x3c72edc08e5da99a, 0x3ff014d8e7ee8d2f), (0x3c857ba2dc7e0c72, 0x3ff0158b4517bb88), (0x3c9b61299ab8cdb8, 0x3ff0163da9fb3335), (0xbc990565902c5f44, 0x3ff016f0169949ed), (0x3c870fc41c5c2d54, 0x3ff017a28af25567), (0x3c94b9a6e145d76c, 0x3ff018550706ab62), (0xbc7008eff5142bfa, 0x3ff019078ad6a19f), (0xbc977669f033c7de, 0x3ff019ba16628de2), (0xbc909bb78eeead0a, 0x3ff01a6ca9aac5f3), (0x3c9371231477ece6, 0x3ff01b1f44af9f9e), (0x3c75e7626621eb5a, 0x3ff01bd1e77170b4), (0xbc9bc72b100828a4, 0x3ff01c8491f08f08), (0xbc6ce39cbbab8bbe, 0x3ff01d37442d5070), (0x3c816996709da2e2, 0x3ff01de9fe280ac8), (0xbc8c11f5239bf536, 0x3ff01e9cbfe113ef), (0x3c8e1d4eb5edc6b4, 0x3ff01f4f8958c1c6), (0xbc9afb99946ee3f0, 0x3ff020025a8f6a35), (0xbc98f06d8a148a32, 0x3ff020b533856324), (0xbc82bf310fc54eb6, 0x3ff02168143b0281), (0xbc9c95a035eb4176, 0x3ff0221afcb09e3e), (0xbc9491793e46834c, 0x3ff022cdece68c4f), (0xbc73e8d0d9c49090, 0x3ff02380e4dd22ad), (0xbc9314aa16278aa4, 0x3ff02433e494b755), (0x3c848daf888e9650, 0x3ff024e6ec0da046), (0x3c856dc8046821f4, 0x3ff02599fb483385), (0x3c945b42356b9d46, 0x3ff0264d1244c719), (0xbc7082ef51b61d7e, 0x3ff027003103b10e), (0x3c72106ed0920a34, 0x3ff027b357854772), (0xbc9fd4cf26ea5d0e, 0x3ff0286685c9e059), (0xbc909f8775e78084, 0x3ff02919bbd1d1d8), (0x3c564cbba902ca28, 0x3ff029ccf99d720a), (0x3c94383ef231d206, 0x3ff02a803f2d170d), (0x3c94a47a505b3a46, 0x3ff02b338c811703), (0x3c9e471202234680, 0x3ff02be6e199c811), ]; static EXPM1_DD1: [(u64, u64); 11] = [ (0x3c65555555555554, 0x3fc5555555555555), (0x3c45555555555123, 0x3fa5555555555555), (0x3c01111111118167, 0x3f81111111111111), (0xbbef49f49e220cea, 0x3f56c16c16c16c17), (0x3b6a019eff6f919c, 0x3f2a01a01a01a01a), (0x3b39fcff48a75b41, 0x3efa01a01a01a01a), (0xbb6c14f73758cd7f, 0x3ec71de3a556c734), (0x3b3dfce97931018f, 0x3e927e4fb7789f5c), (0x3afc513da9e4c9c5, 0x3e5ae64567f544e3), (0x3acca00af84f2b60, 0x3e21eed8eff8d831), (0x3a8f27ac6000898f, 0x3de6124613a86e8f), ]; static EXPM1_DD2: [(u64, u64); 7] = [ (0x3ff0000000000000, 0x0000000000000000), (0x3fe0000000000000, 0x39c712f72ecec2cf), (0x3fc5555555555555, 0x3c65555555554d07), (0x3fa5555555555555, 0x3c455194d28275da), (0x3f81111111111111, 0x3c012faa0e1c0f7b), (0x3f56c16c16da6973, 0xbbf4ba45ab25d2a3), (0x3f2a01a019eb7f31, 0xbbc9091d845ecd36), ]; #[inline] pub(crate) fn opoly_dd_generic( x: DoubleDouble, poly: [(u64, u64); N], ) -> DoubleDouble { let zch = poly.last().unwrap(); let p0 = DoubleDouble::from_exact_add(f64::from_bits(zch.0), x.lo); let ach = p0.hi; let acl = f64::from_bits(zch.1) + p0.lo; let mut ch = DoubleDouble::new(acl, ach); for zch in poly.iter().rev().skip(1) { ch = DoubleDouble::quick_mult_f64(ch, x.hi); let z0 = DoubleDouble::from_bit_pair(*zch); ch = DoubleDouble::add(z0, ch); } ch } #[cold] fn as_expm1_accurate(x: f64) -> f64 { let mut ix; if x.abs() < 0.25 { const CL: [u64; 6] = [ 0x3da93974a8ca5354, 0x3d6ae7f3e71e4908, 0x3d2ae7f357341648, 0x3ce952c7f96664cb, 0x3ca686f8ce633aae, 0x3c62f49b2fbfb5b6, ]; let fl0 = f_fmla(x, f64::from_bits(CL[5]), f64::from_bits(CL[4])); let fl1 = f_fmla(x, fl0, f64::from_bits(CL[3])); let fl2 = f_fmla(x, fl1, f64::from_bits(CL[2])); let fl3 = f_fmla(x, fl2, f64::from_bits(CL[1])); let fl = x * f_fmla(x, fl3, f64::from_bits(CL[0])); let mut f = opoly_dd_generic(DoubleDouble::new(fl, x), EXPM1_DD1); f = DoubleDouble::quick_mult_f64(f, x); f = DoubleDouble::quick_mult_f64(f, x); f = DoubleDouble::quick_mult_f64(f, x); let hx = 0.5 * x; let dx2dd = DoubleDouble::from_exact_mult(x, hx); f = DoubleDouble::add(dx2dd, f); let v0 = DoubleDouble::from_exact_add(x, f.hi); let v1 = DoubleDouble::from_exact_add(v0.lo, f.lo); let v2 = DoubleDouble::from_exact_add(v0.hi, v1.hi); let mut v3 = DoubleDouble::from_exact_add(v2.lo, v1.lo); ix = v3.hi.to_bits(); if (ix & 0x000fffffffffffff) == 0 { let v = v3.lo.to_bits(); let d: i64 = ((((ix as i64) >> 63) ^ ((v as i64) >> 63)) as u64) .wrapping_shl(1) .wrapping_add(1) as i64; ix = ix.wrapping_add(d as u64); v3.hi = f64::from_bits(ix); } v3.hi + v2.hi } else { const S: f64 = f64::from_bits(0x40b71547652b82fe); let t = (x * S).round_ties_even(); let jt: i64 = t as i64; let i0 = (jt >> 6) & 0x3f; let i1 = jt & 0x3f; let ie = jt >> 12; let t0 = DoubleDouble::from_bit_pair(EXPM1_T0[i0 as usize]); let t1 = DoubleDouble::from_bit_pair(EXPM1_T1[i1 as usize]); let bt = DoubleDouble::quick_mult(t0, t1); const L2H: f64 = f64::from_bits(0x3f262e42ff000000); const L2L: f64 = f64::from_bits(0x3d0718432a1b0e26); const L2LL: f64 = f64::from_bits(0x3999ff0342542fc3); let dx = f_fmla(-L2H, t, x); let dxl = L2L * t; let dxll = f_fmla(L2LL, t, dd_fmla(L2L, t, -dxl)); let dxh = dx + dxl; let dxl = (dx - dxh) + dxl + dxll; let mut f = poly_dekker_generic(DoubleDouble::new(dxl, dxh), EXPM1_DD2); f = DoubleDouble::quick_mult(DoubleDouble::new(dxl, dxh), f); f = DoubleDouble::quick_mult(f, bt); f = DoubleDouble::add(bt, f); let off: u64 = (2048i64 + 1023i64).wrapping_sub(ie).wrapping_shl(52) as u64; let e: f64; if ie < 53 { let fhz = DoubleDouble::from_exact_add(f64::from_bits(off), f.hi); f.hi = fhz.hi; e = fhz.lo; } else if ie < 104 { let fhz = DoubleDouble::from_exact_add(f.hi, f64::from_bits(off)); f.hi = fhz.hi; e = fhz.lo; } else { e = 0.; } f.lo += e; let dst = DoubleDouble::from_exact_add(f.hi, f.lo); fast_ldexp(dst.hi, ie as i32) } } /// Computes e^x - 1 /// /// Max found ULP 0.5 pub fn f_expm1(x: f64) -> f64 { let ix = x.to_bits(); let aix: u64 = ix & 0x7fff_ffff_ffff_ffff; if aix < 0x3fd0000000000000u64 { if aix < 0x3ca0000000000000u64 { if aix == 0 { return x; } return dyad_fmla(f64::from_bits(0x3c90000000000000), x.abs(), x); } let sx = f64::from_bits(0x4060000000000000) * x; let fx = sx.round_ties_even(); let z = sx - fx; let z2 = z * z; let i: i64 = fx as i64; let t = DoubleDouble::from_bit_pair(TZ[i.wrapping_add(32) as usize]); const C: [u64; 6] = [ 0x3f80000000000000, 0x3f00000000000000, 0x3e755555555551ad, 0x3de555555555599c, 0x3d511111ad1ad69d, 0x3cb6c16c168b1fb5, ]; let fh = z * f64::from_bits(C[0]); let fl0 = f_fmla(z, f64::from_bits(C[5]), f64::from_bits(C[4])); let fl1 = f_fmla(z, f64::from_bits(C[2]), f64::from_bits(C[1])); let fw0 = f_fmla(z, fl0, f64::from_bits(C[3])); let fl = z2 * f_fmla(z2, fw0, fl1); let mut f = DoubleDouble::new(fl, fh); let e0 = f64::from_bits(0x3bea000000000000); let eps = z2 * e0 + f64::from_bits(0x3970000000000000); let mut r = DoubleDouble::from_exact_add(t.hi, f.hi); r.lo += t.lo + f.lo; f = DoubleDouble::quick_mult(t, f); f = DoubleDouble::add(r, f); let ub = f.hi + (f.lo + eps); let lb = f.hi + (f.lo - eps); if ub != lb { return as_expm1_accurate(x); } lb } else { if aix >= 0x40862e42fefa39f0u64 { if aix > 0x7ff0000000000000u64 { return x + x; } // nan if aix == 0x7ff0000000000000u64 { return if (ix >> 63) != 0 { -1.0 } else { x }; } if (ix >> 63) == 0 { const Z: f64 = f64::from_bits(0x7fe0000000000000); return black_box(Z) * black_box(Z); } } if ix >= 0xc0425e4f7b2737fau64 { if ix >= 0xc042b708872320e2u64 { return black_box(-1.0) + black_box(f64::from_bits(0x3c80000000000000)); } return (f64::from_bits(0x40425e4f7b2737fa) + x + f64::from_bits(0x3cc8486612173c69)) * f64::from_bits(0x3c971547652b82fe) - f64::from_bits(0x3fefffffffffffff); } const S: f64 = f64::from_bits(0x40b71547652b82fe); let t = (x * S).round_ties_even(); let jt: i64 = t as i64; let i0 = (jt >> 6) & 0x3f; let i1 = jt & 0x3f; let ie = jt >> 12; let t0 = DoubleDouble::from_bit_pair(EXPM1_T0[i0 as usize]); let t1 = DoubleDouble::from_bit_pair(EXPM1_T1[i1 as usize]); let bt = DoubleDouble::quick_mult(t0, t1); const L2H: f64 = f64::from_bits(0x3f262e42ff000000); const L2L: f64 = f64::from_bits(0x3d0718432a1b0e26); let dx = dd_fmla(L2L, t, f_fmla(-L2H, t, x)); let dx2 = dx * dx; const CH: [u64; 4] = [ 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc55555557e54ff, 0x3fa55555553a12f4, ]; let p0 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let p1 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let p = f_fmla(dx2, p0, p1); let mut fh = bt.hi; let tx = bt.hi * dx; let mut fl = f_fmla(tx, p, bt.lo); let eps = f64::from_bits(0x3c0833beace2b6fe) * bt.hi; let off: u64 = ((2048i64 + 1023i64).wrapping_sub(ie) as u64).wrapping_shl(52); let e: f64; if ie < 53 { let flz = DoubleDouble::from_exact_add(f64::from_bits(off), fh); e = flz.lo; fh = flz.hi; } else if ie < 75 { let flz = DoubleDouble::from_exact_add(fh, f64::from_bits(off)); e = flz.lo; fh = flz.hi; } else { e = 0.; } fl += e; let ub = fh + (fl + eps); let lb = fh + (fl - eps); if ub != lb { return as_expm1_accurate(x); } fast_ldexp(lb, ie as i32) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_expm1() { assert_eq!(f_expm1(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028321017343872864), 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028321017343872864 ); assert_eq!(f_expm1(36.52188110363568), 7265264535836525.); assert_eq!(f_expm1(2.), 6.38905609893065); assert_eq!(f_expm1(0.4321321), 0.5405386068701713); assert_eq!(f_expm1(-0.0000004321321), -4.321320066309375e-7); } } pxfm-0.1.23/src/exponents/expm1f.rs000064400000000000000000000146511046102023000152500ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use std::hint::black_box; static TD: [u64; 32] = [ 0x3ff0000000000000, 0x3ff059b0d3158574, 0x3ff0b5586cf9890f, 0x3ff11301d0125b51, 0x3ff172b83c7d517b, 0x3ff1d4873168b9aa, 0x3ff2387a6e756238, 0x3ff29e9df51fdee1, 0x3ff306fe0a31b715, 0x3ff371a7373aa9cb, 0x3ff3dea64c123422, 0x3ff44e086061892d, 0x3ff4bfdad5362a27, 0x3ff5342b569d4f82, 0x3ff5ab07dd485429, 0x3ff6247eb03a5585, 0x3ff6a09e667f3bcd, 0x3ff71f75e8ec5f74, 0x3ff7a11473eb0187, 0x3ff82589994cce13, 0x3ff8ace5422aa0db, 0x3ff93737b0cdc5e5, 0x3ff9c49182a3f090, 0x3ffa5503b23e255d, 0x3ffae89f995ad3ad, 0x3ffb7f76f2fb5e47, 0x3ffc199bdd85529c, 0x3ffcb720dcef9069, 0x3ffd5818dcfba487, 0x3ffdfc97337b9b5f, 0x3ffea4afa2a490da, 0x3fff50765b6e4540, ]; #[cold] fn exp1m1f_accurate(ux: u32, z: f64, sv: u64, ia: f64) -> f32 { if ux > 0xc18aa123u32 { // x < -17.32 return -1.0 + f32::from_bits(0x32800000); } const ILN2H: f64 = f64::from_bits(0x4047154765000000); const ILN2L: f64 = f64::from_bits(0x3e55c17f0bbbe880); let s = f64::from_bits(sv); let h = f_fmla(ILN2H, z, -ia) + ILN2L * z; let h2 = h * h; let w = s * h; const CH: [u64; 6] = [ 0x3f962e42fefa39ef, 0x3f2ebfbdff82c58f, 0x3ebc6b08d702e0ed, 0x3e43b2ab6fb92e5e, 0x3dc5d886e6d54203, 0x3d4430976b8ce6ef, ]; let h0 = f_fmla(h, f64::from_bits(CH[5]), f64::from_bits(CH[4])); let h1 = f_fmla(h, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let h2t = f_fmla(h, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let t0 = f_fmla(h2, h0, h1); let t1 = f_fmla(h2, t0, h2t); let r = f_fmla(w, t1, s - 1.); r as f32 } #[cold] fn expm1f_small(z: f64) -> f32 { const B: [u64; 8] = [ 0x3fdfffffffffffc2, 0x3fc55555555555fe, 0x3fa555555559767f, 0x3f81111111098dc1, 0x3f56c16bca988aa9, 0x3f2a01a07658483f, 0x3efa05b04d2c3503, 0x3ec71de3a960b5e3, ]; let z2 = z * z; let z4 = z2 * z2; let r0 = f_fmla(z, f64::from_bits(B[7]), f64::from_bits(B[6])); let r1 = f_fmla(z, f64::from_bits(B[5]), f64::from_bits(B[4])); let r2 = f_fmla(z, f64::from_bits(B[3]), f64::from_bits(B[2])); let r3 = f_fmla(z, f64::from_bits(B[1]), f64::from_bits(B[0])); let w0 = f_fmla(z2, r0, r1); let w1 = f_fmla(z2, r2, r3); let q0 = f_fmla(z4, w0, w1); let r = f_fmla(z2, q0, z); r as f32 } /// Computes e^x - 1 /// /// Max ULP 0.5 #[inline] pub fn f_expm1f(x: f32) -> f32 { const ILN2: f64 = f64::from_bits(0x40471547652b82fe); const BIG: f64 = f64::from_bits(0x4338000000000000); let t = x.to_bits(); let z = x as f64; let ux = t; let ax = ux.wrapping_shl(1); if ax < 0x7c400000u32 { // |x| < 0.15625 if ax < 0x676a09e8u32 { // |x| < 0x1.6a09e8p-24 if ax == 0x0u32 { return x; } // x = +-0 let res = dd_fmlaf(x.abs(), f32::from_bits(0x33000000), x); return res; } return expm1f_small(z); } if ax >= 0x8562e430u32 { // |x| > 88.72 if ax > (0xffu32 << 24) { return x + x; } // nan if ux >> 31 != 0 { // x < 0 if ax == (0xffu32 << 24) { return -1.0; } return black_box(-1.0) + black_box(f32::from_bits(0x32800000)); } if ax == (0xffu32 << 24) { return f32::INFINITY; } let r = f64::from_bits(0x47efffffe0000000) * z; return r as f32; } let a = ILN2 * z; let ia = a.round_ties_even(); let h = a - ia; let h2 = h * h; let u = (ia + BIG).to_bits(); const C: [u64; 4] = [ 0x3ff0000000000000, 0x3f962e42fef4c4e7, 0x3f2ebfd1b232f475, 0x3ebc6b19384ecd93, ]; let c2 = f_fmla(h, f64::from_bits(C[3]), f64::from_bits(C[2])); let c0 = f_fmla(h, f64::from_bits(C[1]), f64::from_bits(C[0])); let tdl = TD[(u & 0x1f) as usize]; let sv: u64 = tdl.wrapping_add((u >> 5).wrapping_shl(52)); let r = f_fmla(h2, c2, c0) * f64::from_bits(sv) - 1.0; let ub: f32 = r as f32; let lb = (r - f64::from_bits(sv) * f64::from_bits(0x3de3b30000000000)) as f32; // Ziv's accuracy test if ub != lb { return exp1m1f_accurate(ux, z, sv, ia); } ub } #[cfg(test)] mod tests { use crate::f_expm1f; #[test] fn test_expm1f() { assert_eq!(f_expm1f(2.213121), 8.144211); assert_eq!(f_expm1f(-3.213121), -0.9597691); assert_eq!(f_expm1f(-2.35099e-38), -2.35099e-38); assert_eq!( f_expm1f(0.00000000000000000000000000000000000004355616), 0.00000000000000000000000000000000000004355616 ); } } pxfm-0.1.23/src/exponents/mod.rs000064400000000000000000000046501046102023000146250ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![deny(unreachable_pub)] mod auxiliary; mod exp; mod exp10; mod exp10f; mod exp10m1; mod exp10m1f; mod exp2; mod exp2f; mod exp2m1; mod exp2m1f; mod exp_f128; mod expf; mod expm1; mod expm1f; pub(crate) use auxiliary::{fast_ldexp, ldexp}; pub(crate) use exp::{EXP_REDUCE_T0, EXP_REDUCE_T1}; pub use exp::{exp, f_exp}; pub(crate) use exp_f128::rational128_exp; pub use exp2::f_exp2; pub(crate) use exp2f::dirty_exp2f; pub use exp2f::f_exp2f; pub(crate) use exp2m1::exp2m1_accurate_tiny; pub use exp2m1::f_exp2m1; pub use exp2m1f::f_exp2m1f; pub use exp10::f_exp10; pub use exp10f::f_exp10f; pub use exp10m1::f_exp10m1; pub use exp10m1f::f_exp10m1f; pub(crate) use expf::{core_expdf, core_expf}; pub use expf::{expf, f_expf}; pub use expm1::f_expm1; pub(crate) use expm1::{EXPM1_T0, EXPM1_T1}; pub use expm1f::f_expm1f; pxfm-0.1.23/src/floor.rs000064400000000000000000000047731046102023000131520ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::{ceil, ceilf, trunc, truncf}; /// Round to integer towards minus infinity #[inline] pub const fn floorf(x: f32) -> f32 { if x.is_sign_negative() { -ceilf(-x) } else { truncf(x) } } /// Floors value #[inline] pub const fn floor(x: f64) -> f64 { if x.is_sign_negative() { -ceil(-x) } else { trunc(x) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_floorf() { assert_eq!(floorf(-1.0), -1.0); assert_eq!(floorf(1.0), 1.0); assert_eq!(floorf(0.0), 0.0); assert_eq!(floorf(1.234211), 1.0); assert_eq!(floorf(-1.234211), -2.0); } #[test] fn test_floor() { assert_eq!(floor(-1.0), -1.0); assert_eq!(floor(1.0), 1.0); assert_eq!(floor(0.0), 0.0); assert_eq!(floor(1.234211), 1.0); assert_eq!(floor(-1.234211), -2.0); } } pxfm-0.1.23/src/gamma/digamma.rs000064400000000000000000000352641046102023000145110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::gamma::digamma_coeffs::digamma_coeefs; use crate::logs::fast_log_d_to_dd; use crate::tangent::cotpi_core; #[inline] fn approx_digamma_hard(x: f64) -> DoubleDouble { if x <= 12. { let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let (p, q) = digamma_coeefs(x); let e0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[1]), x, DoubleDouble::from_bit_pair(p[0]), ); let e1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[3]), x, DoubleDouble::from_bit_pair(p[2]), ); let e2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[5]), x, DoubleDouble::from_bit_pair(p[4]), ); let e3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[7]), x, DoubleDouble::from_bit_pair(p[6]), ); let e4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[9]), x, DoubleDouble::from_bit_pair(p[8]), ); let e5 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[11]), x, DoubleDouble::from_bit_pair(p[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); let rcp = DoubleDouble::from_quick_recip(x); let e0 = DoubleDouble::mul_f64_add_f64( DoubleDouble::from_bit_pair(q[1]), x, f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[3]), x, DoubleDouble::from_bit_pair(q[2]), ); let e2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[5]), x, DoubleDouble::from_bit_pair(q[4]), ); let e3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[7]), x, DoubleDouble::from_bit_pair(q[6]), ); let e4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[9]), x, DoubleDouble::from_bit_pair(q[8]), ); let e5 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[11]), x, DoubleDouble::from_bit_pair(q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let q = DoubleDouble::div(p_num, p_den); let r = DoubleDouble::quick_dd_sub(q, rcp); return r; } // digamma asymptotic expansion // digamma(x) ~ ln(z)+1/(2z)-sum_(n=1)^(infty)(Bernoulli(2n))/(2nz^(2n)) // Generated in SageMath: // var('x') // // def bernoulli_terms(x, N): // S = 0 // S += QQ(1)/QQ(2)/x // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / QQ(2*k))*x**(-2*k) // S += term // return S // // terms = bernoulli_terms(x, 9) // // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(1, 13): // c = terms.coefficient(x, -k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") const C: [(u64, u64); 10] = [ (0x3c55555555555555, 0x3fb5555555555555), (0xbc01111111111111, 0xbf81111111111111), (0x3c10410410410410, 0x3f70410410410410), (0xbbf1111111111111, 0xbf71111111111111), (0xbc0f07c1f07c1f08, 0x3f7f07c1f07c1f08), (0x3c39a99a99a99a9a, 0xbf95995995995996), (0x3c55555555555555, 0x3fb5555555555555), (0xbc77979797979798, 0xbfdc5e5e5e5e5e5e), (0xbc69180646019180, 0x40086e7f9b9fe6e8), (0x3ccad759ad759ad7, 0xc03a74ca514ca515), ]; let rcp = DoubleDouble::from_quick_recip(x); let rcp_sqr = DoubleDouble::quick_mult(rcp, rcp); let rx = rcp_sqr; let x2 = DoubleDouble::quick_mult(rx, rx); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let q0 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[1]), rx, DoubleDouble::from_bit_pair(C[0]), ); let q1 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[3]), rx, DoubleDouble::from_bit_pair(C[2]), ); let q2 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[5]), rx, DoubleDouble::from_bit_pair(C[4]), ); let q3 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[7]), rx, DoubleDouble::from_bit_pair(C[6]), ); let q4 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[9]), rx, DoubleDouble::from_bit_pair(C[8]), ); let q0 = DoubleDouble::quick_mul_add(x2, q1, q0); let q1 = DoubleDouble::quick_mul_add(x2, q3, q2); let r0 = DoubleDouble::quick_mul_add(x4, q1, q0); let mut p = DoubleDouble::quick_mul_add(x8, q4, r0); p = DoubleDouble::quick_mul_f64_add( rcp, f64::from_bits(0x3fe0000000000000), DoubleDouble::quick_mult(p, rcp_sqr), ); let v_log = fast_log_d_to_dd(x); DoubleDouble::quick_dd_sub(v_log, p) } #[inline] fn approx_digamma_hard_dd(x: DoubleDouble) -> DoubleDouble { if x.hi <= 12. { let x2 = DoubleDouble::quick_mult(x, x); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let (p, q) = digamma_coeefs(x.hi); let e0 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[1]), x, DoubleDouble::from_bit_pair(p[0]), ); let e1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[3]), x, DoubleDouble::from_bit_pair(p[2]), ); let e2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[5]), x, DoubleDouble::from_bit_pair(p[4]), ); let e3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[7]), x, DoubleDouble::from_bit_pair(p[6]), ); let e4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[9]), x, DoubleDouble::from_bit_pair(p[8]), ); let e5 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[11]), x, DoubleDouble::from_bit_pair(p[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); let rcp = x.recip(); let e0 = DoubleDouble::mul_add_f64( DoubleDouble::from_bit_pair(q[1]), x, f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[3]), x, DoubleDouble::from_bit_pair(q[2]), ); let e2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[5]), x, DoubleDouble::from_bit_pair(q[4]), ); let e3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[7]), x, DoubleDouble::from_bit_pair(q[6]), ); let e4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[9]), x, DoubleDouble::from_bit_pair(q[8]), ); let e5 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[11]), x, DoubleDouble::from_bit_pair(q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let q = DoubleDouble::div(p_num, p_den); let r = DoubleDouble::quick_dd_sub(q, rcp); return r; } // digamma asymptotic expansion // digamma(x) ~ ln(z)+1/(2z)-sum_(n=1)^(infty)(Bernoulli(2n))/(2nz^(2n)) // Generated in SageMath: // var('x') // // def bernoulli_terms(x, N): // S = 0 // S += QQ(1)/QQ(2)/x // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / QQ(2*k))*x**(-2*k) // S += term // return S // // terms = bernoulli_terms(x, 9) // // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(1, 13): // c = terms.coefficient(x, -k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") const C: [(u64, u64); 10] = [ (0x3c55555555555555, 0x3fb5555555555555), (0xbc01111111111111, 0xbf81111111111111), (0x3c10410410410410, 0x3f70410410410410), (0xbbf1111111111111, 0xbf71111111111111), (0xbc0f07c1f07c1f08, 0x3f7f07c1f07c1f08), (0x3c39a99a99a99a9a, 0xbf95995995995996), (0x3c55555555555555, 0x3fb5555555555555), (0xbc77979797979798, 0xbfdc5e5e5e5e5e5e), (0xbc69180646019180, 0x40086e7f9b9fe6e8), (0x3ccad759ad759ad7, 0xc03a74ca514ca515), ]; let rcp = x.recip(); let rcp_sqr = DoubleDouble::quick_mult(rcp, rcp); let rx = rcp_sqr; let x2 = DoubleDouble::quick_mult(rx, rx); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let q0 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[1]), rx, DoubleDouble::from_bit_pair(C[0]), ); let q1 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[3]), rx, DoubleDouble::from_bit_pair(C[2]), ); let q2 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[5]), rx, DoubleDouble::from_bit_pair(C[4]), ); let q3 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[7]), rx, DoubleDouble::from_bit_pair(C[6]), ); let q4 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[9]), rx, DoubleDouble::from_bit_pair(C[8]), ); let q0 = DoubleDouble::quick_mul_add(x2, q1, q0); let q1 = DoubleDouble::quick_mul_add(x2, q3, q2); let r0 = DoubleDouble::quick_mul_add(x4, q1, q0); let mut p = DoubleDouble::quick_mul_add(x8, q4, r0); p = DoubleDouble::quick_mul_f64_add( rcp, f64::from_bits(0x3fe0000000000000), DoubleDouble::quick_mult(p, rcp_sqr), ); let mut v_log = fast_log_d_to_dd(x.hi); v_log.lo += x.lo / x.hi; DoubleDouble::quick_dd_sub(v_log, p) } /// Computes digamma(x) /// pub fn f_digamma(x: f64) -> f64 { let xb = x.to_bits(); if !x.is_normal() { if x.is_infinite() { return if x.is_sign_negative() { f64::NAN } else { f64::INFINITY }; } if x.is_nan() { return f64::NAN; } if xb == 0 { return 1. / x; } } let dx = x; if x.abs() <= f64::EPSILON { // |x| < ulp(1) // digamma near where x -> 1 ~ Digamma[x] = -euler + O(x) // considering identity Digamma[x+1] = Digamma[x] + 1/x, // hence x < ulp(1) then x+1 ~= 1 that gives // Digamma[x] = Digamma[x+1] - 1/x = -euler - 1/x // euler is dropped since 1/x >> euler // that gives: // Digamma[x] = Digamma[x+1] - 1/x = -1/x return -1. / x; } if x < 0. { // at negative integers it's inf let k = x.floor(); if k == x { return f64::NAN; } // reflection Gamma(1-x) + Gamma(x) = Pi/tan(PI*x) const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18)); let r = DoubleDouble::from_full_exact_sub(1., x); let mut result = PI * cotpi_core(-x); let app = approx_digamma_hard_dd(r); result = DoubleDouble::quick_dd_add(result, app); result.to_f64() } else { let app = approx_digamma_hard(dx); app.to_f64() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_digamma() { assert_eq!(f_digamma(0.0019531200000040207), -512.5753182109892); assert_eq!(f_digamma(-13.999000000012591), -997.3224450000563); assert_eq!(f_digamma(13.999000000453323), 2.602844047257257); } } pxfm-0.1.23/src/gamma/digamma_coeffs.rs000064400000000000000000001174171046102023000160370ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /* Poly numerators for digamma with step 0.25 from 0 to 1: [-0.99999999,-0.75], [-0.75, -0.5] etc. Generated by Wolfram: <75,MaxIterations->100] num=Numerator[approx]; den=Denominator[approx]; poly=num; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] poly=den; coeffs=CoefficientList[poly,z]; TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] */ static DIGAMMA_P: [[(u64, u64); 12]; 5] = [ [ (0x3c56cb8ed2e8f89d, 0xbfe2788cfc6fb619), (0xbc3f4a887143e1a0, 0x3face2294e40a23d), (0x3c66cbeeb663e02b, 0x3ff93da24c048557), (0xbc99dce69443c3a1, 0x3ffb9ca4e7e3b448), (0x3c86642ccc010b7c, 0x3febdebcbbc26740), (0xbc6b0b2f44dae75c, 0x3fcfec9b12222c41), (0xbbf4498c8a1b0940, 0x3fa62080e59486a8), (0x3c0b9dc350a33198, 0x3f72bc74facca682), (0xbbcd99184e051c10, 0x3f32c94b7b2fb002), (0xbb8738e809ec0cee, 0x3ee48ad4af286d1f), (0x3b130f69e7502da5, 0x3e84788fd8c782e7), (0xbaabf9ce6f6a39c0, 0x3e075df82b55c605), ], [ (0x3c56cb907008b543, 0xbfe2788cfc6fb619), (0xbc100842dc7f9e7f, 0x3fb01301a3e98b73), (0xbc823b1b4a0eb7aa, 0x3ff938b063dae04f), (0xbc9ad21ad2ab96c5, 0x3ffb55c29a135ea7), (0xbc7d5ba993767236, 0x3feb4f810b04c753), (0x3c64772eb3244da3, 0x3fcee4afd0031184), (0x3c31c1810f303099, 0x3fa513f613ed0729), (0x3c0bd0845bf7f471, 0x3f717f05f5d10c47), (0xbbd5725001e2660d, 0x3f311a7e461bfdbc), (0xbb8598e1d6bf14c5, 0x3ee21971cbf5769f), (0x3b2c987b53229a3f, 0x3e81461991174455), (0xbaa40e6fc1c3cdbd, 0x3e029575e1cf2d2e), ], [ (0x3c56cb90701fbfa6, 0xbfe2788cfc6fb619), (0xbc5fccfe13017bdd, 0x3fb1afc092258787), (0xbc5e1697dc2cc4ab, 0x3ff9337b6bb944de), (0x3c7ec613451b31b9, 0x3ffb0fd93c22113b), (0x3c69294dd477ad47, 0x3feac3c7b64adea4), (0xbc69ac8bff5565b5, 0x3fcde66e558d148f), (0x3c41acf6837637f5, 0x3fa4154b581a555a), (0xbc000c1483343db8, 0x3f70580604407f51), (0x3bbc673a5ee2174f, 0x3f2f290c93113075), (0x3b7ea2e3314e056e, 0x3edfed2db5039158), (0xbaf8d7013fff21f7, 0x3e7d35fdf2716965), (0xba739bf5ff69075f, 0x3dfdb070ae4d9275), ], [ (0x3c56cb90701fbfab, 0xbfe2788cfc6fb619), (0x3c32d7bac835354c, 0x3fb34c4468e4cca5), (0x3c83dfd7ab2663ee, 0x3ff92df4d81668e8), (0x3c99f27ceb6a6462, 0x3ffaca12fb44387d), (0xbc873d42ae8bf0ee, 0x3fea39db2aa6755c), (0x3c6f0709b773a576, 0x3fccee948fe7d9a3), (0xbc319c78a343f2ba, 0x3fa320f0d611b675), (0xbba5feb85ab5acbc, 0x3f6e855445cb1dae), (0x3bba9b56af9b20c5, 0x3f2c5ecc73cbcdd8), (0xbb79a32258828ace, 0x3edc257fc6ffd42d), (0x3b1efad7acd7d7f1, 0x3e78b3710a7cc9b4), (0xba9b941fb3ff6b0c, 0x3df7c1965f2d7194), ], [ (0x3c56cb90701fbfab, 0xbfe2788cfc6fb619), (0xbc0f99d5dc5f8b06, 0x3fb4e913ab76f9ab), (0x3c3191e63046dc0e, 0x3ff9281aa8398c82), (0xbc8dca8def824c6e, 0x3ffa845a59ce1115), (0xbc84dbb9117bcea5, 0x3fe9b18e7fe7829a), (0xbc5e38525daac915, 0x3fcbfcbc6601a1fe), (0x3c4df8dcb4769fe3, 0x3fa2364b5ab136dd), (0x3c03a220e74edede, 0x3f6c7b78bf3817d2), (0xbb831144f7e90d73, 0x3f29d06f3db25586), (0x3b7b4bf8f2ec756c, 0x3ed8cd0278bee187), (0x3b0c2bf25bbf39b5, 0x3e74e2f6a044ec34), (0x3a942086a4928038, 0x3df3096d2199706d), ], ]; static DIGAMMA_Q: [[(u64, u64); 12]; 5] = [ [ (0x0000000000000000, 0x3ff0000000000000), (0xbca6adb0ceca2bb2, 0x4006042dff16f40e), (0xbc85b67e7a730640, 0x4008379d3bb3e8e0), (0xbc9f004eb95ee438, 0x3ffc7e68e904512d), (0xbc86ee1922dc4c80, 0x3fe407ea97357260), (0xbc4a51002b1b8870, 0x3fc1a70e08dee4dd), (0x3c3c858930786915, 0x3f93c1e4eef4b20b), (0x3be9a73c7d428d88, 0x3f5baa2f04f498b1), (0x3bbad1b8117f7756, 0x3f171c5667c8dffc), (0x3b173ce742b4d895, 0x3ec4e29a45581499), (0xbadceb3243cdae8f, 0x3e60a2d5d1c5f8e4), (0xba72b2562de7b14b, 0x3ddb303e7518d74b), ], [ (0x0000000000000000, 0x3ff0000000000000), (0x3c91779e812448f8, 0x4005ed8db27be60e), (0x3ca08f641dca5f12, 0x4007fb6b0dcbcebe), (0xbc9b5b059968427b, 0x3ffc005c8adea86d), (0x3c7a6c4119840b60, 0x3fe37d5ff5b97171), (0xbc530ac1661d05de, 0x3fc0f56578da17ee), (0xbc0418ed2bc636c5, 0x3f92ad4e7387f851), (0xbbc1f659b88045fd, 0x3f599f72920bc12d), (0x3bba548ec376cb95, 0x3f14dae97a930698), (0x3b440fec06d88466, 0x3ec239fbc98052c7), (0xbae8bd7909c83aaf, 0x3e5bcab555b96b0c), (0x3a7da912eade2739, 0x3dd5684408d505b7), ], [ (0x0000000000000000, 0x3ff0000000000000), (0xbca91be54288a0e0, 0x4005d735308bb4dd), (0xbcad30b7bbf2b783, 0x4007c03f8e4c4fe6), (0xbc9eeb30365815fb, 0x3ffb854f0db08baa), (0x3c782d2becaf6172, 0x3fe2f7622383d14d), (0xbc5e010ee89a3662, 0x3fc04badf9bdbed9), (0x3c2af3eb8a7d2bde, 0x3f91a94aee0050b0), (0xbbd2450502e41cf9, 0x3f57be27fec5860c), (0xbb4d401f4b8a5f96, 0x3f12d5723c46d383), (0xbb56834644f0201f, 0x3ebfda938f459b86), (0x3ada0645f44a4bcd, 0x3e574563cf974833), (0xba7147ae6edcbc3d, 0x3dd0f0bfcad5f047), ], [ (0x0000000000000000, 0x3ff0000000000000), (0xbc9045b43a44ffbd, 0x4005c0dfe199018b), (0x3cadc1c9c8ce4d30, 0x40078563dd87aa1b), (0xbc7ee1018a57916d, 0x3ffb0bbe462659fc), (0x3c84b1e3cb3c10f4, 0x3fe2743f18457656), (0x3c5ce0b8927bff8a, 0x3fbf4f3f5d1d2c88), (0x3c227cc874c2781a, 0x3f90b1f8cc772eb7), (0x3bea9648da0df3bd, 0x3f55fdcf409bac26), (0x3bbc08910e142370, 0x3f11003e3494b94d), (0x3b5a6e0762b57f19, 0x3ebbd3ea01684109), (0xbae425ecbc8c7993, 0x3e537e51126d11b7), (0xba656f95223fc44f, 0x3dcadec5fd0f622c), ], [ (0x0000000000000000, 0x3ff0000000000000), (0x3caa0a86221a0755, 0x4005aa867d56dca4), (0xbcac770719607c75, 0x40074ac4f6ca5a47), (0x3c90d03a36128d7f, 0x3ffa93815f190569), (0x3c4d48dbdc6c9a7c, 0x3fe1f3c3b4044619), (0x3c55f2ca2ba72f08, 0x3fbe11c76c6789f6), (0x3c07ca0eacaa9a9c, 0x3f8f8d146c709524), (0xbbd3ae3ef7bb9792, 0x3f545be615cbebf2), (0xbb86e82ec7f13b7f, 0x3f0ead31c1a5b093), (0xbb3275f4a13e5259, 0x3eb84d337c38d867), (0xbaf557dfebeee67e, 0x3e505544e8f1eb85), (0xba664f9845fcddf2, 0x3dc559cc156a72a5), ], ]; #[inline] #[allow(clippy::type_complexity)] pub(crate) fn digamma_coeefs(x: f64) -> (&'static [(u64, u64); 12], &'static [(u64, u64); 12]) { if x < 1.25 { const FOUR: u64 = 2 << 52; let idx = f64::from_bits(x.to_bits().wrapping_add(FOUR)) as usize; let p = &DIGAMMA_P[idx]; let q = &DIGAMMA_Q[idx]; (p, q) } else if x <= 1.461632144 { // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0x3c56cb90701fbfac, 0xbfe2788cfc6fb619), (0x3c519fc5fe329992, 0x3fb66b6f7ca77b95), (0x3c934d7e8434b86d, 0x3ff92255627f42b7), (0x3c637005ae2e1665, 0x3ffa43326e6dda36), (0x3c3cadafce6428f4, 0x3fe9338d9b2539f1), (0xbc5934a30d152b54, 0x3fcb1febac693a97), (0xbc3d4ec7808fa04f, 0x3fa1636286a89dfe), (0xbbf577e9f832bec3, 0x3f6aafbc9ad0d5ad), (0xbbcd6cc934d6ba4e, 0x3f279eaf8168ee05), (0xbb774ef4099bad0c, 0x3ed605efaec77016), (0xbb13d911fcebafac, 0x3e71dae45db651bb), (0x3a8f943200c1fd92, 0x3deefe67af5b7c69), ]; // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ca0fb55209ad44d, 0x4005959bb2d38810), (0xbc4a7dccb43a2a97, 0x40071428acb23be5), (0xbc8b9d316e4d2eac, 0x3ffa24400e09040c), (0xbc82963c4efb8cd1, 0x3fe17dfa742912bc), (0x3c57e765f5582745, 0x3fbcf24965915c1f), (0xbc2bfe1e01bc34f0, 0x3f8de96be6a73955), (0x3bff6a6cc1679110, 0x3f52ef034cdc300f), (0xbb95e707835497ae, 0x3f0bd94abae4b483), (0xbb435b31a77f1eac, 0x3eb5673711efb89a), (0xbab7879ef73e896a, 0x3e4bb1a59a808117), (0xba50ff72e575b8bd, 0x3dc13fef9cd36cd7), ]; (&P, &Q) } else if x <= 1.75 { // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0x3c56cb907020a112, 0xbfe2788cfc6fb619), (0xbc3cc4d6d2ddccf8, 0x3fb8010bfcb83141), (0x3c953d47923ee59b, 0x3ff91bf87a8009ef), (0x3c856cf1c819abcd, 0x3ff9fee67ab017a1), (0xbc7e5e24a77dd53e, 0x3fe8b0e3f74e8969), (0xbc60cf6e08c2898c, 0x3fca3dc2ac288997), (0xbc4d6745fb4dd03b, 0x3fa08eb928fceb5d), (0x3c0153615a07e895, 0x3f68e95d5669dc9c), (0x3bcc104646590a9e, 0x3f25818c7facb551), (0xbb6ce130dd405fa2, 0x3ed36f27c8982809), (0xbae5a7d3777ea48d, 0x3e6e4b3d604133f4), (0xba86b002676d830d, 0x3de9027ae9347c77), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ca13038b3e9b2fe, 0x40057fa6128d0d08), (0xbcacf21951ec09a9, 0x4006db1750ade888), (0x3c9fd268ab672291, 0x3ff9b0c5a589896f), (0xbc4b818d4493b88a, 0x3fe104d8aeed391e), (0xbc5531e244a9d256, 0x3fbbce38cef1dcd3), (0x3c14e017cdbf9c7b, 0x3f8c45ceb3fbe0a3), (0x3bff3d4bd6748d1c, 0x3f51898acc32fa08), (0xbb6c0ebdb9714f4b, 0x3f09266424ad60b1), (0x3b30abd2021dc5ea, 0x3eb2ba49a890927f), (0xba9629f3ce206d76, 0x3e474b9f374cf052), (0x39f3beca069e2142, 0x3dbba0c4466d2dcd), ]; (&P, &Q) } else if x <= 2. { // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0x3c56cb907bb52809, 0xbfe2788cfc6fb619), (0xbc420cb940ff1bad, 0x3fb9b8ce99af6686), (0xbc9554bebef623c7, 0x3ff914b779852ffb), (0x3c81daceacffe906, 0x3ff9b4fb845f87b4), (0xbc589d02262e231e, 0x3fe8251c504ee4e7), (0xbc48b053e0ac1f18, 0x3fc94f0c5b394803), (0xbc12b44611d0cc3d, 0x3f9f6411022b8fee), (0x3bf71626c3a722d6, 0x3f671bef7af39602), (0x3bca802abbe6c032, 0x3f236afc88364acd), (0xbb73ba0bffc04b11, 0x3ed0f71a4569fdd2), (0x3ae6866974b3745b, 0x3e695b19eb1a11d0), (0x3a53fcd00ba0f0cd, 0x3de3dbee8f81e7d1), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ca79b06fde08bf7, 0x400567d727c212e8), (0xbc9b0efe8b146dee, 0x40069d86c47f0240), (0xbc8299a0687d2bc4, 0x3ff9351a45c9504d), (0xbc7146fcb08e6211, 0x3fe0846a56e8c617), (0xbc482c27fd2b0de3, 0x3fba9ca29930f546), (0x3beaea4e7ed3058f, 0x3f8a96406d35271a), (0x3bf776396bc4adbd, 0x3f5021eb0152afad), (0xbb96d179aedf8a7a, 0x3f0682935c1f4e53), (0xbb469533a5f262d4, 0x3eb033bbf3243fc1), (0x3ad33e062bbd7ac2, 0x3e43535be5d463ef), (0x3a5a7d127f1db626, 0x3db5c4427025e959), ]; (&P, &Q) } else if x <= 3. { // x <= 3 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0x3c56d1cc8bcd2834, 0xbfe2788cfc6fb619), (0x3c50701f78e64a63, 0x3fbd8bb4f2220f15), (0xbc6f91b861a7c3f1, 0x3ff903416798b207), (0x3c8c53da657116b3, 0x3ff910f28e38ea3f), (0xbc8720408446640c, 0x3fe6f4e66e069dae), (0xbc34e63b5e59b9bd, 0x3fc75316d7a07060), (0xbc22cfa33a314334, 0x3f9bd312bdf809fb), (0xbbfd6f2d0a941d18, 0x3f638321ec193179), (0xbbbd1cabd7d7d204, 0x3f1edf0eeec2ed8f), (0x3b62b3641fcc9055, 0x3ec908c824d24ebd), (0x3b09f21b5bfbaac3, 0x3e61119012a56c3c), (0xba7ccbf11ca33a44, 0x3dd7e364822d6038), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ca8ae32e83e7971, 0x400532d7f57a1fb8), (0x3ca7e06fe036f034, 0x4006159f6c8559a6), (0x3c696aeb79408ada, 0x3ff8276de15b9949), (0x3c6b4b6c4100ee75, 0x3fdee20a3a9510d1), (0xbc5366197ca045c2, 0x3fb81bb8b46e3ac9), (0x3c2f178bb9cecf1c, 0x3f8726ac2011b61b), (0x3be51ce661a77196, 0x3f4abe5166a64e0d), (0xbb84cb13a26b099d, 0x3f018de8d20c9ae7), (0xbb4f127e563d4fce, 0x3ea772bc233a7f3d), (0xbad8391ca6522a23, 0x3e398817e8c8a3f5), (0x3a46dbfc8fc0a31f, 0x3da9c1eb2bb8a09d), ]; (&P, &Q) } else if x <= 4. { // x <= 4 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc1138539f5170ce, 0xbfe2788cfc6fb617), (0x3c5c28276512f306, 0x3fc1fc2364555134), (0xbc6a09be4de1611c, 0x3ff8e1befdb6bc25), (0x3c74ca0e29a4c28f, 0x3ff7ff202fdee96b), (0xbc81af890e1880a0, 0x3fe50bb10d8d3f83), (0xbc63ea18b51ff6b6, 0x3fc444e2fde41a82), (0x3c3778d316f51d1e, 0x3f969f9868302eb9), (0x3be358e50a96a230, 0x3f5d3a1baf51425c), (0x3bbc38a174d2733f, 0x3f14e8fe4a7dddfb), (0x3b5f5ed1876db6a7, 0x3ebe07d4dbcc1ad4), (0x3af907af35fa32d0, 0x3e51b3f54fae106f), (0x3a62af4ca3fd0f35, 0x3dc4d88e2dc21ca8), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c9648605b16dd34, 0x4004d9ced1a59873), (0x3c7dc6b76d368927, 0x400534eafce36582), (0xbc3ce3eb41ed98ed, 0x3ff673eeb71c9f83), (0xbc66f13de6a48d20, 0x3fdb84d7f538c20d), (0x3c5035f4fefd130a, 0x3fb45b63620b1db4), (0x3c1923173b36285f, 0x3f8246e776c12954), (0x3be4c733ad174a92, 0x3f436ec81a059c76), (0x3b8012652ce0bc96, 0x3ef70fe1dc481482), (0x3b2d0670cd6004bc, 0x3e9b497296f5f46e), (0xba85189a8dab3039, 0x3e29bb6d630a41ac), (0x3a3cb2bee18cf77a, 0x3d95f146af7f3514), ]; (&P, &Q) } else if x <= 5. { // x <= 5 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0x3c82777617606035, 0xbfe2788cfc6fb22a), (0x3c6a89168e92a2bd, 0x3fc5286b343ecbe5), (0xbc7562c3f1327b91, 0x3ff8bb7dfd30d653), (0xbc8167bf7208ef96, 0x3ff6f31495ad9560), (0x3c82d2177e694dd6, 0x3fe3431bda031b31), (0xbc6be5da70840171, 0x3fc19291a81dd8a2), (0x3c3bf690d21eb357, 0x3f9258218b3ef7bf), (0xbbffd8d4b0692fbb, 0x3f55d7a5623a2dcf), (0x3babb591eb87dd6c, 0x3f0c56ac18bd4d6b), (0xbb5c8b806eef4ae7, 0x3eb2209eb7acd22b), (0xbad36fc4d27a4168, 0x3e42af070578d594), (0xb9dfe0085849fd5a, 0x3db2d9b6d2913a2a), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbca9a57355580b15, 0x400481dafdd7bdb2), (0x3c8c54a5f9c29d95, 0x40045b68f0902217), (0xbc795347ec01fbd2, 0x3ff4daef6b912517), (0x3c699ae8f19cf3ec, 0x3fd87d05ac8eb769), (0x3c59ea5ce4904986, 0x3fb12877d62826ca), (0x3be6bd7425bdd967, 0x3f7cce33e2dd0530), (0xbbc460e353f4c8bc, 0x3f3c38bcf76c94b5), (0xbb712ad762f9ec9d, 0x3eee601d38ab6d9b), (0xbb23ce6868791dc5, 0x3e9006213ba059aa), (0xbab95abdc33a7321, 0x3e1a7ac297a0a53d), (0xba174f07c41d8cfd, 0x3d836fa7694a651d), ]; (&P, &Q) } else if x <= 6. { // x <= 6 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc8032a1d2c0ad13, 0xbfe2788cfc6e9dbe), (0x3c38696772d75917, 0x3fc849d273d05d75), (0x3c954ca48d09b1aa, 0x3ff890aef7dc27e1), (0xbc963b4b7c9a58af, 0x3ff5ed5797be10f8), (0x3c87390c0470f3c6, 0x3fe19a75e3a5dbe3), (0xbc4a8fca8acf4f1f, 0x3fbe68afab720ce8), (0x3c1ed20f546b9104, 0x3f8db0bf34ed5e72), (0xbbd6b67d3f6d936e, 0x3f504f9138773832), (0x3bae68dee81a333d, 0x3f033ff5436fb4e3), (0xbb1fad498922c758, 0x3ea61338f9837209), (0x3ad4cdce5341705f, 0x3e341863900b259b), (0xba1368ab344aa52f, 0x3da1a36dc66478ff), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc8415c937927b80, 0x40042b14ac1de31a), (0xbca02e650cfc91cb, 0x4003893428b832f0), (0x3c85d3d357beac28, 0x3ff35bb913ab979e), (0x3c763ef88de8bbf4, 0x3fd5c47e7c28af74), (0x3c4624d0ce63afac, 0x3face2a04d07592f), (0x3befca3faad26d95, 0x3f76adbb8f0c9e71), (0x3bd6bb21845ab51f, 0x3f3482259071c038), (0xbb888fad8984adb0, 0x3ee4182fa08710cd), (0xbb2ec0c609c2589a, 0x3e83082e53b39cd4), (0xbaa2954cc8fe5ef2, 0x3e0bd8dfedf43944), (0x39e30166e0cac476, 0x3d71dc88357652c3), ]; (&P, &Q) } else if x <= 7. { // x <= 7 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc81dfd5a5534592, 0xbfe2788cfc565c6c), (0x3c5ee519bbeafb4a, 0x3fcb5e9b249cc2ae), (0x3c8df433a8ab926f, 0x3ff86195ebe61e55), (0xbc9c26e874cedb94, 0x3ff4eeb2d59b9e46), (0xbc8b629f64d30eb4, 0x3fe011547d3b4deb), (0x3c4877eafbf1d0bf, 0x3fba461689f2d09b), (0xbc02cb677bd729e7, 0x3f8801390c64edcd), (0x3be6bb411d2772bf, 0x3f4861722dbdb621), (0x3b95c312dfadf0f8, 0x3efa4589f0866235), (0x3b2e65576c0b0642, 0x3e9b2d2386424cdf), (0x3acbcd0ab8139043, 0x3e260e89319914dd), (0x3a2bde33fa1ac8f3, 0x3d9110236b17c522), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c8ff6dd498c91b2, 0x4003d5ac26d888b6), (0x3c9acb90be620fba, 0x4002be9b5e78f13f), (0x3c80944df7c8a780, 0x3ff1f5e5ec0c3d71), (0x3c50f7c451bbdd2e, 0x3fd355e0f87c5218), (0xbc4cd8f8f78b44a1, 0x3fa84c8863aae54b), (0xbc13df2d02c4d3c4, 0x3f71dc00f5ff8e9c), (0x3bc942f7fa51682f, 0x3f2de1134f7b2de6), (0xbb5bcf5da39fb215, 0x3edac2e18af5b8d1), (0xbb11b483e6820b4e, 0x3e76e765628dffe0), (0x3a89bf8734fc1f0e, 0x3dfdf503240dffa2), (0xb9fcaf5858297b35, 0x3d610182e7d328a5), ]; (&P, &Q) } else if x <= 8. { // x <= 8 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc8162f86e7bad36, 0xbfe2788cfb513f92), (0xbc6ddc13d58b297e, 0x3fce652fd3cec73c), (0x3c701fd75f0e2153, 0x3ff82e7ee851190e), (0x3c86494ccd407812, 0x3ff3f7d8f2cc7221), (0x3c71d5a4a3016802, 0x3fdd4df807c7f6a2), (0xbc55bd847484e7bd, 0x3fb6aeaa992b7e5e), (0x3c1d99552c28a292, 0x3f8368db68048c4f), (0xbbecf51acbe60763, 0x3f42437beb7b56ec), (0x3b7ec2e94f896a2d, 0x3ef20a7a9ea0accc), (0x3a9a0a1b60fffd51, 0x3e90f02feda221d2), (0x3ab8a5da0c600246, 0x3e18b9818d3b86a1), (0xba1dc40c982b9669, 0x3d810bda1d0bde80), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c95f4382d9f9dbc, 0x400381cd52a27389), (0x3ca36a2a63377659, 0x4001fbd9cbbdde5b), (0xbc83cb5796f6bba0, 0x3ff0a8db1d651315), (0x3c779f72905d08e8, 0x3fd12b8a9f02c16c), (0xbc4dacaf20322afe, 0x3fa47160278b25ee), (0xbc0262fab0a08a3c, 0x3f6c2a94e4e5cf4f), (0x3bc553f072d7f874, 0x3f25d9d7c995af31), (0x3b62f92e30dbacb9, 0x3ed1f75f5d275707), (0x3b02b661ecc2ba69, 0x3e6bf75615fe0e2f), (0x3a571b7290df94bc, 0x3df07d3db0951aef), (0xb9f18f3d33a27e32, 0x3d50bfea8f77e0c3), ]; (&P, &Q) } else if x <= 9. { // x <= 9 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0x3c8efd7fe9db6e79, 0xbfe2788cf4b3267f), (0x3c6a2e8811472031, 0x3fd0ae258336bb2b), (0x3c7399e3844d1e5f, 0x3ff7f7b99c5c43be), (0x3c822ee42e5fe80d, 0x3ff30958a7e8d80e), (0x3c6848d741adf8c4, 0x3fdab4b23acdeb18), (0x3c5aa072e08707aa, 0x3fb393aa5016e08a), (0xbc18b1985dc2c38c, 0x3f7f6b771fa6e163), (0x3bdc86329c365200, 0x3f3b75a61ceee8c8), (0x3b8e8f8ff597b2e6, 0x3ee8f7bf1b272a81), (0x3b19b561962f8b4e, 0x3e8566c7b18e4a14), (0x3aadf125c1ad7adb, 0x3e0c4f51c4444e9a), (0x39f1e1df7a4c3a8b, 0x3d7190106017b110), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ca684bdc1b74b83, 0x40032f9b62c83c86), (0x3ca5d8d28ceedbb4, 0x4001410ed7fd4814), (0x3c7686b33443b989, 0x3feee782a9ab5027), (0x3c53620c43b8821f, 0x3fce7f4d1d2ffe3c), (0xbc33e2abe9a40984, 0x3fa1362ff4c8e4cb), (0xbbef2639d9860de0, 0x3f66430cca12747e), (0xbbb8084e63a55a7b, 0x3f200faaa577da43), (0x3b6b0dea347bf9f3, 0x3ec859b423a711e8), (0x3b04cb8df32e9178, 0x3e61563b86bed1a2), (0xba801506c55d0eb4, 0x3de292d18eb8fd2f), (0xb9d06300f4b9226a, 0x3d4109bff966bb51), ]; (&P, &Q) } else if x <= 10. { // x <= 10 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc8593c1df8ef6c7, 0xbfe2788cd6e083bb), (0x3c6415b1331fd1e0, 0x3fd2217df51ae592), (0x3c9c29eeb5fe4731, 0x3ff7bd965beb1b87), (0xbc85fe7985564d6e, 0x3ff2239b9feaa8a7), (0xbc5cc9b9441046be, 0x3fd8541d3ac20fdc), (0xbc243a1d71c1b7e2, 0x3fb0e6b0237a2f28), (0xbc1534c74442766c, 0x3f797a05781bf99b), (0xbbd8ba51ad9881fe, 0x3f34bc78d4108de1), (0xbb81efd29f25726f, 0x3ee16d09b7ddc32f), (0xba96ec9993a947f2, 0x3e7b6c967312dff2), (0xbaa2a0b4acd633ea, 0x3e008d27d632d14c), (0xb9ff596e6d378d22, 0x3d62a21a99d77977), ]; // Generated by Wolfram Mathematica: //<75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c6f1ef07b1b5dc9, 0x4002df30458e626a), (0xbc960127cb9e2eab, 0x40008e3f3217718d), (0x3c8412d2aabe8bf8, 0x3fecab1dc0e9bcac), (0x3c64edc0f7754efe, 0x3fcb18b1038e24f6), (0xbc3abc16284838a3, 0x3f9d05522b423e2f), (0xbc0e44998e55a65f, 0x3f61a64c0a74479e), (0xbbb190403d2a5a61, 0x3f17c0a8b1842890), (0x3b598fe19ed917ac, 0x3ec0ab7613d6b90e), (0xbaf7c33460b01c25, 0x3e55d581be9c2732), (0xba7278196b41c6f6, 0x3dd565843701949d), (0x39912fb123ad4ce0, 0x3d31de54105a6ae4), ]; (&P, &Q) } else if x <= 11. { // x <= 11 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc7002de428656f8, 0xbfe2788c706086ea), (0xbc7e5dea366e1224, 0x3fd38c4fa29daad3), (0x3c95297f4120d6e1, 0x3ff780642930e686), (0xbc7cdcec6276d962, 0x3ff146e905a85e7c), (0xbc4dde11481dc9d7, 0x3fd629105bd7a86b), (0x3c29f43835822d7e, 0x3fad342a0507d56a), (0x3c1f98d2402273b2, 0x3f74b55e06fd0100), (0x3bc61bf252df59de, 0x3f2f7b95f117d541), (0x3b4f7f3c66a58c10, 0x3ed88c81b5a7bffc), (0xbb1ba95a86f7955a, 0x3e71d2d46e31e04c), (0xb9feae47109db197, 0x3df3c1020acf06fb), (0xb9ed26ed15eff6d5, 0x3d5453226c1a47c8), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc8f67d2f15a73c9, 0x4002909d472a6258), (0x3c94a8e3edcab93b, 0x3fffc6b132050914), (0xbc5b982f33a20a73, 0x3fea9a2aba70b06e), (0x3c619d024f5cdba4, 0x3fc817cd43625de8), (0xbc3dc40df7f1ecbb, 0x3f9882a708f4756f), (0x3b88f0ba3ff4834f, 0x3f5c16f3fb9fe3e9), (0xbb8ed7db88e71ba0, 0x3f11ae1da151fd8f), (0x3b3437f8aa73a246, 0x3eb711185a5568ff), (0x3ab876889e88ff72, 0x3e4bee89a4622cb4), (0xba6ac2419dbe0e2f, 0x3dc930ba3560eb64), (0xb9b2124aaf27b632, 0x3d234925cfe9d5d8), ]; (&P, &Q) } else { // x <= 12 // Polynomial generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P: [(u64, u64); 12] = [ (0xbc88aa87989ef5a1, 0xbfe2788b51df7906), (0xbc7af1e1932b591c, 0x3fd4ee69b56504f9), (0x3c740a2c04d19bfc, 0x3ff7406f9cf46140), (0xbc917572eb9329ef, 0x3ff07369547283f5), (0x3c54e46eaf6429e3, 0x3fd4301a4c091a22), (0x3c3c3ba8aa15ca20, 0x3fa9426e448ee7db), (0xbc1f041777b9f035, 0x3f70e2032a465789), (0xbbb783cb47e19f83, 0x3f28099ad5f73d16), (0xbb6932c40b32e5e0, 0x3ed175058b1e67e6), (0x3b024c00ae6427d0, 0x3e677fd917aaa847), (0x3a50b5029ff4eadf, 0x3de80bf02bf0e221), (0x39e405e48a7d9326, 0x3d46c1a62ef66417), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c67856052188c26, 0x400243ec3166f349), (0x3c2b34f0f808ddac, 0x3ffe806cb15a71b3), (0xbc823b5d5bc54e38, 0x3fe8b21e296d1320), (0xbc52f7423180111c, 0x3fc571b5d26833f9), (0xbc33e19defee24d6, 0x3f94bf1ad662d38a), (0x3beb180e8d55583a, 0x3f56723080074543), (0xbb7d192d116623ad, 0x3f0a818d001404be), (0x3b194b9889dea9d1, 0x3eb021f1a8b7f978), (0x3a8ca7cbf623a001, 0x3e4224e2c71fae88), (0xba4d8314f1a91e06, 0x3dbe48212e08d6f2), (0xb9a210925f26ebb8, 0x3d15627ecb7e02ac), ]; (&P, &Q) } } pxfm-0.1.23/src/gamma/digammaf.rs000064400000000000000000000410721046102023000146510ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::logs::simple_fast_log; use crate::polyeval::{ f_estrin_polyeval7, f_estrin_polyeval8, f_estrin_polyeval9, f_polyeval4, f_polyeval6, f_polyeval10, }; use crate::tangent::cotpif_core; #[inline] fn approx_digamma(x: f64) -> f64 { if x <= 1. { // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval10( x, f64::from_bits(0xbfe2788cfc6fb619), f64::from_bits(0x3fca347925788707), f64::from_bits(0x3ff887e0f068df69), f64::from_bits(0x3ff543446198b4d2), f64::from_bits(0x3fe03e4455fbad95), f64::from_bits(0x3fb994be8389e4f6), f64::from_bits(0x3f84eb98b830c9b1), f64::from_bits(0x3f4025193ac4ad97), f64::from_bits(0x3ee18c1d683d866a), f64::from_bits(0x3e457cb5b4a07c95), ); let p_den = f_estrin_polyeval9( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4003f5f42d95aca8), f64::from_bits(0x4002f96e541d0513), f64::from_bits(0x3ff22c34843313fa), f64::from_bits(0x3fd33574180109bf), f64::from_bits(0x3fa6c07b99ebb277), f64::from_bits(0x3f6cdd7b8fa68926), f64::from_bits(0x3f212b74d39e287f), f64::from_bits(0x3ebabd247f366583), ); return p_num / p_den - 1. / x; } else if x < 1.461632144 { // exception if x == 1.4616321325302124 { return -1.2036052e-8; } // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval9( x, f64::from_bits(0xbfe2788cfc6fb619), f64::from_bits(0x3fd0ad221e8c3b8b), f64::from_bits(0x3ff813be4dee2e90), f64::from_bits(0x3ff2f64cbfa7d1a4), f64::from_bits(0x3fd9a8c4798f426c), f64::from_bits(0x3fb111a34898f6bf), f64::from_bits(0x3f75dd3efac1e579), f64::from_bits(0x3f272596b2582f0d), f64::from_bits(0x3eb9b074f4ca6263), ); let p_den = f_estrin_polyeval9( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x40032fd3a1fe3a25), f64::from_bits(0x40012969bcd7fef3), f64::from_bits(0x3fee1a267ee7a97a), f64::from_bits(0x3fcc1522178a69a6), f64::from_bits(0x3f9bd89421334af0), f64::from_bits(0x3f5b40bc3203df4c), f64::from_bits(0x3f05ac6be0b79fac), f64::from_bits(0x3e9047c3d8071f18), ); return p_num / p_den - 1. / x; } else if x <= 2. { // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval8( x, f64::from_bits(0xbfe2788cfc6fb613), f64::from_bits(0x3fd690553caa1c6b), f64::from_bits(0x3ff721cf4d9e008f), f64::from_bits(0x3fee9f4096f34b09), f64::from_bits(0x3fd055e88830fc71), f64::from_bits(0x3f9e66bceee16960), f64::from_bits(0x3f55d436778b3403), f64::from_bits(0x3eeef6bc214819b3), ); let p_den = f_estrin_polyeval8( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4001e96eaab05729), f64::from_bits(0x3ffcb1aa289077da), f64::from_bits(0x3fe5499e89b757b6), f64::from_bits(0x3fbee531a912bca9), f64::from_bits(0x3f84d46f2121ceb7), f64::from_bits(0x3f35abd7eb7440e6), f64::from_bits(0x3ec43bf7c110aad1), ); return p_num / p_den - 1. / x; } else if x <= 3. { // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval8( x, f64::from_bits(0xbfe2788cfc63695f), f64::from_bits(0x3fdb63791eb688ea), f64::from_bits(0x3ff625ed84968583), f64::from_bits(0x3fe900ea36e59e02), f64::from_bits(0x3fc5319409f4fec6), f64::from_bits(0x3f8b6e7cacff2a59), f64::from_bits(0x3f34a7e591bf2af3), f64::from_bits(0x3e9c323866d138db), ); let p_den = f_estrin_polyeval7( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4000ddf448e34181), f64::from_bits(0x3ff87188f2414f79), f64::from_bits(0x3fdeff74d18f811a), f64::from_bits(0x3fb1a0cddeb3a320), f64::from_bits(0x3f701050c1344800), f64::from_bits(0x3f10480a4ea8cf57), ); return p_num / p_den - 1. / x; } else if x <= 8. { // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval8( x, f64::from_bits(0xbfe2788c3725fd5e), f64::from_bits(0x3fde39f54e5a651a), f64::from_bits(0x3ff56983b839b94f), f64::from_bits(0x3fe60d6118d8fc08), f64::from_bits(0x3fc0e889ace69a30), f64::from_bits(0x3f844e10e399bd93), f64::from_bits(0x3f3099741afda7cb), f64::from_bits(0x3eb74a15144af8e9), ); let p_den = f_estrin_polyeval8( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4000409ed08c0553), f64::from_bits(0x3ff63746cb6183e3), f64::from_bits(0x3fda1196b1a75351), f64::from_bits(0x3fab4ba9fad2d187), f64::from_bits(0x3f67de6e6987e3a3), f64::from_bits(0x3f0c9d85ca31182e), f64::from_bits(0x3e8b269f154c8f12), ); return p_num / p_den - 1. / x; } else if x <= 15. { // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_estrin_polyeval8( x, f64::from_bits(0xbfe272e75f131710), f64::from_bits(0x3fe53fce507de081), f64::from_bits(0x3ff182957d4f961a), f64::from_bits(0x3fd6d1652dea00e9), f64::from_bits(0x3fa45e16488abe0f), f64::from_bits(0x3f5a52a8f3f3663f), f64::from_bits(0x3ef5b767554d208e), f64::from_bits(0x3e6d2393b100353d), ); let p_den = f_estrin_polyeval8( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x3ffb1f295c6e5fc5), f64::from_bits(0x3feb88eb913eb117), f64::from_bits(0x3fc570f3aed83ff7), f64::from_bits(0x3f8afe819fdfa5a5), f64::from_bits(0x3f3a2cec9041f361), f64::from_bits(0x3ed0549335964bb9), f64::from_bits(0x3e3ebdcb0002d63e), ); return p_num / p_den - 1. / x; } // digamma asymptotic expansion // digamma(x) ~ ln(z)+1/(2z)-sum_(n=1)^(infty)(Bernoulli(2n))/(2nz^(2n)) // Generated in SageMath: // var('x') // // def bernoulli_terms(x, N): // S = 0 // S += QQ(1)/QQ(2)/x // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / QQ(2*k))*x**(-2*k) // S += term // return S // // terms = bernoulli_terms(x, 5) // // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(1, 13): // c = terms.coefficient(x, -k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") let rcp = 1. / x; let rcp_sqr = rcp * rcp; let p = f_polyeval6( rcp_sqr, f64::from_bits(0x3fb5555555555555), f64::from_bits(0xbf81111111111111), f64::from_bits(0x3f70410410410410), f64::from_bits(0xbf71111111111111), f64::from_bits(0x3f7f07c1f07c1f08), f64::from_bits(0xbf95995995995996), ); let v_log = simple_fast_log(x); v_log - f_fmla(rcp, f64::from_bits(0x3fe0000000000000), p * rcp_sqr) } /// Computes digamma(x) pub fn f_digammaf(x: f32) -> f32 { let xb = x.to_bits(); if (xb & 0x0007_ffff) == 0 { if x.is_infinite() { return if x.is_sign_negative() { f32::NAN } else { f32::INFINITY }; } if x.is_nan() { return f32::NAN; } if xb == 0 { return 1. / x; } } let ax = x.to_bits() & 0x7fff_ffff; if ax <= 0x32abcc77u32 { // |x| < 2e-8 // digamma near where x -> 1 ~ Digamma[x] = -euler + O(x) // considering identity Digamma[x+1] = Digamma[x] + 1/x, // hence x < ulp(1) then x+1 ~= 1 that gives // Digamma[x] = Digamma[x+1] - 1/x = -euler - 1/x const EULER: f64 = f64::from_bits(0x3fe2788cfc6fb619); return (-EULER - 1. / x as f64) as f32; } else if ax <= 0x377ba882u32 { // |x| <= 0.000015 // Laurent series of digamma(x) // Generated by SageMath: // from mpmath import mp // mp.prec = 150 // R = RealField(150) // var('x') // def laurent_terms(x, N): // S = 0 // S += -1/x - R(mp.euler) // S1 = 0 // for k in range(1, N+1): // zet = R(mp.zeta(k + 1)) // term = zet*(-x)**k // S1 += term // return S - S1 // // terms = laurent_terms(x, 4) // // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(1, 13): // c = terms.coefficient(x, k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") const EULER: f64 = f64::from_bits(0x3fe2788cfc6fb619); let dx = x as f64; let start = -1. / dx; let neg_dx = -dx; let z = f_polyeval4( neg_dx, f64::from_bits(0x3ffa51a6625307d3), f64::from_bits(0xbff33ba004f00621), f64::from_bits(0x3ff151322ac7d848), f64::from_bits(0xbff097418eca7cce), ); let r = f_fmla(z, dx, -EULER) + start; return r as f32; } let mut dx = x as f64; let mut result: f64 = 0.; if x < 0. { // at negative integers it's inf if x.floor() == x { return f32::NAN; } // reflection Gamma(1-x) + Gamma(x) = Pi/tan(PI*x) const PI: f64 = f64::from_bits(0x400921fb54442d18); let cot_x_angle = -dx; dx = 1. - dx; result = PI * cotpif_core(cot_x_angle); } let approx = approx_digamma(dx); result += approx; result as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_digamma() { assert_eq!(f_digammaf(-13.999000000012591), -996.9182); assert_eq!(f_digammaf(15.3796425), 2.700182); assert_eq!(f_digammaf(0.0005187988), -1928.1058); assert_eq!(f_digammaf(0.0019531252), -512.574); assert_eq!(f_digammaf(-96.353516), 6.1304626); assert_eq!(f_digammaf(-31.06964), 17.582127); assert_eq!(f_digammaf(-0.000000000000001191123), 839543830000000.); assert_eq!(f_digammaf(f32::INFINITY), f32::INFINITY); assert!(f_digammaf(f32::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/gamma/lgamma.rs000064400000000000000000001315711046102023000143460ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::f_log; use crate::logs::{fast_log_d_to_dd, fast_log_dd, log_dd}; use crate::polyeval::{f_polyeval4, f_polyeval5, f_polyeval6, f_polyeval10}; use crate::sincospi::f_fast_sinpi_dd; #[inline] fn apply_sign_and_sum(z: DoubleDouble, parity: f64, s: DoubleDouble) -> DoubleDouble { if parity >= 0. { z } else { DoubleDouble::full_dd_sub(s, z) } } #[inline] fn apply_sign_and_sum_quick(z: DoubleDouble, parity: f64, s: DoubleDouble) -> DoubleDouble { if parity >= 0. { z } else { DoubleDouble::quick_dd_sub(s, z) } } #[cold] fn lgamma_0p5(dx: f64, v_log: DoubleDouble, f_res: DoubleDouble, sum_parity: f64) -> f64 { // Log[Gamma[x+1]] // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 9] = [ (0x349d90fba23c9118, 0xb7f552eee31fa8d2), (0x3c56cb95ec26b8b0, 0xbfe2788cfc6fb619), (0xbc98554b6e8ebe5c, 0xbff15a4f25fcc40b), (0x3c51b37126e8f9ee, 0xbfc2d93ef9720645), (0xbc85a532dd358f5d, 0x3fec506397ef590a), (0x3c7dc535e77ac796, 0x3fe674f6812154ca), (0x3c4ff02dbae30f4d, 0x3fc9aacc2b0173a0), (0xbc3aa29e4d4e6c9d, 0x3f95d8cbe81572b6), (0x3bed03960179ad28, 0x3f429e0ecfd47eb2), ]; let mut p_num = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[8]), dx, DoubleDouble::from_bit_pair(P[7]), ); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 8] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc93d5d3e154eb7a, 0x400a6e37d475364e), (0xbcb465441d96e6c2, 0x401112f3f3b083a7), (0x3ca1b893e8188325, 0x4005cbfc6085847f), (0xbc8608a5840fb86b, 0x3fec920358d35f3a), (0x3c5dc5b89a3624bd, 0x3fc21011cbbc6923), (0x3bfbe999bea0b965, 0x3f822ae49ffa14ce), (0x3b90cb3bd523bf32, 0x3f20d6565fe86116), ]; let mut p_den = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[7]), dx, DoubleDouble::from_bit_pair(Q[6]), ); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000)); let v0 = DoubleDouble::full_dd_sub(DoubleDouble::div(p_num, p_den), v_log); let v_res = apply_sign_and_sum(v0, sum_parity, f_res); v_res.to_f64() } #[cold] fn lgamma_0p5_to_1(dx: f64, v_log: DoubleDouble, f_res: DoubleDouble, sum_parity: f64) -> f64 { // Log[Gamma[x+1]] // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 10] = [ (0xb967217bfcc647c2, 0xbcc9b2c47481ff4f), (0xbc7eff78623354d7, 0xbfe2788cfc6fb552), (0xbc9886c6f42886e0, 0xbff3c6a7f676cf4c), (0x3c77ed956ff8e661, 0xbfdaf57ee2a64253), (0x3c8723f3a5de4fd5, 0x3feb961a3d8bbe89), (0x3c8848ddf2e2726f, 0x3fedc9f11015d4ca), (0xbc799f3b76da571b, 0x3fd7ac6e82c07787), (0xbc5cb131b054a5f5, 0x3fb103e7e288f4da), (0x3bfe93ab961d39a4, 0x3f74789410ab2cf5), (0x3babcb1e8a573475, 0x3f1d74e78621d316), ]; let mut p_num = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[9]), dx, DoubleDouble::from_bit_pair(P[8]), ); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[7])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbca99871cf68ff41, 0x400c87945e972c56), (0xbc8292764aa01c02, 0x401477d734273be4), (0xbcaf0f1758e16cb3, 0x400e53c84c87f686), (0xbc901825b170e576, 0x3ff8c99df9c66865), (0x3c78af0564323160, 0x3fd629441413e902), (0x3c3293dd176164f3, 0x3fa42e466fd1464e), (0xbbf3fbc18666280b, 0x3f5f9cd4c60c4e7d), (0xbb4036ba7be37458, 0x3efb2d3ed43aab6f), (0xbaf7a3a7d5321f53, 0xbe665e3fadf143a6), ]; let mut p_den = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[9]), dx, DoubleDouble::from_bit_pair(Q[8]), ); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[7])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[6])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000)); let v0 = DoubleDouble::full_dd_sub(DoubleDouble::div(p_num, p_den), v_log); let v_res = apply_sign_and_sum(v0, sum_parity, f_res); v_res.to_f64() } #[cold] fn lgamma_1_to_4(dx: f64, v_log: DoubleDouble, f_res: DoubleDouble, sum_parity: f64) -> f64 { // Log[Gamma[x+1]] // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 14] = [ (0x398e8eb32d541d21, 0xbcf55335b06a5df1), (0xbc60fc919ad95ffb, 0xbfe2788cfc6fb2c4), (0x3c98d8e5e64ea307, 0xbffb5e5c82450af5), (0x3c778a3bdabcdb1f, 0xbff824ecfcecbcd5), (0x3c77768d59db11a0, 0x3fd6a097c5fa0036), (0x3c9f4a74ad888f08, 0x3ff9297ba86cc14e), (0xbc97e1e1819d78bd, 0x3ff3dd0025109756), (0xbc6f1b00b6ce8a2a, 0x3fdfded97a03f2f3), (0xbc55487a80e322fe, 0x3fbd5639f2258856), (0x3bede86c7e0323ce, 0x3f8f7261ccd00da5), (0x3bcde1ee8e81b7b5, 0x3f52fbfb5a8c7221), (0x3ba8ed54c3db7fde, 0x3f07d48361a072b6), (0xbb4c30e2cdaa48f2, 0x3eaa8661f0313183), (0xbac575d303dd9b93, 0x3e3205d52df415e6), ]; let mut p_num = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[13]), dx, DoubleDouble::from_bit_pair(P[12]), ); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[11])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[10])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[9])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[8])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[7])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 14] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3cbde8d771be8aba, 0x40118da297250deb), (0xbccdbba67547f5dc, 0x4020589156c4058c), (0x3caca498a3ea822e, 0x4020e9442d441e22), (0xbca6a7d3651d1b42, 0x40156480b1dc22fe), (0x3ca79ba727e70ad6, 0x40013006d1e5d08c), (0x3c8c2b824cfce390, 0x3fe1b0eb2f75de3f), (0xbc5208ab1ad4d8e0, 0x3fb709e145993376), (0xbc21d64934aab809, 0x3f825ee5a8799658), (0x3bc29531f5a4518d, 0x3f40ed532b6bffdd), (0x3b994fb11dace77e, 0x3ef052da92364c6d), (0xbb1f0fb3869f715e, 0x3e8b6bbbe7aae5eb), (0x3a81d8373548a8a8, 0x3e09b5304c6d77ba), (0x3992e1e6b163e1f7, 0xbd50eee2d9d4e7b9), ]; let mut p_den = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[13]), dx, DoubleDouble::from_bit_pair(Q[12]), ); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[11])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[10])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[9])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[8])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[7])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[6])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000)); let mut k = DoubleDouble::div(p_num, p_den); k = DoubleDouble::from_exact_add(k.hi, k.lo); let v0 = DoubleDouble::full_dd_sub(k, v_log); let v_res = apply_sign_and_sum(v0, sum_parity, f_res); v_res.to_f64() } #[cold] fn lgamma_4_to_12(dx: f64, f_res: DoubleDouble, sum_parity: f64) -> f64 { // Log[Gamma[x+1]] // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 11] = [ (0x3c9a767426b2d1e8, 0x400e45c3573057bb), (0xbcccc22bbae40ac4, 0x403247d3a1b9b0e9), (0xbc82c1d4989e7813, 0x3ffe955db10dd744), (0x3cb4669cf9238f48, 0xc036a67a52498757), (0x3cb4c4039d4da434, 0xc01a8d26ec4b2f7b), (0x3ca43834ea54b437, 0x400c92b79f85b787), (0x3c930746944a1bc1, 0x3ff8b3afe3e0525c), (0xbc68499f7a8b0f87, 0x3fc8059ff9cb3e10), (0x3c0e16d9f08b7e18, 0x3f81c282c77a3862), (0xbbcec78600b42cd0, 0x3f22fe2577cf1017), (0x3b1c222faf24d4a1, 0x3ea5511d126ad883), ]; let mut p_num = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[10]), dx, DoubleDouble::from_bit_pair(P[9]), ); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[8])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[7])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1])); p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0])); const Q: [(u64, u64); 11] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3ccaa60b201a29f2, 0x40288b76f18d51d8), (0xbcd831f5042551f9, 0x403d383173e1839d), (0x3cb2b77730673e36, 0x4037e8a6dda469df), (0x3cb8c229012ae276, 0x40207ddd53aa3098), (0xbc8aba961299355d, 0x3ff4c90761849336), (0xbc3e844b2b1f0edb, 0x3fb832c6fba5ff26), (0xbbc70261cd94cb90, 0x3f68b185e16f05c1), (0xbb6c1c2dfe90e592, 0x3f0303509bbb9cf8), (0xbb0f160d6b147ae5, 0x3e7d1bd86b15f52e), (0x3a5714448b9c17d2, 0xbdba82d4d2ccf533), ]; let mut p_den = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[10]), dx, DoubleDouble::from_bit_pair(Q[9]), ); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[8])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[7])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[6])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2])); p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1])); p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000)); let v_res = apply_sign_and_sum(DoubleDouble::div(p_num, p_den), sum_parity, f_res); v_res.to_f64() } #[cold] fn stirling_accurate(dx: f64, parity: f64, f_res: DoubleDouble) -> f64 { let y_recip = DoubleDouble::from_quick_recip(dx); let y_sqr = DoubleDouble::mult(y_recip, y_recip); // Bernoulli coefficients generated by SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / (2*k*(2*k-1))) * x**((2*k-1)) // S += term // return S // // terms = bernoulli_terms(x, 10) const BERNOULLI_C: [(u64, u64); 10] = [ (0x3c55555555555555, 0x3fb5555555555555), (0x3bff49f49f49f49f, 0xbf66c16c16c16c17), (0x3b8a01a01a01a01a, 0x3f4a01a01a01a01a), (0x3befb1fb1fb1fb20, 0xbf43813813813814), (0x3be5c3a9ce01b952, 0x3f4b951e2b18ff23), (0x3bff82553c999b0e, 0xbf5f6ab0d9993c7d), (0x3c10690690690690, 0x3f7a41a41a41a41a), (0x3c21efcdab896745, 0xbf9e4286cb0f5398), (0xbc279e2405a71f88, 0x3fc6fe96381e0680), (0x3c724246319da678, 0xbff6476701181f3a), ]; let bernoulli_poly = f_polyeval10( y_sqr, DoubleDouble::from_bit_pair(BERNOULLI_C[0]), DoubleDouble::from_bit_pair(BERNOULLI_C[1]), DoubleDouble::from_bit_pair(BERNOULLI_C[2]), DoubleDouble::from_bit_pair(BERNOULLI_C[3]), DoubleDouble::from_bit_pair(BERNOULLI_C[4]), DoubleDouble::from_bit_pair(BERNOULLI_C[5]), DoubleDouble::from_bit_pair(BERNOULLI_C[6]), DoubleDouble::from_bit_pair(BERNOULLI_C[7]), DoubleDouble::from_bit_pair(BERNOULLI_C[8]), DoubleDouble::from_bit_pair(BERNOULLI_C[9]), ); // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms const LOG2_PI_OVER_2: DoubleDouble = DoubleDouble::from_bit_pair((0xbc865b5a1b7ff5df, 0x3fed67f1c864beb5)); let mut log_gamma = DoubleDouble::add( DoubleDouble::mul_add_f64(bernoulli_poly, y_recip, -dx), LOG2_PI_OVER_2, ); let dy_log = log_dd(dx); log_gamma = DoubleDouble::mul_add( DoubleDouble::from_exact_add(dy_log.hi, dy_log.lo), DoubleDouble::from_full_exact_add(dx, -0.5), log_gamma, ); let res = apply_sign_and_sum(log_gamma, parity, f_res); res.to_f64() } /// due to log(x) leading terms cancellation happens around 2, /// hence we're using different approximation around LogGamma(2). /// Coefficients are ill-conditioned here so Minimal Newton form is used #[cold] fn lgamma_around_2(x: f64, parity: f64, f_res: DoubleDouble) -> f64 { let dx = DoubleDouble::from_full_exact_sub(x, 2.); // Generated by Wolfram Mathematica: // <90] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // x0=SetPrecision[2,90]; // NumberForm[Series[num,{x,x0,9}],ExponentFunction->(Null&)] // coeffs=Table[SeriesCoefficient[num,{x,x0,k}],{k,0,10}]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=Table[SeriesCoefficient[den,{x,x0,k}],{k,0,10}]; // NumberForm[Series[den,{x,x0,9}],ExponentFunction->(Null&)] // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 10] = [ (0xbd8ef0f02676337a, 0x41000f48befb1b70), (0x3dae9e186ab39649, 0x411aeb5de0ba157d), (0xbdcfe4bca8f58298, 0x4122d673e1f69e2c), (0x3db1e3de8e53cfce, 0x411d0fdd168e56a8), (0x3d9114d199dacd01, 0x410b4a1ce996f910), (0x3d9172663132c0b6, 0x40f02d95ceca2c8a), (0x3d52988b7d30cfd3, 0x40c83a4c6e145abc), (0xbd14327346a3db7b, 0x409632fe8dc80419), (0x3cfe9f975e5e9984, 0x4057219509ba1d62), (0xbca0fdd3506bf429, 0x4007988259d795c4), ]; let dx2 = dx * dx; let dx4 = dx2 * dx2; let dx8 = dx4 * dx4; let p0 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(P[1]), DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(P[3]), DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(P[5]), DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(P[7]), DoubleDouble::from_bit_pair(P[6]), ); let p4 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(P[9]), DoubleDouble::from_bit_pair(P[8]), ); let q0 = DoubleDouble::quick_mul_add(dx2, p1, p0); let q1 = DoubleDouble::quick_mul_add(dx2, p3, p2); let r0 = DoubleDouble::quick_mul_add(dx4, q1, q0); let mut p_num = DoubleDouble::quick_mul_add(dx8, p4, r0); p_num = DoubleDouble::quick_mult(p_num, dx); const Q: [(u64, u64); 11] = [ (0x3da0f8e36723f959, 0x4112fe27249fc6f1), (0xbdc289e4a571ddb8, 0x412897be1a39b97b), (0xbdb8d18ab489860f, 0x412b4fcbc6d9cb44), (0x3da0550c9f65a5ef, 0x4120fe765c0f6a79), (0xbd90a121e792bf7f, 0x4109fa9eaa0f816a), (0xbd7168de8e78812e, 0x40e9269d002372a5), (0x3d4e4d052cd6982a, 0x40beab7f948d82f0), (0xbd0cebe53b7e81bf, 0x4086a91c01d7241f), (0xbcd2edf097020841, 0x4042a780e9d1b74b), (0xbc73d1a40910845f, 0x3fecd007ff47224f), (0xbc06e4de631047f3, 0x3f7ad97267872491), ]; let q0 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(Q[1]), DoubleDouble::from_bit_pair(Q[0]), ); let q1 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let q2 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let q3 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(Q[7]), DoubleDouble::from_bit_pair(Q[6]), ); let q4 = DoubleDouble::quick_mul_add( dx, DoubleDouble::from_bit_pair(Q[9]), DoubleDouble::from_bit_pair(Q[8]), ); let r0 = DoubleDouble::quick_mul_add(dx2, q1, q0); let r1 = DoubleDouble::quick_mul_add(dx2, q3, q2); let s0 = DoubleDouble::quick_mul_add(dx4, r1, r0); let s1 = DoubleDouble::quick_mul_add(dx2, DoubleDouble::from_bit_pair(Q[10]), q4); let p_den = DoubleDouble::quick_mul_add(dx8, s1, s0); let v_res = apply_sign_and_sum_quick(DoubleDouble::div(p_num, p_den), parity, f_res); v_res.to_f64() } /// Computes log(gamma(x)) /// /// ulp 0.52 pub fn f_lgamma(x: f64) -> f64 { let nx = x.to_bits().wrapping_shl(1); if nx >= 0xfeaea9b24f16a34cu64 { // |x| >= 0x1.006df1bfac84ep+1015 if x.is_infinite() { return f64::INFINITY; } if x.is_nan() { return f64::NAN; } return f64::INFINITY; } if x.floor() == x { if x == 2. || x == 1. { return 0.; } if x.is_sign_negative() { return f64::INFINITY; } } let ax = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); let dx = ax; let is_positive = x.is_sign_positive(); let mut sum_parity = 1f64; if ax < f64::EPSILON { return -f_log(dx); } let mut f_res = DoubleDouble::default(); // 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); if !is_positive { let y1 = ax.floor(); let fraction = ax - y1; // excess over the boundary let a = f_fast_sinpi_dd(fraction); sum_parity = -1.; const LOG_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3c67abf2ad8d5088, 0x3ff250d048e7a1bd)); let mut den = DoubleDouble::quick_mult_f64(a, dx); den = DoubleDouble::from_exact_add(den.hi, den.lo); f_res = fast_log_dd(den); f_res = DoubleDouble::from_exact_add(f_res.hi, f_res.lo); f_res = DoubleDouble::quick_dd_sub(LOG_PI, f_res); } if ax <= 0.5 { // Log[Gamma[x + 1]] poly generated by Wolfram // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let ps_num = f_polyeval4( dx, f64::from_bits(0x3fea8287cc94dc31), f64::from_bits(0x3fe000cbc75a2ab7), f64::from_bits(0x3fba69bac2495765), f64::from_bits(0x3f78eb3984eb55ee), ); let ps_den = f_polyeval5( dx, f64::from_bits(0x3ffee073402b349e), f64::from_bits(0x3fe04c62232d12ec), f64::from_bits(0x3fad09ff23ffb930), f64::from_bits(0x3f5c253f6e8af7d2), f64::from_bits(0xbee18a68b4ed9516), ); let mut p_num = DoubleDouble::f64_mul_f64_add( ps_num, dx, DoubleDouble::from_bit_pair((0x3c4d671927a50f5b, 0x3fb184cdffda39b0)), ); p_num = DoubleDouble::mul_f64_add( p_num, dx, DoubleDouble::from_bit_pair((0xbc8055e20f9945f5, 0xbfedba6e22cced8a)), ); p_num = DoubleDouble::mul_f64_add( p_num, dx, DoubleDouble::from_bit_pair((0x3c56cc8e006896be, 0xbfe2788cfc6fb619)), ); p_num = DoubleDouble::mul_f64_add( p_num, dx, DoubleDouble::from_bit_pair((0x34c1e175ecd02e7e, 0xb84ed528d8df1c88)), ); let mut p_den = DoubleDouble::f64_mul_f64_add( ps_den, dx, DoubleDouble::from_bit_pair((0xbc70ab0b3b299408, 0x400c16483bffaf57)), ); p_den = DoubleDouble::mul_f64_add( p_den, dx, DoubleDouble::from_bit_pair((0xbcac74fbe90fa7cb, 0x400846598b0e4750)), ); p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000)); let d_log = fast_log_d_to_dd(dx); let v0 = DoubleDouble::sub(DoubleDouble::div(p_num, p_den), d_log); let l_res = f_res; f_res = apply_sign_and_sum_quick(v0, sum_parity, f_res); let err = f_fmla( f_res.hi.abs(), f64::from_bits(0x3c56a09e667f3bcd), // 2^-57.5 f64::from_bits(0x3c20000000000000), // 2^-61 ); let ub = f_res.hi + (f_res.lo + err); let lb = f_res.hi + (f_res.lo - err); if ub == lb { return ub; } lgamma_0p5(dx, d_log, l_res, sum_parity) } else if ax <= 1. { let distance_to_2 = ax - 2.; if distance_to_2.abs() < 0.05 { return lgamma_around_2(ax, sum_parity, f_res); } // Log[Gamma[x+1]] // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] const P: [(u64, u64); 10] = [ (0xb967217bfcc647c2, 0xbcc9b2c47481ff4f), (0xbc7eff78623354d7, 0xbfe2788cfc6fb552), (0xbc9886c6f42886e0, 0xbff3c6a7f676cf4c), (0x3c77ed956ff8e661, 0xbfdaf57ee2a64253), (0x3c8723f3a5de4fd5, 0x3feb961a3d8bbe89), (0x3c8848ddf2e2726f, 0x3fedc9f11015d4ca), (0xbc799f3b76da571b, 0x3fd7ac6e82c07787), (0xbc5cb131b054a5f5, 0x3fb103e7e288f4da), (0x3bfe93ab961d39a4, 0x3f74789410ab2cf5), (0x3babcb1e8a573475, 0x3f1d74e78621d316), ]; let ps_den = f_polyeval4( dx, f64::from_bits(0x3fa42e466fd1464e), f64::from_bits(0x3f5f9cd4c60c4e7d), f64::from_bits(0x3efb2d3ed43aab6f), f64::from_bits(0xbe665e3fadf143a6), ); let dx2 = DoubleDouble::from_exact_mult(dx, dx); let dx4 = DoubleDouble::quick_mult(dx2, dx2); let dx8 = DoubleDouble::quick_mult(dx4, dx4); let p0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[1]), dx, DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[3]), dx, DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[5]), dx, DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[7]), dx, DoubleDouble::from_bit_pair(P[6]), ); let p4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[9]), dx, DoubleDouble::from_bit_pair(P[8]), ); let q0 = DoubleDouble::mul_add(dx2, p1, p0); let q1 = DoubleDouble::mul_add(dx2, p3, p2); let r0 = DoubleDouble::mul_add(dx4, q1, q0); let p_num = DoubleDouble::mul_add(dx8, p4, r0); let mut p_den = DoubleDouble::f64_mul_f64_add( ps_den, dx, DoubleDouble::from_bit_pair((0x3c78af0564323160, 0x3fd629441413e902)), ); p_den = DoubleDouble::mul_f64_add( p_den, dx, DoubleDouble::from_bit_pair((0xbc901825b170e576, 0x3ff8c99df9c66865)), ); p_den = DoubleDouble::mul_f64_add( p_den, dx, DoubleDouble::from_bit_pair((0xbcaf0f1758e16cb3, 0x400e53c84c87f686)), ); p_den = DoubleDouble::mul_f64_add( p_den, dx, DoubleDouble::from_bit_pair((0xbc8292764aa01c02, 0x401477d734273be4)), ); p_den = DoubleDouble::mul_f64_add( p_den, dx, DoubleDouble::from_bit_pair((0xbca99871cf68ff41, 0x400c87945e972c56)), ); p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000)); let d_log = fast_log_d_to_dd(dx); let v0 = DoubleDouble::sub(DoubleDouble::div(p_num, p_den), d_log); let l_res = f_res; f_res = apply_sign_and_sum_quick(v0, sum_parity, f_res); let err = f_fmla( f_res.hi.abs(), f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3c20000000000000), // 2^-61 ); let ub = f_res.hi + (f_res.lo + err); let lb = f_res.hi + (f_res.lo - err); if ub == lb { return f_res.to_f64(); } lgamma_0p5_to_1(dx, d_log, l_res, sum_parity) } else if ax <= 4. { let distance_to_2 = ax - 2.; if distance_to_2.abs() < 0.05 { return lgamma_around_2(ax, sum_parity, f_res); } // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); const P: [(u64, u64); 10] = [ (0x3a8ea8c71173ba1f, 0xbde8c6619bc06d43), (0x3c8f2502d288b7e1, 0xbfe2788cfb0f13f7), (0xbc873b33ddea3333, 0xbfebd290912f0200), (0x3c223d47fd7b2e30, 0x3fb52786e934492b), (0xbc8f4e91d7f48aa5, 0x3fe8204c68bc38f4), (0x3c5356ff82d857c6, 0x3fde676d587374a4), (0x3c5d8deef0e6c21f, 0x3fbef2e284faabe5), (0xbc24ea363b4779fb, 0x3f8bb45183525b51), (0xbbec808b7b332822, 0x3f43b11bd314773b), (0xbb777d551025e6da, 0x3edf7931f7cb9cd1), ]; let p0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[1]), dx, DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[3]), dx, DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[5]), dx, DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[7]), dx, DoubleDouble::from_bit_pair(P[6]), ); let p4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[9]), dx, DoubleDouble::from_bit_pair(P[8]), ); let q0 = DoubleDouble::mul_add(x2, p1, p0); let q1 = DoubleDouble::mul_add(x2, p3, p2); let r0 = DoubleDouble::mul_add(x4, q1, q0); let p_num = DoubleDouble::mul_add(x8, p4, r0); const Q: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc9ad7b53d7da072, 0x4007730c69fb4a20), (0xbc93d2a47740a995, 0x400ab6d03e2d6528), (0x3c9cd643c37f1205, 0x3ffe2cccacb6740b), (0xbc7b616646543538, 0x3fe1f36f793ad9c6), (0xbc483b2cb83a34ba, 0x3fb630083527c66f), (0x3c1089007cac404c, 0x3f7a6b85d9c297ea), (0xbbcfc269fc4a2c55, 0x3f298d01a660c3d9), (0xbb43342127aafe5a, 0x3eb9c8ba657b4b0a), (0xbaac5e3aa213d878, 0xbe14186c41f01fd1), ]; let p0 = DoubleDouble::mul_f64_add_f64( DoubleDouble::from_bit_pair(Q[1]), dx, f64::from_bits(0x3ff0000000000000), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[3]), dx, DoubleDouble::from_bit_pair(Q[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[5]), dx, DoubleDouble::from_bit_pair(Q[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[7]), dx, DoubleDouble::from_bit_pair(Q[6]), ); let p4 = DoubleDouble::f64_mul_f64_add( f64::from_bits(0xbe14186c41f01fd1), // Q[9].hi dx, DoubleDouble::from_bit_pair(Q[8]), ); let q0 = DoubleDouble::mul_add(x2, p1, p0); let q1 = DoubleDouble::mul_add(x2, p3, p2); let r0 = DoubleDouble::mul_add(x4, q1, q0); let p_den = DoubleDouble::mul_add(x8, p4, r0); let d_log = fast_log_d_to_dd(dx); let prod = DoubleDouble::div(p_num, p_den); let v0 = DoubleDouble::sub(prod, d_log); let l_res = f_res; f_res = apply_sign_and_sum_quick(v0, sum_parity, f_res); let err = f_fmla( f_res.hi.abs(), f64::from_bits(0x3c40000000000000), // 2^-59 f64::from_bits(0x3c00000000000000), // 2^-63 ); let ub = f_res.hi + (f_res.lo + err); let lb = f_res.hi + (f_res.lo - err); if ub == lb { return f_res.to_f64(); } lgamma_1_to_4(dx, d_log, l_res, sum_parity) } else if ax <= 12. { // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); const P: [(u64, u64); 10] = [ (0x3ca9a6c909e67304, 0x400c83f8e5e68934), (0xbcc3a71a296d1f00, 0x40278d8a2abd6aec), (0xbca623fa8857b35a, 0xc0144dd0190486d6), (0x3cc1845532bca122, 0xc02920aaae63c5a7), (0x3c57111721fd9df2, 0xbfc9a27952cac38f), (0xbca78a77f8acae38, 0x400043078ac20503), (0xbc721a88d770af7e, 0x3fdbeba4a1a95bfd), (0xbc09c9e5917a665e, 0x3f9e18ff2504fd11), (0xbbeb6e5c1cdf8c87, 0x3f45b0595f7eb903), (0xbaf149d407d419d3, 0x3ecf5336ddb96b5f), ]; let p0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[1]), dx, DoubleDouble::from_bit_pair(P[0]), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[3]), dx, DoubleDouble::from_bit_pair(P[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[5]), dx, DoubleDouble::from_bit_pair(P[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[7]), dx, DoubleDouble::from_bit_pair(P[6]), ); let p4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(P[9]), dx, DoubleDouble::from_bit_pair(P[8]), ); let q0 = DoubleDouble::mul_add(x2, p1, p0); let q1 = DoubleDouble::mul_add(x2, p3, p2); let r0 = DoubleDouble::mul_add(x4, q1, q0); let p_num = DoubleDouble::mul_add(x8, p4, r0); const Q: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3cc5e0cfc2a3ed2f, 0x4023561fd4efbbb2), (0x3c829f67da778215, 0x403167ff0d04f99a), (0x3ca3c8e7b81b165f, 0x4024f2d3c7d9439f), (0xbca90199265d1bfc, 0x40045530db97bad5), (0xbc3e89169d10977f, 0x3fd0d9f46084a388), (0x3c1c2b7582566435, 0x3f872f7f248227bd), (0x3ba8f3f0294e144f, 0x3f271e198971c58e), (0x3b4d13ceca0a9bf7, 0x3ea62e85cd267c65), (0xba896f9fc0c4f644, 0xbde99e5ee24ff6ba), ]; let p0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[1]), dx, DoubleDouble::from_bit_pair(Q[0]), ); let p1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[3]), dx, DoubleDouble::from_bit_pair(Q[2]), ); let p2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[5]), dx, DoubleDouble::from_bit_pair(Q[4]), ); let p3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(Q[7]), dx, DoubleDouble::from_bit_pair(Q[6]), ); let p4 = DoubleDouble::f64_mul_f64_add( f64::from_bits(0xbde99e5ee24ff6ba), //Q[9].hi dx, DoubleDouble::from_bit_pair(Q[8]), ); let q0 = DoubleDouble::mul_add(x2, p1, p0); let q1 = DoubleDouble::mul_add(x2, p3, p2); let r0 = DoubleDouble::mul_add(x4, q1, q0); let p_den = DoubleDouble::mul_add(x8, p4, r0); let l_res = f_res; f_res = apply_sign_and_sum_quick(DoubleDouble::div(p_num, p_den), sum_parity, f_res); let err = f_fmla( f_res.hi.abs(), f64::from_bits(0x3c50000000000000), // 2^-58 f64::from_bits(0x3bd0000000000000), // 2^-66 ); let ub = f_res.hi + (f_res.lo + err); let lb = f_res.hi + (f_res.lo - err); if ub == lb { return f_res.to_f64(); } lgamma_4_to_12(dx, l_res, sum_parity) } else { // Stirling's approximation of Log(Gamma) and then Exp[Log[Gamma]] let y_recip = DoubleDouble::from_quick_recip(dx); let y_sqr = DoubleDouble::mult(y_recip, y_recip); // Bernoulli coefficients generated by SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / (2*k*(2*k-1))) * x**((2*k-1)) // S += term // return S // // terms = bernoulli_terms(x, 7) let bernoulli_poly_s = f_polyeval6( y_sqr.hi, f64::from_bits(0xbf66c16c16c16c17), f64::from_bits(0x3f4a01a01a01a01a), f64::from_bits(0xbf43813813813814), f64::from_bits(0x3f4b951e2b18ff23), f64::from_bits(0xbf5f6ab0d9993c7d), f64::from_bits(0x3f7a41a41a41a41a), ); let bernoulli_poly = DoubleDouble::mul_f64_add( y_sqr, bernoulli_poly_s, DoubleDouble::from_bit_pair((0x3c55555555555555, 0x3fb5555555555555)), ); // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms const LOG2_PI_OVER_2: DoubleDouble = DoubleDouble::from_bit_pair((0xbc865b5a1b7ff5df, 0x3fed67f1c864beb5)); let mut log_gamma = DoubleDouble::add( DoubleDouble::mul_add_f64(bernoulli_poly, y_recip, -dx), LOG2_PI_OVER_2, ); let dy_log = fast_log_d_to_dd(dx); log_gamma = DoubleDouble::mul_add( DoubleDouble::from_exact_add(dy_log.hi, dy_log.lo), DoubleDouble::from_full_exact_add(dx, -0.5), log_gamma, ); let l_res = f_res; f_res = apply_sign_and_sum_quick(log_gamma, sum_parity, f_res); let err = f_fmla( f_res.hi.abs(), f64::from_bits(0x3c30000000000000), // 2^-60 f64::from_bits(0x3bc0000000000000), // 2^-67 ); let ub = f_res.hi + (f_res.lo + err); let lb = f_res.hi + (f_res.lo - err); if ub == lb { return f_res.to_f64(); } stirling_accurate(dx, sum_parity, l_res) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_lgamma() { assert_eq!(f_lgamma(-4.039410591125488), -0.001305303022594149); assert_eq!(f_lgamma(-2.000001907348633), 12.47664749001284); assert_eq!( f_lgamma(0.0000000000000006939032951805219), 34.90419906721559 ); assert_eq!(f_lgamma(0.9743590354901843), 0.01534797880086699); assert_eq!(f_lgamma(1.9533844296518055), -0.019000687007583488); assert_eq!(f_lgamma(1.9614259600725743), -0.015824770893504085); assert_eq!(f_lgamma(1.961426168688831), -0.015824687947423532); assert_eq!(f_lgamma(2.0000000026484486), 0.0000000011197225706325235); assert_eq!(f_lgamma(f64::INFINITY), f64::INFINITY); assert!(f_lgamma(f64::NAN).is_nan()); // assert_eq!(f_lgamma(1.2902249255008019e301), // 8932652024571557000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!( f_lgamma(2.000000000000014), 0.000000000000006008126761947661 ); assert_eq!(f_lgamma(-2.74999999558122), 0.004487888879321723); assert_eq!( f_lgamma(0.00000000000001872488985570349), 31.608922747730112 ); assert_eq!(f_lgamma(-2.7484742253727745), 0.0015213685011468314); assert_eq!(f_lgamma(0.9759521409866919), 0.014362097695996162); } } pxfm-0.1.23/src/gamma/lgammaf.rs000064400000000000000000000240631046102023000145110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::logs::{fast_logf, simple_fast_log}; use crate::polyeval::{f_polyeval3, f_polyeval5, f_polyeval7, f_polyeval8}; use crate::sin_cosf::fast_sinpif; /// Computes log(gamma(x)) /// /// ulp 0.5 pub fn f_lgammaf(x: f32) -> f32 { if (x.to_bits() & 0x0007_ffff) == 0 { if x.is_infinite() { return f32::INFINITY; } if x.is_nan() { return f32::NAN; } if x == 0. { return 1. / x; } } if x.floor() == x { if x == 2. || x == 1. { return 0.; } if x.is_sign_negative() { return f32::INFINITY; } } let ax = f32::from_bits(x.to_bits() & 0x7fff_ffff); let dx = ax as f64; let is_positive = x.is_sign_positive(); let mut sum_parity = 1f64; let mut f_res = 0f64; // 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); if !is_positive { let y1 = ax.floor(); let fraction = ax - y1; // excess over the boundary let a = fast_sinpif(fraction); sum_parity = -1.; const LOG_PI: f64 = f64::from_bits(0x3ff250d048e7a1bd); f_res = LOG_PI - simple_fast_log(a * dx); } if ax <= 0.007 { // Log[Gamma(x)] = -x.log() - euler * x + (zeta(2)/2)*x^2 - (zeta(3)/3)*x^3 let fp = f_polyeval3( dx, f64::from_bits(0xbfe2788cfc6fb619), f64::from_bits(0x3fea51a6625307d3), f64::from_bits(0xbfd9a4d55beab2d7), ); let d_log = simple_fast_log(dx); let log_gamma = f_fmla(fp, dx, -d_log); f_res = f_fmla(log_gamma, sum_parity, f_res); } else if ax < 1. { // Poly for loggamma(x + 1) - log(x) generated by Wolfram Mathematica // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let num = f_polyeval7( dx, f64::from_bits(0xbd24e4cf78c8818a), f64::from_bits(0xbfe2788cfc6f64e6), f64::from_bits(0xbfe1ea632fe853b2), f64::from_bits(0x3fd988d2daad3806), f64::from_bits(0x3fe1f4870eaafdf4), f64::from_bits(0x3fc51e12d5b97330), f64::from_bits(0x3f889ebeb9f0c8ff), ); let den = f_polyeval7( dx, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4003289872066f33), f64::from_bits(0x4000373d88c32fe5), f64::from_bits(0x3fe71e95bc874164), f64::from_bits(0x3fb9936a0e008be7), f64::from_bits(0x3f6cba20a1988a60), f64::from_bits(0xbef3ca884ba4237a), ); f_res = f_fmla(num / den - fast_logf(ax), sum_parity, f_res); } else if ax <= 4. { // Poly for loggamma(x + 1) - log(x) generated by Wolfram Mathematica // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let num = f_polyeval8( dx, f64::from_bits(0xbe630847302a205f), f64::from_bits(0xbfe2788c24a7deff), f64::from_bits(0xbfdd0f61b8171907), f64::from_bits(0x3fdab4ec27801e42), f64::from_bits(0x3fde11fd49427a3c), f64::from_bits(0x3fc0dbce39c660da), f64::from_bits(0x3f88e0b4cd3e97f7), f64::from_bits(0x3f328fcd9e9ee94e), ); let den = f_polyeval8( dx, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4001b135a31bffae), f64::from_bits(0x3ffbbecb5e39f4ea), f64::from_bits(0x3fe2e4da095d10bd), f64::from_bits(0x3fb63cb7548d0d30), f64::from_bits(0x3f73a67613163399), f64::from_bits(0x3f10edd4e2b80e6f), f64::from_bits(0xbe77f4e4068f9d32), ); f_res = f_fmla(num / den - fast_logf(ax), sum_parity, f_res); } else if ax <= 12. { // Poly for loggamma(x) generated by Wolfram Mathematica // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let num = f_polyeval8( dx, f64::from_bits(0x40086069fcc21690), f64::from_bits(0x4008c8ef8602e78d), f64::from_bits(0xc0186323149757ae), f64::from_bits(0xbff6a9ded42d3f31), f64::from_bits(0x3ff1adb5566cd807), f64::from_bits(0x3fcff023390dead6), f64::from_bits(0x3f8977a5454ec393), f64::from_bits(0x3f21361088f694dc), ); let den = f_polyeval8( dx, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4016096b397dbe73), f64::from_bits(0x401478926593a395), f64::from_bits(0x3ff6a931f9e31511), f64::from_bits(0x3fc0fbe57bf263a4), f64::from_bits(0x3f7023f51ba39a98), f64::from_bits(0x3efabd75ebfbde40), f64::from_bits(0xbe4b2c9e2e4e7daa), ); f_res = f_fmla(num / den, sum_parity, f_res); } else { // Stirling's approximation of Log(Gamma) and then Exp[Log[Gamma]] let y_recip = 1. / dx; let y_sqr = y_recip * y_recip; // Bernoulli coefficients generated by SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / (2*k*(2*k-1))) * x**((2*k-1)) // S += term // return S // // terms = bernoulli_terms(x, 5) let bernoulli_poly = f_polyeval5( y_sqr, f64::from_bits(0x3fb5555555555555), f64::from_bits(0xbf66c16c16c16c17), f64::from_bits(0x3f4a01a01a01a01a), f64::from_bits(0xbf43813813813814), f64::from_bits(0x3f4b951e2b18ff23), ); // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms const LOG2_PI_OVER_2: f64 = f64::from_bits(0x3fed67f1c864beb5); let mut log_gamma = f_fmla(bernoulli_poly, y_recip, -dx) + LOG2_PI_OVER_2; log_gamma = f_fmla(fast_logf(ax), dx - 0.5, log_gamma); f_res = f_fmla(log_gamma, sum_parity, f_res); } f_res as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_lgammaf() { assert_eq!( f_lgammaf(0.000000000000000000000000000000000000000015425), 93.97255 ); assert_eq!(f_lgammaf(1.7506484), -0.0842405); assert_eq!(f_lgammaf(7.095007e-8), 16.461288); assert!(f_lgammaf(-12.).is_infinite()); assert_eq!(f_lgammaf(2.), 0.); assert_eq!(f_lgammaf(1.), 0.); assert_eq!(f_lgammaf(0.53), 0.5156078); assert_eq!(f_lgammaf(1.53), -0.11927056); assert_eq!(f_lgammaf(4.53), 2.4955146); assert_eq!(f_lgammaf(11.77), 16.94281); assert_eq!(f_lgammaf(22.77), 47.756233); assert_eq!(f_lgammaf(-0.53), 1.2684484); assert_eq!(f_lgammaf(-1.53), 0.84318066); assert_eq!(f_lgammaf(-4.53), -2.8570588); assert_eq!(f_lgammaf(-11.77), -17.850103); assert_eq!(f_lgammaf(-22.77), -49.323418); assert_eq!(f_lgammaf(f32::NEG_INFINITY), f32::INFINITY); } } pxfm-0.1.23/src/gamma/mod.rs000064400000000000000000000037271046102023000136700ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod digamma; mod digamma_coeffs; mod digammaf; mod lgamma; mod lgammaf; mod tgamma; mod tgammaf; mod trigamma; mod trigammaf; pub use digamma::f_digamma; pub use digammaf::f_digammaf; pub use lgamma::f_lgamma; pub use lgammaf::f_lgammaf; pub use tgamma::f_tgamma; pub use tgammaf::f_tgammaf; pub use trigamma::f_trigamma; pub use trigammaf::f_trigammaf; pxfm-0.1.23/src/gamma/tgamma.rs000064400000000000000000000313711046102023000143530ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::fast_log_dd; use crate::polyeval::{f_polyeval6, f_polyeval7, f_polyeval8}; use crate::pow_exec::exp_dd_fast; use crate::sincospi::f_fast_sinpi_dd; /// Computes gamma(x) /// /// ulp 1 pub fn f_tgamma(x: f64) -> f64 { let x_a = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); if !x.is_normal() { if x == 0.0 { return 1. / x; } if x.is_nan() { return x + x; } if x.is_infinite() { if x.is_sign_negative() { return f64::NAN; } return x; } } if x >= 171.624 { return f64::INFINITY; } if x.floor() == x { if x < 0. { return f64::NAN; } if x < 38. { let mut t = DoubleDouble::new(0., 1.); let k = x as i64; let mut x0 = 1.0; for _i in 1..k { t = DoubleDouble::quick_mult_f64(t, x0); t = DoubleDouble::from_exact_add(t.hi, t.lo); x0 += 1.0; } return t.to_f64(); } } if x <= -184.0 { /* negative non-integer */ /* For x <= -184, x non-integer, |gamma(x)| < 2^-1078. */ static SIGN: [f64; 2] = [ f64::from_bits(0x0010000000000000), f64::from_bits(0x8010000000000000), ]; let k = x as i64; return f64::from_bits(0x0010000000000000) * SIGN[((k & 1) != 0) as usize]; } const EULER_DD: DoubleDouble = DoubleDouble::from_bit_pair((0xbc56cb90701fbfab, 0x3fe2788cfc6fb619)); if x_a < 0.006 { if x_a.to_bits() < (0x71e0000000000000u64 >> 1) { // |x| < 0x1p-112 return 1. / x; } if x_a < 2e-10 { // x is tiny then Gamma(x) = 1/x - euler let p = DoubleDouble::full_dd_sub(DoubleDouble::from_quick_recip(x), EULER_DD); return p.to_f64(); } else if x_a < 2e-6 { // x is small then Gamma(x) = 1/x - euler + a2*x // a2 = 1/12 * (6 * euler^2 + pi^2) const A2: DoubleDouble = DoubleDouble::from_bit_pair((0x3c8dd92b465a8221, 0x3fefa658c23b1578)); let rcp = DoubleDouble::from_quick_recip(x); let p = DoubleDouble::full_dd_add(DoubleDouble::mul_f64_add(A2, x, -EULER_DD), rcp); return p.to_f64(); } // Laurent series of Gamma(x) const C: [(u64, u64); 8] = [ (0x3c8dd92b465a8221, 0x3fefa658c23b1578), (0x3c53a4f483760950, 0xbfed0a118f324b63), (0x3c7fabe4f7369157, 0x3fef6a51055096b5), (0x3c8c9fc795fc6142, 0xbfef6c80ec38b67b), (0xbc5042339d62e721, 0x3fefc7e0a6eb310b), (0xbc86fd0d8bdc0c1e, 0xbfefdf3f157b7a39), (0xbc89b912df09395d, 0x3feff07b5a17ff6c), (0x3c4e626faf780ff9, 0xbfeff803d68a0bd4), ]; let rcp = DoubleDouble::from_quick_recip(x); let mut p = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(C[7]), x, DoubleDouble::from_bit_pair(C[6]), ); p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[5])); p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[4])); p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[0])); let z = DoubleDouble::mul_f64_add(p, x, DoubleDouble::full_dd_sub(rcp, EULER_DD)); return z.to_f64(); } let mut fact = DoubleDouble::new(0., 0.0f64); let mut parity = 1.0; const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18)); let mut dy = DoubleDouble::new(0., x); let mut result: DoubleDouble; // reflection if dy.hi < 0. { if dy.hi.floor() == dy.hi { return f64::NAN; } dy.hi = f64::from_bits(dy.hi.to_bits() & 0x7fff_ffff_ffff_ffff); let y1 = x_a.floor(); let fraction = x_a - y1; if fraction != 0.0 // is it an integer? { // is it odd or even? if y1 != (y1 * 0.5).trunc() * 2.0 { parity = -1.0; } fact = DoubleDouble::div(-PI, f_fast_sinpi_dd(fraction)); fact = DoubleDouble::from_exact_add(fact.hi, fact.lo); dy = DoubleDouble::from_full_exact_add(dy.hi, 1.0); } } if dy.hi < 12.0 { let y1 = dy; let z: DoubleDouble; let mut n = 0; // x is in (0.06, 1.0). if dy.hi < 1.0 { z = dy; dy = DoubleDouble::full_add_f64(dy, 1.0); } else // x is in [1.0, max]. { n = dy.hi as i32 - 1; dy = DoubleDouble::full_add_f64(dy, -n as f64); z = DoubleDouble::full_add_f64(dy, -1.0); } // Gamma(x+1) on [1;2] generated by Wolfram Mathematica: // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let ps_num = f_polyeval8( z.hi, f64::from_bits(0x3fb38b80568a42aa), f64::from_bits(0xbf8e7685b00d63a6), f64::from_bits(0xbf80629ed2c48f1a), f64::from_bits(0xbf6dfc4cdbcee96a), f64::from_bits(0xbf471816939dc42b), f64::from_bits(0xbf24bede7d8b3c20), f64::from_bits(0xbeef56936d891e42), f64::from_bits(0xbec3e2b405350813), ); let mut p_num = DoubleDouble::mul_f64_add( z, ps_num, DoubleDouble::from_bit_pair((0xbc700f441aea2edb, 0x3fd218bdde7878b8)), ); p_num = DoubleDouble::mul_add( z, p_num, DoubleDouble::from_bit_pair((0x3b7056a45a2fa50e, 0x3ff0000000000000)), ); p_num = DoubleDouble::from_exact_add(p_num.hi, p_num.lo); let ps_den = f_polyeval7( z.hi, f64::from_bits(0xbfdaa4f09f0caab1), f64::from_bits(0xbfc960ba48423f9d), f64::from_bits(0x3fb6873b64e8ccd6), f64::from_bits(0x3f69ea1ca5b8a225), f64::from_bits(0xbf77b166f68a2e63), f64::from_bits(0x3f4fd1eff9193728), f64::from_bits(0xbf0c1a43f4985c97), ); let mut p_den = DoubleDouble::mul_f64_add( z, ps_den, DoubleDouble::from_bit_pair((0xbc759594c51ad8b7, 0x3feb84ebebabf275)), ); p_den = DoubleDouble::mul_add_f64(z, p_den, f64::from_bits(0x3ff0000000000000)); p_den = DoubleDouble::from_exact_add(p_den.hi, p_den.lo); result = DoubleDouble::div(p_num, p_den); if y1.hi < dy.hi { result = DoubleDouble::div(result, y1); } else if y1.hi > dy.hi { for _ in 0..n { result = DoubleDouble::mult(result, dy); dy = DoubleDouble::full_add_f64(dy, 1.0); } } } else { if x > 171.624e+0 { return f64::INFINITY; } // Stirling's approximation of Log(Gamma) and then Exp[Log[Gamma]] let y_recip = dy.recip(); let y_sqr = DoubleDouble::mult(y_recip, y_recip); // Bernoulli coefficients generated by SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / (2*k*(2*k-1))) * x**((2*k-1)) // S += term // return S // // terms = bernoulli_terms(x, 7) let bernoulli_poly_s = f_polyeval6( y_sqr.hi, f64::from_bits(0xbf66c16c16c16c17), f64::from_bits(0x3f4a01a01a01a01a), f64::from_bits(0xbf43813813813814), f64::from_bits(0x3f4b951e2b18ff23), f64::from_bits(0xbf5f6ab0d9993c7d), f64::from_bits(0x3f7a41a41a41a41a), ); let bernoulli_poly = DoubleDouble::mul_f64_add( y_sqr, bernoulli_poly_s, DoubleDouble::from_bit_pair((0x3c55555555555555, 0x3fb5555555555555)), ); // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms const LOG2_PI_OVER_2: DoubleDouble = DoubleDouble::from_bit_pair((0xbc865b5a1b7ff5df, 0x3fed67f1c864beb5)); let mut log_gamma = DoubleDouble::add( DoubleDouble::mul_add(bernoulli_poly, y_recip, -dy), LOG2_PI_OVER_2, ); let dy_log = fast_log_dd(dy); log_gamma = DoubleDouble::mul_add( DoubleDouble::from_exact_add(dy_log.hi, dy_log.lo), DoubleDouble::add_f64(dy, -0.5), log_gamma, ); let log_prod = log_gamma.to_f64(); if log_prod >= 690. { // underflow/overflow case log_gamma = DoubleDouble::quick_mult_f64(log_gamma, 0.5); result = exp_dd_fast(log_gamma); let exp_result = result; result.hi *= parity; result.lo *= parity; if fact.lo != 0. && fact.hi != 0. { // y / x = y / (z*z) = y / z * 1/z result = DoubleDouble::from_exact_add(result.hi, result.lo); result = DoubleDouble::div(fact, result); result = DoubleDouble::div(result, exp_result); } else { result = DoubleDouble::quick_mult(result, exp_result); } let err = f_fmla( result.hi.abs(), f64::from_bits(0x3c20000000000000), // 2^-61 f64::from_bits(0x3bd0000000000000), // 2^-65 ); let ub = result.hi + (result.lo + err); let lb = result.hi + (result.lo - err); if ub == lb { return result.to_f64(); } return result.to_f64(); } result = exp_dd_fast(log_gamma); } if fact.lo != 0. && fact.hi != 0. { // y / x = y / (z*z) = y / z * 1/z result = DoubleDouble::from_exact_add(result.hi, result.lo); result = DoubleDouble::div(fact, result); } result.to_f64() * parity } #[cfg(test)] mod tests { use super::*; #[test] fn test_tgamma() { // assert_eq!(f_tgamma(6.757812502211891), 459.54924419209556); assert_eq!(f_tgamma(-1.70000000042915), 2.513923520668069); assert_eq!(f_tgamma(5.), 24.); assert_eq!(f_tgamma(24.), 25852016738884980000000.); assert_eq!(f_tgamma(6.4324324), 255.1369211339094); assert_eq!(f_tgamma(f64::INFINITY), f64::INFINITY); assert_eq!(f_tgamma(0.), f64::INFINITY); assert!(f_tgamma(f64::NAN).is_nan()); } } pxfm-0.1.23/src/gamma/tgammaf.rs000064400000000000000000000176441046102023000145300ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::f_exp; use crate::logs::simple_fast_log; use crate::polyeval::{f_polyeval5, f_polyeval18}; use crate::sin_cosf::fast_sinpif; /// True gamma function /// /// ulp 0.5 pub fn f_tgammaf(x: f32) -> f32 { let x_a = f32::from_bits(x.to_bits() & 0x7fff_ffff); if !x.is_normal() { if x == 0.0 { return 1. / x; } if x.is_nan() { return x + x; } if x.is_infinite() { if x.is_sign_negative() { return f32::NAN; } return x; } } if x.is_sign_positive() && x_a.to_bits() >= 0x420c2910u32 { // x >= 35.0401 return f32::INFINITY; } else if x.is_sign_negative() && x_a.to_bits() >= 0x421a67dau32 { // x <= -38.601418 if x == x.floor() { // integer where x < 0 return f32::NAN; } return -0.0; } if x_a < 2e-8 { // x is tiny then Gamma(x) = 1/x - euler const EULER: f64 = f64::from_bits(0x3fe2788cfc6fb619); let dx = x as f64; let p = 1. / dx - EULER; return p as f32; } else if x_a < 2e-6 { // x is small then Gamma(x) = 1/x - euler + a2*x // a2 = 1/12 * (6 * euler^2 + pi^2) const EULER: f64 = f64::from_bits(0x3fe2788cfc6fb619); const A2: f64 = f64::from_bits(0x3fefa658c23b1578); let dx = x as f64; let p = 1. / dx + f_fmla(dx, A2, -EULER); return p as f32; } let mut fact = 1.0f64; let mut parity = 1.0; const PI: f64 = f64::from_bits(0x400921fb54442d18); let mut dy = x as f64; let mut result; // reflection if dy < 0. { if dy.floor() == dy { return f32::NAN; } dy = f64::from_bits(dy.to_bits() & 0x7fff_ffff_ffff_ffff); // x < ulp(x) if x_a < f32::EPSILON { return (1. / x as f64) as f32; } let y1 = x_a.trunc(); let fraction = x_a - y1; if fraction != 0.0 // is it an integer? { // is it odd or even? if y1 != (y1 * 0.5).trunc() * 2.0 { parity = -1.0; } fact = -PI / fast_sinpif(fraction); dy += 1.0; } } if dy < 12.0 { let y1 = dy; let z; let mut n = 0; // x is in (eps, 1.0). if dy < 1.0 { z = dy; dy += 1.0; } else // x is in [1.0, max]. { n = dy as i32 - 1; dy -= n as f64; z = dy - 1.0; } // Gamma(x+1) on [1;2] generated by Wolfram Mathematica: // <90] // num=Numerator[approx][[1]]; // den=Denominator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]], {50,50}, ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] result = f_polyeval18( z, f64::from_bits(0x3fefffffffffff19), f64::from_bits(0xbfe2788cfc6d59a6), f64::from_bits(0x3fefa658c133abd2), f64::from_bits(0xbfed0a116184e1d0), f64::from_bits(0x3fef6a4cd2befb54), f64::from_bits(0xbfef6c4479fe9aca), f64::from_bits(0x3fefc59bfa97e9bf), f64::from_bits(0xbfefcfde03bfb0d9), f64::from_bits(0x3fefa3ee5eab6681), f64::from_bits(0xbfeed8130a67dd46), f64::from_bits(0x3fecb6e603fdb5ed), f64::from_bits(0xbfe8801e901b4c10), f64::from_bits(0x3fe2356219082d3e), f64::from_bits(0xbfd64ad556b6062a), f64::from_bits(0x3fc5219e235288f4), f64::from_bits(0xbfacad444cb0f4ec), f64::from_bits(0x3f888ea3bfa9155a), f64::from_bits(0xbf53d1776abc9eaa), ); if y1 < dy { result /= y1; } else if y1 > dy { for _ in 0..n { result *= dy; dy += 1.0; } } } else { // Stirling's approximation of Log(Gamma) and then Exp[Log[Gamma]] let y_recip = 1. / dy; let y_sqr = y_recip * y_recip; // Bernoulli coefficients generated by SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = (B / (2*k*(2*k-1))) * x**((2*k-1)) // S += term // return S // // terms = bernoulli_terms(x, 5) let bernoulli_poly = f_polyeval5( y_sqr, f64::from_bits(0x3fb5555555555555), f64::from_bits(0xbf66c16c16c16c17), f64::from_bits(0x3f4a01a01a01a01a), f64::from_bits(0xbf43813813813814), f64::from_bits(0x3f4b951e2b18ff23), ); // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms const LOG2_PI_OVER_2: f64 = f64::from_bits(0x3fed67f1c864beb5); let mut log_gamma = f_fmla(bernoulli_poly, y_recip, -dy) + LOG2_PI_OVER_2; log_gamma = f_fmla(simple_fast_log(dy), dy - 0.5, log_gamma); result = f_exp(log_gamma); } result *= parity; if fact != 1.0 { result = fact / result; } result as f32 } #[cfg(test)] mod tests { use crate::f_tgammaf; #[test] fn test_gammaf() { assert!(f_tgammaf(-3.).is_nan()); assert_eq!(f_tgammaf(12.58038769), 167149000.0); assert_eq!(f_tgammaf(4.566854e-7), 2189690.8); assert_eq!(f_tgammaf(4.9587783e-8), 20166258.0); assert_eq!(f_tgammaf(-46.1837), -0.0); assert_eq!(f_tgammaf(1.1502532e-19), 8.6937384e18); assert_eq!(f_tgammaf(0.04038769), 24.221333); assert_eq!(f_tgammaf(2.58038769), 1.4088479); assert_eq!(f_tgammaf(-1.3559477), 2.892815); assert_eq!(f_tgammaf(-2.3559477), -1.2278775); assert_eq!(f_tgammaf(0.0), f32::INFINITY); assert_eq!(f_tgammaf(-0.0), f32::NEG_INFINITY); assert_eq!(f_tgammaf(f32::INFINITY), f32::INFINITY); assert!(f_tgammaf(f32::NEG_INFINITY).is_nan()); assert!(f_tgammaf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/gamma/trigamma.rs000064400000000000000000000516571046102023000147170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::sincospi::f_fast_sinpi_dd; // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P_1: [(u64, u64); 12] = [ (0x3c81873d89121fec, 0x3ffa51a6625307d3), (0x3cb78bf7af507504, 0x4016a65cbac476ca), (0xbc94179c65e021c2, 0x40218234a0a79582), (0x3cb842a8ab5e0994, 0x401fde32175f8515), (0xbc8768b33f5776b7, 0x4012de6bde49abff), (0x3c8e06354a27f081, 0x3ffe5d6ef3a2eac6), (0xbc8b391d09fed17a, 0x3fe0d186688252cf), (0xbc59a5c46bb8b8cc, 0x3fb958f9a0f156b7), (0x3c2ac44c6a197244, 0x3f88e605f24e1a89), (0x3bd2d05fa8be27f2, 0x3f4cd369f5d68104), (0x3b84ad0a748fdd22, 0x3efde955ebb17874), (0xb96aa8b9a65e0899, 0xbce053d04459ead7), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx][[1]]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P_2: [(u64, u64); 12] = [ (0x3c81873d8912236c, 0x3ffa51a6625307d3), (0xbcbc731a62342288, 0x40176c23f7ea51e6), (0xbcc45a6fd00e67a8, 0x4022cb5ae67657ef), (0x3cc0876fde7fe4e6, 0x4021d766062b9550), (0xbcaec4a4859cba1d, 0x401629f91cd4f291), (0x3c76184014e4d7e3, 0x4002d43da3352004), (0x3c812c7609483e0e, 0x3fe62e3266eef8c7), (0xbc5f991047f52d2b, 0x3fc1eacb910b951c), (0x3c28b9f38d603f2f, 0x3f930960a301df34), (0x3bf9b620eb930504, 0x3f5814f8e057b14b), (0xbb990860b88b54e4, 0x3f0b9f67c71aa3bf), (0x38e5cb6acfbaab77, 0xbc4194b8c01afe9a), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // num=Numerator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static P_3: [(u64, u64); 12] = [ (0x3c9cd56dbb295efc, 0x3ffa51a662556db9), (0x3c9f4ee74f5f9daf, 0x4018ff913088cb34), (0x3ccf08737350609c, 0x402593d55686b8b1), (0xbcc6cd4ed33afebb, 0x402641d10de4def5), (0xbcb24d1957c1303c, 0x401e682c37e8e2cf), (0x3ca30ac79162ceb2, 0x400ccfc7c4566f55), (0x3c9efea5ff293dc9, 0x3ff33eb2c6e89d0b), (0x3c74670a11068abc, 0x3fd1fbf456e5c6f0), (0x3c47b5dcdea19c36, 0x3fa6a6a2148c482c), (0xbc14642012a1cc1e, 0x3f71851e927f52e7), (0x3bc7db88a4ec5478, 0x3f29a45059a43475), (0xb7bc31e55271eab0, 0xbb375518529c52fb), ]; // Generated in Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q_1: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbcb84c43a11fc28a, 0x40139d9587da0fb5), (0x3ca1cf3dbcddbb57, 0x402507cb6225f0f0), (0x3cb01aa6ddcc3cfd, 0x402a1b416d0ed4e6), (0xbcbc31c216b5ff66, 0x4024ec8829e535d4), (0xbcb335c23022f43e, 0x4016d2ba6d1a18e6), (0x3cafbfffc03ad28a, 0x400158c4611ed51f), (0xbc8d1fb10a031a27, 0x3fe26f15bb52f89b), (0x3c56a9fea160eecb, 0x3fbaec13f663049d), (0xbc2f4ee869ba9364, 0x3f89cde0500cd68f), (0x3be3f23afc9398b6, 0x3f4d4b0f4dcf3eb8), (0x3b67a3ed4795d33e, 0x3efde955eafac9c2), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx][[1]]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q_2: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc81a3e4e026b7b1, 0x401415d1a20a9339), (0x3cc279576dfe3ec9, 0x402627c1a95d33d2), (0x3c9a94b5cf0cae88, 0x402c724dc5cf4577), (0xbc8aa1fa0c3820a8, 0x4027b7a332bb07f4), (0xbc96968367088d66, 0x401b14376177bdd7), (0x3ca2d3dfa5847f4d, 0x4005b0511cd98f2c), (0xbc8cfad394d41dd1, 0x3fe877bc2d02c7f3), (0xbc51592b8ec81a92, 0x3fc31f52afc72b95), (0x3c2cbef277d587e9, 0x3f93cb2f0e574376), (0xbbfbb670fd94f6ba, 0x3f5883767f745a92), (0xbb931b04d74e5893, 0x3f0b9f67c71a60f3), ]; // Generated by Wolfram Mathematica: // <75,MaxIterations->100] // den=Denominator[approx]; // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] static Q_3: [(u64, u64); 12] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3cbafcb4b6d646d9, 0x40150b12a79fc9cf), (0x3c989ef814b8dd2a, 0x40288c1d26ffdca5), (0x3cb0282cfea9c473, 0x4030d737c893cd5f), (0x3cc955b8aaadb37d, 0x402e5c289b6de3e0), (0x3cb377161f8861d2, 0x4022fb66d87bd522), (0xbcb4b0e4cff46ad6, 0x4010e5d13c2a5907), (0xbc8824539e4b1bd6, 0x3ff58c8fe8f26fca), (0xbc7d34220d810ea0, 0x3fd36c1351f43e66), (0xbc4cbdbe85570017, 0x3fa7c1170466605e), (0xbc0c3afb98775c53, 0x3f71ebafd3e5e3b9), (0x3bc0b0b7f16afd0a, 0x3f29a45059a43475), ]; #[inline] fn approx_trigamma(x: f64) -> DoubleDouble { if x <= 10. { let (p, q) = if x <= 1. { (&P_1, &Q_1) } else if x <= 4. { (&P_2, &Q_2) } else { (&P_3, &Q_3) }; let x2 = DoubleDouble::from_exact_mult(x, x); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[1]), x, DoubleDouble::from_bit_pair(p[0]), ); let e1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[3]), x, DoubleDouble::from_bit_pair(p[2]), ); let e2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[5]), x, DoubleDouble::from_bit_pair(p[4]), ); let e3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[7]), x, DoubleDouble::from_bit_pair(p[6]), ); let e4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[9]), x, DoubleDouble::from_bit_pair(p[8]), ); let e5 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(p[11]), x, DoubleDouble::from_bit_pair(p[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); let rcp = DoubleDouble::from_quick_recip(x); let rcp2 = DoubleDouble::quick_mult(rcp, rcp); let e0 = DoubleDouble::mul_f64_add_f64( DoubleDouble::from_bit_pair(q[1]), x, f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[3]), x, DoubleDouble::from_bit_pair(q[2]), ); let e2 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[5]), x, DoubleDouble::from_bit_pair(q[4]), ); let e3 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[7]), x, DoubleDouble::from_bit_pair(q[6]), ); let e4 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[9]), x, DoubleDouble::from_bit_pair(q[8]), ); let e5 = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(q[11]), x, DoubleDouble::from_bit_pair(q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let q = DoubleDouble::div(p_num, p_den); let r = DoubleDouble::quick_dd_add(q, rcp2); return r; } // asymptotic expansion Trigamma[x] = 1/x + 1/x^2 + sum(Bernoulli(2*k)/x^(2*k + 1)) // Generated in SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = B*x**(-(2*k+1)) // S += term // return S // // terms = bernoulli_terms(x, 10) // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(0, 14): // c = terms.coefficient(x, -k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") const C: [(u64, u64); 10] = [ (0x3c65555555555555, 0x3fc5555555555555), (0xbc21111111111111, 0xbfa1111111111111), (0x3c38618618618618, 0x3f98618618618618), (0xbc21111111111111, 0xbfa1111111111111), (0xbc4364d9364d9365, 0x3fb364d9364d9365), (0xbc6981981981981a, 0xbfd0330330330330), (0xbc95555555555555, 0x3ff2aaaaaaaaaaab), (0xbcb7979797979798, 0xc01c5e5e5e5e5e5e), (0xbcac3b070ec1c3b0, 0x404b7c4f8f13e3c5), (0x3cc8d3018d3018d3, 0xc08088fe72cfe72d), ]; let rcp = DoubleDouble::from_quick_recip(x); let q = DoubleDouble::quick_mult(rcp, rcp); let q2 = DoubleDouble::quick_mult(q, q); let q4 = q2 * q2; let q8 = q4 * q4; let e0 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[1]), q, DoubleDouble::from_bit_pair(C[0]), ); let e1 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[3]), q, DoubleDouble::from_bit_pair(C[2]), ); let e2 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[5]), q, DoubleDouble::from_bit_pair(C[4]), ); let e3 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[7]), q, DoubleDouble::from_bit_pair(C[6]), ); let e4 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[9]), q, DoubleDouble::from_bit_pair(C[8]), ); let q0 = DoubleDouble::quick_mul_add(q2, e1, e0); let q1 = DoubleDouble::quick_mul_add(q2, e3, e2); let r0 = DoubleDouble::quick_mul_add(q4, q1, q0); let mut p = DoubleDouble::quick_mul_add(q8, e4, r0); let q_over_2 = DoubleDouble::quick_mult_f64(q, 0.5); p = DoubleDouble::quick_mult(p, q); p = DoubleDouble::quick_mult(p, rcp); p = DoubleDouble::quick_dd_add(q_over_2, p); p = DoubleDouble::quick_dd_add(p, rcp); p } #[inline] fn approx_trigamma_dd(x: DoubleDouble) -> DoubleDouble { if x.hi <= 10. { let (p, q) = if x.hi <= 1. { (&P_1, &Q_1) } else if x.hi <= 4. { (&P_2, &Q_2) } else { (&P_3, &Q_3) }; let x2 = DoubleDouble::quick_mult(x, x); let x4 = DoubleDouble::quick_mult(x2, x2); let x8 = DoubleDouble::quick_mult(x4, x4); let e0 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[1]), x, DoubleDouble::from_bit_pair(p[0]), ); let e1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[3]), x, DoubleDouble::from_bit_pair(p[2]), ); let e2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[5]), x, DoubleDouble::from_bit_pair(p[4]), ); let e3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[7]), x, DoubleDouble::from_bit_pair(p[6]), ); let e4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[9]), x, DoubleDouble::from_bit_pair(p[8]), ); let e5 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(p[11]), x, DoubleDouble::from_bit_pair(p[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_num = DoubleDouble::mul_add(x8, f2, g0); let rcp = x.recip(); let rcp2 = DoubleDouble::quick_mult(rcp, rcp); let e0 = DoubleDouble::mul_add_f64( DoubleDouble::from_bit_pair(q[1]), x, f64::from_bits(0x3ff0000000000000), ); let e1 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[3]), x, DoubleDouble::from_bit_pair(q[2]), ); let e2 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[5]), x, DoubleDouble::from_bit_pair(q[4]), ); let e3 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[7]), x, DoubleDouble::from_bit_pair(q[6]), ); let e4 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[9]), x, DoubleDouble::from_bit_pair(q[8]), ); let e5 = DoubleDouble::mul_add( DoubleDouble::from_bit_pair(q[11]), x, DoubleDouble::from_bit_pair(q[10]), ); let f0 = DoubleDouble::mul_add(x2, e1, e0); let f1 = DoubleDouble::mul_add(x2, e3, e2); let f2 = DoubleDouble::mul_add(x2, e5, e4); let g0 = DoubleDouble::mul_add(x4, f1, f0); let p_den = DoubleDouble::mul_add(x8, f2, g0); let q = DoubleDouble::div(p_num, p_den); let r = DoubleDouble::quick_dd_add(q, rcp2); return r; } // asymptotic expansion Trigamma[x] = 1/x + 1/x^2 + sum(Bernoulli(2*k)/x^(2*k + 1)) // Generated in SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = B*x**(-(2*k+1)) // S += term // return S // // terms = bernoulli_terms(x, 10) // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(0, 14): // c = terms.coefficient(x, -k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") const C: [(u64, u64); 10] = [ (0x3c65555555555555, 0x3fc5555555555555), (0xbc21111111111111, 0xbfa1111111111111), (0x3c38618618618618, 0x3f98618618618618), (0xbc21111111111111, 0xbfa1111111111111), (0xbc4364d9364d9365, 0x3fb364d9364d9365), (0xbc6981981981981a, 0xbfd0330330330330), (0xbc95555555555555, 0x3ff2aaaaaaaaaaab), (0xbcb7979797979798, 0xc01c5e5e5e5e5e5e), (0xbcac3b070ec1c3b0, 0x404b7c4f8f13e3c5), (0x3cc8d3018d3018d3, 0xc08088fe72cfe72d), ]; let rcp = x.recip(); let q = DoubleDouble::quick_mult(rcp, rcp); let q2 = DoubleDouble::quick_mult(q, q); let q4 = q2 * q2; let q8 = q4 * q4; let e0 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[1]), q, DoubleDouble::from_bit_pair(C[0]), ); let e1 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[3]), q, DoubleDouble::from_bit_pair(C[2]), ); let e2 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[5]), q, DoubleDouble::from_bit_pair(C[4]), ); let e3 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[7]), q, DoubleDouble::from_bit_pair(C[6]), ); let e4 = DoubleDouble::quick_mul_add( DoubleDouble::from_bit_pair(C[9]), q, DoubleDouble::from_bit_pair(C[8]), ); let q0 = DoubleDouble::quick_mul_add(q2, e1, e0); let q1 = DoubleDouble::quick_mul_add(q2, e3, e2); let r0 = DoubleDouble::quick_mul_add(q4, q1, q0); let mut p = DoubleDouble::quick_mul_add(q8, e4, r0); let q_over_2 = DoubleDouble::quick_mult_f64(q, 0.5); p = DoubleDouble::quick_mult(p, q); p = DoubleDouble::quick_mult(p, rcp); p = DoubleDouble::quick_dd_add(q_over_2, p); p = DoubleDouble::quick_dd_add(p, rcp); p } /// Computes the trigamma function ψ₁(x). /// /// The trigamma function is the second derivative of the logarithm of the gamma function. pub fn f_trigamma(x: f64) -> f64 { let xb = x.to_bits(); if !x.is_normal() { if x.is_infinite() { return if x.is_sign_negative() { f64::NEG_INFINITY } else { 0. }; } if x.is_nan() { return f64::NAN; } if xb == 0 { return f64::INFINITY; } } let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 52 { // |x| < 2^-52 let dx = x; return 1. / (dx * dx); } if x < 0. { if x.floor() == x { return f64::INFINITY; } // reflection formula // Trigamma[1-x] + Trigamma[x] = PI^2 / sinpi^2(x) const SQR_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3cc692b71366cc05, 0x4023bd3cc9be45de)); // pi^2 let sinpi_ax = f_fast_sinpi_dd(-x); let dx = DoubleDouble::from_full_exact_sub(1., x); let result = DoubleDouble::div(SQR_PI, DoubleDouble::quick_mult(sinpi_ax, sinpi_ax)); let trigamma_x = approx_trigamma_dd(dx); return DoubleDouble::quick_dd_sub(result, trigamma_x).to_f64(); } approx_trigamma(x).to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_trigamma() { assert_eq!(f_trigamma(-27.058018), 300.35629698636757); assert_eq!(f_trigamma(27.058018), 0.037648965757704725); assert_eq!(f_trigamma(8.058018), 0.13211796975281037); assert_eq!(f_trigamma(-8.058018), 300.2758629255111); assert_eq!(f_trigamma(2.23432), 0.5621320243666134); assert_eq!(f_trigamma(-2.4653), 9.653674003034206); assert_eq!(f_trigamma(0.123541), 66.91128231455282); assert_eq!(f_trigamma(-0.54331), 9.154415950366596); assert_eq!(f_trigamma(-5.), f64::INFINITY); assert_eq!(f_trigamma(f64::INFINITY), 0.0); assert_eq!(f_trigamma(f64::NEG_INFINITY), f64::NEG_INFINITY); assert!(f_trigamma(f64::NAN).is_nan()); } } pxfm-0.1.23/src/gamma/trigammaf.rs000064400000000000000000000244671046102023000150640ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::{f_polyeval6, f_polyeval10}; use crate::sin_cosf::fast_sinpif; #[inline] fn approx_trigamma(x: f64) -> f64 { if x <= 1. { // Polynomial for Trigamma[x+1] // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval10( x, f64::from_bits(0x3ffa51a6625307d3), f64::from_bits(0x40142fc9c4f02b3f), f64::from_bits(0x401b30a762805b44), f64::from_bits(0x4014dc84c95656bd), f64::from_bits(0x4003e44f4c820b4c), f64::from_bits(0x3fe81f37523197d3), f64::from_bits(0x3fc22bffe2490221), f64::from_bits(0x3f8f221a6329ea36), f64::from_bits(0x3f47406930b9563c), f64::from_bits(0xbd99cd44c6ad497a), ); let p_den = f_polyeval10( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x40121e3db4e0a2f3), f64::from_bits(0x40218e97a5430c4f), f64::from_bits(0x402329897737b159), f64::from_bits(0x401a0fdc27807c2d), f64::from_bits(0x4006ff242e1f3a51), f64::from_bits(0x3fea6eda129c4e85), f64::from_bits(0x3fc32700b2ae2e88), f64::from_bits(0x3f8fdc1dc6116d41), f64::from_bits(0x3f4740690261cfbc), ); return p_num / p_den + 1. / (x * x); } else if x <= 4. { // Polynomial for Trigamma[x+1] // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval10( x, f64::from_bits(0x3ffa51a6625307d3), f64::from_bits(0x4015167fa2d2b5a8), f64::from_bits(0x401dd40865d5985e), f64::from_bits(0x4018353d9425fb58), f64::from_bits(0x4008a12aa45851fa), f64::from_bits(0x3ff018736d0c5dbe), f64::from_bits(0x3fca715702bdb519), f64::from_bits(0x3f9908a9d73d983c), f64::from_bits(0x3f54fd9cbbb46314), f64::from_bits(0xbd00b8a28c578ab5), ); let p_den = f_polyeval10( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4012aa7f041a768b), f64::from_bits(0x4022c2604e5f9c7a), f64::from_bits(0x4025655b63c2db22), f64::from_bits(0x401eaa8e59c8295d), f64::from_bits(0x400cc8724a58809c), f64::from_bits(0x3ff1c7a91c8e3c40), f64::from_bits(0x3fcc05613a11183e), f64::from_bits(0x3f99b096bd3ce542), f64::from_bits(0x3f54fd9cbb9c6167), ); return p_num / p_den + 1. / (x * x); } else if x <= 10. { // Polynomial for Trigamma[x+1] // <75,MaxIterations->100] // num=Numerator[approx]; // den=Denominator[approx]; // poly=num; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] // poly=den; // coeffs=CoefficientList[poly,z]; // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]] let p_num = f_polyeval10( x, f64::from_bits(0x3ffa51a664b1b211), f64::from_bits(0x4016d7f75881312a), f64::from_bits(0x4021b10defb47bcc), f64::from_bits(0x401fe9633665e1bf), f64::from_bits(0x4012601cce6766d7), f64::from_bits(0x3ffbd0ece1c435f1), f64::from_bits(0x3fdb3fd0e233c485), f64::from_bits(0x3faffdedea90b870), f64::from_bits(0x3f71a4bbf0d00147), f64::from_bits(0xbc0aae286498a357), ); let p_den = f_polyeval10( x, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x4013bbbd604d685d), f64::from_bits(0x40253a4fca05438e), f64::from_bits(0x402a4aba4634f14f), f64::from_bits(0x4024cdd23bd6284a), f64::from_bits(0x4015fbe371275c3f), f64::from_bits(0x3fff4d7ebf7d1ed0), f64::from_bits(0x3fdd459154d7bc72), f64::from_bits(0x3fb08c1cd4cedca3), f64::from_bits(0x3f71a4bbf0d0012d), ); return p_num / p_den + 1. / (x * x); } // asymptotic expansion Trigamma[x] = 1/x + 1/x^2 + sum(Bernoulli(2*k)/x^(2*k + 1)) // Generated in SageMath: // var('x') // def bernoulli_terms(x, N): // S = 0 // for k in range(1, N+1): // B = bernoulli(2*k) // term = B*x**(-(2*k+1)) // S += term // return S // // terms = bernoulli_terms(x, 7) // coeffs = [RealField(150)(terms.coefficient(x, n)) for n in range(0, terms.degree(x)+1, 1)] // for k in range(0, 14): // c = terms.coefficient(x, -k) # coefficient of x^(-k) // if c == 0: // continue // print("f64::from_bits(" + double_to_hex(c) + "),") let r = 1. / x; let r2 = r * r; let p = f_polyeval6( r2, f64::from_bits(0x3fc5555555555555), f64::from_bits(0xbfa1111111111111), f64::from_bits(0x3f98618618618618), f64::from_bits(0xbfa1111111111111), f64::from_bits(0x3fb364d9364d9365), f64::from_bits(0xbfd0330330330330), ); f_fmla(p, r2 * r, f_fmla(r2, 0.5, r)) } /// Computes the trigamma function ψ₁(x). /// /// The trigamma function is the second derivative of the logarithm of the gamma function. pub fn f_trigammaf(x: f32) -> f32 { let xb = x.to_bits(); if !x.is_normal() { if x.is_infinite() { return if x.is_sign_negative() { f32::NEG_INFINITY } else { 0. }; } if x.is_nan() { return f32::NAN; } if xb == 0 { return f32::INFINITY; } } let ax = x.to_bits() & 0x7fff_ffff; if ax <= 0x34000000u32 { // |x| < f32::EPSILON let dx = x as f64; return (1. / (dx * dx)) as f32; } let mut dx = x as f64; let mut result = 0.; let mut sum_parity: f64 = 1.0; if x < 0. { // singularity at negative integers if x.floor() == x { return f32::INFINITY; } // reflection formula // Trigamma[1-x] + Trigamma[x] = PI^2 / sinpi^2(x) const SQR_PI: f64 = f64::from_bits(0x4023bd3cc9be45de); // pi^2 let sinpi_ax = fast_sinpif(-x); dx = 1. - dx; result = SQR_PI / (sinpi_ax * sinpi_ax); sum_parity = -1.; } let r = approx_trigamma(dx) * sum_parity; result += r; result as f32 } #[cfg(test)] mod tests { use crate::f_trigammaf; #[test] fn test_trigamma() { assert_eq!(f_trigammaf(-27.058018), 300.35904); assert_eq!(f_trigammaf(27.058018), 0.037648965); assert_eq!(f_trigammaf(8.058018), 0.13211797); assert_eq!(f_trigammaf(-8.058018), 300.27863); assert_eq!(f_trigammaf(2.23432), 0.56213206); assert_eq!(f_trigammaf(-2.4653), 9.653673); assert_eq!(f_trigammaf(0.123541), 66.911285); assert_eq!(f_trigammaf(-0.54331), 9.154416); assert_eq!(f_trigammaf(-5.), f32::INFINITY); assert_eq!(f_trigammaf(f32::INFINITY), 0.0); assert_eq!(f_trigammaf(f32::NEG_INFINITY), f32::NEG_INFINITY); assert!(f_trigammaf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/hyperbolic/acosh.rs000064400000000000000000000605521046102023000152630ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; pub(crate) static ACOSH_ASINH_LL: [[(u64, u64, u64); 17]; 4] = [ [ (0x0000000000000000, 0x0000000000000000, 0x0000000000000000), (0x3f962e432b240000, 0xbd5745af34bb54b8, 0xb9e17e3ec05cde70), (0x3fa62e42e4a80000, 0x3d3111a4eadf3120, 0x3a2cff3027abb119), (0x3fb0a2b233f10000, 0xbd588ac4ec78af80, 0x3a24fa087ca75dfd), (0x3fb62e43056c0000, 0x3d16bd65e8b0b700, 0xba0b18e160362c24), (0x3fbbb9d3cbd60000, 0x3d5de14aa55ec2b0, 0xba1c6ac3f1862a6b), (0x3fc0a2b244da0000, 0x3d594def487fea70, 0xba1dead1a4581acf), (0x3fc3687aa9b78000, 0x3d49cec9a50db220, 0x3a234a70684f8e0e), (0x3fc62e42faba0000, 0xbd3d69047a3aeb00, 0xba04e061f79144e2), (0x3fc8f40b56d28000, 0x3d5de7d755fd2e20, 0x3a1bdc7ecf001489), (0x3fcbb9d3b61f0000, 0x3d1c14f1445b1200, 0x3a2a1d78cbdc5b58), (0x3fce7f9c11f08000, 0xbd46e3e0000dae70, 0x3a16a4559fadde98), (0x3fd0a2b242ec4000, 0x3d5bb7cf852a5fe8, 0x3a2a6aef11ee43bd), (0x3fd205966c764000, 0x3d2ad3a5f2142940, 0x3a25cc344fa10652), (0x3fd3687a98aac000, 0x3d21623671842f00, 0xba10b428fe1f9e43), (0x3fd4cb5ec93f4000, 0x3d53d50980ea5130, 0x3a267f0ea083b1c4), (0x3fd62e42fefa4000, 0xbd38432a1b0e2640, 0x3a2803f2f6af40f3), ], [ (0x0000000000000000, 0x0000000000000000, 0x0000000000000000), (0x3f562e462b400000, 0x3d5061d003b97318, 0x3a2d7faee66a2e1e), (0x3f662e44c9200000, 0x3d595a7bff5e2390, 0xba0f7e788a871350), (0x3f70a2b1e3300000, 0x3d42a3a1a65aa3a0, 0xba254599c9605442), (0x3f762e4367c00000, 0xbd24a995b6d9ddc0, 0xb9b56bb79b254f33), (0x3f7bb9d449a00000, 0x3d58a119c42e9bc0, 0xba28ecf7d8d661f1), (0x3f80a2b1f1900000, 0x3d58863771bd10a8, 0x3a1e9731de7f0155), (0x3f83687ad1100000, 0x3d5e026a347ca1c8, 0x39efadc62522444d), (0x3f862e436f280000, 0x3d525b84f71b70b8, 0xb9ffcb3f98612d27), (0x3f88f40b7b380000, 0xbd462a0a4fd47580, 0x3a23cb3c35d9f6a1), (0x3f8bb9d3abb00000, 0xbd50ec48f94d7860, 0xba26b47d410e4cc7), (0x3f8e7f9bb2300000, 0x3d4e4415cbc97a00, 0xba23729fdb677231), (0x3f90a2b224780000, 0xbd5cb73f4505b030, 0xba21b3b3a3bc370a), (0x3f92059691e80000, 0xbd4abcc3412f2640, 0xba0fe6e998e48673), (0x3f93687a76800000, 0xbd543901e5c97a90, 0x39fb54cdd52a5d88), (0x3f94cb5eb5d80000, 0xbd58f106f00f13b8, 0xba28f793f5fce148), (0x3f962e432b240000, 0xbd5745af34bb54b8, 0xb9e17e3ec05cde70), ], [ (0x0000000000000000, 0x0000000000000000, 0x0000000000000000), (0x3f162e7b00000000, 0xbd3868625640a680, 0xba234bf0db910f65), (0x3f262e35f6000000, 0xbd42ee3d96b696a0, 0x3a1a2948cd558655), (0x3f30a2b4b2000000, 0x3d053edbcf116500, 0xb9ecfc26ccf6d0e4), (0x3f362e4be1000000, 0x3cb783e334614000, 0xba204b96da30e63a), (0x3f3bb9e085000000, 0xbd460785f20acb20, 0xb9ff33369bf7dff1), (0x3f40a2b94d000000, 0x3d5fd4b3a2733530, 0xb9f685a35575eff1), (0x3f4368810f800000, 0x3d07ded26dc81300, 0xb9f4c4d1abca79bf), (0x3f462e4787800000, 0x3d57d2bee9a1f630, 0x3a2860233b7ad130), (0x3f48f40cb4800000, 0xbd5af034eaf471c0, 0x3a1ae748822d57b7), (0x3f4bb9d094000000, 0xbd57a223013a20f0, 0xba21e499087075b6), (0x3f4e7fa32c800000, 0xbd4b2e67b1b59bd0, 0xba254a41eda30fa6), (0x3f50a2b237000000, 0xbd37ad97ff4ac7a0, 0x3a2f932da91371dd), (0x3f52059a33800000, 0xbd396422d90df400, 0xba190800fbbf2ed3), (0x3f53687982400000, 0x3d30f90540018120, 0x3a29567e01e48f9a), (0x3f54cb602c000000, 0xbd40d709a5ec0b50, 0x3a1253dfd44635d2), (0x3f562e462b400000, 0x3d5061d003b97318, 0x3a2d7faee66a2e1e), ], [ (0x0000000000000000, 0x0000000000000000, 0x0000000000000000), (0x3ed63007c0000000, 0xbd4db0e38e5aaaa0, 0x3a2259a7b94815b9), (0x3ee6300f60000000, 0x3d32b1c755804380, 0x3a278cabba01e3e4), (0x3ef0a21150000000, 0xbd55ff2237307590, 0x3a08074feacfe49d), (0x3ef62e1ec0000000, 0xbd285d6f6487ce40, 0x3a205485074b9276), (0x3efbba3010000000, 0xbd4af5d58a7c9210, 0xba230a8c0fd2ff5f), (0x3f00a32298000000, 0x3d4590faa0883bd0, 0x3a295e9bda999947), (0x3f03682f10000000, 0x3d5f0224376efaf8, 0xba25843c0db50d10), (0x3f062e3d80000000, 0xbd4142c13daed4a0, 0x3a2c68a61183ce87), (0x3f08f44dd8000000, 0xbd4aa489f3999310, 0x3a111c5c376854ea), (0x3f0bb96010000000, 0x3d59904d8b6a3638, 0x3a28c89554493c8f), (0x3f0e7f7440000000, 0x3d55785ddbe7cba8, 0x3a1e7ff3cde7d70c), (0x3f10a2c530000000, 0xbd46d9e8780d0d50, 0x3a1ad9c178106693), (0x3f1205d134000000, 0xbd4214a2e893fcc0, 0x3a2548a9500c9822), (0x3f13685e28000000, 0x3d4e235886461030, 0x3a12a97b26da2d88), (0x3f14cb6c18000000, 0x3d52b7cfcea9e0d8, 0xba25095048a6b824), (0x3f162e7b00000000, 0xbd3868625640a680, 0xba234bf0db910f65), ], ]; pub(crate) static ACOSH_SINH_REFINE_T1: [u64; 17] = [ 0x3ff0000000000000, 0x3feea4afa0000000, 0x3fed5818e0000000, 0x3fec199be0000000, 0x3feae89f98000000, 0x3fe9c49180000000, 0x3fe8ace540000000, 0x3fe7a11470000000, 0x3fe6a09e68000000, 0x3fe5ab07e0000000, 0x3fe4bfdad8000000, 0x3fe3dea650000000, 0x3fe306fe08000000, 0x3fe2387a70000000, 0x3fe172b840000000, 0x3fe0b55870000000, 0x3fe0000000000000, ]; pub(crate) static ACOSH_ASINH_REFINE_T2: [u64; 16] = [ 0x3ff0000000000000, 0x3fefe9d968000000, 0x3fefd3c228000000, 0x3fefbdba38000000, 0x3fefa7c180000000, 0x3fef91d800000000, 0x3fef7bfdb0000000, 0x3fef663278000000, 0x3fef507658000000, 0x3fef3ac948000000, 0x3fef252b38000000, 0x3fef0f9c20000000, 0x3feefa1bf0000000, 0x3feee4aaa0000000, 0x3feecf4830000000, 0x3feeb9f488000000, ]; pub(crate) static ACOSH_SINH_REFINE_T3: [u64; 16] = [ 0x3ff0000000000000, 0x3feffe9d20000000, 0x3feffd3a58000000, 0x3feffbd798000000, 0x3feffa74e8000000, 0x3feff91248000000, 0x3feff7afb8000000, 0x3feff64d38000000, 0x3feff4eac8000000, 0x3feff38868000000, 0x3feff22618000000, 0x3feff0c3d0000000, 0x3fefef61a0000000, 0x3fefedff78000000, 0x3fefec9d68000000, 0x3fefeb3b60000000, ]; pub(crate) static ACOSH_ASINH_REFINE_T4: [u64; 16] = [ 0x3ff0000000000000, 0x3fefffe9d0000000, 0x3fefffd3a0000000, 0x3fefffbd78000000, 0x3fefffa748000000, 0x3fefff9118000000, 0x3fefff7ae8000000, 0x3fefff64c0000000, 0x3fefff4e90000000, 0x3fefff3860000000, 0x3fefff2238000000, 0x3fefff0c08000000, 0x3feffef5d8000000, 0x3feffedfa8000000, 0x3feffec980000000, 0x3feffeb350000000, ]; #[cold] fn acosh_refine(x: f64, a: f64) -> f64 { let ix = x.to_bits(); let z: DoubleDouble = if ix < 0x4190000000000000u64 { let dx2 = DoubleDouble::from_exact_mult(x, x); let w = DoubleDouble::from_exact_add(dx2.hi - 1., dx2.lo); let sh = w.hi.sqrt(); let ish = 0.5 / w.hi; let sl = (ish * sh) * (w.lo - dd_fmla(sh, sh, -w.hi)); let mut p = DoubleDouble::from_exact_add(x, sh); p.lo += sl; DoubleDouble::from_exact_add(p.hi, p.lo) } else if ix < 0x4330000000000000 { DoubleDouble::new(-0.5 / x, 2. * x) } else { DoubleDouble::new(0., x) }; let mut t = z.hi.to_bits(); let ex: i32 = (t >> 52) as i32; let e = ex.wrapping_sub(0x3ff) + if z.lo == 0.0 { 1i32 } else { 0i32 }; t &= 0x000fffffffffffff; t |= 0x3ffu64 << 52; let ed = e as f64; let v = (a - ed + f64::from_bits(0x3ff0000800000000)).to_bits(); let i = (v.wrapping_sub(0x3ffu64 << 52)) >> (52 - 16); let i1 = (i >> 12) & 0x1f; let i2 = (i >> 8) & 0xf; let i3 = (i >> 4) & 0xf; let i4 = i & 0xf; const L20: f64 = f64::from_bits(0x3fd62e42fefa3800); const L21: f64 = f64::from_bits(0x3d1ef35793c76800); const L22: f64 = f64::from_bits(0xba49ff0342542fc3); let el2 = L22 * ed; let el1 = L21 * ed; let el0 = L20 * ed; let mut dl0: f64; let ll0i1 = ACOSH_ASINH_LL[0][i1 as usize]; let ll1i2 = ACOSH_ASINH_LL[1][i2 as usize]; let ll2i3 = ACOSH_ASINH_LL[2][i3 as usize]; let ll3i4 = ACOSH_ASINH_LL[3][i4 as usize]; dl0 = f64::from_bits(ll0i1.0) + f64::from_bits(ll1i2.0) + (f64::from_bits(ll2i3.0) + f64::from_bits(ll3i4.0)); let dl1 = f64::from_bits(ll0i1.1) + f64::from_bits(ll1i2.1) + (f64::from_bits(ll2i3.1) + f64::from_bits(ll3i4.1)); let dl2 = f64::from_bits(ll0i1.2) + f64::from_bits(ll1i2.2) + (f64::from_bits(ll2i3.2) + f64::from_bits(ll3i4.2)); dl0 += el0; let t12 = f64::from_bits(ACOSH_SINH_REFINE_T1[i1 as usize]) * f64::from_bits(ACOSH_ASINH_REFINE_T2[i2 as usize]); let t34 = f64::from_bits(ACOSH_SINH_REFINE_T3[i3 as usize]) * f64::from_bits(ACOSH_ASINH_REFINE_T4[i4 as usize]); let th = t12 * t34; let tl = dd_fmla(t12, t34, -th); let dh = th * f64::from_bits(t); let dl = dd_fmla(th, f64::from_bits(t), -dh); let sh = tl * f64::from_bits(t); let sl = dd_fmla(tl, f64::from_bits(t), -sh); let mut dx = DoubleDouble::from_exact_add(dh - 1., dl); if z.lo != 0.0 { t = z.lo.to_bits(); t = t.wrapping_sub((e as i64).wrapping_shl(52) as u64); dx.lo += th * f64::from_bits(t); } dx = DoubleDouble::add(dx, DoubleDouble::new(sl, sh)); const CL: [u64; 3] = [0xbfc0000000000000, 0x3fb9999999a0754f, 0xbfb55555555c3157]; let sl = dx.hi * (f64::from_bits(CL[0]) + dx.hi * (f64::from_bits(CL[1]) + dx.hi * f64::from_bits(CL[2]))); const CH: [(u64, u64); 3] = [ (0x39024b67ee516e3b, 0x3fe0000000000000), (0xb91932ce43199a8d, 0xbfd0000000000000), (0x3c655540c15cf91f, 0x3fc5555555555555), ]; let mut s = lpoly_xd_generic(dx, CH, sl); s = DoubleDouble::quick_mult(dx, s); s = DoubleDouble::add(s, DoubleDouble::new(el2, el1)); s = DoubleDouble::add(s, DoubleDouble::new(dl2, dl1)); let mut v02 = DoubleDouble::from_exact_add(dl0, s.hi); let mut v12 = DoubleDouble::from_exact_add(v02.lo, s.lo); v02.hi *= 2.; v12.hi *= 2.; v12.lo *= 2.; t = v12.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = v12.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } v12.hi = f64::from_bits(t); } v02.hi + v12.hi } pub(crate) static ACOSH_ASINH_B: [[i32; 2]; 32] = [ [301, 27565], [7189, 24786], [13383, 22167], [18923, 19696], [23845, 17361], [28184, 15150], [31969, 13054], [35231, 11064], [37996, 9173], [40288, 7372], [42129, 5657], [43542, 4020], [44546, 2457], [45160, 962], [45399, -468], [45281, -1838], [44821, -3151], [44032, -4412], [42929, -5622], [41522, -6786], [39825, -7905], [37848, -8982], [35602, -10020], [33097, -11020], [30341, -11985], [27345, -12916], [24115, -13816], [20661, -14685], [16989, -15526], [13107, -16339], [9022, -17126], [4740, -17889], ]; pub(crate) static ACOSH_ASINH_R1: [u64; 33] = [ 0x3ff0000000000000, 0x3fef507600000000, 0x3feea4b000000000, 0x3fedfc9800000000, 0x3fed581800000000, 0x3fecb72000000000, 0x3fec199c00000000, 0x3feb7f7600000000, 0x3feae8a000000000, 0x3fea550400000000, 0x3fe9c49200000000, 0x3fe9373800000000, 0x3fe8ace600000000, 0x3fe8258a00000000, 0x3fe7a11400000000, 0x3fe71f7600000000, 0x3fe6a09e00000000, 0x3fe6247e00000000, 0x3fe5ab0800000000, 0x3fe5342c00000000, 0x3fe4bfda00000000, 0x3fe44e0800000000, 0x3fe3dea600000000, 0x3fe371a800000000, 0x3fe306fe00000000, 0x3fe29e9e00000000, 0x3fe2387a00000000, 0x3fe1d48800000000, 0x3fe172b800000000, 0x3fe1130200000000, 0x3fe0b55800000000, 0x3fe059b000000000, 0x3fe0000000000000, ]; pub(crate) static ACOSH_ASINH_R2: [u64; 33] = [ 0x3ff0000000000000, 0x3feffa7400000000, 0x3feff4ea00000000, 0x3fefef6200000000, 0x3fefe9da00000000, 0x3fefe45200000000, 0x3fefdecc00000000, 0x3fefd94600000000, 0x3fefd3c200000000, 0x3fefce3e00000000, 0x3fefc8bc00000000, 0x3fefc33a00000000, 0x3fefbdba00000000, 0x3fefb83a00000000, 0x3fefb2bc00000000, 0x3fefad3e00000000, 0x3fefa7c200000000, 0x3fefa24600000000, 0x3fef9cca00000000, 0x3fef975000000000, 0x3fef91d800000000, 0x3fef8c6000000000, 0x3fef86e800000000, 0x3fef817200000000, 0x3fef7bfe00000000, 0x3fef768a00000000, 0x3fef711600000000, 0x3fef6ba400000000, 0x3fef663200000000, 0x3fef60c200000000, 0x3fef5b5200000000, 0x3fef55e400000000, 0x3fef507600000000, ]; pub(crate) static ACOSH_ASINH_L1: [(u64, u64); 33] = [ (0x0000000000000000, 0x0000000000000000), (0xbd1269e2038315b3, 0x3f962e4eacd40000), (0xbd23f2558bddfc47, 0x3fa62e3ce7218000), (0x3d207ea13c34efb5, 0x3fb0a2ab6d3ec000), (0x3d38f3e77084d3ba, 0x3fb62e4a86d8c000), (0xbd18d92a005f1a7e, 0x3fbbb9db7062c000), (0x3d358239e799bfe5, 0x3fc0a2b1a22cc000), (0xbd3a93fcf5f593b7, 0x3fc3687f0a298000), (0xbd1db4cac32fd2b5, 0x3fc62e4116b64000), (0xbd10e65a92ee0f3b, 0x3fc8f409e4df6000), (0xbd38261383d475f1, 0x3fcbb9d15001c000), (0xbd3359886207513b, 0x3fce7f9a8c940000), (0x3d3811f87496ceb7, 0x3fd0a2b052ddb000), (0x3d34991ec6cb435c, 0x3fd205955ef73000), (0xbd34581abfeb8927, 0x3fd3687bd9121000), (0x3d3cab48f6942703, 0x3fd4cb5e8f2b5000), (0xbd0df2c452fde132, 0x3fd62e4420e20000), (0x3d26109f4fdb74bd, 0x3fd791292c46a000), (0xbd36b95fbdac7696, 0x3fd8f40af84e7000), (0x3d17394fa880cbda, 0x3fda56ed8f865000), (0xbd150b06a94eccab, 0x3fdbb9d6505b4000), (0xbd3be2abf0b38989, 0x3fdd1cb91e728000), (0xbd37d6bf1e34da04, 0x3fde7f9d139e2000), (0xbd3423c1e14de6ed, 0x3fdfe27db9b0e000), (0x3d3c46f1a0efbbc2, 0x3fe0a2b25060a800), (0x3d2834fe4e3e6018, 0x3fe154244482a000), (0x3d16a03d0f02b650, 0x3fe2059731298800), (0x3d3d437056526f30, 0x3fe2b707145de000), (0xbd2a0233728405c5, 0x3fe3687b0e0b2800), (0xbd24dbdda10d2bf1, 0x3fe419ec5d3f6800), (0x3d3f7d0a25d154f2, 0x3fe4cb5f9fc02000), (0x3d315ede4d803b18, 0x3fe57cd28421a800), (0x3d2ef35793c76730, 0x3fe62e42fefa3800), ]; pub(crate) static ACOSH_ASINH_L2: [(u64, u64); 33] = [ (0x0000000000000000, 0x0000000000000000), (0x3d35abdac3638e99, 0x3f4631ec81e00000), (0xbd216b8be9bbe239, 0x3f562fd812700000), (0xbd3364c6315542eb, 0x3f60a25205080000), (0x3d2734abe459c900, 0x3f662dadc1d00000), (0x3d30cf8a761431bf, 0x3f6bb9ff94d00000), (0x3d2da2718eb78708, 0x3f70a2a2def80000), (0x3d334ada62c59b93, 0x3f7368c0fae40000), (0x3d3d09ab376682d4, 0x3f762e58e4f80000), (0xbd23cb7b94329211, 0x3f78f46bd28c0000), (0xbd2eec5c297c41d0, 0x3f7bb9f831200000), (0xbd36411b9395d150, 0x3f7e7fff8f300000), (0xbd31c0e59a43053c, 0x3f80a2c0006e0000), (0x3d16506596e077b6, 0x3f8205bdb6f00000), (0x3d3e256bce6faa27, 0x3f836877c86e0000), (0x3ccbd42467b0c8d1, 0x3f84cb6f55780000), (0xbd3c4f92132ff0f0, 0x3f862e230e8c0000), (0xbd380be08bfab390, 0x3f87911440f60000), (0xbd3f0b1319ceb1f7, 0x3f88f443020a0000), (0x3d2a65fcfb8de99b, 0x3f8a572dbef40000), (0x3d14233885d3779c, 0x3f8bb9d449a60000), (0x3d3f46a59e646edb, 0x3f8d1cb8491c0000), (0xbd3c3d2f11c11446, 0x3f8e7fd9d2aa0000), (0x3d27763f78a1e0cc, 0x3f8fe2b6f9780000), (0x3d3b4c37fc60c043, 0x3f90a2a7c7a50000), (0xbd15b8a822859be3, 0x3f915412ca860000), (0xbd3f2d8c9fc06400, 0x3f92059c90050000), (0xbd3e80e79c20378d, 0x3f92b703f49b0000), (0x3d368256e4329bdb, 0x3f93688a1a8d0000), (0x3d37e9741da248c3, 0x3f9419edc7ba0000), (0x3d2e330dccce602b, 0x3f94cb7034fa0000), (0x3ce2f32b5d18eefb, 0x3f957cd011870000), (0xbd1269e2038315b3, 0x3f962e4eacd40000), ]; #[inline] pub(crate) fn lpoly_xd_generic( x: DoubleDouble, poly: [(u64, u64); N], l: f64, ) -> DoubleDouble { let zch = poly.last().unwrap(); let tch = f64::from_bits(zch.1) + l; let mut ch = DoubleDouble::new( ((f64::from_bits(zch.1) - tch) + l) + f64::from_bits(zch.0), tch, ); for zch in poly.iter().rev().skip(1) { ch = DoubleDouble::mult(ch, x); let th = ch.hi + f64::from_bits(zch.1); let tl = (f64::from_bits(zch.1) - th) + ch.hi; ch.hi = th; ch.lo += tl + f64::from_bits(zch.0); } ch } #[cold] fn as_acosh_one(x: f64, sh: f64, sl: f64) -> f64 { static CH: [(u64, u64); 10] = [ (0xbc55555555554af1, 0xbfb5555555555555), (0x3c29999998933f0e, 0x3f93333333333333), (0x3c024929b16ec6b7, 0xbf76db6db6db6db7), (0x3bdc56d45e265e2c, 0x3f5f1c71c71c71c7), (0x3be6d50ce7188d3d, 0xbf46e8ba2e8ba2e9), (0x3bdc6791d1cf399a, 0x3f31c4ec4ec4ec43), (0x3bbee0d9408a2e2a, 0xbf1c99999999914f), (0xbba1cea281e08012, 0x3f07a878787648e2), (0x3b70335101403d9d, 0xbef3fde50d0cb4b9), (0x3aff9c6b51787043, 0x3ee12ef3bf8a0a74), ]; const CL: [u64; 6] = [ 0xbecdf3b9d1296ea9, 0x3eba681d7d2298eb, 0xbea77ead7b1ca449, 0x3e94edd2ddb3721f, 0xbe81bf173531ee23, 0x3e6613229230e255, ]; let yw0 = f_fmla(x, f64::from_bits(CL[5]), f64::from_bits(CL[4])); let yw1 = f_fmla(x, yw0, f64::from_bits(CL[3])); let yw2 = f_fmla(x, yw1, f64::from_bits(CL[2])); let yw3 = f_fmla(x, yw2, f64::from_bits(CL[1])); let y2 = x * f_fmla(x, yw3, f64::from_bits(CL[0])); let mut y1 = lpoly_xd_generic(DoubleDouble::new(0., x), CH, y2); y1 = DoubleDouble::mult_f64(y1, x); let y0 = DoubleDouble::from_exact_add(1., y1.hi); let yl = y0.lo + y1.lo; let p = DoubleDouble::quick_mult(DoubleDouble::new(yl, y0.hi), DoubleDouble::new(sl, sh)); p.to_f64() } /// Huperbolic acos /// /// Max ULP 0.5 pub fn f_acosh(x: f64) -> f64 { let ix = x.to_bits(); if ix >= 0x7ff0000000000000u64 { let aix = ix.wrapping_shl(1); if ix == 0x7ff0000000000000u64 || aix > (0x7ffu64 << 53) { return x + x; } // +inf or nan return f64::NAN; } if ix <= 0x3ff0000000000000u64 { if ix == 0x3ff0000000000000u64 { return 0.; } return f64::NAN; } let mut off: i32 = 0x3fe; let mut t = ix; let g = if ix < 0x3ff1e83e425aee63u64 { let z = x - 1.; let iz = (-0.25) / z; let zt = 2. * z; let sh = zt.sqrt(); let sl = dd_fmla(sh, sh, -zt) * (sh * iz); const CL: [u64; 9] = [ 0xbfb5555555555555, 0x3f93333333332f95, 0xbf76db6db6d5534c, 0x3f5f1c71c1e04356, 0xbf46e8b8e3e40d58, 0x3f31c4ba825ac4fe, 0xbf1c9045534e6d9e, 0x3f071fedae26a76b, 0xbeef1f4f8cc65342, ]; let z2 = z * z; let z4 = z2 * z2; let ds0 = f_fmla(z, f64::from_bits(CL[8]), f64::from_bits(CL[7])); let ds1 = f_fmla(z, f64::from_bits(CL[6]), f64::from_bits(CL[5])); let ds2 = f_fmla(z, f64::from_bits(CL[4]), f64::from_bits(CL[3])); let ds3 = f_fmla(z, f64::from_bits(CL[2]), f64::from_bits(CL[1])); let dsw0 = f_fmla(z2, ds0, ds1); let dsw1 = f_fmla(z2, ds2, ds3); let dsw2 = f_fmla(z4, dsw0, dsw1); let mut ds = (sh * z) * f_fmla(z, dsw2, f64::from_bits(CL[0])); let eps = ds * f64::from_bits(0x3ccfc00000000000) - f64::from_bits(0x3970000000000000) * sh; ds += sl; let lb = sh + (ds - eps); let ub = sh + (ds + eps); if lb == ub { return lb; } return as_acosh_one(z, sh, sl); } else if ix < 0x405bf00000000000u64 { off = 0x3ff; let x2h = x * x; let wh = x2h - 1.; let wl = dd_fmla(x, x, -x2h); let sh = wh.sqrt(); let ish = 0.5 / wh; let sl = (wl - dd_fmla(sh, sh, -wh)) * (sh * ish); let mut pt = DoubleDouble::from_exact_add(x, sh); pt.lo += sl; t = pt.hi.to_bits(); pt.lo / pt.hi } else if ix < 0x4087100000000000u64 { const CL: [u64; 4] = [ 0x3bd5c4b6148816e2, 0xbfd000000000005c, 0xbfb7fffffebf3e6c, 0xbfaaab6691f2bae7, ]; let z = 1. / (x * x); let zw0 = f_fmla(z, f64::from_bits(CL[3]), f64::from_bits(CL[2])); let zw1 = f_fmla(z, zw0, f64::from_bits(CL[1])); f_fmla(z, zw1, f64::from_bits(CL[0])) } else if ix < 0x40e0100000000000u64 { const CL: [u64; 3] = [0xbbc7f77c8429c6c6, 0xbfcffffffffff214, 0xbfb8000268641bfe]; let z = 1. / (x * x); let zw0 = f_fmla(z, f64::from_bits(CL[2]), f64::from_bits(CL[1])); f_fmla(z, zw0, f64::from_bits(CL[0])) } else if ix < 0x41ea000000000000u64 { const CL: [u64; 2] = [0x3bc7a0ed2effdd10, 0xbfd000000017d048]; let z = 1. / (x * x); f_fmla(z, f64::from_bits(CL[1]), f64::from_bits(CL[0])) } else { 0. }; let ex: i32 = (t >> 52) as i32; let e = ex - off; t &= 0x000fffffffffffff; let ed = e; let i: u64 = t >> (52 - 5); let d: i64 = (t & 0x00007fffffffffff) as i64; let b_i = ACOSH_ASINH_B[i as usize]; let j: u64 = t .wrapping_add((b_i[0] as u64).wrapping_shl(33)) .wrapping_add((b_i[1] as i64).wrapping_mul(d >> 16) as u64) >> (52 - 10); t |= 0x3ffu64 << 52; let i1: i32 = (j >> 5) as i32; let i2 = j & 0x1f; let r = f64::from_bits(ACOSH_ASINH_R1[i1 as usize]) * f64::from_bits(ACOSH_ASINH_R2[i2 as usize]); let dx = dd_fmla(r, f64::from_bits(t), -1.); let dx2 = dx * dx; const C: [u64; 5] = [ 0xbfe0000000000000, 0x3fd5555555555530, 0xbfcfffffffffffa0, 0x3fc99999e33a6366, 0xbfc555559ef9525f, ]; let fw0 = f_fmla(dx, f64::from_bits(C[3]), f64::from_bits(C[2])); let fw1 = f_fmla(dx, f64::from_bits(C[1]), f64::from_bits(C[0])); let fw2 = f_fmla(dx2, f64::from_bits(C[4]), fw0); let f = dx2 * f_fmla(dx2, fw2, fw1); const L2H: f64 = f64::from_bits(0x3fe62e42fefa3800); const L2L: f64 = f64::from_bits(0x3d2ef35793c76730); let l1r = ACOSH_ASINH_L1[i1 as usize]; let l2r = ACOSH_ASINH_L2[i2 as usize]; let lh = f_fmla( L2H, ed as f64, f64::from_bits(l1r.1) + f64::from_bits(l2r.1), ); let mut ll = f_fmla(L2L, ed as f64, dx); ll += g; ll += f64::from_bits(l1r.0) + f64::from_bits(l2r.0); ll += f; let eps = 2.8e-19; let lb = lh + (ll - eps); let ub = lh + (ll + eps); if lb == ub { return lb; } acosh_refine(x, f64::from_bits(0x3ff71547652b82fe) * lb) } #[cfg(test)] mod tests { use super::*; #[test] fn test() { assert_eq!(f_acosh(1.52), 0.9801016289951905); assert_eq!(f_acosh(1.86), 1.2320677765479648); assert_eq!(f_acosh(4.52), 2.189191592518765); } } pxfm-0.1.23/src/hyperbolic/acoshf.rs000064400000000000000000000043651046102023000154310ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::hyperbolic::asinhf::log_eval; /// Hyperbolic arc cosine function /// /// Max ULP 0.5 #[inline] pub fn f_acoshf(x: f32) -> f32 { if x <= 1.0 { if x == 1.0 { return 0.0; } // x < 1. return f32::NAN; } if !x.is_finite() { return x; } let x_d = x as f64; // acosh(x) = log(x + sqrt(x^2 - 1)) log_eval(x_d + (f_fmla(x_d, x_d, -1.0).sqrt())) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_acoshf() { assert_eq!(f_acoshf(2.0), 1.316958); assert!(f_acoshf(0.5).is_nan()); } } pxfm-0.1.23/src/hyperbolic/asinh.rs000064400000000000000000000307731046102023000152720ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::hyperbolic::acosh::{ ACOSH_ASINH_B, ACOSH_ASINH_L1, ACOSH_ASINH_L2, ACOSH_ASINH_LL, ACOSH_ASINH_R1, ACOSH_ASINH_R2, ACOSH_ASINH_REFINE_T2, ACOSH_ASINH_REFINE_T4, ACOSH_SINH_REFINE_T1, ACOSH_SINH_REFINE_T3, lpoly_xd_generic, }; #[cold] fn asinh_refine(x: f64, a: f64, z: DoubleDouble) -> f64 { let mut t = z.hi.to_bits(); let ex: i32 = (t >> 52) as i32; let e = ex.wrapping_sub(0x3ff) + if z.lo == 0.0 { 1i32 } else { 0i32 }; t &= 0x000fffffffffffff; t |= 0x3ffu64 << 52; let ed = e as f64; let v = (a - ed + f64::from_bits(0x3ff0000800000000)).to_bits(); let i = (v.wrapping_sub(0x3ffu64 << 52)) >> (52 - 16); let i1 = (i >> 12) & 0x1f; let i2 = (i >> 8) & 0xf; let i3 = (i >> 4) & 0xf; let i4 = i & 0xf; const L20: f64 = f64::from_bits(0x3fd62e42fefa3800); const L21: f64 = f64::from_bits(0x3d1ef35793c76800); const L22: f64 = f64::from_bits(0xba49ff0342542fc3); let el2 = L22 * ed; let el1 = L21 * ed; let el0 = L20 * ed; let mut dl0: f64; let ll0i1 = ACOSH_ASINH_LL[0][i1 as usize]; let ll1i2 = ACOSH_ASINH_LL[1][i2 as usize]; let ll2i3 = ACOSH_ASINH_LL[2][i3 as usize]; let ll3i4 = ACOSH_ASINH_LL[3][i4 as usize]; dl0 = f64::from_bits(ll0i1.0) + f64::from_bits(ll1i2.0) + (f64::from_bits(ll2i3.0) + f64::from_bits(ll3i4.0)); let dl1 = f64::from_bits(ll0i1.1) + f64::from_bits(ll1i2.1) + (f64::from_bits(ll2i3.1) + f64::from_bits(ll3i4.1)); let dl2 = f64::from_bits(ll0i1.2) + f64::from_bits(ll1i2.2) + (f64::from_bits(ll2i3.2) + f64::from_bits(ll3i4.2)); dl0 += el0; let t12 = f64::from_bits(ACOSH_SINH_REFINE_T1[i1 as usize]) * f64::from_bits(ACOSH_ASINH_REFINE_T2[i2 as usize]); let t34 = f64::from_bits(ACOSH_SINH_REFINE_T3[i3 as usize]) * f64::from_bits(ACOSH_ASINH_REFINE_T4[i4 as usize]); let th = t12 * t34; let tl = dd_fmla(t12, t34, -th); let dh = th * f64::from_bits(t); let dl = dd_fmla(th, f64::from_bits(t), -dh); let sh = tl * f64::from_bits(t); let sl = dd_fmla(tl, f64::from_bits(t), -sh); let mut dx = DoubleDouble::from_exact_add(dh - 1., dl); if z.lo != 0.0 { t = z.lo.to_bits(); t = t.wrapping_sub((e as i64).wrapping_shl(52) as u64); dx.lo += th * f64::from_bits(t); } dx = DoubleDouble::add(dx, DoubleDouble::new(sl, sh)); const CL: [u64; 3] = [0xbfc0000000000000, 0x3fb9999999a0754f, 0xbfb55555555c3157]; let sl0 = f_fmla(dx.hi, f64::from_bits(CL[2]), f64::from_bits(CL[1])); let sl1 = f_fmla(dx.hi, sl0, f64::from_bits(CL[0])); let sl = dx.hi * sl1; const CH: [(u64, u64); 3] = [ (0x39024b67ee516e3b, 0x3fe0000000000000), (0xb91932ce43199a8d, 0xbfd0000000000000), (0x3c655540c15cf91f, 0x3fc5555555555555), ]; let mut s = lpoly_xd_generic(dx, CH, sl); s = DoubleDouble::quick_mult(dx, s); s = DoubleDouble::add(s, DoubleDouble::new(el2, el1)); s = DoubleDouble::add(s, DoubleDouble::new(dl2, dl1)); let mut v02 = DoubleDouble::from_exact_add(dl0, s.hi); let mut v12 = DoubleDouble::from_exact_add(v02.lo, s.lo); let scale = f64::copysign(2., x); v02.hi *= scale; v12.hi *= scale; v12.lo *= scale; t = v12.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = v12.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } v12.hi = f64::from_bits(t); } v02.hi + v12.hi } #[cold] fn as_asinh_zero(x: f64, x2h: f64, x2l: f64) -> f64 { static CH: [(u64, u64); 12] = [ (0xbc65555555555555, 0xbfc5555555555555), (0x3c499999999949df, 0x3fb3333333333333), (0x3c32492496091b0c, 0xbfa6db6db6db6db7), (0x3c1c71a35cfa0671, 0x3f9f1c71c71c71c7), (0x3c317f937248cf81, 0xbf96e8ba2e8ba2e9), (0xbc374e3c1dfd4c3d, 0x3f91c4ec4ec4ec4f), (0xbc238e7a467ecc55, 0xbf8c999999999977), (0x3c2a83c7bace55eb, 0x3f87a87878786c7e), (0xbc2d024df7fa0542, 0xbf83fde50d764083), (0xbc2ba9c13deb261f, 0x3f812ef3ceae4d12), (0xbc1546da9bc5b32a, 0xbf7df3bd104aa267), (0x3c140d284a1d67f9, 0x3f7a685fc5de7a04), ]; const CL: [u64; 5] = [ 0xbf77828d553ec800, 0x3f751712f7bee368, 0xbf72e6d98527bcc6, 0x3f70095da47b392c, 0xbf63b92d6368192c, ]; let yw0 = f_fmla(x2h, f64::from_bits(CL[4]), f64::from_bits(CL[3])); let yw1 = f_fmla(x2h, yw0, f64::from_bits(CL[2])); let yw2 = f_fmla(x2h, yw1, f64::from_bits(CL[1])); let y2 = x2h * f_fmla(x2h, yw2, f64::from_bits(CL[0])); let mut y1 = lpoly_xd_generic(DoubleDouble::new(x2l, x2h), CH, y2); y1 = DoubleDouble::quick_mult(y1, DoubleDouble::new(x2l, x2h)); y1 = DoubleDouble::quick_mult_f64(y1, x); let y0 = DoubleDouble::from_exact_add(x, y1.hi); let mut p = DoubleDouble::from_exact_add(y0.lo, y1.lo); let mut t = p.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = p.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } p.hi = f64::from_bits(t); } y0.hi + p.hi } /// Huperbolic sine function /// /// Max ULP 0.5 pub fn f_asinh(x: f64) -> f64 { let ax = x.abs(); let ix = ax.to_bits(); let u = ix; if u < 0x3fbb000000000000u64 { // |x| < 0x1.bp-4 // for |x| < 0x1.7137449123ef7p-26, asinh(x) rounds to x to nearest // for |x| < 0x1p-1022 we have underflow but not for 0x1p-1022 (to nearest) if u < 0x3e57137449123ef7u64 { // |x| < 0x1.7137449123ef7p-26 if u == 0 { return x; } let res = f_fmla(f64::from_bits(0xbc30000000000000), x, x); return res; } let x2h = x * x; let x2l = dd_fmla(x, x, -x2h); let x3h = x2h * x; let sl; if u < 0x3f93000000000000u64 { // |x| < 0x1.3p-6 if u < 0x3f30000000000000u64 { // |x| < 0x1p-12 if u < 0x3e5a000000000000u64 { // |x| < 0x1.ap-26 sl = x3h * f64::from_bits(0xbfc5555555555555); } else { const CL: [u64; 2] = [0xbfc5555555555555, 0x3fb3333327c57c60]; let sl0 = f_fmla(x2h, f64::from_bits(CL[1]), f64::from_bits(CL[0])); sl = x3h * sl0; } } else { const CL: [u64; 4] = [ 0xbfc5555555555555, 0x3fb333333332f2ff, 0xbfa6db6d9a665159, 0x3f9f186866d775f0, ]; let sl0 = f_fmla(x2h, f64::from_bits(CL[3]), f64::from_bits(CL[2])); let sl1 = f_fmla(x2h, sl0, f64::from_bits(CL[1])); sl = x3h * f_fmla(x2h, sl1, f64::from_bits(CL[0])); } } else { const CL: [u64; 7] = [ 0xbfc5555555555555, 0x3fb3333333333310, 0xbfa6db6db6da466c, 0x3f9f1c71c2ea7be4, 0xbf96e8b651b09d72, 0x3f91c309fc0e69c2, 0xbf8bab7833c1e000, ]; let c1 = f_fmla(x2h, f64::from_bits(CL[2]), f64::from_bits(CL[1])); let c3 = f_fmla(x2h, f64::from_bits(CL[4]), f64::from_bits(CL[3])); let c5 = f_fmla(x2h, f64::from_bits(CL[6]), f64::from_bits(CL[5])); let x4 = x2h * x2h; let sl0 = f_fmla(x4, c5, c3); let sl1 = f_fmla(x4, sl0, c1); sl = x3h * f_fmla(x2h, sl1, f64::from_bits(CL[0])); } let eps = f64::from_bits(0x3ca6000000000000) * x3h; let lb = x + (sl - eps); let ub = x + (sl + eps); if lb == ub { return lb; } return as_asinh_zero(x, x2h, x2l); } // |x| >= 0x1.bp-4 let mut x2h: f64 = 0.; let mut x2l: f64 = 0.; let mut off: i32 = 0x3ff; let va: DoubleDouble = if u < 0x4190000000000000 { // x < 0x1p+26 x2h = x * x; x2l = dd_fmla(x, x, -x2h); let mut dt = if u < 0x3ff0000000000000 { DoubleDouble::from_exact_add(1., x2h) } else { DoubleDouble::from_exact_add(x2h, 1.) }; dt.lo += x2l; let ah = dt.hi.sqrt(); let rs = 0.5 / dt.hi; let al = (dt.lo - dd_fmla(ah, ah, -dt.hi)) * (rs * ah); let mut ma = DoubleDouble::from_exact_add(ah, ax); ma.lo += al; ma } else if u < 0x4330000000000000 { DoubleDouble::new(0.5 / ax, 2. * ax) } else { if u >= 0x7ff0000000000000u64 { return x + x; } // +-inf or nan off = 0x3fe; DoubleDouble::new(0., ax) }; let mut t = va.hi.to_bits(); let ex = (t >> 52) as i32; let e = ex.wrapping_sub(off); t &= 0x000fffffffffffff; let ed = e as f64; let i = t >> (52 - 5); let d = (t & 0x00007fffffffffff) as i64; let b_i = ACOSH_ASINH_B[i as usize]; let j: u64 = t .wrapping_add((b_i[0] as u64).wrapping_shl(33)) .wrapping_add((b_i[1] as i64).wrapping_mul(d >> 16) as u64) >> (52 - 10); t |= 0x3ffu64 << 52; let i1 = (j >> 5) as i32; let i2 = j & 0x1f; let r = f64::from_bits(ACOSH_ASINH_R1[i1 as usize]) * f64::from_bits(ACOSH_ASINH_R2[i2 as usize]); let dx = dd_fmla(r, f64::from_bits(t), -1.); let dx2 = dx * dx; const C: [u64; 5] = [ 0xbfe0000000000000, 0x3fd5555555555530, 0xbfcfffffffffffa0, 0x3fc99999e33a6366, 0xbfc555559ef9525f, ]; let fw0 = f_fmla(dx, f64::from_bits(C[3]), f64::from_bits(C[2])); let fw1 = f_fmla(dx, f64::from_bits(C[1]), f64::from_bits(C[0])); let fw2 = f_fmla(dx2, f64::from_bits(C[4]), fw0); let f = dx2 * f_fmla(dx2, fw2, fw1); const L2H: f64 = f64::from_bits(0x3fe62e42fefa3800); const L2L: f64 = f64::from_bits(0x3d2ef35793c76730); let l1i1 = ACOSH_ASINH_L1[i1 as usize]; let l1i2 = ACOSH_ASINH_L2[i2 as usize]; let mut lh = f_fmla(L2H, ed, f64::from_bits(l1i1.1) + f64::from_bits(l1i2.1)); let mut ll = f_fmla( L2L, ed, f64::from_bits(l1i1.0) + f64::from_bits(l1i2.0) + va.lo / va.hi + f, ); ll += dx; lh *= f64::copysign(1., x); ll *= f64::copysign(1., x); let eps = 1.63e-19; let lb = lh + (ll - eps); let ub = lh + (ll + eps); if lb == ub { return lb; } if ax < f64::from_bits(0x3fd0000000000000) { return as_asinh_zero(x, x2h, x2l); } asinh_refine(x, f64::from_bits(0x3ff71547652b82fe) * lb.abs(), va) } #[cfg(test)] mod tests { use super::*; #[test] fn test_asinh() { assert_eq!(f_asinh(-0.05268859863273256), -0.05266425100170862); assert_eq!(f_asinh(1.05268859863273256), 0.9181436936151385); } } pxfm-0.1.23/src/hyperbolic/asinhf.rs000064400000000000000000000262711046102023000154360ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{get_exponent_f64, set_exponent_f64}; use crate::common::f_fmla; use crate::polyeval::{f_polyeval4, f_polyeval10}; // Lookup table for (1/f) where f = 1 + n*2^(-7), n = 0..127. static ONE_OVER_F: [u64; 128] = [ 0x3ff0000000000000, 0x3fefc07f01fc07f0, 0x3fef81f81f81f820, 0x3fef44659e4a4271, 0x3fef07c1f07c1f08, 0x3feecc07b301ecc0, 0x3fee9131abf0b767, 0x3fee573ac901e574, 0x3fee1e1e1e1e1e1e, 0x3fede5d6e3f8868a, 0x3fedae6076b981db, 0x3fed77b654b82c34, 0x3fed41d41d41d41d, 0x3fed0cb58f6ec074, 0x3fecd85689039b0b, 0x3feca4b3055ee191, 0x3fec71c71c71c71c, 0x3fec3f8f01c3f8f0, 0x3fec0e070381c0e0, 0x3febdd2b899406f7, 0x3febacf914c1bad0, 0x3feb7d6c3dda338b, 0x3feb4e81b4e81b4f, 0x3feb2036406c80d9, 0x3feaf286bca1af28, 0x3feac5701ac5701b, 0x3fea98ef606a63be, 0x3fea6d01a6d01a6d, 0x3fea41a41a41a41a, 0x3fea16d3f97a4b02, 0x3fe9ec8e951033d9, 0x3fe9c2d14ee4a102, 0x3fe999999999999a, 0x3fe970e4f80cb872, 0x3fe948b0fcd6e9e0, 0x3fe920fb49d0e229, 0x3fe8f9c18f9c18fa, 0x3fe8d3018d3018d3, 0x3fe8acb90f6bf3aa, 0x3fe886e5f0abb04a, 0x3fe8618618618618, 0x3fe83c977ab2bedd, 0x3fe8181818181818, 0x3fe7f405fd017f40, 0x3fe7d05f417d05f4, 0x3fe7ad2208e0ecc3, 0x3fe78a4c8178a4c8, 0x3fe767dce434a9b1, 0x3fe745d1745d1746, 0x3fe724287f46debc, 0x3fe702e05c0b8170, 0x3fe6e1f76b4337c7, 0x3fe6c16c16c16c17, 0x3fe6a13cd1537290, 0x3fe6816816816817, 0x3fe661ec6a5122f9, 0x3fe642c8590b2164, 0x3fe623fa77016240, 0x3fe6058160581606, 0x3fe5e75bb8d015e7, 0x3fe5c9882b931057, 0x3fe5ac056b015ac0, 0x3fe58ed2308158ed, 0x3fe571ed3c506b3a, 0x3fe5555555555555, 0x3fe5390948f40feb, 0x3fe51d07eae2f815, 0x3fe5015015015015, 0x3fe4e5e0a72f0539, 0x3fe4cab88725af6e, 0x3fe4afd6a052bf5b, 0x3fe49539e3b2d067, 0x3fe47ae147ae147b, 0x3fe460cbc7f5cf9a, 0x3fe446f86562d9fb, 0x3fe42d6625d51f87, 0x3fe4141414141414, 0x3fe3fb013fb013fb, 0x3fe3e22cbce4a902, 0x3fe3c995a47babe7, 0x3fe3b13b13b13b14, 0x3fe3991c2c187f63, 0x3fe3813813813814, 0x3fe3698df3de0748, 0x3fe3521cfb2b78c1, 0x3fe33ae45b57bcb2, 0x3fe323e34a2b10bf, 0x3fe30d190130d190, 0x3fe2f684bda12f68, 0x3fe2e025c04b8097, 0x3fe2c9fb4d812ca0, 0x3fe2b404ad012b40, 0x3fe29e4129e4129e, 0x3fe288b01288b013, 0x3fe27350b8812735, 0x3fe25e22708092f1, 0x3fe2492492492492, 0x3fe23456789abcdf, 0x3fe21fb78121fb78, 0x3fe20b470c67c0d9, 0x3fe1f7047dc11f70, 0x3fe1e2ef3b3fb874, 0x3fe1cf06ada2811d, 0x3fe1bb4a4046ed29, 0x3fe1a7b9611a7b96, 0x3fe19453808ca29c, 0x3fe1811811811812, 0x3fe16e0689427379, 0x3fe15b1e5f75270d, 0x3fe1485f0e0acd3b, 0x3fe135c81135c811, 0x3fe12358e75d3033, 0x3fe1111111111111, 0x3fe0fef010fef011, 0x3fe0ecf56be69c90, 0x3fe0db20a88f4696, 0x3fe0c9714fbcda3b, 0x3fe0b7e6ec259dc8, 0x3fe0a6810a6810a7, 0x3fe0953f39010954, 0x3fe0842108421084, 0x3fe073260a47f7c6, 0x3fe0624dd2f1a9fc, 0x3fe05197f7d73404, 0x3fe0410410410410, 0x3fe03091b51f5e1a, 0x3fe0204081020408, 0x3fe0101010101010, ]; // Lookup table for log(f) = log(1 + n*2^(-7)) where n = 0..127. static LOG_F: [u64; 128] = [ 0x0000000000000000, 0x3f7fe02a6b106788, 0x3f8fc0a8b0fc03e3, 0x3f97b91b07d5b11a, 0x3f9f829b0e783300, 0x3fa39e87b9febd5f, 0x3fa77458f632dcfc, 0x3fab42dd711971be, 0x3faf0a30c01162a6, 0x3fb16536eea37ae0, 0x3fb341d7961bd1d0, 0x3fb51b073f06183f, 0x3fb6f0d28ae56b4b, 0x3fb8c345d6319b20, 0x3fba926d3a4ad563, 0x3fbc5e548f5bc743, 0x3fbe27076e2af2e5, 0x3fbfec9131dbeaba, 0x3fc0d77e7cd08e59, 0x3fc1b72ad52f67a0, 0x3fc29552f81ff523, 0x3fc371fc201e8f74, 0x3fc44d2b6ccb7d1e, 0x3fc526e5e3a1b437, 0x3fc5ff3070a793d3, 0x3fc6d60fe719d21c, 0x3fc7ab890210d909, 0x3fc87fa06520c910, 0x3fc9525a9cf456b4, 0x3fca23bc1fe2b563, 0x3fcaf3c94e80bff2, 0x3fcbc286742d8cd6, 0x3fcc8ff7c79a9a21, 0x3fcd5c216b4fbb91, 0x3fce27076e2af2e5, 0x3fcef0adcbdc5936, 0x3fcfb9186d5e3e2a, 0x3fd0402594b4d040, 0x3fd0a324e27390e3, 0x3fd1058bf9ae4ad5, 0x3fd1675cababa60e, 0x3fd1c898c16999fa, 0x3fd22941fbcf7965, 0x3fd2895a13de86a3, 0x3fd2e8e2bae11d30, 0x3fd347dd9a987d54, 0x3fd3a64c556945e9, 0x3fd404308686a7e3, 0x3fd4618bc21c5ec2, 0x3fd4be5f957778a0, 0x3fd51aad872df82d, 0x3fd5767717455a6c, 0x3fd5d1bdbf5809ca, 0x3fd62c82f2b9c795, 0x3fd686c81e9b14ae, 0x3fd6e08eaa2ba1e3, 0x3fd739d7f6bbd006, 0x3fd792a55fdd47a2, 0x3fd7eaf83b82afc3, 0x3fd842d1da1e8b17, 0x3fd89a3386c1425a, 0x3fd8f11e873662c7, 0x3fd947941c2116fa, 0x3fd99d958117e08a, 0x3fd9f323ecbf984b, 0x3fda484090e5bb0a, 0x3fda9cec9a9a0849, 0x3fdaf1293247786b, 0x3fdb44f77bcc8f62, 0x3fdb9858969310fb, 0x3fdbeb4d9da71b7b, 0x3fdc3dd7a7cdad4d, 0x3fdc8ff7c79a9a21, 0x3fdce1af0b85f3eb, 0x3fdd32fe7e00ebd5, 0x3fdd83e7258a2f3e, 0x3fddd46a04c1c4a0, 0x3fde24881a7c6c26, 0x3fde744261d68787, 0x3fdec399d2468cc0, 0x3fdf128f5faf06ec, 0x3fdf6123fa7028ac, 0x3fdfaf588f78f31e, 0x3fdffd2e0857f498, 0x3fe02552a5a5d0fe, 0x3fe04bdf9da926d2, 0x3fe0723e5c1cdf40, 0x3fe0986f4f573520, 0x3fe0be72e4252a82, 0x3fe0e44985d1cc8b, 0x3fe109f39e2d4c96, 0x3fe12f719593efbc, 0x3fe154c3d2f4d5e9, 0x3fe179eabbd899a0, 0x3fe19ee6b467c96e, 0x3fe1c3b81f713c24, 0x3fe1e85f5e7040d0, 0x3fe20cdcd192ab6d, 0x3fe23130d7bebf42, 0x3fe2555bce98f7cb, 0x3fe2795e1289b11a, 0x3fe29d37fec2b08a, 0x3fe2c0e9ed448e8b, 0x3fe2e47436e40268, 0x3fe307d7334f10be, 0x3fe32b1339121d71, 0x3fe34e289d9ce1d3, 0x3fe37117b54747b5, 0x3fe393e0d3562a19, 0x3fe3b68449fffc22, 0x3fe3d9026a7156fa, 0x3fe3fb5b84d16f42, 0x3fe41d8fe84672ae, 0x3fe43f9fe2f9ce67, 0x3fe4618bc21c5ec2, 0x3fe48353d1ea88df, 0x3fe4a4f85db03ebb, 0x3fe4c679afccee39, 0x3fe4e7d811b75bb0, 0x3fe50913cc01686b, 0x3fe52a2d265bc5aa, 0x3fe54b2467999497, 0x3fe56bf9d5b3f399, 0x3fe58cadb5cd7989, 0x3fe5ad404c359f2c, 0x3fe5cdb1dc6c1764, 0x3fe5ee02a9241675, 0x3fe60e32f44788d8, ]; #[inline] pub(crate) fn log_eval(x: f64) -> f64 { let ex = get_exponent_f64(x); // p1 is the leading 7 bits of mx, i.e. // p1 * 2^(-7) <= m_x < (p1 + 1) * 2^(-7). let p1 = ((x.to_bits() & ((1u64 << 52) - 1)) >> (52 - 7)) as i32; // Set bs to (1 + (mx - p1*2^(-7)) let mut bs = x.to_bits() & (((1u64 << 52) - 1) >> 7); const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; bs = set_exponent_f64(bs, EXP_BIAS); // dx = (mx - p1*2^(-7)) / (1 + p1*2^(-7)). let dx = (f64::from_bits(bs) - 1.0) * f64::from_bits(ONE_OVER_F[p1 as usize]); // Minimax polynomial of log(1 + dx) generated by Sollya with: // > P = fpminimax(log(1 + x)/x, 6, [|D...|], [0, 2^-7]); const COEFFS: [u64; 6] = [ 0xbfdffffffffffffc, 0x3fd5555555552dde, 0xbfcffffffefe562d, 0x3fc9999817d3a50f, 0xbfc554317b3f67a5, 0x3fc1dc5c45e09c18, ]; let dx2 = dx * dx; let c1 = f_fmla(dx, f64::from_bits(COEFFS[1]), f64::from_bits(COEFFS[0])); let c2 = f_fmla(dx, f64::from_bits(COEFFS[3]), f64::from_bits(COEFFS[2])); let c3 = f_fmla(dx, f64::from_bits(COEFFS[5]), f64::from_bits(COEFFS[4])); let p = f_polyeval4(dx2, dx, c1, c2, c3); f_fmla( ex as f64, /*log(2)*/ f64::from_bits(0x3fe62e42fefa39ef), f64::from_bits(LOG_F[p1 as usize]) + p, ) } /// Hyperbolic arcsine function /// /// Max ULP 0.5 #[inline] pub fn f_asinhf(x: f32) -> f32 { let x_u = x.to_bits(); let x_abs = x_u & 0x7fff_ffff; // |x| <= 2^-3 if x_abs <= 0x3e80_0000u32 { // |x| <= 2^-26 if x_abs <= 0x3280_0000u32 { return if x_abs == 0 { x } else { (x as f64 - f64::from_bits(0x3fc5555555555555) * x as f64 * x as f64 * x as f64) as f32 }; } let x_d = x as f64; let x_sq = x_d * x_d; // Generated by Sollya with: // R = remez(asinh(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [0, 2^-3]); // P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18|], [|D...|], [0, 2^-3], absolute, floating, R); // See `./notes/asinhf.sollya let p = f_polyeval10( x_sq, 0.0, f64::from_bits(0xbfc5555555555555), f64::from_bits(0x3fb3333333333333), f64::from_bits(0xbfa6db6db6db6d8e), f64::from_bits(0x3f9f1c71c71beb52), f64::from_bits(0xbf96e8ba2e0dde02), f64::from_bits(0x3f91c4ec071a2f97), f64::from_bits(0xbf8c9966fc6b6fda), f64::from_bits(0x3f879da45ad06ce8), f64::from_bits(0xbf82b3657f620c14), ); return f_fmla(x_d, p, x_d) as f32; } static SIGN: [f64; 2] = [1.0, -1.0]; let x_sign = SIGN[(x_u >> 31) as usize]; let x_d = x as f64; if !x.is_finite() { return x; } // asinh(x) = log(x + sqrt(x^2 + 1)) (x_sign * log_eval(f_fmla(x_d, x_sign, f_fmla(x_d, x_d, 1.0).sqrt()))) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_asinhf() { assert_eq!(f_asinhf(-0.24319594), -0.2408603); assert_eq!(f_asinhf(2.0), 1.4436355); assert_eq!(f_asinhf(-2.0), -1.4436355); assert_eq!(f_asinhf(1.054234), 0.9192077); } } pxfm-0.1.23/src/hyperbolic/atanh.rs000064400000000000000000000355301046102023000152570ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::hyperbolic::acosh::{ ACOSH_ASINH_B, ACOSH_ASINH_LL, ACOSH_ASINH_R1, ACOSH_ASINH_R2, ACOSH_ASINH_REFINE_T2, ACOSH_ASINH_REFINE_T4, ACOSH_SINH_REFINE_T1, ACOSH_SINH_REFINE_T3, lpoly_xd_generic, }; static ATANH_L1: [(u64, u64); 33] = [ (0x0000000000000000, 0x0000000000000000), (0xbe4532c1269e2038, 0x3f862e5000000000), (0x3e4ce42d81b54e84, 0x3f962e3c00000000), (0xbe525826f815ec3d, 0x3fa0a2ac00000000), (0x3e50db1b1e7cee11, 0x3fa62e4a00000000), (0xbe51f3a8c6c95003, 0x3fabb9dc00000000), (0xbe5774cd4fb8c30d, 0x3fb0a2b200000000), (0x3e2452e56c030a0a, 0x3fb3687f00000000), (0x3e36b63c4966a79a, 0x3fb62e4100000000), (0xbe3b20a21ccb525e, 0x3fb8f40a00000000), (0x3e54006cfb3d8f85, 0x3fbbb9d100000000), (0xbe5cdb026b310c41, 0x3fbe7f9b00000000), (0xbe569124fdc0f16d, 0x3fc0a2b080000000), (0xbe5084656cdc2727, 0x3fc2059580000000), (0xbe5376fa8b0357fd, 0x3fc3687c00000000), (0x3e3e56ae55a47b4a, 0x3fc4cb5e80000000), (0x3e5070ff8834eeb4, 0x3fc62e4400000000), (0x3e5623516109f4fe, 0x3fc7912900000000), (0xbe2ec656b95fbdac, 0x3fc8f40b00000000), (0x3e3f0ca2e729f510, 0x3fca56ed80000000), (0xbe57d260a858354a, 0x3fcbb9d680000000), (0x3e4e7279075503d3, 0x3fcd1cb900000000), (0x3e439e1a0a503873, 0x3fce7f9d00000000), (0x3e5cd86d7b87c3d6, 0x3fcfe27d80000000), (0x3e5060ab88de341e, 0x3fd0a2b240000000), (0x3e320a860d3f9390, 0x3fd1542440000000), (0xbe4dacee95fc2f10, 0x3fd2059740000000), (0x3e545de3a86e0aca, 0x3fd2b70700000000), (0x3e4c164cbfb991af, 0x3fd3687b00000000), (0x3e5d3f66b24225ef, 0x3fd419ec40000000), (0x3e5fc023efa144ba, 0x3fd4cb5f80000000), (0x3e3086a8af6f26c0, 0x3fd57cd280000000), (0xbe105c610ca86c39, 0x3fd62e4300000000), ]; static ATANH_L2: [(u64, u64); 33] = [ (0x0000000000000000, 0x0000000000000000), (0xbe337e152a129e4e, 0x3f36320000000000), (0xbe53f6c916b8be9c, 0x3f46300000000000), (0x3e520505936739d5, 0x3f50a24000000000), (0xbe523e2e8cb541ba, 0x3f562dc000000000), (0xbdfacb7983ac4f5e, 0x3f5bba0000000000), (0x3e36f7c7689c63ae, 0x3f60a2a000000000), (0x3e1f5ca695b4c58b, 0x3f6368c000000000), (0xbe4c6c18bd953226, 0x3f662e6000000000), (0x3e57a516c34846bd, 0x3f68f46000000000), (0xbe4f3b83dd8b8530, 0x3f6bba0000000000), (0xbe0c3459046e4e57, 0x3f6e800000000000), (0x3d9b5c7e34cb79f6, 0x3f70a2c000000000), (0xbe42487e9af9a692, 0x3f7205c000000000), (0x3e5f21bbc4ad79ce, 0x3f73687000000000), (0xbe2550ffc857b731, 0x3f74cb7000000000), (0x3e487458ec1b7b34, 0x3f762e2000000000), (0x3e5103d4fe83ee81, 0x3f77911000000000), (0x3e4810483d3b398c, 0x3f78f44000000000), (0xbe42085cb340608e, 0x3f7a573000000000), (0x3e512698a119c42f, 0x3f7bb9d000000000), (0xbe5edb8c172b4c33, 0x3f7d1cc000000000), (0xbe58b55b87a5e238, 0x3f7e7fe000000000), (0x3e5be5e17763f78a, 0x3f7fe2b000000000), (0xbe1c2d496790073e, 0x3f80a2a800000000), (0x3e56542f523abeec, 0x3f81541000000000), (0xbe5b7fdbe5b193f8, 0x3f8205a000000000), (0x3e5fa4d42fe30c7c, 0x3f82b70000000000), (0x3e50d46ad04adc86, 0x3f83688800000000), (0xbe51c22d02d17c4c, 0x3f8419f000000000), (0x3e1a7d1e330dccce, 0x3f84cb7000000000), (0x3e0187025e656ba3, 0x3f857cd000000000), (0xbe4532c1269e2038, 0x3f862e5000000000), ]; #[cold] fn as_atanh_zero(x: f64) -> f64 { static CH: [(u64, u64); 13] = [ (0x3c75555555555555, 0x3fd5555555555555), (0xbc6999999999611c, 0x3fc999999999999a), (0x3c62492490f76b25, 0x3fc2492492492492), (0x3c5c71cd5c38a112, 0x3fbc71c71c71c71c), (0xbc47556c4165f4ca, 0x3fb745d1745d1746), (0xbc4b893c3b36052e, 0x3fb3b13b13b13b14), (0x3c44e1afd723ed1f, 0x3fb1111111111105), (0xbc4f86ea96fb1435, 0x3fae1e1e1e1e2678), (0x3c31e51a6e54fde9, 0x3faaf286bc9f90cc), (0xbc2ab913de95c3bf, 0x3fa8618618c779b6), (0x3c4632e747641b12, 0x3fa642c84aa383eb), (0xbc30c9617e7bcff2, 0x3fa47ae2d205013c), (0x3c23adb3e2b7f35e, 0x3fa2f664d60473f9), ]; const CL: [u64; 5] = [ 0x3fa1a9a91fd692af, 0x3fa06dfbb35e7f44, 0x3fa037bed4d7588f, 0x3f95aca6d6d720d6, 0x3fa99ea5700d53a5, ]; let dx2 = DoubleDouble::from_exact_mult(x, x); let yw0 = f_fmla(dx2.hi, f64::from_bits(CL[4]), f64::from_bits(CL[3])); let yw1 = f_fmla(dx2.hi, yw0, f64::from_bits(CL[2])); let yw2 = f_fmla(dx2.hi, yw1, f64::from_bits(CL[1])); let y2 = dx2.hi * f_fmla(dx2.hi, yw2, f64::from_bits(CL[0])); let mut y1 = lpoly_xd_generic(dx2, CH, y2); y1 = DoubleDouble::quick_mult_f64(y1, x); y1 = DoubleDouble::quick_mult(y1, dx2); let y0 = DoubleDouble::from_exact_add(x, y1.hi); let mut p = DoubleDouble::from_exact_add(y0.lo, y1.lo); let mut t = p.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = p.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } p.hi = f64::from_bits(t); } y0.hi + p.hi } #[cold] fn atanh_refine(x: f64, a: f64, z: DoubleDouble) -> f64 { let mut t = z.hi.to_bits(); let ex: i32 = (t >> 52) as i32; let e = ex.wrapping_sub(0x3ff); t &= 0x000fffffffffffff; t |= 0x3ffu64 << 52; let ed = e as f64; let v = (a - ed + f64::from_bits(0x3ff0000800000000)).to_bits(); let i = (v.wrapping_sub(0x3ffu64 << 52)) >> (52 - 16); let i1: i32 = ((i >> 12) as i32) & 0x1f; let i2 = (i >> 8) & 0xf; let i3 = (i >> 4) & 0xf; let i4 = i & 0xf; const L20: f64 = f64::from_bits(0x3fd62e42fefa3a00); const L21: f64 = f64::from_bits(0xbcd0ca86c3898d00); const L22: f64 = f64::from_bits(0x397f97b57a079a00); let el2 = L22 * ed; let el1 = L21 * ed; let el0 = L20 * ed; let ll0i1 = ACOSH_ASINH_LL[0][i1 as usize]; let ll1i2 = ACOSH_ASINH_LL[1][i2 as usize]; let ll2i3 = ACOSH_ASINH_LL[2][i3 as usize]; let ll3i4 = ACOSH_ASINH_LL[3][i4 as usize]; let mut dl0 = f64::from_bits(ll0i1.0) + f64::from_bits(ll1i2.0) + (f64::from_bits(ll2i3.0) + f64::from_bits(ll3i4.0)); let dl1 = f64::from_bits(ll0i1.1) + f64::from_bits(ll1i2.1) + (f64::from_bits(ll2i3.1) + f64::from_bits(ll3i4.1)); let dl2 = f64::from_bits(ll0i1.2) + f64::from_bits(ll1i2.2) + (f64::from_bits(ll2i3.2) + f64::from_bits(ll3i4.2)); dl0 += el0; let t12 = f64::from_bits(ACOSH_SINH_REFINE_T1[i1 as usize]) * f64::from_bits(ACOSH_ASINH_REFINE_T2[i2 as usize]); let t34 = f64::from_bits(ACOSH_SINH_REFINE_T3[i3 as usize]) * f64::from_bits(ACOSH_ASINH_REFINE_T4[i4 as usize]); let th = t12 * t34; let tl = f_fmla(t12, t34, -th); let dh = th * f64::from_bits(t); let dl = f_fmla(th, f64::from_bits(t), -dh); let sh = tl * f64::from_bits(t); let sl = f_fmla(tl, f64::from_bits(t), -sh); let mut dx = DoubleDouble::from_exact_add(dh - 1., dl); t = z.lo.to_bits(); t = t.wrapping_sub(((e as i64) << 52) as u64); dx.lo += th * f64::from_bits(t); dx = DoubleDouble::add(dx, DoubleDouble::new(sl, sh)); const CL: [u64; 3] = [0xbfc0000000000000, 0x3fb9999999a0754f, 0xbfb55555555c3157]; let slw0 = f_fmla(dx.hi, f64::from_bits(CL[2]), f64::from_bits(CL[1])); let sl = dx.hi * f_fmla(dx.hi, slw0, f64::from_bits(CL[0])); static CH: [(u64, u64); 3] = [ (0x39024b67ee516e3b, 0x3fe0000000000000), (0xb91932ce43199a8d, 0xbfd0000000000000), (0x3c655540c15cf91f, 0x3fc5555555555555), ]; let mut s = lpoly_xd_generic(dx, CH, sl); s = DoubleDouble::mult(dx, s); s = DoubleDouble::add(s, DoubleDouble::new(el2, el1)); s = DoubleDouble::add(s, DoubleDouble::new(dl2, dl1)); let mut v02 = DoubleDouble::from_exact_add(dl0, s.hi); let mut v12 = DoubleDouble::from_exact_add(v02.lo, s.lo); t = v12.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = v12.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } v12.hi = f64::from_bits(t); } v02.hi *= f64::copysign(1., x); v12.hi *= f64::copysign(1., x); v02.hi + v12.hi } /// Hyperbolic tangent /// /// Max ULP 0.5 pub fn f_atanh(x: f64) -> f64 { let ax = x.abs(); let ix = ax.to_bits(); let aix = ix; if aix >= 0x3ff0000000000000u64 { // |x| >= 1 if aix == 0x3ff0000000000000u64 { // |x| = 1 return f64::copysign(1., x) / 0.0; } if aix > 0x7ff0000000000000u64 { return x + x; } // nan return (-1.0f64).sqrt(); } if aix < 0x3fd0000000000000u64 { // |x| < 0x1p-2 // atanh(x) rounds to x to nearest for |x| < 0x1.d12ed0af1a27fp-27 if aix < 0x3e4d12ed0af1a27fu64 { // |x| < 0x1.d12ed0af1a27fp-27 /* We have underflow exactly when 0 < |x| < 2^-1022: for RNDU, atanh(2^-1022-2^-1074) would round to 2^-1022-2^-1075 with unbounded exponent range */ return f_fmla(x, f64::from_bits(0x3c80000000000000), x); } let x2 = x * x; const C: [u64; 9] = [ 0x3fc999999999999a, 0x3fc2492492492244, 0x3fbc71c71c79715f, 0x3fb745d16f777723, 0x3fb3b13ca4174634, 0x3fb110c9724989bd, 0x3fae2d17608a5b2e, 0x3faa0b56308cba0b, 0x3fafb6341208ad2e, ]; let dx2: f64 = dd_fmla(x, x, -x2); let x4 = x2 * x2; let x3 = x2 * x; let x8 = x4 * x4; let zdx3: f64 = dd_fmla(x2, x, -x3); let dx3 = f_fmla(dx2, x, zdx3); let pw0 = f_fmla(x2, f64::from_bits(C[7]), f64::from_bits(C[6])); let pw1 = f_fmla(x2, f64::from_bits(C[5]), f64::from_bits(C[4])); let pw2 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2])); let pw3 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0])); let pw4 = f_fmla(x4, pw0, pw1); let pw5 = f_fmla(x8, f64::from_bits(C[8]), pw4); let pw6 = f_fmla(x4, pw2, pw3); let p = f_fmla(x8, pw5, pw6); let t = f64::from_bits(0x3c75555555555555) + x2 * p; let mut p = DoubleDouble::from_exact_add(f64::from_bits(0x3fd5555555555555), t); p = DoubleDouble::mult(p, DoubleDouble::new(dx3, x3)); let z0 = DoubleDouble::from_exact_add(x, p.hi); p.lo += z0.lo; p.hi = z0.hi; let eps = x * f_fmla( x4, f64::from_bits(0x3cad000000000000), f64::from_bits(0x3980000000000000), ); let lb = p.hi + (p.lo - eps); let ub = p.hi + (p.lo + eps); if lb == ub { return lb; } return as_atanh_zero(x); } let p = DoubleDouble::from_exact_add(1.0, ax); let q = DoubleDouble::from_exact_sub(1.0, ax); let iqh = 1.0 / q.hi; let th = p.hi * iqh; let tl = dd_fmla(p.hi, iqh, -th) + (p.lo + p.hi * (dd_fmla(-q.hi, iqh, 1.) - q.lo * iqh)) * iqh; const C: [u64; 5] = [ 0xbff0000000000000, 0x3ff5555555555530, 0xbfffffffffffffa0, 0x40099999e33a6366, 0xc01555559ef9525f, ]; let mut t = th.to_bits(); let ex: i32 = (t >> 52) as i32; let e = ex.wrapping_sub(0x3ff); t &= 0x000fffffffffffff; let ed = e as f64; let i = t >> (52 - 5); let d: i64 = (t & 0x00007fffffffffff) as i64; let b_i = ACOSH_ASINH_B[i as usize]; let j: u64 = t .wrapping_add((b_i[0] as u64).wrapping_shl(33)) .wrapping_add((b_i[1] as i64).wrapping_mul(d >> 16) as u64) >> (52 - 10); t |= 0x3ffu64 << 52; let i1: i32 = (j >> 5) as i32; let i2 = j & 0x1f; let r = (0.5 * f64::from_bits(ACOSH_ASINH_R1[i1 as usize])) * f64::from_bits(ACOSH_ASINH_R2[i2 as usize]); let dx = dd_fmla(r, f64::from_bits(t), -0.5); let dx2 = dx * dx; let rx = r * f64::from_bits(t); let dxl = dd_fmla(r, f64::from_bits(t), -rx); let fw0 = f_fmla(dx, f64::from_bits(C[3]), f64::from_bits(C[2])); let fw2 = f_fmla(dx, f64::from_bits(C[1]), f64::from_bits(C[0])); let fw1 = f_fmla(dx2, f64::from_bits(C[4]), fw0); let f = dx2 * f_fmla(dx2, fw1, fw2); const L2H: f64 = f64::from_bits(0x3fd62e42fefa3a00); const L2L: f64 = f64::from_bits(0xbcd0ca86c3898d00); let l1i1 = ATANH_L1[i1 as usize]; let l1i2 = ATANH_L2[i2 as usize]; let lh = f_fmla(L2H, ed, f64::from_bits(l1i1.1) + f64::from_bits(l1i2.1)); let mut zl = DoubleDouble::from_exact_add(lh, rx - 0.5); zl.lo += f_fmla(L2L, ed, f64::from_bits(l1i1.0) + f64::from_bits(l1i2.0)) + dxl + 0.5 * tl / th; zl.lo += f; zl.hi *= f64::copysign(1., x); zl.lo *= f64::copysign(1., x); let eps = 31e-24 + dx2 * f64::from_bits(0x3ce0000000000000); let lb = zl.hi + (zl.lo - eps); let ub = zl.hi + (zl.lo + eps); if lb == ub { return lb; } let t = DoubleDouble::from_exact_add(th, tl); atanh_refine( x, f64::from_bits(0x40071547652b82fe) * (zl.hi + zl.lo).abs(), t, ) } #[cfg(test)] mod tests { use super::*; #[test] fn test_atanh() { assert_eq!(f_atanh(-0.5000824928283691), -0.5494161408216048); assert_eq!(f_atanh(-0.24218760943040252), -0.24709672810738792); } } pxfm-0.1.23/src/hyperbolic/atanhf.rs000064400000000000000000000065641046102023000154320ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::hyperbolic::asinhf::log_eval; use crate::polyeval::f_polyeval6; /// Hyperbolic atan /// /// Max ULP 0.5 #[inline] pub fn f_atanhf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffff; // |x| >= 1.0 if x_abs >= 0x3F80_0000u32 { if x.is_nan() { return x; } // |x| == 1.0 return if x_abs == 0x3F80_0000u32 { if x.is_sign_positive() { f32::INFINITY } else { f32::NEG_INFINITY } } else { f32::NAN }; } // |x| < ~0.10 if x_abs <= 0x3dcc_0000u32 { // |x| <= 2^-26 if x_abs <= 0x3280_0000u32 { return if x_abs == 0 { x } else { (x as f64 + f64::from_bits(0x3fd5555555555555) * x as f64 * x as f64 * x as f64) as f32 }; } let xdbl = x as f64; let x2 = xdbl * xdbl; // Pure Taylor series. let pe = f_polyeval6( x2, 0.0, f64::from_bits(0x3fd5555555555555), f64::from_bits(0x3fc999999999999a), f64::from_bits(0x3fc2492492492492), f64::from_bits(0x3fbc71c71c71c71c), f64::from_bits(0x3fb745d1745d1746), ); return f_fmla(xdbl, pe, xdbl) as f32; } let xdbl = x as f64; (0.5 * log_eval((xdbl + 1.0) / (xdbl - 1.0))) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_atanhf() { assert_eq!(f_atanhf(0.0), 0.0); assert_eq!(f_atanhf(1.0), f32::INFINITY); assert!(f_atanhf(-1.5).is_nan()); assert_eq!(f_atanhf(0.25), 0.25541282); assert_eq!(f_atanhf(0.124121), 0.12476436); } } pxfm-0.1.23/src/hyperbolic/cosh.rs000064400000000000000000000244021046102023000151140ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1}; use crate::hyperbolic::acosh::lpoly_xd_generic; use crate::hyperbolic::sinh::hyperbolic_exp_accurate; #[cold] fn as_cosh_zero(x: f64) -> f64 { static CH: [(u64, u64); 4] = [ (0xb90c7e8db669f624, 0x3fe0000000000000), (0x3c45555555556135, 0x3fa5555555555555), (0xbbef49f4a6e838f2, 0x3f56c16c16c16c17), (0x3b3a4ffbe15316aa, 0x3efa01a01a01a01a), ]; const CL: [u64; 4] = [ 0x3e927e4fb7789f5c, 0x3e21eed8eff9089c, 0x3da939749ce13dad, 0x3d2ae9891efb6691, ]; let dx2 = DoubleDouble::from_exact_mult(x, x); let yw0 = f_fmla(dx2.hi, f64::from_bits(CL[3]), f64::from_bits(CL[2])); let yw1 = f_fmla(dx2.hi, yw0, f64::from_bits(CL[1])); let y2 = dx2.hi * f_fmla(dx2.hi, yw1, f64::from_bits(CL[0])); let mut y1 = lpoly_xd_generic(dx2, CH, y2); y1 = DoubleDouble::quick_mult(y1, dx2); // y2 = y1.l let y0 = DoubleDouble::from_exact_add(1.0, y1.hi); // y0 = y0.hi let mut p = DoubleDouble::from_exact_add(y0.lo, y1.lo); let mut t = p.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = p.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } p.hi = f64::from_bits(t); } y0.hi + p.hi } /// Hyperbolic cosine function /// /// Max ULP 0.5 pub fn f_cosh(x: f64) -> f64 { /* The function sinh(x) is approximated by a minimax polynomial cosh(x)~1+x^2*P(x^2) for |x|<0.125. For other arguments the identity cosh(x)=(exp(|x|)+exp(-|x|))/2 is used. For |x|<5 both exponents are calculated with slightly higher precision than double. For 5<|x|<36.736801 the exp(-|x|) is rather small and is calculated with double precision but exp(|x|) is calculated with higher than double precision. For 36.736801<|x|<710.47586 exp(-|x|) becomes too small and only exp(|x|) is calculated. */ const S: f64 = f64::from_bits(0x40b71547652b82fe); let ax = x.abs(); let v0 = f_fmla(ax, S, f64::from_bits(0x4198000002000000)); let jt = v0.to_bits(); let mut v = v0.to_bits(); v &= 0xfffffffffc000000; let t = f64::from_bits(v) - f64::from_bits(0x4198000000000000); let ix = ax.to_bits(); let aix = ix; if aix < 0x3fc0000000000000u64 { if aix < 0x3e50000000000000u64 { return f_fmla(ax, f64::from_bits(0x3c80000000000000), 1.); } const C: [u64; 5] = [ 0x3fe0000000000000, 0x3fa555555555554e, 0x3f56c16c16c26737, 0x3efa019ffbbcdbda, 0x3e927ffe2df106cb, ]; let x2 = x * x; let x4 = x2 * x2; let p0 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2])); let p1 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0])); let p2 = f_fmla(x4, f64::from_bits(C[4]), p0); let p = x2 * f_fmla(x4, p2, p1); let e = x2 * (4. * f64::from_bits(0x3ca0000000000000)); let lb = 1. + (p - e); let ub = 1. + (p + e); if lb == ub { return lb; } return as_cosh_zero(x); } // treat large values apart to avoid a spurious invalid exception if aix > 0x408633ce8fb9f87du64 { // |x| > 0x1.633ce8fb9f87dp+9 if aix > 0x7ff0000000000000u64 { return x + x; } // nan if aix == 0x7ff0000000000000u64 { return x.abs(); } // inf return f64::from_bits(0x7fe0000000000000) * 2.0; } let il: i64 = ((jt.wrapping_shl(14)) >> 40) as i64; let jl: i64 = -il; let i1 = il & 0x3f; let i0 = (il >> 6) & 0x3f; let ie = il >> 12; let j1 = jl & 0x3f; let j0 = (jl >> 6) & 0x3f; let je = jl >> 12; let mut sp = (1022i64.wrapping_add(ie) as u64).wrapping_shl(52); let sm = (1022i64.wrapping_add(je) as u64).wrapping_shl(52); let sn0 = EXP_REDUCE_T0[i0 as usize]; let sn1 = EXP_REDUCE_T1[i1 as usize]; let t0h = f64::from_bits(sn0.1); let t0l = f64::from_bits(sn0.0); let t1h = f64::from_bits(sn1.1); let t1l = f64::from_bits(sn1.0); let mut th = t0h * t1h; let mut tl = f_fmla(t0h, t1l, t1h * t0l) + dd_fmla(t0h, t1h, -th); const L2H: f64 = f64::from_bits(0x3f262e42ff000000); const L2L: f64 = f64::from_bits(0x3d0718432a1b0e26); let dx = f_fmla(L2L, t, f_fmla(-L2H, t, ax)); let dx2 = dx * dx; let mx = -dx; const CH: [u64; 4] = [ 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555aaaaae, 0x3fa55555551c98c0, ]; let pw0 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pw1 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let pp = dx * f_fmla(dx2, pw0, pw1); let (mut rh, mut rl); if aix > 0x4014000000000000u64 { // |x| > 5 if aix > 0x40425e4f7b2737fau64 { // |x| >~ 36.736801 sp = (1021i64.wrapping_add(ie) as u64).wrapping_shl(52); rh = th; rl = f_fmla(th, pp, tl); let e = 0.11e-18 * th; let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return (lb * f64::from_bits(sp)) * 2.; } let mut tt = hyperbolic_exp_accurate(ax, t, DoubleDouble::new(tl, th)); tt = DoubleDouble::from_exact_add(tt.hi, tt.lo); th = tt.hi; tl = tt.lo; th += tl; th *= 2.; th *= f64::from_bits(sp); return th; } let q0h = f64::from_bits(EXP_REDUCE_T0[j0 as usize].1); let q1h = f64::from_bits(EXP_REDUCE_T1[j1 as usize].1); let mut qh = q0h * q1h; th *= f64::from_bits(sp); tl *= f64::from_bits(sp); qh *= f64::from_bits(sm); let pmw0 = f_fmla(mx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pmw1 = f_fmla(mx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let pm = mx * f_fmla(dx2, pmw0, pmw1); let em = f_fmla(qh, pm, qh); rh = th; rl = f_fmla(th, pp, tl + em); let e = 0.09e-18 * rh; let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return lb; } let tt = hyperbolic_exp_accurate(ax, t, DoubleDouble::new(tl, th)); th = tt.hi; tl = tt.lo; if aix > 0x403f666666666666u64 { rh = th + qh; rl = ((th - rh) + qh) + tl; } else { qh = q0h * q1h; let q0l = f64::from_bits(EXP_REDUCE_T0[j0 as usize].0); let q1l = f64::from_bits(EXP_REDUCE_T1[j1 as usize].0); let mut ql = f_fmla(q0h, q1l, q1h * q0l) + dd_fmla(q0h, q1h, -qh); qh *= f64::from_bits(sm); ql *= f64::from_bits(sm); let qq = hyperbolic_exp_accurate(-ax, -t, DoubleDouble::new(ql, qh)); qh = qq.hi; ql = qq.lo; rh = th + qh; rl = (((th - rh) + qh) + ql) + tl; } } else { let tq0 = EXP_REDUCE_T0[j0 as usize]; let tq1 = EXP_REDUCE_T1[j1 as usize]; let q0h = f64::from_bits(tq0.1); let q0l = f64::from_bits(tq0.0); let q1h = f64::from_bits(tq1.1); let q1l = f64::from_bits(tq1.0); let mut qh = q0h * q1h; let mut ql = f_fmla(q0h, q1l, q1h * q0l) + dd_fmla(q0h, q1h, -qh); th *= f64::from_bits(sp); tl *= f64::from_bits(sp); qh *= f64::from_bits(sm); ql *= f64::from_bits(sm); let pmw0 = f_fmla(mx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pmw1 = f_fmla(mx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let pm = mx * f_fmla(dx2, pmw0, pmw1); let fph = th; let fpl = f_fmla(th, pp, tl); let fmh = qh; let fml = f_fmla(qh, pm, ql); rh = fph + fmh; rl = ((fph - rh) + fmh) + fml + fpl; let e = 0.28e-18 * rh; let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return lb; } let tt = hyperbolic_exp_accurate(ax, t, DoubleDouble::new(tl, th)); let qq = hyperbolic_exp_accurate(-ax, -t, DoubleDouble::new(ql, qh)); rh = tt.hi + qq.hi; rl = ((tt.hi - rh) + qq.hi) + qq.lo + tt.lo; } let r = DoubleDouble::from_exact_add(rh, rl); rh = r.hi; rl = r.lo; rh += rl; rh } #[cfg(test)] mod tests { use super::*; #[test] fn test_cosh() { assert_eq!(f_cosh(1.), 1.5430806348152437); assert_eq!(f_cosh(1.5454354343), 2.451616191647056); assert_eq!(f_cosh(15.5454354343), 2820115.088877147); } } pxfm-0.1.23/src/hyperbolic/coshf.rs000064400000000000000000000136001046102023000152600ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf}; use std::hint::black_box; static TB: [u64; 32] = [ 0x3fe0000000000000, 0x3fe059b0d3158574, 0x3fe0b5586cf9890f, 0x3fe11301d0125b51, 0x3fe172b83c7d517b, 0x3fe1d4873168b9aa, 0x3fe2387a6e756238, 0x3fe29e9df51fdee1, 0x3fe306fe0a31b715, 0x3fe371a7373aa9cb, 0x3fe3dea64c123422, 0x3fe44e086061892d, 0x3fe4bfdad5362a27, 0x3fe5342b569d4f82, 0x3fe5ab07dd485429, 0x3fe6247eb03a5585, 0x3fe6a09e667f3bcd, 0x3fe71f75e8ec5f74, 0x3fe7a11473eb0187, 0x3fe82589994cce13, 0x3fe8ace5422aa0db, 0x3fe93737b0cdc5e5, 0x3fe9c49182a3f090, 0x3fea5503b23e255d, 0x3feae89f995ad3ad, 0x3feb7f76f2fb5e47, 0x3fec199bdd85529c, 0x3fecb720dcef9069, 0x3fed5818dcfba487, 0x3fedfc97337b9b5f, 0x3feea4afa2a490da, 0x3fef50765b6e4540, ]; #[cold] fn coshf_accurate(z: f64, ia: f64, sp: u64, sm: u64) -> f32 { const CH: [u64; 7] = [ 0x3ff0000000000000, 0x3f962e42fefa39ef, 0x3f2ebfbdff82c58f, 0x3ebc6b08d702e0ed, 0x3e43b2ab6fb92e5e, 0x3dc5d886e6d54203, 0x3d4430976b8ce6ef, ]; const ILN2H: f64 = f64::from_bits(0x4047154765000000); const ILN2L: f64 = f64::from_bits(0x3e55c17f0bbbe880); let h = f_fmla(ILN2L, z, f_fmla(ILN2H, z, -ia)); let h2 = h * h; let q0 = f_fmla(h2, f64::from_bits(CH[6]), f64::from_bits(CH[4])); let q1 = f_fmla(h2, f64::from_bits(CH[2]), f64::from_bits(CH[0])); let te = f_fmla(h2 * h2, q0, q1); let j0 = f_fmla(h2, f64::from_bits(CH[5]), f64::from_bits(CH[3])); let to = f_fmla(h2, j0, f64::from_bits(CH[1])); let z0 = f_fmla(h, to, te); let z1 = f_fmla(-h, to, te); f_fmla(f64::from_bits(sp), z0, f64::from_bits(sm) * z1) as f32 } /// Hyperbolic cos /// /// Max found ULP 0.4999996 #[inline] pub fn f_coshf(x: f32) -> f32 { const C: [u64; 4] = [ 0x3ff0000000000000, 0x3f962e42fef4c4e7, 0x3f2ebfd1b232f475, 0x3ebc6b19384ecd93, ]; const I_LN2: f64 = f64::from_bits(0x40471547652b82fe); let t = x.to_bits(); let z = x as f64; let ax = t.wrapping_shl(1); if ax > 0x8565a9f8u32 { // |x| >~ 89.4 if ax >= 0xff000000u32 { if ax.wrapping_shl(8) != 0 { return x + x; } // nan return f32::INFINITY; // +-inf } let r = black_box(2.0) * black_box(f64::from_bits(0x47efffffe0000000) as f32); return r; } if ax < 0x7c000000u32 { // |x| < 0.125 if ax < 0x74000000u32 { // |x| < 0.000488281 if ax < 0x66000000u32 { // |x| < 5.96046e-08 return f_fmlaf(x.abs(), f64::from_bits(0x3e60000000000000) as f32, 1.0); } return f_fmlaf(0.5 * x, x, 1.0); } const CP: [u64; 4] = [ 0x3fdfffffffffffe3, 0x3fa55555555723cf, 0x3f56c16bee4a5986, 0x3efa0483fc0328f7, ]; let z2 = z * z; let z4 = z2 * z2; let w0 = f_fmla(z2, f64::from_bits(CP[1]), f64::from_bits(CP[0])); let w1 = f_fmla(z2, f64::from_bits(CP[3]), f64::from_bits(CP[2])); return f_fmla(z2, f_fmla(z4, w1, w0), 1.0) as f32; } let a = I_LN2 * z; let ia = a.round_ties_even(); let h = a - ia; let h2 = h * h; let ja = (ia + f64::from_bits(0x4338000000000000)).to_bits(); let jp: i64 = ja as i64; let jm = -jp; let sp = TB[(jp & 31) as usize].wrapping_add(jp.wrapping_shr(5).wrapping_shl(52) as u64); let sm = TB[(jm & 31) as usize].wrapping_add(jm.wrapping_shr(5).wrapping_shl(52) as u64); let te = f_fmla(h2, f64::from_bits(C[2]), f64::from_bits(C[0])); let to = f_fmla(h2, f64::from_bits(C[3]), f64::from_bits(C[1])); let rp = f64::from_bits(sp) * f_fmla(h, to, te); let rm = f64::from_bits(sm) * f_fmla(-h, to, te); let r = rp + rm; let ub = r; let lb = r - f64::from_bits(0x3de3edbbe4560327) * r; // Ziv's accuracy test if ub != lb { return coshf_accurate(z, ia, sp, sm); } ub as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_coshf() { assert_eq!(f_coshf(-0.5), 1.127626); assert_eq!(f_coshf(0.5), 1.127626); assert_eq!(f_coshf(7.), 548.317); } } pxfm-0.1.23/src/hyperbolic/mod.rs000064400000000000000000000040631046102023000147400ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![deny(unreachable_pub)] mod acosh; mod acoshf; mod asinh; mod asinhf; mod atanh; mod atanhf; mod cosh; mod coshf; mod sinh; mod sinhf; mod tanh; mod tanhf; pub use acosh::f_acosh; pub use acoshf::f_acoshf; pub use asinh::f_asinh; pub use asinhf::f_asinhf; pub use atanh::f_atanh; pub use atanhf::f_atanhf; pub use cosh::f_cosh; pub use coshf::f_coshf; pub use sinh::f_sinh; pub use sinhf::f_sinhf; pub use tanh::f_tanh; pub use tanhf::f_tanhf; pxfm-0.1.23/src/hyperbolic/sinh.rs000064400000000000000000000272461046102023000151320ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1}; use crate::hyperbolic::acosh::lpoly_xd_generic; #[cold] pub(crate) fn hyperbolic_exp_accurate(x: f64, t: f64, zt: DoubleDouble) -> DoubleDouble { static CH: [(u64, u64); 3] = [ (0x3a16c16bd194535d, 0x3ff0000000000000), (0xba28259d904fd34f, 0x3fe0000000000000), (0x3c653e93e9f26e62, 0x3fc5555555555555), ]; const L2H: f64 = f64::from_bits(0x3f262e42ff000000); const L2L: f64 = f64::from_bits(0x3d0718432a1b0e26); const L2LL: f64 = f64::from_bits(0x3999ff0342542fc3); let dx = x - L2H * t; let mut dxl = L2L * t; let dxll = f_fmla(L2LL, t, dd_fmla(L2L, t, -dxl)); let dxh = dx + dxl; dxl = ((dx - dxh) + dxl) + dxll; let fl0 = f_fmla( dxh, f64::from_bits(0x3f56c16c169400a7), f64::from_bits(0x3f811111113e93e9), ); let fl = dxh * f_fmla(dxh, fl0, f64::from_bits(0x3fa5555555555555)); let mut f = lpoly_xd_generic(DoubleDouble::new(dxl, dxh), CH, fl); f = DoubleDouble::quick_mult(DoubleDouble::new(dxl, dxh), f); f = DoubleDouble::quick_mult(zt, f); let zh = zt.hi + f.hi; let zl = (zt.hi - zh) + f.hi; let uh = zh + zt.lo; let ul = ((zh - uh) + zt.lo) + zl; let vh = uh + f.lo; let vl = ((uh - vh) + f.lo) + ul; DoubleDouble::new(vl, vh) } #[cold] fn as_sinh_zero(x: f64) -> f64 { static CH: [(u64, u64); 5] = [ (0x3c6555555555552f, 0x3fc5555555555555), (0x3c011111115cf00d, 0x3f81111111111111), (0x3b6a0011c925b85c, 0x3f2a01a01a01a01a), (0xbb6b4e2835532bcd, 0x3ec71de3a556c734), (0xbaedefcf17a6ab79, 0x3e5ae64567f54482), ]; let d2x = DoubleDouble::from_exact_mult(x, x); let yw0 = f_fmla( d2x.hi, f64::from_bits(0x3ce95785063cd974), f64::from_bits(0x3d6ae7f36beea815), ); let y2 = d2x.hi * f_fmla(d2x.hi, yw0, f64::from_bits(0x3de6124613aef206)); let mut y1 = lpoly_xd_generic(d2x, CH, y2); y1 = DoubleDouble::quick_mult_f64(y1, x); y1 = DoubleDouble::quick_mult(y1, d2x); // y2 = y1.l let y0 = DoubleDouble::from_exact_add(x, y1.hi); // y0 = y0.hi let mut p = DoubleDouble::from_exact_add(y0.lo, y1.lo); let mut t = p.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = p.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } p.hi = f64::from_bits(t); } y0.hi + p.hi } /// Hyperbolic sine function /// /// Max ULP 0.5 pub fn f_sinh(x: f64) -> f64 { /* The function sinh(x) is approximated by a minimax polynomial for |x|<0.25. For other arguments the identity sinh(x)=(exp(|x|)-exp(-|x|))/2*copysign(1,x) is used. For |x|<5 both exponents are calculated with slightly higher precision than double. For 5<|x|<36.736801 the exp(-|x|) is small and is calculated with double precision but exp(|x|) is calculated with higher than double precision. For 36.736801<|x|<710.47586 exp(-|x|) becomes too small and only exp(|x|) is calculated. */ const S: f64 = f64::from_bits(0x40b71547652b82fe); let ax = x.abs(); let v0 = dd_fmla(ax, S, f64::from_bits(0x4198000002000000)); let jt = v0.to_bits(); let v = v0.to_bits() & 0xfffffffffc000000; let t = f64::from_bits(v) - f64::from_bits(0x4198000000000000); let ix = ax.to_bits(); let aix = ix; if aix < 0x3fd0000000000000u64 { // |x| < 0x1p-2 if aix < 0x3e57137449123ef7u64 { // |x| < 0x1.7137449123ef7p-26 /* We have underflow exactly when 0 < |x| < 2^-1022: for RNDU, sinh(2^-1022-2^-1074) would round to 2^-1022-2^-1075 with unbounded exponent range */ return dd_fmla(x, f64::from_bits(0x3c80000000000000), x); } const C: [u64; 5] = [ 0x3fc5555555555555, 0x3f81111111111087, 0x3f2a01a01a12e1c3, 0x3ec71de2e415aa36, 0x3e5aed2bff4269e6, ]; let x2 = x * x; let x3 = x2 * x; let x4 = x2 * x2; let pw0 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2])); let pw1 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0])); let pw2 = f_fmla(x4, f64::from_bits(C[4]), pw0); let p = x3 * f_fmla(x4, pw2, pw1); let e = x3 * f64::from_bits(0x3ca9000000000000); let lb = x + (p - e); let ub = x + (p + e); if lb == ub { return lb; } return as_sinh_zero(x); } if aix > 0x408633ce8fb9f87du64 { // |x| >~ 710.47586 if aix >= 0x7ff0000000000000u64 { return x + x; } // nan Inf return f64::copysign(f64::from_bits(0x7fe0000000000000), x) * 2.0; } let il: i64 = ((jt.wrapping_shl(14)) >> 40) as i64; let jl = -il; let i1 = il & 0x3f; let i0 = (il >> 6) & 0x3f; let ie = il >> 12; let j1 = jl & 0x3f; let j0 = (jl >> 6) & 0x3f; let je = jl >> 12; let mut sp = (1022i64.wrapping_add(ie) as u64).wrapping_shl(52); let sm = (1022i64.wrapping_add(je) as u64).wrapping_shl(52); let sn0 = EXP_REDUCE_T0[i0 as usize]; let sn1 = EXP_REDUCE_T1[i1 as usize]; let t0h = f64::from_bits(sn0.1); let t0l = f64::from_bits(sn0.0); let t1h = f64::from_bits(sn1.1); let t1l = f64::from_bits(sn1.0); let mut th = t0h * t1h; let mut tl = f_fmla(t0h, t1l, t1h * t0l) + dd_fmla(t0h, t1h, -th); const L2H: f64 = f64::from_bits(0x3f262e42ff000000); const L2L: f64 = f64::from_bits(0x3d0718432a1b0e26); let dx = f_fmla(L2L, t, f_fmla(-L2H, t, ax)); let dx2 = dx * dx; let mx = -dx; const CH: [u64; 4] = [ 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555aaaaae, 0x3fa55555551c98c0, ]; let (mut rl, mut rh); let pp0 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pp1 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let pp = dx * f_fmla(dx2, pp0, pp1); if aix > 0x4014000000000000u64 { // |x| > 5 if aix > 0x40425e4f7b2737fau64 { // |x| >~ 36.736801 sp = (1021i64.wrapping_add(ie) as u64).wrapping_shl(52); let mut rh = th; let mut rl = tl + th * pp; rh *= f64::copysign(1., x); rl *= f64::copysign(1., x); let e = 0.11e-18 * th; let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return (lb * f64::from_bits(sp)) * 2.; } let mut tt = hyperbolic_exp_accurate(ax, t, DoubleDouble::new(tl, th)); tt = DoubleDouble::from_exact_add(tt.hi, tt.lo); th = tt.hi; tl = tt.lo; th *= f64::copysign(1., x); tl *= f64::copysign(1., x); th += tl; th *= 2.; th *= f64::from_bits(sp); return th; } let q0h = f64::from_bits(EXP_REDUCE_T0[j0 as usize].1); let q1h = f64::from_bits(EXP_REDUCE_T1[j1 as usize].1); let mut qh = q0h * q1h; th *= f64::from_bits(sp); tl *= f64::from_bits(sp); qh *= f64::from_bits(sm); let pm0 = f_fmla(mx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pm1 = f_fmla(mx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let pm = mx * f_fmla(dx2, pm0, pm1); let em = f_fmla(qh, pm, qh); rh = th; rl = f_fmla(th, pp, tl - em); rh *= f64::copysign(1., x); rl *= f64::copysign(1., x); let e = 0.09e-18 * rh; let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return lb; } let tt = hyperbolic_exp_accurate(ax, t, DoubleDouble::new(tl, th)); th = tt.hi; tl = tt.lo; if aix > 0x403f666666666666u64 { rh = th - qh; rl = ((th - rh) - qh) + tl; } else { qh = q0h * q1h; let q0l = f64::from_bits(EXP_REDUCE_T0[j0 as usize].0); let q1l = f64::from_bits(EXP_REDUCE_T1[j1 as usize].0); let mut ql = f_fmla(q0h, q1l, q1h * q0l) + dd_fmla(q0h, q1h, -qh); qh *= f64::from_bits(sm); ql *= f64::from_bits(sm); let qq = hyperbolic_exp_accurate(-ax, -t, DoubleDouble::new(ql, qh)); rh = th - qq.hi; rl = (((th - rh) - qq.hi) - qq.lo) + tl; } } else { let tq0 = EXP_REDUCE_T0[j0 as usize]; let tq1 = EXP_REDUCE_T1[j1 as usize]; let q0h = f64::from_bits(tq0.1); let q0l = f64::from_bits(tq0.0); let q1h = f64::from_bits(tq1.1); let q1l = f64::from_bits(tq1.0); let mut qh = q0h * q1h; let mut ql = f_fmla(q0h, q1l, q1h * q0l) + dd_fmla(q0h, q1h, -qh); th *= f64::from_bits(sp); tl *= f64::from_bits(sp); qh *= f64::from_bits(sm); ql *= f64::from_bits(sm); let pm0 = f_fmla(mx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pm1 = f_fmla(mx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let pm = mx * f_fmla(dx2, pm0, pm1); let fph = th; let fpl = f_fmla(th, pp, tl); let fmh = qh; let fml = f_fmla(qh, pm, ql); rh = fph - fmh; rl = ((fph - rh) - fmh) - fml + fpl; rh *= f64::copysign(1., x); rl *= f64::copysign(1., x); let e = 0.28e-18 * rh; let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return lb; } let tt = hyperbolic_exp_accurate(ax, t, DoubleDouble::new(tl, th)); let qq = hyperbolic_exp_accurate(-ax, -t, DoubleDouble::new(ql, qh)); rh = tt.hi - qq.hi; rl = ((tt.hi - rh) - qq.hi) - qq.lo + tt.lo; } let r = DoubleDouble::from_exact_add(rh, rl); rh = r.hi; rl = r.lo; rh *= f64::copysign(1., x); rl *= f64::copysign(1., x); rh += rl; rh } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_sinh() { assert_eq!(f_sinh(1.), 1.1752011936438014); } } pxfm-0.1.23/src/hyperbolic/sinhf.rs000064400000000000000000000142671046102023000152770ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf}; static TB: [u64; 32] = [ 0x3fe0000000000000, 0x3fe059b0d3158574, 0x3fe0b5586cf9890f, 0x3fe11301d0125b51, 0x3fe172b83c7d517b, 0x3fe1d4873168b9aa, 0x3fe2387a6e756238, 0x3fe29e9df51fdee1, 0x3fe306fe0a31b715, 0x3fe371a7373aa9cb, 0x3fe3dea64c123422, 0x3fe44e086061892d, 0x3fe4bfdad5362a27, 0x3fe5342b569d4f82, 0x3fe5ab07dd485429, 0x3fe6247eb03a5585, 0x3fe6a09e667f3bcd, 0x3fe71f75e8ec5f74, 0x3fe7a11473eb0187, 0x3fe82589994cce13, 0x3fe8ace5422aa0db, 0x3fe93737b0cdc5e5, 0x3fe9c49182a3f090, 0x3fea5503b23e255d, 0x3feae89f995ad3ad, 0x3feb7f76f2fb5e47, 0x3fec199bdd85529c, 0x3fecb720dcef9069, 0x3fed5818dcfba487, 0x3fedfc97337b9b5f, 0x3feea4afa2a490da, 0x3fef50765b6e4540, ]; #[cold] fn sinhf_accurate(z: f64, ia: f64, sp: u64, sm: u64) -> f32 { const CH: [u64; 7] = [ 0x3ff0000000000000, 0x3f962e42fefa39ef, 0x3f2ebfbdff82c58f, 0x3ebc6b08d702e0ed, 0x3e43b2ab6fb92e5e, 0x3dc5d886e6d54203, 0x3d4430976b8ce6ef, ]; const ILN2H: f64 = f64::from_bits(0x4047154765000000); const ILN2L: f64 = f64::from_bits(0x3e55c17f0bbbe880); let h = f_fmla(ILN2L, z, f_fmla(ILN2H, z, -ia)); let h2 = h * h; let q0 = f_fmla(h2, f64::from_bits(CH[6]), f64::from_bits(CH[4])); let q1 = f_fmla(h2, f64::from_bits(CH[2]), f64::from_bits(CH[0])); let te = f_fmla(h2 * h2, q0, q1); let q2 = f_fmla(h2, f64::from_bits(CH[5]), f64::from_bits(CH[3])); let to = f_fmla(h2, q2, f64::from_bits(CH[1])); let b0 = f_fmla(h, to, te); let b1 = f_fmla(-h, to, te); f_fmla(f64::from_bits(sp), b0, -f64::from_bits(sm) * b1) as f32 } /// Huperbolic sine function /// /// Max found ULP 0.4954563 #[inline] pub fn f_sinhf(x: f32) -> f32 { const C: [u64; 4] = [ 0x3ff0000000000000, 0x3f962e42fef4c4e7, 0x3f2ebfd1b232f475, 0x3ebc6b19384ecd93, ]; const ST: [(u32, u32, u32); 1] = [(0x74250bfeu32, 0x3a1285ff, 0x2d800000)]; const ILN2: f64 = f64::from_bits(0x40471547652b82fe); let t = x.to_bits(); let z: f64 = x as f64; let ux = t.wrapping_shl(1); if ux > 0x8565a9f8u32 { // |x| > 89.416 let sgn = f32::copysign(2.0, x); if ux >= 0xff000000u32 { if ux.wrapping_shl(8) != 0 { return x + x; } // nan return sgn * f32::INFINITY; // +-inf } let r = sgn * f64::from_bits(0x47efffffe0000000) as f32; return r; } if ux < 0x7c000000u32 { // |x| < 0.125 if ux <= 0x74250bfeu32 { // |x| <= 0.000558942 if ux < 0x66000000u32 { // |x| < 5.96046e-08 return f_fmlaf(x, x.abs(), x); } if ST[0].0 == ux { let sgn = f32::copysign(1.0, x); return f_fmlaf(sgn, f32::from_bits(ST[0].1), sgn * f32::from_bits(ST[0].2)); } return f_fmlaf(x * f64::from_bits(0x3fc5555560000000) as f32, x * x, x); } const CP: [u64; 4] = [ 0x3fc5555555555555, 0x3f811111111146e1, 0x3f2a01a00930dda6, 0x3ec71f92198aa6e9, ]; let z2 = z * z; let z4 = z2 * z2; let w0 = f_fmla(z2, f64::from_bits(CP[3]), f64::from_bits(CP[2])); let w1 = f_fmla(z2, f64::from_bits(CP[1]), f64::from_bits(CP[0])); let w2 = f_fmla(z4, w0, w1); return f_fmla(z2 * z, w2, z) as f32; } let a = ILN2 * z; let ia = a.round_ties_even(); let h = a - ia; let h2 = h * h; let ja = (ia + f64::from_bits(0x4338000000000000)).to_bits(); let jp: i64 = ja as i64; let jm = -jp; let sp = TB[(jp & 31) as usize].wrapping_add(jp.wrapping_shr(5).wrapping_shl(52) as u64); let sm = TB[(jm & 31) as usize].wrapping_add(jm.wrapping_shr(5).wrapping_shl(52) as u64); let te = f_fmla(h2, f64::from_bits(C[2]), f64::from_bits(C[0])); let to = f_fmla(h2, f64::from_bits(C[3]), f64::from_bits(C[1])); let rp = f64::from_bits(sp) * f_fmla(h, to, te); let rm = f64::from_bits(sm) * f_fmla(-h, to, te); let r = rp - rm; let ub = r; let lb = r - f64::from_bits(0x3de4e406496685f4) * r; // Ziv's accuracy test if ub != lb { return sinhf_accurate(z, ia, sp, sm); } ub as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_sinhf() { assert_eq!(f_sinhf(-0.5), -0.5210953); assert_eq!(f_sinhf(0.5), 0.5210953); assert_eq!(f_sinhf(7.), 548.3161); } } pxfm-0.1.23/src/hyperbolic/tanh.rs000064400000000000000000000245631046102023000151220ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1}; use crate::hyperbolic::acosh::lpoly_xd_generic; use crate::hyperbolic::sinh::hyperbolic_exp_accurate; #[cold] fn as_tanh_zero(x: f64) -> f64 { static CH: [(u64, u64); 10] = [ (0xbc75555555555555, 0xbfd5555555555555), (0x3c41111111110916, 0x3fc1111111111111), (0x3c47917917a46f2c, 0xbfaba1ba1ba1ba1c), (0xbc09a52a06f1e599, 0x3f9664f4882c10fa), (0x3c2c297394c24e38, 0xbf8226e355e6c23d), (0xbc0311087e5b1526, 0x3f6d6d3d0e157de0), (0xbbe2868cde54ea0c, 0xbf57da36452b75e1), (0x3bd2cd8fc406c3f7, 0x3f4355824803667b), (0x3b9da22861b4ca80, 0xbf2f57d7734c821d), (0xbbb0831108273a74, 0x3f1967e18ad3facf), ]; let dx2 = DoubleDouble::from_exact_mult(x, x); const CL: [u64; 6] = [ 0xbf0497d8e6462927, 0x3ef0b1318c243bd7, 0xbedb0f2935e9a120, 0x3ec5e9444536e654, 0xbeb174ff2a31908c, 0x3e9749698c8d338d, ]; let yw0 = f_fmla(dx2.hi, f64::from_bits(CL[5]), f64::from_bits(CL[4])); let yw1 = f_fmla(dx2.hi, yw0, f64::from_bits(CL[3])); let yw2 = f_fmla(dx2.hi, yw1, f64::from_bits(CL[2])); let yw3 = f_fmla(dx2.hi, yw2, f64::from_bits(CL[1])); let yw4 = f_fmla(dx2.hi, yw3, f64::from_bits(CL[0])); let y2 = dx2.hi * yw4; let mut y1 = lpoly_xd_generic(dx2, CH, y2); y1 = DoubleDouble::quick_mult_f64(y1, x); y1 = DoubleDouble::quick_mult(y1, dx2); // y2 = y1.l let y0 = DoubleDouble::from_exact_add(x, y1.hi); // y0 = y0.hi let mut p = DoubleDouble::from_exact_add(y0.lo, y1.lo); let mut t = p.hi.to_bits(); if (t & 0x000fffffffffffff) == 0 { let w = p.lo.to_bits(); if ((w ^ t) >> 63) != 0 { t = t.wrapping_sub(1); } else { t = t.wrapping_add(1); } p.hi = f64::from_bits(t); } y0.hi + p.hi } /// Hyperbolic tan /// /// Max ULP 0.5 pub fn f_tanh(x: f64) -> f64 { /* The function tanh(x) is approximated by minimax polynomial for |x|<0.25. For other values we use this identity tanh(|x|) = 1 - 2*exp(-2*|x|)/(1 + exp(-2*|x|)). For large |x|>3.683 the term 2*exp(-2*|x|)/(1 + exp(-2*|x|)) becomes small and we can use less precise formula for exponent. */ let ax = x.abs(); let ix = ax.to_bits(); let aix: u64 = ix; /* for |x| >= 0x1.30fc1931f09cap+4, tanh(x) rounds to +1 or -1 to nearest, this avoid a spurious overflow in the computation of v0 below */ if aix >= 0x40330fc1931f09cau64 { if aix > 0x7ff0000000000000u64 { return x + x; } // nan let f = f64::copysign(1.0, x); if aix == 0x7ff0000000000000u64 { return f; } let df = f64::copysign(f64::from_bits(0x3c80000000000000), x); return f - df; } const S: f64 = f64::from_bits(0xc0c71547652b82fe); let v0 = dd_fmla(ax, S, f64::from_bits(0x4188000004000000)); let jt = v0.to_bits(); let v = v0.to_bits() & 0xfffffffff8000000; let t = f64::from_bits(v) - f64::from_bits(0x4188000000000000); let i1: i64 = ((jt >> 27) & 0x3f) as i64; let i0 = (jt >> 33) & 0x3f; let ie = ((jt.wrapping_shl(13)) >> 52) as i64; let sp = (1023i64.wrapping_add(ie) as u64).wrapping_shl(52); const CH: [u64; 4] = [ 0x4000000000000000, 0x4000000000000000, 0x3ff55555557e54ff, 0x3fe55555553a12f4, ]; let t0h = f64::from_bits(EXP_REDUCE_T0[i0 as usize].1); let t1h = f64::from_bits(EXP_REDUCE_T1[i1 as usize].1); let mut th = t0h * t1h; let mut tl; if aix < 0x400d76c8b4395810u64 { // |x| ~< 3.683 if aix < 0x3fd0000000000000u64 { // |x| < 0x1p-2 if aix < 0x3e10000000000000u64 { // |x| < 0x1p-30 if aix < 0x3df0000000000000u64 { // |x| < 0x1p-32 if aix == 0 { return x; } /* We have underflow when 0 < |x| < 2^-1022 or when |x| = 2^-1022 and rounding towards zero. */ let res = dd_fmla(x, f64::from_bits(0xbc80000000000000), x); return res; } let x3 = x * x * x; return x - x3 / 3.; } const C: [u64; 8] = [ 0xbfd5555555555554, 0x3fc1111111110d61, 0xbfaba1ba1b983d8b, 0x3f9664f4820e99f0, 0xbf8226e11e4ac7cf, 0x3f6d6c4ab70668b6, 0xbf57bbecb57ce996, 0x3f41451443697dd8, ]; let x2 = x * x; let x3 = x2 * x; let x4 = x2 * x2; let x8 = x4 * x4; let p1w0 = f_fmla(x2, f64::from_bits(C[7]), f64::from_bits(C[6])); let p1w1 = f_fmla(x2, f64::from_bits(C[5]), f64::from_bits(C[4])); let p0w0 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2])); let p0w1 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0])); let p1 = f_fmla(x4, p1w0, p1w1); let mut p0 = f_fmla(x4, p0w0, p0w1); p0 += x8 * p1; p0 *= x3; let r = DoubleDouble::from_exact_add(x, p0); let e = x3 * f64::from_bits(0x3cba000000000000); let lb = r.hi + (r.lo - e); let ub = r.hi + (r.lo + e); if lb == ub { return lb; } return as_tanh_zero(x); } let t0l = f64::from_bits(EXP_REDUCE_T0[i0 as usize].0); let t1l = f64::from_bits(EXP_REDUCE_T1[i1 as usize].0); tl = f_fmla(t0h, t1l, t1h * t0l) + dd_fmla(t0h, t1h, -th); th *= f64::from_bits(sp); tl *= f64::from_bits(sp); const L2H: f64 = f64::from_bits(0xbf162e42ff000000); const L2L: f64 = f64::from_bits(0xbcf718432a1b0e26); let dx = f_fmla(-L2L, t, f_fmla(L2H, t, -ax)); let dx2 = dx * dx; let pw0 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pw1 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let p = dx * f_fmla(dx2, pw0, pw1); let mut rh = th; let mut rl = tl + rh * p; let mut r = DoubleDouble::from_exact_add(rh, rl); let ph = r.hi; let pl = r.lo; let mut qh = r.hi; let mut ql = r.lo; let qq = DoubleDouble::from_exact_add(1.0, qh); qh = qq.hi; ql += qq.lo; let rqh = 1.0 / qh; let rql = f_fmla(ql, rqh, dd_fmla(rqh, qh, -1.)) * -rqh; let p = DoubleDouble::mult(DoubleDouble::new(pl, ph), DoubleDouble::new(rql, rqh)); let e = r.hi * f64::from_bits(0x3c10000000000000); r = DoubleDouble::from_exact_sub(0.5, p.hi); r.lo -= p.lo; rh = r.hi * f64::copysign(2., x); rl = r.lo * f64::copysign(2., x); let lb = rh + (rl - e); let ub = rh + (rl + e); if lb == ub { return lb; } } else { const L2: f64 = f64::from_bits(0xbf162e42fefa39ef); let dx = dd_fmla(L2, t, -ax); let dx2 = dx * dx; let pw0 = f_fmla(dx, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let pw1 = f_fmla(dx, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let p = dx * f_fmla(dx2, pw0, pw1); let mut rh = th * f64::from_bits(sp); rh += (p + ((2. * f64::from_bits(0x3c83000000000000)) * ax)) * rh; let e = rh * f64::from_bits(0x3ce1000000000000); rh = (2. * rh) / (1. + rh); let one = f64::copysign(1., x); rh = f64::copysign(rh, x); let lb = one - (rh + e); let ub = one - (rh - e); if lb == ub { return lb; } let t0l = f64::from_bits(EXP_REDUCE_T0[i0 as usize].0); let t1l = f64::from_bits(EXP_REDUCE_T1[i1 as usize].0); tl = f_fmla(t0h, t1l, t1h * t0l) + dd_fmla(t0h, t1h, -th); th *= f64::from_bits(sp); tl *= f64::from_bits(sp); } let mut r = hyperbolic_exp_accurate(-2. * ax, t, DoubleDouble::new(tl, th)); let mut q = DoubleDouble::from_exact_add(1.0, r.hi); q.lo += r.lo; q = DoubleDouble::from_exact_add(q.hi, q.lo); let rqh = 1. / q.hi; let rql = f_fmla(q.lo, rqh, dd_fmla(rqh, q.hi, -1.)) * -rqh; let p = DoubleDouble::mult(r, DoubleDouble::new(rql, rqh)); r = DoubleDouble::from_exact_sub(0.5, p.hi); r.lo -= p.lo; r = DoubleDouble::from_exact_add(r.hi, r.lo); f_fmla(f64::copysign(2., x), r.hi, f64::copysign(2., x) * r.lo) } #[cfg(test)] mod tests { use super::*; #[test] fn test_tanh() { assert_eq!(f_tanh(4.799980150947863), 0.9998645463239773); assert_eq!(f_tanh(2.549980150947863), 0.9878799187977153); } } pxfm-0.1.23/src/hyperbolic/tanhf.rs000064400000000000000000000101651046102023000152610ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf}; /// Hyperbolic tangent /// /// Max found ULP 0.4999994 #[inline] pub fn f_tanhf(x: f32) -> f32 { let z = x as f64; let t = x.to_bits(); let ux = t; let e = ux.wrapping_shr(23) & 0xff; if e == 0xff { if ux << 9 != 0 { return x + x; } // x = nan const IR: [f32; 2] = [1.0, -1.0]; return IR[ux.wrapping_shr(31) as usize]; // x = +-inf } if e < 115 { // |x| < 2^-13 if e < 102 { // |x| < 2^-26 if ux.wrapping_shl(1) == 0 { return x; } let res = f_fmlaf(-x, x.abs(), x); return res; } let x2 = x * x; return f_fmlaf(x, -f64::from_bits(0x3fd5555560000000) as f32 * x2, x); } if ux.wrapping_shl(1) > (0x41102cb3u32 << 1) { return f32::copysign(1.0, x) - f32::copysign(f64::from_bits(0x3e60000000000000) as f32, x); } let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; const CN: [u64; 8] = [ 0x3ff0000000000000, 0x3fc30877b8b72d33, 0x3f7694aa09ae9e5e, 0x3f14101377abb729, 0x3e9e0392b1db0018, 0x3e12533756e546f7, 0x3d6d62e5abe6ae8a, 0x3c9b06be534182de, ]; const CD: [u64; 8] = [ 0x3ff0000000000000, 0x3fded99131b0ebea, 0x3fa0d27ed6c95a69, 0x3f47cbdaca0e9fcc, 0x3edb4e60b892578e, 0x3e5a6f707c5c71ab, 0x3dc35a8b6e2cd94c, 0x3d0ca8230677aa01, ]; let mut n0 = f_fmla(z2, f64::from_bits(CN[1]), f64::from_bits(CN[0])); let n2 = f_fmla(z2, f64::from_bits(CN[3]), f64::from_bits(CN[2])); let mut n4 = f_fmla(z2, f64::from_bits(CN[5]), f64::from_bits(CN[4])); let n6 = f_fmla(z2, f64::from_bits(CN[7]), f64::from_bits(CN[6])); n0 = f_fmla(z4, n2, n0); n4 = f_fmla(z4, n6, n4); n0 = f_fmla(z8, n4, n0); let mut d0 = f_fmla(z2, f64::from_bits(CD[1]), f64::from_bits(CD[0])); let d2 = f_fmla(z2, f64::from_bits(CD[3]), f64::from_bits(CD[2])); let mut d4 = f_fmla(z2, f64::from_bits(CD[5]), f64::from_bits(CD[4])); let d6 = f_fmla(z2, f64::from_bits(CD[7]), f64::from_bits(CD[6])); d0 = f_fmla(z4, d2, d0); d4 = f_fmla(z4, d6, d4); d0 = f_fmla(z8, d4, d0); let r = z * n0 / d0; r as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_tanhf() { assert_eq!(f_tanhf(-0.5), -0.46211717); assert_eq!(f_tanhf(0.5), 0.46211717); assert_eq!(f_tanhf(7.), 0.99999833); } } pxfm-0.1.23/src/lib.rs000064400000000000000000000115171046102023000125710ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ // #![forbid(unsafe_code)] #![deny(unreachable_pub)] #![allow( clippy::excessive_precision, clippy::approx_constant, clippy::manual_range_contains )] #![deny( clippy::print_stdout, clippy::print_stderr, clippy::print_literal, clippy::print_in_format_impl )] mod acos; mod acosf; mod acospi; mod acospif; mod asin; mod asin_eval_dyadic; mod asinf; mod asinpi; mod asinpif; mod bessel; mod bits; mod ceil; mod common; mod compound; mod cosm1; mod csc; mod cube_roots; mod double_double; mod dyadic_float; mod dyadic_float256; mod err; mod exponents; mod floor; mod gamma; mod hyperbolic; mod logs; mod polyeval; mod pow; mod pow_exec; mod pow_tables; mod powf; mod powf_tables; mod round; mod round_ties_even; mod sec; mod shared_eval; mod sin; mod sin_cosf; mod sin_helper; mod sin_table; mod sinc; mod sincos; mod sincos_dyadic; mod sincos_reduce; mod sincos_reduce_tables; mod sincospi; mod sincospi_tables; mod sincpi; mod sinmx; mod square_root; mod tangent; mod triangle; mod triple_double; mod trunc; mod u256; pub use acos::f_acos; pub use acosf::f_acosf; pub use acospi::f_acospi; pub use acospif::f_acospif; pub use asin::f_asin; pub use asinf::f_asinf; pub use asinpi::f_asinpi; pub use asinpif::f_asinpif; pub use bessel::{ f_i0, f_i0f, f_i1, f_i1f, f_i2, f_i2f, f_j0, f_j0f, f_j1, f_j1f, f_jincpi, f_jincpif, f_k0, f_k0f, f_k1, f_k1f, f_k2f, f_y0, f_y0f, f_y1, f_y1f, }; pub use ceil::{ceil, ceilf}; pub use common::{copysignfk, copysignk}; pub use compound::{f_compound, f_compound_m1, f_compound_m1f, f_compoundf, f_powm1, f_powm1f}; pub use cosm1::f_cosm1; pub use csc::f_csc; pub use cube_roots::{cbrtf, f_cbrt, f_cbrtf, f_rcbrt, f_rcbrtf}; pub use err::{ f_erf, f_erfc, f_erfcf, f_erfcinv, f_erfcinvf, f_erfcx, f_erfcxf, f_erff, f_erfinv, f_erfinvf, f_rerf, f_rerff, }; pub use exponents::{ exp, expf, f_exp, f_exp2, f_exp2f, f_exp2m1, f_exp2m1f, f_exp10, f_exp10f, f_exp10m1, f_exp10m1f, f_expf, f_expm1, f_expm1f, }; pub use floor::{floor, floorf}; pub use gamma::{ f_digamma, f_digammaf, f_lgamma, f_lgammaf, f_tgamma, f_tgammaf, f_trigamma, f_trigammaf, }; pub use hyperbolic::{ f_acosh, f_acoshf, f_asinh, f_asinhf, f_atanh, f_atanhf, f_cosh, f_coshf, f_sinh, f_sinhf, f_tanh, f_tanhf, }; pub use logs::{ f_log, f_log1p, f_log1pf, f_log1pmx, f_log1pmxf, f_log2, f_log2f, f_log2p1, f_log2p1f, f_log10, f_log10f, f_log10p1, f_log10p1f, f_logf, log, logf, }; pub use pow::{f_pow, pow}; pub use powf::{dirty_powf, f_powf, powf}; pub use round::{round, roundf}; pub use round_ties_even::{round_ties_even, roundf_ties_even}; pub use sec::f_sec; pub use sin::{f_cos, f_sin}; pub use sin_cosf::{ f_cosf, f_cosm1f, f_cospif, f_cscf, f_secf, f_sincf, f_sincosf, f_sincospif, f_sincpif, f_sinf, f_sinmxf, f_sinpif, }; pub use sinc::f_sinc; pub use sincos::f_sincos; pub use sincospi::{f_cospi, f_sincospi, f_sinpi}; pub use sincpi::f_sincpi; pub use sinmx::f_sinmx; pub use square_root::{f_rsqrt, f_rsqrtf, sqrtf}; pub use tangent::{ f_atan, f_atan2, f_atan2f, f_atan2pi, f_atan2pif, f_atanf, f_atanpi, f_atanpif, f_cot, f_cotf, f_cotpi, f_cotpif, f_tan, f_tanf, f_tanpi, f_tanpif, }; pub use triangle::{f_cathetus, f_cathetusf, f_hypot, f_hypot3f, f_hypotf}; pub use trunc::{trunc, truncf}; pxfm-0.1.23/src/logs/fast_log.rs000064400000000000000000000104141046102023000145600ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::{LOG_COEFFS, LOG_R_DD, LOG_RANGE_REDUCTION}; use crate::polyeval::f_polyeval4; #[inline] pub(crate) fn simple_fast_log(x: f64) -> f64 { let x_u = x.to_bits(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut x_e: i32 = -(E_BIAS as i32); // log2(x) = log2(2^x_e * x_m) // = x_e + log2(x_m) // Range reduction for log2(x_m): // For each x_m, we would like to find r such that: // -2^-8 <= r * x_m - 1 < 2^-7 let shifted = (x_u >> 45) as i32; let index = shifted & 0x7F; let r = f64::from_bits(LOG_RANGE_REDUCTION[index as usize]); // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are // all 1's. x_e = x_e.wrapping_add(x_u.wrapping_add(1u64 << 45).wrapping_shr(52) as i32); let e_x = x_e as f64; const LOG_2_HI: f64 = f64::from_bits(0x3fe62e42fefa3800); const LOG_2_LO: f64 = f64::from_bits(0x3d2ef35793c76730); let log_r_dd = LOG_R_DD[index as usize]; // hi is exact let hi = f_fmla(e_x, LOG_2_HI, f64::from_bits(log_r_dd.1)); // lo errors ~ e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo) + rounding err // <= 2 * (e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo)) let lo = f_fmla(e_x, LOG_2_LO, f64::from_bits(log_r_dd.0)); // Set m = 1.mantissa. let x_m = (x_u & 0x000F_FFFF_FFFF_FFFFu64) | 0x3FF0_0000_0000_0000u64; let m = f64::from_bits(x_m); let u; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { u = f_fmla(r, m, -1.0); // exact } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::LOG_CD; let c_m = x_m & 0x3FFF_E000_0000_0000u64; let c = f64::from_bits(c_m); u = f_fmla(r, m - c, f64::from_bits(LOG_CD[index as usize])); // exact } let r1 = DoubleDouble::from_exact_add(hi, u); let u_sq = u * u; // Degree-7 minimax polynomial let p0 = f_fmla( u, f64::from_bits(LOG_COEFFS[1]), f64::from_bits(LOG_COEFFS[0]), ); let p1 = f_fmla( u, f64::from_bits(LOG_COEFFS[3]), f64::from_bits(LOG_COEFFS[2]), ); let p2 = f_fmla( u, f64::from_bits(LOG_COEFFS[5]), f64::from_bits(LOG_COEFFS[4]), ); let p = f_polyeval4(u_sq, lo + r1.lo, p0, p1, p2); r1.hi + p } pxfm-0.1.23/src/logs/fast_log_dd.rs000064400000000000000000000354631046102023000152420ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /* Given 2^-1074 <= x <= 0x1.fffffffffffffp+1023, this routine puts in h+l an approximation of log(x) such that |l| < 2^-23.89*|h| and | h + l - log(x) | <= elog * |log x| with elog = 2^-73.527 if x < 1/sqrt(2) or sqrt(2) < x, and elog = 2^-67.0544 if 1/sqrt(2) < x < sqrt(2) (note that x cannot equal 1/sqrt(2) nor sqrt(2)). */ use crate::common::dd_fmla; use crate::double_double::DoubleDouble; use crate::pow_exec::log_poly_1; use crate::pow_tables::POW_INVERSE; // Generated by SageMath: // values = POW_INVERSE // R = RealField(150) // // def hex_to_float(h): // return struct.unpack('>d', struct.pack('>Q', h))[0] // // real_array = [R(hex_to_float(h)) for h in values] // // for r in real_array: // print_double_double("", -RealField(180)(r).log()) pub(crate) static FAST_LOG_DD_INV: [(u64, u64); 182] = [ (0x3c6bc60efafc6f6e, 0xbfd5ff3070a793d4), (0x3c78ebcb7dee9a3d, 0xbfd5a42ab0f4cfe2), (0x3c6819cf7e308ddb, 0xbfd548a2c3add263), (0x3c742a87d977dc5e, 0xbfd4ec973260026a), (0x3c69ffc341f177dc, 0xbfd49006804009d1), (0x3c729931715ac903, 0xbfd432ef2a04e814), (0x3c70bcfb6082ce6d, 0xbfd404308686a7e4), (0x3c6c68651945f97c, 0xbfd3a64c556945ea), (0x3c64dd4c580919f8, 0xbfd347dd9a987d55), (0x3c78f4cdb95ebdf9, 0xbfd2e8e2bae11d31), (0xbc77ad24c13f040e, 0xbfd2895a13de86a3), (0x3c776f5eb09628af, 0xbfd22941fbcf7966), (0x3c7c9fdf9a0c4b07, 0xbfd1f8ff9e48a2f3), (0xbc79d3d1b0e4d147, 0xbfd1980d2dd4236f), (0xbc77b66298edd24a, 0xbfd136870293a8b0), (0xbc589fa0ab4cb31d, 0xbfd1058bf9ae4ad5), (0xbc77dcfde8061c03, 0xbfd0a324e27390e3), (0x3c628ec217a5022d, 0xbfd0402594b4d041), (0x3c6caaae64f21acb, 0xbfcfb9186d5e3e2b), (0xbc2c5f6dfd018c37, 0xbfcf550a564b7b37), (0x3c46e03a39bfc89b, 0xbfce8c0252aa5a60), (0x3c461578001e0162, 0xbfce27076e2af2e6), (0xbc66e443597e4d40, 0xbfcd5c216b4fbb91), (0x3c64f689f8434012, 0xbfcc8ff7c79a9a22), (0x3c673dee38a3fb6b, 0xbfcc2968558c18c1), (0xbc6ba27fdc19e1a0, 0xbfcb5b519e8fb5a4), (0x3c5398cff3641985, 0xbfcaf3c94e80bff3), (0xbc493711b07a998c, 0xbfca23bc1fe2b563), (0xbc6575e31f003e0c, 0xbfc9bb362e7dfb83), (0x3c6569d851a56770, 0xbfc8e928de886d41), (0x3c6bf7fdbfa08d9a, 0xbfc87fa06520c911), (0xbc4be36b2d6a0608, 0xbfc7ab890210d909), (0x3c5b264062a84cdb, 0xbfc740f8f54037a5), (0x3c6caae268ecd179, 0xbfc6d60fe719d21d), (0x3c5bc60efafc6f6e, 0xbfc5ff3070a793d4), (0x3c565d22aa8ad7cf, 0xbfc59338d9982086), (0xbc668981bcc36756, 0xbfc4ba36f39a55e5), (0xbc69f4f6543e1f88, 0xbfc44d2b6ccb7d1e), (0x3c5ab3a8e7d81017, 0xbfc3dfc2b0ecc62a), (0x3c06b9c7d96091fa, 0xbfc303d718e47fd3), (0xbc6301771c407dbf, 0xbfc29552f81ff523), (0xbc6f547bf1809e88, 0xbfc2266f190a5acb), (0xbc6a28813e3a7f07, 0xbfc14785846742ac), (0xbc69a5dc5e9030ac, 0xbfc0d77e7cd08e59), (0xbc550c647eb86499, 0xbfc0671512ca596e), (0xbc585f325c5bbacd, 0xbfbf0a30c01162a6), (0x3c361578001e0162, 0xbfbe27076e2af2e6), (0xbc5790dd951d90fa, 0xbfbd4313d66cb35d), (0xbc35d617ef8161b1, 0xbfbc5e548f5bc743), (0xbc5942f48aa70ea9, 0xbfba926d3a4ad563), (0x3c42099e1c184e8e, 0xbfb9ab42462033ad), (0x3c24a697ab3424a9, 0xbfb8c345d6319b21), (0x3c5eeedfcdd94131, 0xbfb7da766d7b12cd), (0x3c5388458ec21b6a, 0xbfb60658a93750c4), (0xbc5a49e39a1a8be4, 0xbfb51b073f06183f), (0xbc4ddd4f935996c9, 0xbfb42edcbea646f0), (0x3c5b599f227becbb, 0xbfb341d7961bd1d1), (0x3c1c125963fc4cfd, 0xbfb253f62f0a1417), (0x3c379da3e8c22cda, 0xbfb16536eea37ae1), (0xbc485f325c5bbacd, 0xbfaf0a30c01162a6), (0xbc21e3c53257fd47, 0xbfad276b8adb0b52), (0x3c3eb9759c130499, 0xbfab42dd711971bf), (0xbc4f5a0e80520bf2, 0xbfa95c830ec8e3eb), (0xbc418d3ca87b9296, 0xbfa77458f632dcfc), (0x3c4ce55c2b4e2b72, 0xbfa58a5bafc8e4d5), (0x3c45bfa937f551bb, 0xbfa39e87b9febd60), (0x3c3e9ae889bac481, 0xbfa1b0d98923d980), (0xbc333e3f04f1ef23, 0xbf9f829b0e783300), (0x3bf0ae69229dc868, 0xbf9b9fc027af9198), (0x3c35b602ace3a510, 0xbf97b91b07d5b11b), (0x3c10cb5a902b3a1c, 0xbf93cea44346a575), (0x3c183092c59642a1, 0xbf8fc0a8b0fc03e4), (0x3c116d7687d3df21, 0xbf87dc475f810a77), (0x3bce44b7e3711ebf, 0xbf7fe02a6b106789), (0x0000000000000000, 0x0000000000000000), (0x0000000000000000, 0x0000000000000000), (0x3bec14b9f9377a1d, 0x3f78121214586b54), (0xbc2c5517f64bc223, 0x3f841929f96832f0), (0x3c2806208c04c220, 0x3f8c317384c75f06), (0xbc2cd7b66e01c26d, 0x3f9228fb1fea2e28), (0xbbf8ed4d357c9c97, 0x3f963d6178690bd6), (0x3c1ec1a5f86d41f9, 0x3f9a55f548c5c43f), (0x3c375b44595cab18, 0x3f9e72bf2813ce51), (0x3c4c05cf1d753622, 0x3fa0415d89e74444), (0xbc4947f792615916, 0x3fa252f32f8d183f), (0xbc4cdd6f7f4a137e, 0x3fa466aed42de3ea), (0x3c40413e6505e603, 0x3fa67c94f2d4bb58), (0x3c3a8be97660a23d, 0x3fa894aa149fb343), (0x3c2a353bb42e0add, 0x3faaaef2d0fb10fc), (0x3c3e5cf3a0f56f72, 0x3fabbcebfc68f420), (0x3c44e6c986f44c55, 0x3fadda8adc67ee4e), (0xbc4cd9f1f95c2eed, 0x3faffa6911ab9301), (0xbc5a4a128d192686, 0x3fb10e45b3cae831), (0xbc5cc0fbce104eaa, 0x3fb2207b5c78549e), (0xbc5d15d38d2fa3f7, 0x3fb2aa04a44717a5), (0x3c47a976d3b5b45f, 0x3fb3bdf5a7d1ee64), (0x3c5769f42c7842cc, 0x3fb4d3115d207eac), (0xbc545f9d61c68c1b, 0x3fb55e10050e0384), (0xbc59acd8b33f8fdc, 0x3fb674f089365a7a), (0x3c5abca5b4fdb880, 0x3fb78d02263d82d3), (0x3c3b9f2dffbeed43, 0x3fb8197e2f40e3f0), (0xbc5478a85704ccb7, 0x3fb9335e5d594989), (0xbc55b5ca203e4259, 0x3fba4e7640b1bc38), (0x3c537d8f39bee659, 0x3fbadc77ee5aea8c), (0xbc4cdc9f6f5f38c7, 0x3fbbf968769fca11), (0x3c49daf7df76ad2a, 0x3fbd179788219364), (0x3c5401fa71733019, 0x3fbda727638446a2), (0xbc4a2bf991780d3f, 0x3fbec739830a1120), (0xbc59361574fb24e2, 0x3fbf57bc7d9005db), (0x3c639e2d3f8b7d10, 0x3fc03cdc0a51ec0d), (0xbc6dd7009902bf32, 0x3fc08598b59e3a07), (0xbc50e63a5f01c691, 0x3fc1178e8227e47c), (0xbc62d56ff61c2bfb, 0x3fc160c8024b27b1), (0x3c462c9ef939ac5d, 0x3fc1f3b925f25d41), (0xbc66e38161051d69, 0x3fc23d712a49c202), (0xbc5499a3f25af95f, 0x3fc2d1610c86813a), (0xbc5c4716bdfc0cc9, 0x3fc31b994d3a4f85), (0x3c370d6cdf05266c, 0x3fc3b08b6757f2a9), (0xbc6d87e6a354d056, 0x3fc3fb45a59928cc), (0xbc50d5604930f135, 0x3fc4913d8333b561), (0xbc6927d47803c5f4, 0x3fc4dc7b897bc1c8), (0x3c64f4d710fec38e, 0x3fc5737cc9018cdd), (0xbc21f5b44c0df7e7, 0x3fc5bf406b543db2), (0xbc3d34f0f4621bed, 0x3fc6574ebe8c133a), (0x3c696332bd4b341f, 0x3fc6a399dabbd383), (0xbc68de59c21e166c, 0x3fc6f0128b756abc), (0x3c5ef8f6ebcfb201, 0x3fc7898d85444c73), (0xbc4ac5f0c075b847, 0x3fc7d6903caf5ad0), (0x3c6d685f35eea2a0, 0x3fc871213750e994), (0x3c555aa8b6997a40, 0x3fc8beafeb38fe8c), (0x3c6054473941ad99, 0x3fc90c6db9fcbcd9), (0x3c6f47dfd871f87f, 0x3fc9a8778debaa38), (0x3c435a19605e67ef, 0x3fc9f6c407089664), (0x3c5df207dc5c34c6, 0x3fca454082e6ab05), (0x3c6ab5ca9eaa088a, 0x3fcae2ca6f672bd4), (0xbc66353ab386a94d, 0x3fcb31d8575bce3d), (0x3c3a0ee735d9f0ec, 0x3fcb811730b823d2), (0x3c3dd355f6a516d7, 0x3fcbd087383bd8ad), (0xbc68e58b2c57a4a5, 0x3fcc6ffbc6f00f71), (0x3c653d154280394f, 0x3fccc000c9db3c52), (0x3c660629242471a2, 0x3fcd1037f2655e7b), (0x3c5aa11d49f96cb9, 0x3fcdb13db0d48940), (0x3c5fea48dd7b81d1, 0x3fce020cc6235ab5), (0x3c42276041f43042, 0x3fce530effe71012), (0xbc6d33919ab94074, 0x3fcea4449f04aaf5), (0xbc527c77ded76aad, 0x3fcf474b134df229), (0x3c6f665066f980a2, 0x3fcf991c6cb3b379), (0x3c28de00938b4c40, 0x3fcfeb2233ea07cd), (0xbc418290bd2932e2, 0x3fd01eae5626c691), (0xbc70779634061cbc, 0x3fd047e60cde83b8), (0x3c643c2e68684d53, 0x3fd09aa572e6c6d4), (0x3c5162c79d5d11ee, 0x3fd0c42d676162e3), (0xbc692b49ef282b09, 0x3fd0edd060b78081), (0xbc60e63a5f01c691, 0x3fd1178e8227e47c), (0x3c1e0936abd4fa6e, 0x3fd14167ef367783), (0x3c766fbd28b40935, 0x3fd16b5ccbacfb73), (0xbc612aeb84249223, 0x3fd1bf99635a6b95), (0x3c7512c3749a1e4e, 0x3fd1e9e1678899f4), (0x3c6f7ae91aeba60a, 0x3fd214456d0eb8d4), (0x3c3bb75d1addf870, 0x3fd23ec5991eba49), (0x3c7e0efadd9db02b, 0x3fd269621134db92), (0xbc6856e61c515740, 0x3fd2941afb186b7c), (0xbc782dad7fd86088, 0x3fd2bef07cdc9354), (0xbc73d69909e5c3dc, 0x3fd314f1e1d35ce4), (0xbc5cd55b8a4746c0, 0x3fd3401e12aecba1), (0xbc5324f0e883858e, 0x3fd36b6776be1117), (0xbc5ce2b31b31e8b0, 0x3fd396ce359bbf54), (0xbc72ad27e50a8ec6, 0x3fd3c25277333184), (0x3c783d680d3c1084, 0x3fd3edf463c1683e), (0x3c60dbb243827392, 0x3fd419b423d5e8c7), (0xbc72b125247b0fa5, 0x3fd44591e0539f49), (0x3c38fb4c14c56eef, 0x3fd4718dc271c41b), (0xbc69964a168ccaca, 0x3fd49da7f3bcc41f), (0xbc5123615b147a5d, 0x3fd4c9e09e172c3c), (0xbc758cb3124b9245, 0x3fd4f637ebba9810), (0xbc68f7e9b38a6979, 0x3fd522ae0738a3d8), (0xbc7aacfdbbdab914, 0x3fd54f431b7be1a9), (0xbc60908d15f88b63, 0x3fd57bf753c8d1fb), (0xbc5e6c2bdfb3e037, 0x3fd5a8cadbbedfa1), (0xbc76541148cbb8a2, 0x3fd5d5bddf595f30), (0xbc56e8920c09b73f, 0x3fd602d08af091ec), (0x3c6dc18ce51fff99, 0x3fd630030b3aac49), ]; #[inline] pub(crate) fn fast_log_dd(ddx: DoubleDouble) -> DoubleDouble { // We'll compute log((z+1)+1) as log(xh+xl) = log(xh) + log(1+xl/xh). // since xl/xh < ulp(xh) we'll use for log(1+xl/xh) // one taylor term what means that log(1+xl/xh) = log_lo + O(x^2) let log_lo = if ddx.hi <= f64::from_bits(0x7fd0000000000000) || ddx.lo.abs() >= 4.0 { ddx.lo / ddx.hi } else { 0. }; // avoid spurious underflow let x_u = ddx.hi.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; /* i/2^8 <= t < (i+1)/2^8 */ /* when c=1, we have 0x16a09e667f3bcd <= m < 2^53, thus 90 <= i <= 127; when c=0, we have 2^52 <= m < 0x16a09e667f3bcd, thus 128 <= i <= 181 */ t *= CY[c]; /* now 0x1.6a09e667f3bcdp-1 <= t < 0x1.6a09e667f3bcdp+0, and log(x) = E * log(2) + log(t) */ let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = DoubleDouble::from_bit_pair(FAST_LOG_DD_INV[(i - 181) as usize]); let z = dd_fmla(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7abc9e3b39803f), f64::from_bits(0x3fe62e42fefa39ef), ); let dt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r); let mut v = DoubleDouble::f64_add(dt.hi, DoubleDouble::new(dt.lo, z)); let p = log_poly_1(z); v = DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo + log_lo, p.hi)); v } #[inline] pub(crate) fn fast_log_d_to_dd(ddx: f64) -> DoubleDouble { // We'll compute log((z+1)+1) as log(xh+xl) = log(xh) + log(1+xl/xh). // since xl/xh < ulp(xh) we'll use for log(1+xl/xh) // one taylor term what means that log(1+xl/xh) = log_lo + O(x^2) let x_u = ddx.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; /* i/2^8 <= t < (i+1)/2^8 */ /* when c=1, we have 0x16a09e667f3bcd <= m < 2^53, thus 90 <= i <= 127; when c=0, we have 2^52 <= m < 0x16a09e667f3bcd, thus 128 <= i <= 181 */ t *= CY[c]; /* now 0x1.6a09e667f3bcdp-1 <= t < 0x1.6a09e667f3bcdp+0, and log(x) = E * log(2) + log(t) */ let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = DoubleDouble::from_bit_pair(FAST_LOG_DD_INV[(i - 181) as usize]); let z = dd_fmla(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7abc9e3b39803f), f64::from_bits(0x3fe62e42fefa39ef), ); let dt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r); let mut v = DoubleDouble::f64_add(dt.hi, DoubleDouble::new(dt.lo, z)); let p = log_poly_1(z); v = DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)); DoubleDouble::from_exact_add(v.hi, v.lo) } pxfm-0.1.23/src/logs/log.rs000064400000000000000000000346131046102023000135520ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, fmla, min_normal_f64}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log_dyadic::{LOG_STEP_1, LOG_STEP_2, LOG_STEP_3, LOG_STEP_4}; use crate::logs::log_range_reduction::log_range_reduction; use crate::logs::log_td::log_td; use crate::logs::log2::LOG_RANGE_REDUCTION; use crate::logs::log10::LOG_R_DD; use crate::logs::{LOG_COEFFS, log_dd}; use crate::polyeval::f_polyeval4; /// Assumes that NaN and infinities, negatives were filtered out pub(crate) fn log_dyadic(x: f64) -> DyadicFloat128 { let mut x_u = x.to_bits(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut x_e: i32 = -(E_BIAS as i32); const MAX_NORMAL: u64 = f64::to_bits(f64::MAX); if x_u == 1f64.to_bits() { // log2(1.0) = +0.0 return DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0u128, }; } if x_u < min_normal_f64().to_bits() || x_u > MAX_NORMAL { // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4330000000000000)).to_bits(); x_e -= 52; } // Range reduction for log2(x_m): // For each x_m, we would like to find r such that: // -2^-8 <= r * x_m - 1 < 2^-7 let shifted = (x_u >> 45) as i32; let index = shifted & 0x7F; let r = f64::from_bits(LOG_RANGE_REDUCTION[index as usize]); // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are // all 1's. x_e = x_e.wrapping_add(x_u.wrapping_add(1u64 << 45).wrapping_shr(52) as i32); // Set m = 1.mantissa. let x_m = (x_u & 0x000F_FFFF_FFFF_FFFFu64) | 0x3FF0_0000_0000_0000u64; let m = f64::from_bits(x_m); let u; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { u = f_fmla(r, m, -1.0); // exact } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log2::LOG_CD; let c_m = x_m & 0x3FFF_E000_0000_0000u64; let c = f64::from_bits(c_m); u = f_fmla(r, m - c, f64::from_bits(LOG_CD[index as usize])); // exact } log_accurate(x_e, index, u) } // Reuse the output of the fast pass range reduction. // -2^-8 <= m_x < 2^-7 #[cold] fn log_accurate(e_x: i32, index: i32, m_x: f64) -> DyadicFloat128 { // > P = fpminimax((log(1 + x) - x)/x^2, 2, [|1, 128...|], // [-0x1.0002143p-29 , 0x1p-29]); // > P; // > dirtyinfnorm(log(1 + x)/x - x*P, [-0x1.0002143p-29 , 0x1p-29]); // 0x1.99a3...p-121 const BIG_COEFFS: [DyadicFloat128; 3] = [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x8000_0000_0006_a710_b59c_58e5_554d_581c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaaaa_aaaa_aaaa_aabd_de05_c7c9_4ae9_cbae_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, ]; const LOG_2: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb17217f7_d1cf79ab_c9e3b398_03f2f6af_u128, }; let e_x_f128 = DyadicFloat128::new_from_f64(e_x as f64); let mut sum = LOG_2 * e_x_f128; sum = sum + LOG_STEP_1[index as usize]; let (v_f128, mut sum) = log_range_reduction( m_x, &[&LOG_STEP_1, &LOG_STEP_2, &LOG_STEP_3, &LOG_STEP_4], sum, ); sum = sum + v_f128; // Polynomial approximation let mut p = v_f128 * BIG_COEFFS[0]; p = v_f128 * (p + BIG_COEFFS[1]); p = v_f128 * (p + BIG_COEFFS[2]); p = v_f128 * p; sum + p } /// Natural logarithm /// /// Max found ULP 0.5 pub fn f_log(x: f64) -> f64 { let mut x_u = x.to_bits(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut x_e: i32 = -(E_BIAS as i32); const MAX_NORMAL: u64 = f64::to_bits(f64::MAX); if x_u == 1f64.to_bits() { // log2(1.0) = +0.0 return 0.0; } if x_u < min_normal_f64().to_bits() || x_u > MAX_NORMAL { if x == 0.0 { return f64::NEG_INFINITY; } if x < 0. || x.is_nan() { return f64::NAN; } if x.is_infinite() || x.is_nan() { return x + x; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4330000000000000)).to_bits(); x_e -= 52; } // log2(x) = log2(2^x_e * x_m) // = x_e + log2(x_m) // Range reduction for log2(x_m): // For each x_m, we would like to find r such that: // -2^-8 <= r * x_m - 1 < 2^-7 let shifted = (x_u >> 45) as i32; let index = shifted & 0x7F; let r = f64::from_bits(LOG_RANGE_REDUCTION[index as usize]); // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are // all 1's. x_e = x_e.wrapping_add(x_u.wrapping_add(1u64 << 45).wrapping_shr(52) as i32); let e_x = x_e as f64; const LOG_2_HI: f64 = f64::from_bits(0x3fe62e42fefa3800); const LOG_2_LO: f64 = f64::from_bits(0x3d2ef35793c76730); let log_r_dd = LOG_R_DD[index as usize]; // hi is exact let hi = f_fmla(e_x, LOG_2_HI, f64::from_bits(log_r_dd.1)); // lo errors ~ e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo) + rounding err // <= 2 * (e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo)) let lo = f_fmla(e_x, LOG_2_LO, f64::from_bits(log_r_dd.0)); // Set m = 1.mantissa. let x_m = (x_u & 0x000F_FFFF_FFFF_FFFFu64) | 0x3FF0_0000_0000_0000u64; let m = f64::from_bits(x_m); let u; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { u = f_fmla(r, m, -1.0); // exact } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log2::LOG_CD; let c_m = x_m & 0x3FFF_E000_0000_0000u64; let c = f64::from_bits(c_m); u = f_fmla(r, m - c, f64::from_bits(LOG_CD[index as usize])); // exact } let r1 = DoubleDouble::from_exact_add(hi, u); let u_sq = u * u; // Degree-7 minimax polynomial // Minimax polynomial for (log(1 + x) - x)/x^2, generated by sollya with: // > P = fpminimax((log(1 + x) - x)/x^2, 5, [|D...|], [-2^-8, 2^-7]); let p0 = f_fmla( u, f64::from_bits(LOG_COEFFS[1]), f64::from_bits(LOG_COEFFS[0]), ); let p1 = f_fmla( u, f64::from_bits(LOG_COEFFS[3]), f64::from_bits(LOG_COEFFS[2]), ); let p2 = f_fmla( u, f64::from_bits(LOG_COEFFS[5]), f64::from_bits(LOG_COEFFS[4]), ); let p = f_polyeval4(u_sq, lo + r1.lo, p0, p1, p2); const HI_ERR: f64 = f64::from_bits(0x3aa0000000000000); // Extra errors from P is from using x^2 to reduce evaluation latency. const P_ERR: f64 = f64::from_bits(0x3cd0000000000000); // Technicallly error of r1.lo is bounded by: // hi*ulp(log(2)_lo) + C*ulp(u^2) // To simplify the error computation a bit, we replace |hi|*ulp(log(2)_lo) // with the upper bound: 2^11 * ulp(log(2)_lo) = 2^-85. // Total error is bounded by ~ C * ulp(u^2) + 2^-85. let err = f_fmla(u_sq, P_ERR, HI_ERR); // Lower bound from the result let left = r1.hi + (p - err); // Upper bound from the result let right = r1.hi + (p + err); // Ziv's test if fast pass is accurate enough. if left == right { return left; } log_accurate_slow(x) } #[cold] #[inline(never)] fn log_accurate_slow(x: f64) -> f64 { let r = log_dd(x); let err = f_fmla( r.hi, f64::from_bits(0x3b50000000000000), // 2^-74 f64::from_bits(0x3990000000000000), // 2^-102 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } log_accurate_slow_td(x) } #[cold] #[inline(never)] fn log_accurate_slow_td(x: f64) -> f64 { log_td(x).to_f64() } /// Log for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn log(d: f64) -> f64 { const LN_POLY_2_D: f64 = 0.6666666666666762678e+0; const LN_POLY_3_D: f64 = 0.3999999999936908641e+0; const LN_POLY_4_D: f64 = 0.2857142874046159249e+0; const LN_POLY_5_D: f64 = 0.2222219947428228041e+0; const LN_POLY_6_D: f64 = 0.1818349302807168999e+0; const LN_POLY_7_D: f64 = 0.1531633000781658996e+0; const LN_POLY_8_D: f64 = 0.1476969208015536904e+0; let e = d.to_bits().wrapping_shr(52).wrapping_sub(0x3ff); if e >= 0x400 || e == 0x00000000fffffc01 { let minf = 0xfffu64 << 52; if e == 0x400 || (e == 0xc00 && d != f64::from_bits(minf)) { /* +Inf or NaN */ return d + d; } if d <= 0. { return if d < 0. { f64::NAN } else { f64::NEG_INFINITY }; } } // reduce into [sqrt(2)/2;sqrt(2)] let mut ui: u64 = d.to_bits(); let mut hx = (ui >> 32) as u32; hx = hx.wrapping_add(0x3ff00000 - 0x3fe6a09e); let n = (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff).wrapping_add(0x3fe6a09e); ui = (hx as u64) << 32 | (ui & 0xffffffff); let a = f64::from_bits(ui); let m = a - 1.; let x = m / (a + 1.); let x2 = x * x; let f = x2; const LN2_H: f64 = 0.6931471805599453; const LN2_L: f64 = 2.3190468138462996e-17; let mut u = LN_POLY_8_D; u = fmla(u, f, LN_POLY_7_D); u = fmla(u, f, LN_POLY_6_D); u = fmla(u, f, LN_POLY_5_D); u = fmla(u, f, LN_POLY_4_D); u = fmla(u, f, LN_POLY_3_D); u = fmla(u, f, LN_POLY_2_D); u *= f; let t = m * m * 0.5; let r = fmla(x, t, fmla(x, u, LN2_L * n as f64)) - t + m; fmla(LN2_H, n as f64, r) } #[cfg(test)] mod tests { use super::*; #[test] fn log_test() { assert!( (log(1f64) - 0f64).abs() < 1e-8, "Invalid result {}", log(1f64) ); assert!( (log(5f64) - 1.60943791243410037460f64).abs() < 1e-8, "Invalid result {}", log(5f64) ); } #[test] fn f_log_test() { assert_eq!(f_log(1.99999999779061), 0.693147179455250308807056); assert_eq!(f_log(0.9999999999999999), -1.1102230246251565e-16); assert!( (f_log(1f64) - 0f64).abs() < 1e-8, "Invalid result {}", f_log(1f64) ); assert!( (f_log(5f64) - 5f64.ln()).abs() < 1e-8, "Invalid result {}, expected {}", f_log(5f64), 5f64.ln() ); assert_eq!( f_log(23f64), 3.13549421592914969080675283181019611844238031484043574199863537748299324598, "Invalid result {}, expected {}", f_log(23f64), 3.13549421592914969080675283181019611844238031484043574199863537748299324598, ); assert_eq!(f_log(0.), f64::NEG_INFINITY); assert!(f_log(-1.).is_nan()); assert!(f_log(f64::NAN).is_nan()); assert!(f_log(f64::NEG_INFINITY).is_nan()); assert_eq!(f_log(f64::INFINITY), f64::INFINITY); } #[test] fn log_control_values() { assert_eq!( f_log(f64::from_bits(0x3ff1211bef8f68e9)), 0.06820362355801819 ); assert_eq!( f_log(f64::from_bits(0x3ff008000db2e8be)), 0.0019512710640270448 ); assert_eq!( f_log(f64::from_bits(0x3ff10803885617a6)), 0.062464334544603616 ); assert_eq!( f_log(f64::from_bits(0x3ff48ae5a67204f5)), 0.24991043470757288 ); assert_eq!( f_log(f64::from_bits(0x3fedc0b586f2b260)), -0.07281366978582131 ); assert_eq!( f_log(f64::from_bits(0x3fe490af72a25a81)), -0.44213668842326787 ); assert_eq!( f_log(f64::from_bits(0x4015b6e7e4e96f86)), 1.6916847703128641 ); assert_eq!( f_log(f64::from_bits(0x3ff0ffc349469a2f)), 0.06057012512237759 ); assert_eq!( f_log(f64::from_bits(0x3fe69e7aa6da2df5)), -0.3469430325599064 ); assert_eq!( f_log(f64::from_bits(0x3fe5556123e8a2b0)), -0.4054566631657151 ); } } pxfm-0.1.23/src/logs/log10.rs000064400000000000000000000315671046102023000137200ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, min_normal_f64}; use crate::double_double::DoubleDouble; use crate::logs::log2::LOG_COEFFS; use crate::logs::log10dd::log10_dd; use crate::logs::log10td::log10_td; use crate::polyeval::f_polyeval4; pub(crate) static LOG_R_DD: [(u64, u64); 128] = [ (0x0000000000000000, 0x0000000000000000), (0xbd10c76b999d2be8, 0x3f80101575890000), (0xbd23dc5b06e2f7d2, 0x3f90205658938000), (0xbd2aa0ba325a0c34, 0x3f98492528c90000), (0x3d0111c05cf1d753, 0x3fa0415d89e74000), (0xbd2c167375bdfd28, 0x3fa466aed42e0000), (0xbd197995d05a267d, 0x3fa894aa149fc000), (0xbd1a68f247d82807, 0x3faccb73cdddc000), (0xbd17e5dd7009902c, 0x3fb08598b59e4000), (0xbd25325d560d9e9b, 0x3fb1973bd1466000), (0x3d2cc85ea5db4ed7, 0x3fb3bdf5a7d1e000), (0xbd2c69063c5d1d1e, 0x3fb5e95a4d97a000), (0x3cec1e8da99ded32, 0x3fb700d30aeac000), (0x3d23115c3abd47da, 0x3fb9335e5d594000), (0xbd1390802bf768e5, 0x3fbb6ac88dad6000), (0x3d2646d1c65aacd3, 0x3fbc885801bc4000), (0xbd2dc068afe645e0, 0x3fbec739830a2000), (0xbd2534d64fa10afd, 0x3fbfe89139dbe000), (0x3d21ef78ce2d07f2, 0x3fc1178e8227e000), (0x3d2ca78e44389934, 0x3fc1aa2b7e23f000), (0x3d039d6ccb81b4a1, 0x3fc2d1610c868000), (0x3cc62fa8234b7289, 0x3fc365fcb0159000), (0x3d25837954fdb678, 0x3fc4913d8333b000), (0x3d2633e8e5697dc7, 0x3fc527e5e4a1b000), (0x3d19cf8b2c3c2e78, 0x3fc6574ebe8c1000), (0xbd25118de59c21e1, 0x3fc6f0128b757000), (0x3d1e0ddb9a631e83, 0x3fc823c16551a000), (0xbd073d54aae92cd1, 0x3fc8beafeb390000), (0x3d07f22858a0ff6f, 0x3fc95a5adcf70000), (0xbd28724350562169, 0x3fca93ed3c8ae000), (0xbd0c358d4eace1aa, 0x3fcb31d8575bd000), (0xbd2d4bc4595412b6, 0x3fcbd087383be000), (0xbd084a7e75b6f6e4, 0x3fcd1037f2656000), (0xbd2aff2af715b035, 0x3fcdb13db0d49000), (0x3cc212276041f430, 0x3fce530effe71000), (0xbcca211565bb8e11, 0x3fcef5ade4dd0000), (0x3d1bcbecca0cdf30, 0x3fcf991c6cb3b000), (0x3cf89cdb16ed4e91, 0x3fd07138604d5800), (0x3d27188b163ceae9, 0x3fd0c42d67616000), (0xbd2c210e63a5f01c, 0x3fd1178e8227e800), (0x3d2b9acdf7a51681, 0x3fd16b5ccbacf800), (0x3d2ca6ed5147bdb7, 0x3fd1bf99635a6800), (0x3d2c93c1df5bb3b6, 0x3fd269621134d800), (0x3d2a9cfa4a5004f4, 0x3fd2bef07cdc9000), (0xbd28e27ad3213cb8, 0x3fd314f1e1d36000), (0x3d116ecdb0f177c8, 0x3fd36b6776be1000), (0x3d183b54b606bd5c, 0x3fd3c25277333000), (0x3d08e436ec90e09d, 0x3fd419b423d5e800), (0xbd2f27ce0967d675, 0x3fd4718dc271c800), (0xbd2e20891b0ad8a4, 0x3fd4c9e09e173000), (0x3d2ebe708164c759, 0x3fd522ae0738a000), (0x3d1fadedee5d40ef, 0x3fd57bf753c8d000), (0xbd0a0b2a08a465dc, 0x3fd5d5bddf596000), (0xbd2db623e731ae00, 0x3fd630030b3ab000), (0x3d20a0d32756eba0, 0x3fd68ac83e9c6800), (0x3d1721657c222d87, 0x3fd6e60ee6af1800), (0x3d2d8b0949dc60b3, 0x3fd741d876c67800), (0x3d29ec7d2efd1778, 0x3fd79e26687cf800), (0xbd272090c812566a, 0x3fd7fafa3bd81800), (0x3d2fd56f3333778a, 0x3fd85855776dc800), (0xbd205ae1e5e70470, 0x3fd8b639a88b3000), (0xbd1766b52ee6307d, 0x3fd914a8635bf800), (0xbd152313a502d9f0, 0x3fd973a343135800), (0xbd26279e10d0c0b0, 0x3fd9d32bea15f000), (0x3d23c6457f9d79f5, 0x3fda33440224f800), (0x3d23c6457f9d79f5, 0x3fda33440224f800), (0x3d1e36f2bea77a5d, 0x3fda93ed3c8ad800), (0xbd217cc552774458, 0x3fdaf5295248d000), (0x3d1095252d841995, 0x3fdb56fa04462800), (0x3d27d85bf40a666d, 0x3fdbb9611b80e000), (0x3d2cec807fe8e180, 0x3fdc1c60693fa000), (0x3d2cec807fe8e180, 0x3fdc1c60693fa000), (0xbd29b6ddc15249ae, 0x3fdc7ff9c7455800), (0xbd0797c33ec7a6b0, 0x3fdce42f18064800), (0x3d235bafe9a767a8, 0x3fdd490246def800), (0xbd1ea42d60dc616a, 0x3fddae75484c9800), (0xbd1326b207322938, 0x3fde148a1a272800), (0xbd1326b207322938, 0x3fde148a1a272800), (0xbd2465505372bd08, 0x3fde7b42c3ddb000), (0x3d2f27f45a470251, 0x3fdee2a156b41000), (0x3d12cde56f014a8b, 0x3fdf4aa7ee031800), (0x3d12cde56f014a8b, 0x3fdf4aa7ee031800), (0x3d0085fa3c164935, 0x3fdfb358af7a4800), (0xbd053ba3b1727b1c, 0x3fe00e5ae5b20800), (0xbd04c45fe79539e0, 0x3fe04360be760400), (0xbd04c45fe79539e0, 0x3fe04360be760400), (0x3d26812241edf5fd, 0x3fe078bf0533c400), (0x3d1f486b887e7e27, 0x3fe0ae76e2d05400), (0x3d1f486b887e7e27, 0x3fe0ae76e2d05400), (0x3d1c299807801742, 0x3fe0e4898611cc00), (0xbd258647bb9ddcb2, 0x3fe11af823c75c00), (0xbd258647bb9ddcb2, 0x3fe11af823c75c00), (0xbd2edd97a293ae49, 0x3fe151c3f6f29800), (0x3d14cc4ef8ab4650, 0x3fe188ee40f23c00), (0x3d14cc4ef8ab4650, 0x3fe188ee40f23c00), (0x3cccacdeed70e667, 0x3fe1c07849ae6000), (0xbd2a7242c9fe81d3, 0x3fe1f8635fc61800), (0xbd2a7242c9fe81d3, 0x3fe1f8635fc61800), (0x3d12fc066e48667b, 0x3fe230b0d8bebc00), (0xbd0b61f105226250, 0x3fe269621134dc00), (0xbd0b61f105226250, 0x3fe269621134dc00), (0x3d206d2be797882d, 0x3fe2a2786d0ec000), (0xbd17a6e507b9dc11, 0x3fe2dbf557b0e000), (0xbd17a6e507b9dc11, 0x3fe2dbf557b0e000), (0xbd274e93c5a0ed9c, 0x3fe315da44340800), (0xbd274e93c5a0ed9c, 0x3fe315da44340800), (0x3d10b83f9527e6ac, 0x3fe35028ad9d8c00), (0xbd218b7abb5569a4, 0x3fe38ae217197800), (0xbd218b7abb5569a4, 0x3fe38ae217197800), (0xbd02b7367cfe13c2, 0x3fe3c6080c36c000), (0xbd02b7367cfe13c2, 0x3fe3c6080c36c000), (0xbd26ce7930f0c74c, 0x3fe4019c2125cc00), (0xbcfd984f481051f7, 0x3fe43d9ff2f92400), (0xbcfd984f481051f7, 0x3fe43d9ff2f92400), (0xbd22cb6af94d60aa, 0x3fe47a1527e8a400), (0xbd22cb6af94d60aa, 0x3fe47a1527e8a400), (0x3cef7115ed4c541c, 0x3fe4b6fd6f970c00), (0x3cef7115ed4c541c, 0x3fe4b6fd6f970c00), (0xbd2e6c516d93b8fb, 0x3fe4f45a835a5000), (0xbd2e6c516d93b8fb, 0x3fe4f45a835a5000), (0x3d05ccc45d257531, 0x3fe5322e26867800), (0x3d05ccc45d257531, 0x3fe5322e26867800), (0x3d09980bff3303dd, 0x3fe5707a26bb8c00), (0x3d09980bff3303dd, 0x3fe5707a26bb8c00), (0x3d2dfa63ac10c9fb, 0x3fe5af405c364800), (0x3d2dfa63ac10c9fb, 0x3fe5af405c364800), (0x3d2202380cda46be, 0x3fe5ee82aa241800), (0x0000000000000000, 0x0000000000000000), ]; /// Logarithm of base 10 /// /// Max found ULP 0.5 pub fn f_log10(x: f64) -> f64 { let mut x_u = x.to_bits(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut x_e: i64 = -(E_BIAS as i64); const MAX_NORMAL: u64 = f64::to_bits(f64::MAX); if x_u == 1f64.to_bits() { // log2(1.0) = +0.0 return 0.0; } if x_u < min_normal_f64().to_bits() || x_u > MAX_NORMAL { if x == 0.0 { return f64::NEG_INFINITY; } if x < 0. || x.is_nan() { return f64::NAN; } if x.is_infinite() || x.is_nan() { return x + x; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4330000000000000)).to_bits(); x_e -= 52; } // log2(x) = log2(2^x_e * x_m) // = x_e + log2(x_m) // Range reduction for log2(x_m): // For each x_m, we would like to find r such that: // -2^-8 <= r * x_m - 1 < 2^-7 let shifted = (x_u >> 45) as i64; let index = shifted & 0x7F; let r = f64::from_bits(crate::logs::log2::LOG_RANGE_REDUCTION[index as usize]); // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are // all 1's. x_e = x_e.wrapping_add(x_u.wrapping_add(1u64 << 45).wrapping_shr(52) as i64); let e_x = x_e as f64; const LOG_2_HI: f64 = f64::from_bits(0x3fe62e42fefa3800); const LOG_2_LO: f64 = f64::from_bits(0x3d2ef35793c76730); let log_r_dd = LOG_R_DD[index as usize]; // hi is exact let hi = f_fmla(e_x, LOG_2_HI, f64::from_bits(log_r_dd.1)); // lo errors ~ e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo) + rounding err // <= 2 * (e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo)) let lo = f_fmla(e_x, LOG_2_LO, f64::from_bits(log_r_dd.0)); // Set m = 1.mantissa. let x_m = (x_u & 0x000F_FFFF_FFFF_FFFFu64) | 0x3FF0_0000_0000_0000u64; let m = f64::from_bits(x_m); let u; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { u = f_fmla(r, m, -1.0); // exact } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log2::LOG_CD; let c_m = x_m & 0x3FFF_E000_0000_0000u64; let c = f64::from_bits(c_m); u = f_fmla(r, m - c, f64::from_bits(LOG_CD[index as usize])); // exact } let u_sq = u * u; // Degree-7 minimax polynomial let p0 = f_fmla( u, f64::from_bits(LOG_COEFFS[1]), f64::from_bits(LOG_COEFFS[0]), ); let p1 = f_fmla( u, f64::from_bits(LOG_COEFFS[3]), f64::from_bits(LOG_COEFFS[2]), ); let p2 = f_fmla( u, f64::from_bits(LOG_COEFFS[5]), f64::from_bits(LOG_COEFFS[4]), ); let p = f_polyeval4(u_sq, lo, p0, p1, p2); // Exact sum: // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u let mut r1 = DoubleDouble::from_exact_add(hi, u); r1.lo += p; // Quick double-double multiplication: // r2.hi + r2.lo ~ r1 * log10(e), // with error bounded by: // 4*ulp( ulp(r2.hi) ) const LOG10_E: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c695355baaafad3), f64::from_bits(0x3fdbcb7b1526e50e), ); let r2 = DoubleDouble::quick_mult(r1, LOG10_E); const HI_ERR: f64 = f64::from_bits(0x3aa0000000000000); // Extra errors from P is from using x^2 to reduce evaluation latency. const P_ERR: f64 = f64::from_bits(0x3cc0000000000000); // Technicallly error of r1.lo is bounded by: // |hi|*ulp(log(2)_lo) + C*ulp(u^2) // To simplify the error computation a bit, we replace |hi|*ulp(log(2)_lo) // with the upper bound: 2^11 * ulp(log(2)_lo) = 2^-85. // Total error is bounded by ~ C * ulp(u^2) + 2^-85. let err = f_fmla(u_sq, P_ERR, HI_ERR); // Lower bound from the result let left = r2.hi + (r2.lo - err); // Upper bound from the result let right = r2.hi + (r2.lo + err); // Ziv's test if fast pass is accurate enough. if left == right { return left; } log10_dd_accurate(x) } #[cold] #[inline(never)] fn log10_dd_accurate(x: f64) -> f64 { let r = log10_dd(x); let err = f_fmla( r.hi, f64::from_bits(0x3b50000000000000), // 2^-74 f64::from_bits(0x3990000000000000), // 2^-102 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } log10_dd_accurate_slow(x) } #[cold] #[inline(never)] fn log10_dd_accurate_slow(x: f64) -> f64 { log10_td(x).to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_log10d() { assert_eq!(f_log10(0.35), -0.4559319556497244); assert_eq!(f_log10(0.9), -0.045757490560675115); assert_eq!(f_log10(10.), 1.); assert_eq!(f_log10(0.), f64::NEG_INFINITY); assert!(f_log10(-1.).is_nan()); assert!(f_log10(f64::NAN).is_nan()); assert!(f_log10(f64::NEG_INFINITY).is_nan()); assert_eq!(f_log10(f64::INFINITY), f64::INFINITY); } } pxfm-0.1.23/src/logs/log10dd.rs000064400000000000000000000113501046102023000142140ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::logs::log10dd_coeffs::LOG10_NEG_DD; use crate::pow_tables::POW_INVERSE; #[inline(always)] fn log10_poly(z: f64) -> DoubleDouble { /* See ./notes/dd_log10.sollya */ const P: [(u64, u64); 10] = [ (0x3c695355baabd6d2, 0x3fdbcb7b1526e50e), (0xbc595355bababc0c, 0xbfcbcb7b1526e50e), (0xbc59c8c251be5fee, 0x3fc287a7636f435f), (0xbc49515e0a562cbe, 0xbfbbcb7b1526e50e), (0xbc5603802582ebad, 0x3fb63c62775250e2), (0x3c37a0e7de39c80c, 0xbfb287a7636f4371), (0x3c2c4afd722dc9ec, 0x3fafc3fa611f0291), (0xbc4a52f6541b67ee, 0xbfabcb7b14e178e5), (0x3c3ef541147ede8e, 0x3fa8b514ee02cfad), (0xbc28b9ea54e8f3b4, 0xbfa63c9d960501f1), ]; let mut t = DoubleDouble::quick_mul_f64_add( DoubleDouble::from_bit_pair(P[9]), z, DoubleDouble::from_bit_pair(P[8]), ); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[7])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[6])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[5])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[4])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[3])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[2])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[1])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[0])); DoubleDouble::quick_mult_f64(t, z) } #[inline] pub(crate) fn log10_dd(x: f64) -> DoubleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log10(x) = log10(t) + E · log10(e) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log10_r = DoubleDouble::from_bit_pair(LOG10_NEG_DD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG10_2_DD: DoubleDouble = DoubleDouble::from_bit_pair((0xbc49dc1da994fd21, 0x3fd34413509f79ff)); let v = DoubleDouble::mul_f64_add(LOG10_2_DD, be as f64, log10_r); let p = log10_poly(z); DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log10_dd() { assert_eq!(log10_dd(10.).to_f64(), 1.); } } pxfm-0.1.23/src/logs/log10dd_coeffs.rs000064400000000000000000000242101046102023000155400ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by SageMath: ```python values = POW_INVERSE R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] real_array = [R(hex_to_float(h)) for h in values] for r in real_array: print_double_double("", -RealField(180)(r).log10()) ``` **/ pub(crate) static LOG10_NEG_DD: [(u64, u64); 182] = [ (0xbc0b420b9b202edd, 0xbfc31b3055c47118), (0xbc662219537667a2, 0xbfc2cc20b1734279), (0xbc4386d677ad2ead, 0xbfc27c9ffae729c1), (0x3c6fb908b0ca4062, 0xbfc22cacece26ead), (0xbc61b4170b1c73f0, 0xbfc1dc463ca41df8), (0x3c5d6679f737585c, 0xbfc18b6a99c7f679), (0x3c6c6397435bc5b6, 0xbfc162d082ac9d10), (0x3c4b8c4f1b08949b, 0xbfc11142f0811357), (0xbc5e17a06836db63, 0xbfc0bf3d0937c41c), (0xbc65163143f60061, 0xbfc06cbd67a6c3b6), (0xbc6c5e9d9a0e1fd9, 0xbfc019c2a064b486), (0x3c5ec7f2dac60a5c, 0xbfbf8c9683468191), (0x3c54a69937a2d705, 0xbfbf38c0c8325d86), (0x3c53cbb5a6ee659b, 0xbfbe9056bcb315e8), (0x3c51bf355bb72ca1, 0xbfbde6ec0f392b05), (0x3c5ce84c9eaee37a, 0xbfbd91d5866aa99c), (0x3c26f0603909a181, 0xbfbce6e41e463da5), (0x3c58b9190212e5ba, 0xbfbc3aea4a5c6eff), (0x3c2446d00b829ad4, 0xbfbb8de4d3ab3d98), (0x3c5aa2aeaa7bc18d, 0xbfbb36fcb5f8be8a), (0x3c5dd366189ac022, 0xbfba885fa2d6151e), (0x3c4ebf33e9410429, 0xbfba30a9d609efea), (0xbc5c81cca3dd9b7b, 0xbfb9806d9414a209), (0x3c5935d381a0844f, 0xbfb8cf183886480d), (0x3c3666804e99aabc, 0xbfb8760307d355ab), (0xbc21064a1f6dc0c5, 0xbfb7c30164a60836), (0x3c5ac4c370ae3c1d, 0xbfb769140a2526fd), (0xbc5643835531d8ee, 0xbfb6b45df6f3e2c9), (0x3c59d9c8eaf88500, 0xbfb659944f8ba02d), (0xbc48cb0dc78c3961, 0xbfb5a32167b32f02), (0x3c5e1bcfb0476f5d, 0xbfb5477731973e85), (0xbc5782120ed9fd02, 0xbfb48f3ed1df48fb), (0x3c51960cbdfcb2d3, 0xbfb432afab5dd3ff), (0x3c4a83d8a6eb8e2e, 0xbfb3d5d335c53179), (0xbbfb420b9b202edd, 0xbfb31b3055c47118), (0xbc59f5fa977fa091, 0xbfb2bd68e4621371), (0x3c5c2f24fb8a820d, 0xbfb200eb639a3173), (0x3c4f990c2c07d3b5, 0xbfb1a23445501816), (0x3c4114d5dc0b3275, 0xbfb1432c31917d08), (0x3c3ccc49eb0a89d8, 0xbfb08426fcdb1ee7), (0x3c35943d4373d44a, 0xbfb02428c1f08016), (0x3c31436f936096a0, 0xbfaf87aebb43ce06), (0x3c4d4d643174a412, 0xbfae0471aa1868f5), (0x3c47f9dc537bfbfb, 0xbfad41d5164facb4), (0x3c4073b6859dc799, 0xbfac7e8d993509f9), (0x3c46487d64961833, 0xbfaaf5f92b00e610), (0x3c3ebf33e9410429, 0xbfaa30a9d609efea), (0x3c41c8c309cdac54, 0xbfa96aaacfefcf3c), (0x3c4b144b06126f68, 0xbfa8a3fadeb847f4), (0x3c38f0f77fcff1d9, 0xbfa71483427d2a99), (0xbc2eff9decc696f6, 0xbfa64bb912d65c07), (0xbc4efd454f7ea69a, 0xbfa58238eeb353da), (0xbc443795bbf70657, 0xbfa4b8018b21ed4f), (0x3c492b9251ee5832, 0xbfa32167c82bdcda), (0x3c4ff894a084ae68, 0xbfa25502c0fc314c), (0xbc49adc1c7f97f4a, 0xbfa187e12aad8077), (0xbc35f1d45244f437, 0xbfa0ba01a8170000), (0x3c3e7ffa709828ef, 0xbf9fd6c5b0851c4c), (0xbc0af3eb3b443356, 0xbf9e3806acbd058f), (0x3c36487d64961833, 0xbf9af5f92b00e610), (0x3c1f21279ca1bd16, 0xbf9952a4f22c5ae9), (0xbc1b980714c596a3, 0xbf97adc3df3b1ff8), (0xbc36ea248137e395, 0xbf960753003a94ef), (0xbc3dda7897a55eb5, 0xbf945f4f5acb8be0), (0xbc15bcd6d3458191, 0xbf92b5b5ec0209d3), (0x3c37b9fd5428084f, 0xbf910a83a8446c78), (0xbc1b57b9aec33450, 0xbf8ebb6af653e2ee), (0xbbff2e9fe367a511, 0xbf8b5e908eb13790), (0xbc28d4a223a5f7c9, 0xbf87fe71ccc4e6b0), (0x3c18f207a6d0d0b1, 0xbf849b0851443684), (0x3c29383502395c53, 0xbf81344daa2d7553), (0x3c03b252df477a75, 0xbf7b9476a4fcd10f), (0xbbefb495d6440f14, 0xbf74b99563d2a1bd), (0xbc09706ea523f0a5, 0xbf6bafd47221ed26), (0x0000000000000000, 0x0000000000000000), (0x0000000000000000, 0x0000000000000000), (0x3c0dcbdc594292c0, 0x3f64e84e793a474a), (0x3c11e6c1240ced74, 0x3f7175085ab85ff0), (0x3c0e1d6052707e0e, 0x3f787cff9d9147a5), (0xbbee4f45b8df7d67, 0x3f7f8c1b6b0c8d4e), (0x3c22495d8b8e25b7, 0x3f8351352a8e733f), (0x3c1bc0294772c57f, 0x3f86dffd8d3bbf70), (0xbc2b41d4e4ac05d4, 0x3f8a726e53a6056e), (0xbc28d01e8ac8a78b, 0x3f8c3d0837784c41), (0x3c27d5b73769b64c, 0x3f8fd503c3904f1d), (0xbbd646ebcccb6894, 0x3f91b85d6044e9ae), (0x3c37b38a223627b5, 0x3f93881a7b818f9e), (0x3c0521ad5fa98432, 0x3f9559bd2406c3ba), (0xbc29fc37c4e4e576, 0x3f972d4956ca2067), (0x3c3c830373882139, 0x3f9817c846828bbd), (0x3c0be24ddca8b835, 0x3f99ee3a5e9f57e8), (0x3c0999ccc6d592f0, 0x3f9bc6a03117eb97), (0xbc34a65cdeb626ca, 0x3f9da0fde8038de9), (0xbc29dc1111e3b44c, 0x3f9f7d57badb4ee8), (0x3c47db4db93811b8, 0x3fa0362241e638ec), (0xbc3f6975f23b8a99, 0x3fa125d0432ea20e), (0x3c463610c66f42b2, 0x3fa21681b5c8c213), (0x3c3c756ef644213d, 0x3fa28f3c69912a74), (0xbc11b16a272d4ddf, 0x3fa381772a00e604), (0xbc2197beb0be1c78, 0x3fa474baeb77e904), (0xbc0978c592e6c139, 0x3fa4eec0e2458f30), (0x3c2bb9cd2fb75402, 0x3fa5e3966b7e9295), (0x3c377b340fa390ec, 0x3fa6d97ab3ba5e10), (0x3c3ea90ccf791593, 0x3fa754d31b1b179c), (0x3c454596cc7150a8, 0x3fa84c51ebee8d15), (0xbc476df54932f73e, 0x3fa944e56a0d3450), (0xbc286148dd4cfbf5, 0x3fa9c197abf00dd7), (0xbc397d2cb982dac2, 0x3faabbcebd84fca0), (0x3c36591c969ff97b, 0x3fab39542ba23d73), (0xbc40859ccb55560e, 0x3fac3534628016dd), (0x3c4a5aca518d962e, 0x3facb38fccd8bfdb), (0x3c396e1e0dda0b3d, 0x3fadb11ed766abf4), (0x3c332de632195123, 0x3fae30531c76c34a), (0xbc23a73e99099cbd, 0x3faf2f96c6754aee), (0x3c262f731cfeb27b, 0x3fafafa6d397efdb), (0xbc4e0c43230184dc, 0x3fb0585283764178), (0x3c5466dc013d46a9, 0x3fb098c9ec61b3ff), (0xbc5cae3496ce9852, 0x3fb11a294f2569f6), (0xbc56a232c37f20c5, 0x3fb15b11a094a1aa), (0xbc4f587e7a233c80, 0x3fb1dd5460c8b16f), (0x3c5a0dec3a5a500c, 0x3fb21eaf28f57941), (0x3c585a155bb65408, 0x3fb2a1d86b49f1e2), (0xbc5aef53f2ecddb9, 0x3fb2e3a740b7800f), (0xbc5de49ddb15fb04, 0x3fb367ba3aaa1883), (0xbc5514fb6a33e70f, 0x3fb3a9febc60540a), (0x3c5c4c753d98645a, 0x3fb3ec6ad5407868), (0x3c2ce8e795b6ed98, 0x3fb471ba8a7de2b7), (0xbc54f0487863efe6, 0x3fb4b49e86b11e5f), (0x3c4bc478d6071be0, 0x3fb53adfb462ce16), (0xbc187decde1893f1, 0x3fb57e3d47c3af7b), (0x3c481f647ea24688, 0x3fb5c1c3c5557799), (0x3c5ad1738d96af06, 0x3fb6494c46ac6e4d), (0x3c54c74f6a7880e3, 0x3fb68d4eaf26d7ee), (0xbc52a2d69cfac78f, 0x3fb6d17acb3e5f5e), (0x3c4e4ba167ee73dd, 0x3fb75a50ebb1624a), (0x3c57e469fe31a42f, 0x3fb79efb57b0f803), (0xbc4d12e032a3b7af, 0x3fb7e3d04697b704), (0xbc53f06091db6450, 0x3fb828cfed29a215), (0x3c4da13d5c8cb232, 0x3fb8b350364c6257), (0x3be2034e6320e8c0, 0x3fb8f8d144557bdf), (0xbc5d0d01941798b6, 0x3fb93e7de0fc3e80), (0xbc562d3ed69292b0, 0x3fb9ca5aa1729f45), (0x3c5ba75ea17687d3, 0x3fba108b33edb005), (0xbc3113a1fc340179, 0x3fba56e8325f5c87), (0xbc4f648977febad9, 0x3fba9d71d5258484), (0x3c45689de26b43ff, 0x3fbb2b0beb419ad0), (0xbc5a8267d18975f3, 0x3fbb721cd17157e3), (0xbc5cb0a198331caf, 0x3fbbb95b41ab5ce6), (0xbc5b1e2e67b6f4bf, 0x3fbc00c7767225cb), (0xbc5b6b51fca7a9a5, 0x3fbc4861aab93a23), (0xbc58f377e27bbe25, 0x3fbcd820ffd278f3), (0xbc5667bf89866cca, 0x3fbd204698cb42bd), (0xbc1100072d011b81, 0x3fbd689b2193f133), (0x3c496e1e0dda0b3d, 0x3fbdb11ed766abf4), (0x3c55c6bc5d06e932, 0x3fbdf9d1f7f5b674), (0xbc5e018e5642e2ef, 0x3fbe42b4c16caaf3), (0xbc20a89525f3e005, 0x3fbed50a4a26eafc), (0x3c50955b9d99c1b8, 0x3fbf1e7d882b689a), (0xbc5c42f76e4345b0, 0x3fbf68216c9cc727), (0xbc46749ac407ee87, 0x3fbfb1f6381856f4), (0x3c5d60df12c2e13d, 0x3fbffbfc2bbc7803), (0x3c4ef8dd8b73f78d, 0x3fc02319c494f951), (0x3c5f318aa3021710, 0x3fc0484e4942aa43), (0xbc6a12a1c0cb3d7f, 0x3fc093025a19976c), (0xbc609801174f88fd, 0x3fc0b88229b71227), (0x3c65b619c844d28b, 0x3fc0de1b56356b04), (0x3c4dbdf176a1440a, 0x3fc103ce01fae223), (0xbc6ce6c847a6598d, 0x3fc1299a4fb3e306), (0xbc61f5da9e930834, 0x3fc14f806253c3ed), (0x3c5ac676f20a87ab, 0x3fc175805d1587c1), (0xbc6e785b3b894bd7, 0x3fc19b9a637ca295), (0xbc5db924be9633b4, 0x3fc1c1ce9955c0c6), (0x3c6db81c3374e59e, 0x3fc1e81d22b790d4), (0xbc67299601268298, 0x3fc20e8624038fed), (0x3c6ea54c137b0aea, 0x3fc23509c1e6d937), (0x3c50349d03e16325, 0x3fc25ba8215af7fc), (0x3c6557d4cdeffe3f, 0x3fc2826167a6bc9c), (0xbc1f613823fd2a19, 0x3fc2a935ba5f1479), (0xbc63dda694b5fe22, 0x3fc2d0253f67e4cb), (0xbc4c7972ce5f8b57, 0x3fc2f7301cf4e87b), (0x3c54b79d1957630a, 0x3fc31e56798a910a), (0xbc654fd6eb7d970e, 0x3fc345987bfeea91), ]; pxfm-0.1.23/src/logs/log10f.rs000064400000000000000000000172321046102023000140570ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use crate::polyeval::f_polyeval3; static LOG10_R: [u64; 128] = [ 0x0000000000000000, 0x3f6be76bd77b4fc3, 0x3f7c03a80ae5e054, 0x3f851824c7587eb0, 0x3f8c3d0837784c41, 0x3f91b85d6044e9ae, 0x3f9559bd2406c3ba, 0x3f9902c31d62a843, 0x3f9cb38fccd8bfdb, 0x3f9e8eeb09f2f6cb, 0x3fa125d0432ea20e, 0x3fa30838cdc2fbfd, 0x3fa3faf7c663060e, 0x3fa5e3966b7e9295, 0x3fa7d070145f4fd7, 0x3fa8c878eeb05074, 0x3faabbcebd84fca0, 0x3fabb7209d1e24e5, 0x3fadb11ed766abf4, 0x3faeafd05035bd3b, 0x3fb0585283764178, 0x3fb0d966cc6500fa, 0x3fb1dd5460c8b16f, 0x3fb2603072a25f82, 0x3fb367ba3aaa1883, 0x3fb3ec6ad5407868, 0x3fb4f7aad9bbcbaf, 0x3fb57e3d47c3af7b, 0x3fb605735ee985f1, 0x3fb715d0ce367afc, 0x3fb79efb57b0f803, 0x3fb828cfed29a215, 0x3fb93e7de0fc3e80, 0x3fb9ca5aa1729f45, 0x3fba56e8325f5c87, 0x3fbae4285509950b, 0x3fbb721cd17157e3, 0x3fbc902a19e65111, 0x3fbd204698cb42bd, 0x3fbdb11ed766abf4, 0x3fbe42b4c16caaf3, 0x3fbed50a4a26eafc, 0x3fbffbfc2bbc7803, 0x3fc0484e4942aa43, 0x3fc093025a19976c, 0x3fc0de1b56356b04, 0x3fc1299a4fb3e306, 0x3fc175805d1587c1, 0x3fc1c1ce9955c0c6, 0x3fc20e8624038fed, 0x3fc25ba8215af7fc, 0x3fc2a935ba5f1479, 0x3fc2f7301cf4e87b, 0x3fc345987bfeea91, 0x3fc394700f7953fd, 0x3fc3e3b8149739d4, 0x3fc43371cde076c2, 0x3fc4839e83506c87, 0x3fc4d43f8275a483, 0x3fc525561e9256ee, 0x3fc576e3b0bde0a7, 0x3fc5c8e998072fe2, 0x3fc61b6939983048, 0x3fc66e6400da3f77, 0x3fc6c1db5f9bb336, 0x3fc6c1db5f9bb336, 0x3fc715d0ce367afc, 0x3fc76a45cbb7e6ff, 0x3fc7bf3bde099f30, 0x3fc814b4921bd52b, 0x3fc86ab17c10bc7f, 0x3fc86ab17c10bc7f, 0x3fc8c13437695532, 0x3fc9183e673394fa, 0x3fc96fd1b639fc09, 0x3fc9c7efd734a2f9, 0x3fca209a84fbcff8, 0x3fca209a84fbcff8, 0x3fca79d382bc21d9, 0x3fcad39c9c2c6080, 0x3fcb2df7a5c50299, 0x3fcb2df7a5c50299, 0x3fcb88e67cf97980, 0x3fcbe46b087354bc, 0x3fcc4087384f4f80, 0x3fcc4087384f4f80, 0x3fcc9d3d065c5b42, 0x3fccfa8e765cbb72, 0x3fccfa8e765cbb72, 0x3fcd587d96494759, 0x3fcdb70c7e96e7f3, 0x3fcdb70c7e96e7f3, 0x3fce163d527e68cf, 0x3fce76124046b3f3, 0x3fce76124046b3f3, 0x3fced68d819191fc, 0x3fcf37b15bab08d1, 0x3fcf37b15bab08d1, 0x3fcf99801fdb749d, 0x3fcffbfc2bbc7803, 0x3fcffbfc2bbc7803, 0x3fd02f93f4c87101, 0x3fd06182e84fd4ac, 0x3fd06182e84fd4ac, 0x3fd093cc32c90f84, 0x3fd093cc32c90f84, 0x3fd0c6711d6abd7a, 0x3fd0f972f87ff3d6, 0x3fd0f972f87ff3d6, 0x3fd12cd31b9c99ff, 0x3fd12cd31b9c99ff, 0x3fd16092e5d3a9a6, 0x3fd194b3bdef6b9e, 0x3fd194b3bdef6b9e, 0x3fd1c93712abc7ff, 0x3fd1c93712abc7ff, 0x3fd1fe1e5af2c141, 0x3fd1fe1e5af2c141, 0x3fd2336b161b3337, 0x3fd2336b161b3337, 0x3fd2691ecc29f042, 0x3fd2691ecc29f042, 0x3fd29f3b0e15584b, 0x3fd29f3b0e15584b, 0x3fd2d5c1760b86bb, 0x3fd2d5c1760b86bb, 0x3fd30cb3a7bb3625, 0x3fd34413509f79ff, ]; /// Logarithm of base 10 /// /// Max found ULP 0.49999943 #[inline] pub fn f_log10f(x: f32) -> f32 { let mut x_u = x.to_bits(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; let mut m = -(E_BIAS as i32); if x_u < f32::MIN_POSITIVE.to_bits() || x_u > f32::MAX.to_bits() { if x == 0.0 { return f32::NEG_INFINITY; } if x_u == 0x80000000u32 { return f32::NEG_INFINITY; } if x.is_sign_negative() && !x.is_nan() { return f32::NAN + x; } // x is +inf or nan if x.is_nan() || x.is_infinite() { return x + x; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4160000000000000) as f32).to_bits(); m -= 23; } m = m.wrapping_add(x_u.wrapping_shr(23) as i32); let index = (x_u >> 16) & 0x7F; x_u = set_exponent_f32(x_u, 0x7F); let v; let u = f32::from_bits(x_u); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v = f_fmlaf( u, f32::from_bits(crate::logs::logf::LOG_REDUCTION_F32.0[index as usize]), -1.0, ) as f64; // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { v = f_fmla( u as f64, f32::from_bits(crate::logs::logf::LOG_REDUCTION_F32.0[index as usize]) as f64, -1.0, ); // Exact } // Degree-5 polynomial approximation of log10 generated by: // > P = fpminimax(log10(1 + x)/x, 4, [|D...|], [-2^-8, 2^-7]); const COEFFS: [u64; 5] = [ 0x3fdbcb7b1526e2e5, 0xbfcbcb7b1528d43d, 0x3fc287a77eb4ca0d, 0xbfbbcb8110a181b5, 0x3fb60e7e3e747129, ]; let v2 = v * v; // Exact let p2 = f_fmla(v, f64::from_bits(COEFFS[4]), f64::from_bits(COEFFS[3])); let p1 = f_fmla(v, f64::from_bits(COEFFS[2]), f64::from_bits(COEFFS[1])); let p0 = f_fmla( v, f64::from_bits(COEFFS[0]), f64::from_bits(LOG10_R[index as usize]), ); const LOG_10_2: f64 = f64::from_bits(0x3fd34413509f79ff); let r = f_fmla(m as f64, LOG_10_2, f_polyeval3(v2, p0, p1, p2)); r as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_log10f() { assert_eq!(f_log10f(0.35), -0.45593196f32); assert_eq!(f_log10f(0.9), -4.5757502e-2); assert_eq!(f_log10f(10.), 1.); assert_eq!(f_log10f(100.), 2.); assert_eq!(f_log10f(0.), f32::NEG_INFINITY); assert!(f_log10f(-1.).is_nan()); assert!(f_log10f(f32::NAN).is_nan()); assert!(f_log10f(f32::NEG_INFINITY).is_nan()); assert_eq!(f_log10f(f32::INFINITY), f32::INFINITY); } } pxfm-0.1.23/src/logs/log10p1.rs000064400000000000000000000325421046102023000141530ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log2p1::{log_fast, log_p_1a, log2_dyadic}; use crate::logs::log10p1_tables::{LOG10P1_EXACT_INT_S_TABLE, LOG10P1_EXACT_INT_TABLE}; const INV_LOG10_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c695355baaafad3), f64::from_bits(0x3fdbcb7b1526e50e), ); /* deal with |x| < 2^-900, then log10p1(x) ~ x/log(10) */ #[cold] fn log10p1_accurate_tiny(x: f64) -> f64 { /* first scale x to avoid truncation of l in the underflow region */ let sx = x * f64::from_bits(0x4690000000000000); let mut px = DoubleDouble::quick_f64_mult(sx, INV_LOG10_DD); let res = px.to_f64() * f64::from_bits(0x3950000000000000); // expected result px.lo += dd_fmla(-res, f64::from_bits(0x4690000000000000), px.hi); // the correction to apply to res is l*2^-106 /* For RNDN, we have underflow for |x| <= 0x1.26bb1bbb55515p-1021, and for rounding away, for |x| < 0x1.26bb1bbb55515p-1021. */ dyad_fmla(px.lo, f64::from_bits(0x3950000000000000), res) } fn log10p1_accurate_small(x: f64) -> f64 { /* the following is a degree-17 polynomial approximating log10p1(x) for |x| <= 2^-5 with relative error < 2^-105.067, cf log10p1_accurate.sollya */ static P_ACC: [u64; 25] = [ 0x3fdbcb7b1526e50e, 0x3c695355baaafad4, 0xbfcbcb7b1526e50e, 0xbc595355baaae078, 0x3fc287a7636f435f, 0xbc59c871838f83ac, 0xbfbbcb7b1526e50e, 0xbc495355e23285f2, 0x3fb63c62775250d8, 0x3c4442abd5831422, 0xbfb287a7636f435f, 0x3c49d116f225c4e4, 0x3fafc3fa615105c7, 0x3c24e1d7b4790510, 0xbfabcb7b1526e512, 0x3c49f884199ab0ce, 0x3fa8b4df2f3f0486, 0xbfa63c6277522391, 0x3fa436e526a79e5c, 0xbfa287a764c5a762, 0x3fa11ac1e784daec, 0xbf9fc3eedc920817, 0x3f9da5cac3522edb, 0xbf9be5ca1f9a97cd, 0x3f9a44b64ca06e9b, ]; /* for degree 11 or more, ulp(c[d]*x^d) < 2^-105.7*|log10p1(x)| where c[d] is the degree-d coefficient of Pacc, thus we can compute with a double only, and even with degree 10 (this does not increase the number of exceptional cases) */ let mut h = dd_fmla(f64::from_bits(P_ACC[24]), x, f64::from_bits(P_ACC[23])); // degree 16 for i in (10..=15).rev() { h = dd_fmla(h, x, f64::from_bits(P_ACC[(i + 7) as usize])); // degree i } // degree 9 let px = DoubleDouble::from_exact_mult(x, h); let hl = DoubleDouble::from_exact_add(f64::from_bits(P_ACC[9 + 7]), px.hi); h = hl.hi; let mut l = px.lo + hl.lo; for i in (1..=8).rev() { let mut p = DoubleDouble::quick_f64_mult(x, DoubleDouble::new(l, h)); l = p.lo; p = DoubleDouble::from_exact_add(f64::from_bits(P_ACC[(2 * i - 2) as usize]), p.hi); h = p.hi; l += p.lo + f64::from_bits(P_ACC[(2 * i - 1) as usize]); } let pz = DoubleDouble::quick_f64_mult(x, DoubleDouble::new(l, h)); pz.to_f64() } #[cold] fn log10p1_accurate(x: f64) -> f64 { let ax = x.abs(); if ax < f64::from_bits(0x3fa0000000000000) { return if ax < f64::from_bits(0x07b0000000000000) { log10p1_accurate_tiny(x) } else { log10p1_accurate_small(x) }; } let dx = if x > 1.0 { DoubleDouble::from_exact_add(x, 1.0) } else { DoubleDouble::from_exact_add(1.0, x) }; let x_d = DyadicFloat128::new_from_f64(dx.hi); let mut y = log2_dyadic(x_d, dx.hi); let mut c = DyadicFloat128::from_div_f64(dx.lo, dx.hi); let mut bx = c * c; /* multiply X by -1/2 */ bx.exponent -= 1; bx.sign = DyadicSign::Neg; /* C <- C - C^2/2 */ c = c + bx; /* |C-log(1+xl/xh)| ~ 2e-64 */ y = y + c; // Sage Math: // from sage.all import * // // def format_hex2(value): // l = hex(value)[2:] // n = 4 // x = [l[i:i + n] for i in range(0, len(l), n)] // return "0x" + "_".join(x) + "_u128" // (s, m, e) = (RealField(128)(1)/RealField(128)(10)).log().sign_mantissa_exponent(); // print(format_hex2(m)); const LOG10_INV: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xde5b_d8a9_3728_7195_355b_aaaf_ad33_dc32_u128, }; y = y * LOG10_INV; y.fast_as_f64() } #[inline] fn log10p1_fast(x: f64, e: i32) -> (DoubleDouble, f64) { if e < -5 /* e <= -6 thus |x| < 2^-5 */ { if e <= -968 { /* then |x| might be as small as 2^-968, thus h=x/log(10) might in the binade [2^-970,2^-969), with ulp(h) = 2^-1022, and if |l| < ulp(h), then l.ulp() might be smaller than 2^-1074. We defer that case to the accurate path. */ let ax = x.abs(); let result = if ax < f64::from_bits(0x07b0000000000000) { log10p1_accurate_tiny(x) } else { log10p1_accurate_small(x) }; return (DoubleDouble::new(0.0, result), 0.0); } let mut p = log_p_1a(x); let p_lo = p.lo; p = DoubleDouble::from_exact_add(x, p.hi); p.lo += p_lo; /* from analyze_x_plus_p1a(rel=true,Xmax=2^-5.) in the accompanying file log1p.sage, the relative error is bounded by 2^-61.14 with respect to h. We use the fact that we don't need the return value err to be positive, since we add/subtract it in the rounding test. We also get that the ratio |l/h| is bounded by 2^-50.96. */ /* now we multiply h+l by 1/log(2) */ p = DoubleDouble::quick_mult(p, INV_LOG10_DD); /* the d_mul() call decomposes into: a_mul (h_out, l1, h, INVLOG10H) l2 = __builtin_fma (h, INVLOG10L, l1) l_out = __builtin_fma (l, INVLOG10H, l2) we have |l1| <= ulp(h_out) since |INVLOG10L/INVLOG10H| < 2^-55, then |h*INVLOG10L| <= 2^-55*|h_out| and since |x| < 2^53*ulp(x): |h*INVLOG10L| <= ulp(h_out)/4 thus |l2| <= 5/4*ulp(h_out). Now since |l/h| < 2^-50.96, |l*INVLOG10H| < 2^-50.96*|h*INVLOG10H| < 2^-50.96*(1+2^-52)*|h_out| < 2^-50.95*|h_out| < 4.15*ulp(h_out), thus |l_out| < o(4.15*ulp(h_out)+5/4*ulp(h_out)) < 5.5*ulp(h_out). The rounding errors are bounded by ulp(l2)+ulp(l_out) <= ulp(5/4*ulp(h_out)) + ulp(5.5*ulp(h_out)) <= 2^-52*(5/4*ulp(h_out)+5.5*ulp(h_out)) [using ulp(x) <= 2^-52*|x|] <= 2^-49.2*ulp(h_out) We also have to take into account the ignored term l*INVLOG10L: |l*INVLOG10L| < 2^-50.96*|h|*2^-55.97*|INVLOG10H| < 2^-106.93*(1+2^-52)*|h_out| < 2^-106.92*|h_out| < 2^-51.92*ulp(h_out) [using |x| < 2^53*ulp(x)] and the approximation error in INVLOG10H+INVLOG10L: |INVLOG10H + INVLOG10L - 1/log(10)| < 2^-109.84/log(10) The total error of d_mul() is thus bounded by: (2^-49.2+2^-51.92)*ulp(h_out) < 2^-48.99*ulp(h_out) < 2^-100.99*|h_out|, using again ulp(x) <= 2^-52*|x|. The relative error is thus bounded by (1+2^-61.14)*(1+2^-100.99)*(1+2^-109.84)-1 < 2^-61.13 */ return (p, f64::from_bits(0x3c1d400000000000) * p.hi); /* 2^-61.13 < 0x1.d4p-62 */ } /* (xh,xl) <- 1+x */ let zx = DoubleDouble::from_full_exact_add(x, 1.0); let mut v_u = zx.hi.to_bits(); let e = ((v_u >> 52) as i32).wrapping_sub(0x3ff); v_u = (0x3ffu64 << 52) | (v_u & 0xfffffffffffff); let mut p = log_fast(e, v_u); /* log(xh+xl) = log(xh) + log(1+xl/xh) */ let c = if zx.hi <= f64::from_bits(0x7fd0000000000000) || zx.lo.abs() >= 4.0 { zx.lo / zx.hi } else { 0. }; // avoid spurious underflow /* Since |xl| < ulp(xh), we have |xl| < 2^-52 |xh|, thus |c| < 2^-52, and since |log(1+x)-x| < x^2 for |x| < 0.5, we have |log(1+c)-c)| < c^2 < 2^-104. */ p.lo += c; /* Since |l_in| < 2^-18.69 (from the analysis of cr_log_fast, see file ../log/log.c), and |c| < 2^-52, we have |l| < 2^-18.68, thus the rounding error in *l += c is bounded by ulp(2^-18.68) = 2^-71. The total absolute error is thus bounded by: 0x1.b6p-69 + 2^-104 + 2^-71 < 2^-68.02. */ /* now multiply h+l by 1/log(2) */ p = DoubleDouble::quick_mult(p, INV_LOG10_DD); /* the d_mul() call decomposes into: a_mul (h_out, l1, h, INVLOG10H) l2 = __builtin_fma (h, INVLOG10L, l1) l_out = __builtin_fma (l, INVLOG10H, l2) We have three errors: * the rounding error in l2 = __builtin_fma (h, INVLOG10L, l1) * the rounding error in l_out = __builtin_fma (l, INVLOG10H, l2) * the ignored term l * INVLOG10L We have |h| < 745 thus |h*INVLOG10H| < 324 thus |h_out| <= 324 and |l1| <= ulp(h_out) <= 2^-44. Then |h*INVLOG10L+l1| <= 745*INVLOG2L+2^-44 < 2^-43.6 thus |l2| < 2^-43.6*(1+2^-52) < 2^-43.5 and the first rounding error is bounded by ulp(2^-43.5) = 2^-96. Now |l*INVLOG10H+l2| < 2^-18.68*INVLOG10H+2^-43.5 < 2^-19.8 thus |l_out| < 2^-19.8*(1+2^-52) < 2^-19.7 and the second rounding error is bounded by ulp(2^-19.7) = 2^-72. The ignored term is bounded by |l*INVLOG10L| < 2^-18.68*INVLOG10L < 2^-75.0. Thus the absolute error from d_mul() is bounded by: 2^-96 + 2^-72 + 2^-75.0 < 2^-71.83. Adding to the maximal absolute error of 2^-68.02 before d_mul(), we get 2^-68.02 + 2^-71.83 < 2^-67.92. */ (p, f64::from_bits(0x3bb0a00000000000)) /* 2^-67.92 < 0x1.0ap-68 */ } /// Computes log10(x+1) /// /// Max ULP 0.5 pub fn f_log10p1(x: f64) -> f64 { let x_u = x.to_bits(); let e = (((x_u >> 52) & 0x7ff) as i32).wrapping_sub(0x3ff); if e == 0x400 || x == 0. || x <= -1.0 { /* case NaN/Inf, +/-0 or x <= -1 */ if e == 0x400 && x.to_bits() != 0xfffu64 << 52 { /* NaN or + Inf*/ return x + x; } if x <= -1.0 /* we use the fact that NaN < -1 is false */ { /* log2p(x<-1) is NaN, log2p(-1) is -Inf and raises DivByZero */ return if x < -1.0 { f64::NAN } else { // x=-1 f64::NEG_INFINITY }; } return x + x; /* +/-0 */ } /* check x=10^n-1 for 1 <= n <= 15, where log10p1(x) is exact, and we shouldn't raise the inexact flag */ if 3 <= e && e <= 49 && x == f64::from_bits(LOG10P1_EXACT_INT_TABLE[e as usize]) { return LOG10P1_EXACT_INT_S_TABLE[e as usize] as f64; } /* now x = m*2^e with 1 <= m < 2 (m = v.f) and -1074 <= e <= 1023 */ let (p, err) = log10p1_fast(x, e); let left = p.hi + (p.lo - err); let right = p.hi + (p.lo + err); if left == right { return left; } log10p1_accurate(x) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log10p1() { assert_eq!(f_log10p1(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013904929147106097), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006038833999843867 ); assert!(f_log10p1(-2.0).is_nan()); assert_eq!(f_log10p1(9.0), 1.0); assert_eq!(f_log10p1(2.0), 0.47712125471966244); assert_eq!(f_log10p1(-0.5), -0.3010299956639812); } } pxfm-0.1.23/src/logs/log10p1_tables.rs000064400000000000000000000065421046102023000155060ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /* LOG10P1_EXACT_INT_TABLE[e] is zero if there is no value of the form 10^n-1 in the range [2^e, 2^(e+1)), otherwise it is this (unique) value. */ pub(crate) static LOG10P1_EXACT_INT_TABLE: [u64; 50] = [ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x4022000000000000, 0x0000000000000000, 0x0000000000000000, 0x4058c00000000000, 0x0000000000000000, 0x0000000000000000, 0x408f380000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x40c3878000000000, 0x0000000000000000, 0x0000000000000000, 0x40f869f000000000, 0x0000000000000000, 0x0000000000000000, 0x412e847e00000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x416312cfe0000000, 0x0000000000000000, 0x0000000000000000, 0x4197d783fc000000, 0x0000000000000000, 0x0000000000000000, 0x41cdcd64ff800000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x4202a05f1ff80000, 0x0000000000000000, 0x0000000000000000, 0x42374876e7ff0000, 0x0000000000000000, 0x0000000000000000, 0x426d1a94a1ffe000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x42a2309ce53ffe00, 0x0000000000000000, 0x0000000000000000, 0x42d6bcc41e8fffc0, 0x0000000000000000, 0x0000000000000000, 0x430c6bf52633fff8, ]; // LOG10P1_EXACT_INT_S_TABLE[e] is the integer n such that LOG10P1_EXACT_INT_TABLE[e] = 10^n-1 when LOG10P1_EXACT_INT_TABLE[e] is not zero pub(crate) static LOG10P1_EXACT_INT_S_TABLE: [u32; 50] = [ 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0, 0, 10, 0, 0, 11, 0, 0, 12, 0, 0, 0, 13, 0, 0, 14, 0, 0, 15, ]; pxfm-0.1.23/src/logs/log10p1f.rs000064400000000000000000000210651046102023000143170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::logs::log1pf::special_logf; use std::hint::black_box; static TR: [u64; 65] = [ 0x3ff0000000000000, 0x3fef81f820000000, 0x3fef07c1f0000000, 0x3fee9131ac000000, 0x3fee1e1e1e000000, 0x3fedae6077000000, 0x3fed41d41d000000, 0x3fecd85689000000, 0x3fec71c71c000000, 0x3fec0e0704000000, 0x3febacf915000000, 0x3feb4e81b5000000, 0x3feaf286bd000000, 0x3fea98ef60000000, 0x3fea41a41a000000, 0x3fe9ec8e95000000, 0x3fe999999a000000, 0x3fe948b0fd000000, 0x3fe8f9c190000000, 0x3fe8acb90f000000, 0x3fe8618618000000, 0x3fe8181818000000, 0x3fe7d05f41000000, 0x3fe78a4c81000000, 0x3fe745d174000000, 0x3fe702e05c000000, 0x3fe6c16c17000000, 0x3fe6816817000000, 0x3fe642c859000000, 0x3fe6058160000000, 0x3fe5c9882c000000, 0x3fe58ed231000000, 0x3fe5555555000000, 0x3fe51d07eb000000, 0x3fe4e5e0a7000000, 0x3fe4afd6a0000000, 0x3fe47ae148000000, 0x3fe446f865000000, 0x3fe4141414000000, 0x3fe3e22cbd000000, 0x3fe3b13b14000000, 0x3fe3813814000000, 0x3fe3521cfb000000, 0x3fe323e34a000000, 0x3fe2f684be000000, 0x3fe2c9fb4e000000, 0x3fe29e412a000000, 0x3fe27350b9000000, 0x3fe2492492000000, 0x3fe21fb781000000, 0x3fe1f7047e000000, 0x3fe1cf06ae000000, 0x3fe1a7b961000000, 0x3fe1811812000000, 0x3fe15b1e5f000000, 0x3fe135c811000000, 0x3fe1111111000000, 0x3fe0ecf56c000000, 0x3fe0c97150000000, 0x3fe0a6810a000000, 0x3fe0842108000000, 0x3fe0624dd3000000, 0x3fe0410410000000, 0x3fe0204081000000, 0x3fe0000000000000, ]; static TL: [u64; 65] = [ 0xbd4562ec497ef351, 0x3f7b9476892ea99c, 0x3f8b5e909c959eec, 0x3f945f4f59ec84f0, 0x3f9af5f92cbcf2aa, 0x3fa0ba01a6069052, 0x3fa3ed119b99dd41, 0x3fa714834298a088, 0x3faa30a9d98309c1, 0x3fad41d51266b9d9, 0x3fb02428c0f62dfc, 0x3fb1a23444eea521, 0x3fb31b30543f2597, 0x3fb48f3ed39bd5e7, 0x3fb5fe8049a0bd06, 0x3fb769140a6a78ea, 0x3fb8cf1836c96595, 0x3fba30a9d5551a84, 0x3fbb8de4d1ee5b21, 0x3fbce6e4202c7bc9, 0x3fbe3bc1accaa6ea, 0x3fbf8c9683b584b7, 0x3fc06cbd68ca86e0, 0x3fc11142f19de3a2, 0x3fc1b3e71fa795f0, 0x3fc254b4d37a3354, 0x3fc2f3b6912cab79, 0x3fc390f6831144f7, 0x3fc42c7e7fffb21a, 0x3fc4c65808c779ae, 0x3fc55e8c507508c7, 0x3fc5f52445deb049, 0x3fc68a288c3efe72, 0x3fc71da17bdef98b, 0x3fc7af9736089c4b, 0x3fc84011952a11eb, 0x3fc8cf1837a7d6d1, 0x3fc95cb2891e3048, 0x3fc9e8e7b0f85651, 0x3fca73beaa5d9dfe, 0x3fcafd3e39454544, 0x3fcb856cf060c662, 0x3fcc0c5134de0c6d, 0x3fcc91f1371bb611, 0x3fcd1652ffcd2bc5, 0x3fcd997c6f634ae6, 0x3fce1b733ab8fbad, 0x3fce9c3ceadab4c8, 0x3fcf1bdeec438f77, 0x3fcf9a5e7a5f906f, 0x3fd00be05ac02564, 0x3fd04a054d81990c, 0x3fd087a083594e33, 0x3fd0c4b457098b4f, 0x3fd101431aa1f48a, 0x3fd13d4f08b98411, 0x3fd178da53edaecb, 0x3fd1b3e71e9f9391, 0x3fd1ee777defd526, 0x3fd2288d7b48d874, 0x3fd2622b0f52dad8, 0x3fd29b522a4c594c, 0x3fd2d404b0e305b9, 0x3fd30c4478f3f21d, 0x3fd34413509f6f4d, ]; #[cold] fn log10p1f_accurate(ax: u32, ux: u32, v: f64, z: f64, l: f64, e: i32) -> f32 { if ax < 0x3d32743eu32 { // |x| < 0x1.64e87cp-5f if ux == 0xa6aba8afu32 { return black_box(f32::from_bits(0xa61519de)) + black_box(f32::from_bits(0x19800000)); } if ux == 0xaf39b9a7u32 { return black_box(f32::from_bits(0xaea151a1)) + black_box(f32::from_bits(0x22000000)); } if ux == 0x399a7c00u32 { return black_box(f32::from_bits(0x390629e5)) + black_box(f32::from_bits(0x2c800000)); } let z = z / (2.0 + z); let z2 = z * z; let z4 = z2 * z2; const C: [u64; 4] = [ 0x3febcb7b1526e50f, 0x3fd287a76370129d, 0x3fc63c62378fa3db, 0x3fbfca4139a42374, ]; let r0 = f_fmla(z2, f64::from_bits(C[3]), f64::from_bits(C[2])); let r1 = f_fmla(z2, f64::from_bits(C[1]), f64::from_bits(C[0])); let r = z * f_fmla(z4, r0, r1); return r as f32; } if ux == 0x7956ba5eu32 { return black_box(f32::from_bits(0x420b5f5d)) + black_box(f32::from_bits(0x35800000)); } if ux == 0xbd86ffb9u32 { return black_box(f32::from_bits(0xbcf29a9b)) + black_box(f32::from_bits(0x30000000)); } const C: [u64; 7] = [ 0x3fdbcb7b1526e50e, 0xbfcbcb7b1526e53d, 0x3fc287a7636f3fa2, 0xbfbbcb7b146a14b3, 0x3fb63c627d5219cb, 0xbfb2880736c8762d, 0x3fafc1ecf913961a, ]; let v2 = v * v; let xv0 = f_fmla(v, f64::from_bits(C[1]), f64::from_bits(C[0])); let xv1 = f_fmla(v, f64::from_bits(C[3]), f64::from_bits(C[2])); let xv2 = f_fmla(v, f64::from_bits(C[5]), f64::from_bits(C[4])); let xw0 = f_fmla(v2, f64::from_bits(C[6]), xv2); let xw1 = f_fmla(v2, xw0, xv1); let mut f = v * f_fmla(v2, xw1, xv0); f += l - f64::from_bits(TL[0]); let r = f_fmla(e as f64, f64::from_bits(0x3fd34413509f79ff), f); r as f32 } /// Computes log10(x+1) /// /// Max ULP 0.5 #[inline] pub fn f_log10p1f(x: f32) -> f32 { let z = x as f64; let t = x.to_bits(); let ux: u32 = t; if ux >= 0x17fu32 << 23 { // x <= -1 return special_logf(x); } let ax = ux & 0x7fff_ffff; if ax == 0 { return f32::copysign(0., x); } if ax >= (0xff << 23) { // +inf, nan return special_logf(x); } let mut tz = (z + 1.0).to_bits(); let m: u64 = tz & 0x000f_ffff_ffff_ffff; let e: i32 = (tz >> 52).wrapping_sub(1023) as i32; let j: i32 = ((m.wrapping_add((1i64 << 45) as u64)) >> 46) as i32; tz = m | (0x3ffu64 << 52); let ix = f64::from_bits(TR[j as usize]); let l = f64::from_bits(TL[j as usize]); let off = e as f64 * f64::from_bits(0x3fd34413509f79ff) + l; let v = f_fmla(f64::from_bits(tz), ix, -1.); const H: [u64; 4] = [ 0x3fdbcb7b150bf6d8, 0xbfcbcb7b1738c07e, 0x3fc287de19e795c5, 0xbfbbca44edc44bc4, ]; let v2 = v * v; let zwf0 = f_fmla(v, f64::from_bits(H[3]), f64::from_bits(H[2])); let zwf1 = f_fmla(v, f64::from_bits(H[1]), f64::from_bits(H[0])); let f = f_fmla(v2, zwf0, zwf1); let r = f_fmla(v, f, off); let ub: f32 = r as f32; let lb: f32 = (r + f64::from_bits(0x3d55c00000000000)) as f32; if ub != lb { return log10p1f_accurate(ax, ux, v, z, l, e); } ub } #[cfg(test)] mod tests { use super::*; #[test] fn test_log10p1f() { assert_eq!(f_log10p1f(0.0), 0.0); assert_eq!(f_log10p1f(1.0), 0.30103); assert_eq!(f_log10p1f(-0.0432432), -0.019198442); assert_eq!(f_log10p1f(-0.009874634), -0.0043098135); assert_eq!(f_log10p1f(1.2443), 0.35108092); assert!(f_log10p1f(-1.0432432).is_nan()); } } pxfm-0.1.23/src/logs/log10td.rs000064400000000000000000000122611046102023000142360ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::logs::log10td_coeffs::LOG10_NEG_TD; use crate::pow_tables::POW_INVERSE; use crate::triple_double::TripleDouble; #[inline(always)] fn log10_poly(z: f64) -> TripleDouble { /* Poly generated by Sollya: d = [-0.0040283203125,0.0040283203125]; f = log10(1+x)/x; pf = fpminimax(f, 10, [|157...|], d, absolute, floating); See ./notes/td_log10.sollya */ const P: [(u64, u64, u64); 11] = [ (0xb8f29c4663277dc0, 0x3c695355baaafad3, 0x3fdbcb7b1526e50e), (0x38ee76408ee1b680, 0xbc595355bab3a517, 0xbfcbcb7b1526e50e), (0x38f58fe4d121c480, 0xbc59c8718361a853, 0x3fc287a7636f435f), (0xb8e80f425616e240, 0xbc49520fd0630f7e, 0xbfbbcb7b1526e50e), (0x38eb058acb9ab2c0, 0x3c443f5b242c637b, 0x3fb63c62775250d8), (0x38c32c088e8da180, 0xbc4a6666386cc60e, 0xbfb287a7636f436c), (0x38bb2e95bc6a3a80, 0x3c45ac4260107e46, 0x3fafc3fa615105f6), (0xb8e14f1e5b926690, 0x3c421ee12f4a23de, 0xbfabcb7b14ed42da), (0x38d4b4d370b610e0, 0x3c47e2c6f24d3d30, 0x3fa8b4df2ef1a288), (0x38bd632a8b3a6500, 0xbc1a922cdefb3bb1, 0xbfa63c98a8c44069), (0xb8c077b6551291c0, 0x3c4337142dd97816, 0x3fa4372045637cca), ]; let mut t = TripleDouble::f64_mul_add( z, TripleDouble::from_bit_pair(P[9]), TripleDouble::from_bit_pair(P[8]), ); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[7])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[6])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[5])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[4])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[3])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[2])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[1])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[0])); TripleDouble::quick_mult_f64(t, z) } #[inline] pub(crate) fn log10_td(x: f64) -> TripleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log10(x) = log10(t) + E · log10(e) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log10_r = TripleDouble::from_bit_pair(LOG10_NEG_TD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG10_2_DD: DoubleDouble = DoubleDouble::from_bit_pair((0xbc49dc1da994fd21, 0x3fd34413509f79ff)); let v = TripleDouble::f64_mul_dd_add(be as f64, LOG10_2_DD, log10_r); let p = log10_poly(z); TripleDouble::add_f64(v.hi, TripleDouble::new(v.lo + p.lo, v.mid + p.mid, p.hi)) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log10_dd() { assert_eq!(log10_td(10.).to_f64(), 1.); } } pxfm-0.1.23/src/logs/log10td_coeffs.rs000064400000000000000000000332561046102023000155720ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by SageMath: ```python R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] real_array = [R(hex_to_float(h)) for h in values] for r in real_array: print_triple_double("", -RealField(180)(r).log10()) ``` **/ pub(crate) static LOG10_NEG_TD: [(u64, u64, u64); 182] = [ (0xb89002c845c3b128, 0xbc0b420b9b202edd, 0xbfc31b3055c47118), (0x38e5607e92cc3d86, 0xbc662219537667a2, 0xbfc2cc20b1734279), (0xb8c53b02f2c219ad, 0xbc4386d677ad2ead, 0xbfc27c9ffae729c1), (0x390c4925ec4ba355, 0x3c6fb908b0ca4062, 0xbfc22cacece26ead), (0xb907310487c79786, 0xbc61b4170b1c73f0, 0xbfc1dc463ca41df8), (0x38fdec83a542321d, 0x3c5d6679f737585c, 0xbfc18b6a99c7f679), (0x39075e156bc06274, 0x3c6c6397435bc5b6, 0xbfc162d082ac9d10), (0x38b62066cf807969, 0x3c4b8c4f1b08949b, 0xbfc11142f0811357), (0xb8eb79f0297d79fd, 0xbc5e17a06836db63, 0xbfc0bf3d0937c41c), (0xb8baf3f94b418d28, 0xbc65163143f60061, 0xbfc06cbd67a6c3b6), (0x3907cb66c266da5e, 0xbc6c5e9d9a0e1fd9, 0xbfc019c2a064b486), (0xb8fc8f49451b2b9c, 0x3c5ec7f2dac60a5c, 0xbfbf8c9683468191), (0x38a21551cf561003, 0x3c54a69937a2d705, 0xbfbf38c0c8325d86), (0x38f32dcc7f6a5efc, 0x3c53cbb5a6ee659b, 0xbfbe9056bcb315e8), (0x38ff4e6aafdeb6a5, 0x3c51bf355bb72ca1, 0xbfbde6ec0f392b05), (0xb8c5949c22c5c13e, 0x3c5ce84c9eaee37a, 0xbfbd91d5866aa99c), (0xb8c0d2e29710fa1a, 0x3c26f0603909a181, 0xbfbce6e41e463da5), (0x38fcbad44d58c56f, 0x3c58b9190212e5ba, 0xbfbc3aea4a5c6eff), (0x38c3c3b861649e91, 0x3c2446d00b829ad4, 0xbfbb8de4d3ab3d98), (0x38eeab77ea5ae5c0, 0x3c5aa2aeaa7bc18d, 0xbfbb36fcb5f8be8a), (0x38f866aee06a4002, 0x3c5dd366189ac022, 0xbfba885fa2d6151e), (0xb8da496755361f14, 0x3c4ebf33e9410429, 0xbfba30a9d609efea), (0xb8eb9d973d5a81ee, 0xbc5c81cca3dd9b7b, 0xbfb9806d9414a209), (0xb8f25cbc5fc36d82, 0x3c5935d381a0844f, 0xbfb8cf183886480d), (0x38ce162025d7f34a, 0x3c3666804e99aabc, 0xbfb8760307d355ab), (0x38b60052fa072a91, 0xbc21064a1f6dc0c5, 0xbfb7c30164a60836), (0xb8c07c05e9fdb823, 0x3c5ac4c370ae3c1d, 0xbfb769140a2526fd), (0x38f5b5c030bcef17, 0xbc5643835531d8ee, 0xbfb6b45df6f3e2c9), (0x38d21688e77d5afb, 0x3c59d9c8eaf88500, 0xbfb659944f8ba02d), (0xb8efde3e6ebdf069, 0xbc48cb0dc78c3961, 0xbfb5a32167b32f02), (0x38f5f10707d2333c, 0x3c5e1bcfb0476f5d, 0xbfb5477731973e85), (0x38e3d7d43d84e36e, 0xbc5782120ed9fd02, 0xbfb48f3ed1df48fb), (0xb8f268b21a5b88f8, 0x3c51960cbdfcb2d3, 0xbfb432afab5dd3ff), (0x38c42231800bf01c, 0x3c4a83d8a6eb8e2e, 0xbfb3d5d335c53179), (0xb88002c845c3b128, 0xbbfb420b9b202edd, 0xbfb31b3055c47118), (0x38c136f6506c3113, 0xbc59f5fa977fa091, 0xbfb2bd68e4621371), (0x38f1c66402538718, 0x3c5c2f24fb8a820d, 0xbfb200eb639a3173), (0xb8e8305d344af3bf, 0x3c4f990c2c07d3b5, 0xbfb1a23445501816), (0xb8d0911e570f1772, 0x3c4114d5dc0b3275, 0xbfb1432c31917d08), (0xb8d0c670f62a43c9, 0x3c3ccc49eb0a89d8, 0xbfb08426fcdb1ee7), (0x38c282a6187110fe, 0x3c35943d4373d44a, 0xbfb02428c1f08016), (0xb8dae3378c046c6a, 0x3c31436f936096a0, 0xbfaf87aebb43ce06), (0xb8eb644705b7affb, 0x3c4d4d643174a412, 0xbfae0471aa1868f5), (0x38e7097d514f05cc, 0x3c47f9dc537bfbfb, 0xbfad41d5164facb4), (0x38efea466ac41bfd, 0x3c4073b6859dc799, 0xbfac7e8d993509f9), (0x38e735cc6aa10798, 0x3c46487d64961833, 0xbfaaf5f92b00e610), (0xb8ca496755361f14, 0x3c3ebf33e9410429, 0xbfaa30a9d609efea), (0xb8e423cab9979886, 0x3c41c8c309cdac54, 0xbfa96aaacfefcf3c), (0xb8e8d323b0a8265c, 0x3c4b144b06126f68, 0xbfa8a3fadeb847f4), (0xb8d443df1e952f54, 0x3c38f0f77fcff1d9, 0xbfa71483427d2a99), (0xb8c0f02a728b0923, 0xbc2eff9decc696f6, 0xbfa64bb912d65c07), (0x38df7639a3c4fefb, 0xbc4efd454f7ea69a, 0xbfa58238eeb353da), (0xb8d020031b665cbc, 0xbc443795bbf70657, 0xbfa4b8018b21ed4f), (0xb8e5f6d30622464a, 0x3c492b9251ee5832, 0xbfa32167c82bdcda), (0x38dc9bdb87272974, 0x3c4ff894a084ae68, 0xbfa25502c0fc314c), (0xb8cc98efd443d8bd, 0xbc49adc1c7f97f4a, 0xbfa187e12aad8077), (0x38dd736bbeb20108, 0xbc35f1d45244f437, 0xbfa0ba01a8170000), (0x38d9223bf675f3cd, 0x3c3e7ffa709828ef, 0xbf9fd6c5b0851c4c), (0xb89b88f11b4d4ea9, 0xbc0af3eb3b443356, 0xbf9e3806acbd058f), (0x38d735cc6aa10798, 0x3c36487d64961833, 0xbf9af5f92b00e610), (0xb8b16ecc6dcb33a1, 0x3c1f21279ca1bd16, 0xbf9952a4f22c5ae9), (0xb8b049f2508d0405, 0xbc1b980714c596a3, 0xbf97adc3df3b1ff8), (0xb8c31b155a73c7e0, 0xbc36ea248137e395, 0xbf960753003a94ef), (0x38bab270fa22426e, 0xbc3dda7897a55eb5, 0xbf945f4f5acb8be0), (0xb8b2011a6d02a2f9, 0xbc15bcd6d3458191, 0xbf92b5b5ec0209d3), (0x38d9567819f06222, 0x3c37b9fd5428084f, 0xbf910a83a8446c78), (0xb8b695431959f8e4, 0xbc1b57b9aec33450, 0xbf8ebb6af653e2ee), (0x387790ad1c32f033, 0xbbff2e9fe367a511, 0xbf8b5e908eb13790), (0x38b94f863e314105, 0xbc28d4a223a5f7c9, 0xbf87fe71ccc4e6b0), (0xb8a983539059615f, 0x3c18f207a6d0d0b1, 0xbf849b0851443684), (0x38c01a8492cb45d3, 0x3c29383502395c53, 0xbf81344daa2d7553), (0x38a86d6805b5b078, 0x3c03b252df477a75, 0xbf7b9476a4fcd10f), (0xb88d03d2f51efac9, 0xbbefb495d6440f14, 0xbf74b99563d2a1bd), (0x38ae415215a90a2b, 0xbc09706ea523f0a5, 0xbf6bafd47221ed26), (0x0000000000000000, 0x0000000000000000, 0x8000000000000000), (0x0000000000000000, 0x0000000000000000, 0x8000000000000000), (0x38a5c7c42656edc5, 0x3c0dcbdc594292c0, 0x3f64e84e793a474a), (0xb8baa27d025eefb8, 0x3c11e6c1240ced74, 0x3f7175085ab85ff0), (0xb892d9a16b70963f, 0x3c0e1d6052707e0e, 0x3f787cff9d9147a5), (0xb884e8e710379609, 0xbbee4f45b8df7d67, 0x3f7f8c1b6b0c8d4e), (0xb8c08a4af7bab81f, 0x3c22495d8b8e25b7, 0x3f8351352a8e733f), (0xb87e8055cf668c67, 0x3c1bc0294772c57f, 0x3f86dffd8d3bbf70), (0xb8b9b54309dabea5, 0xbc2b41d4e4ac05d4, 0x3f8a726e53a6056e), (0x389370d9e5682f63, 0xbc28d01e8ac8a78b, 0x3f8c3d0837784c41), (0x380107b2c9d18b62, 0x3c27d5b73769b64c, 0x3f8fd503c3904f1d), (0x3879c1318df4f5fb, 0xbbd646ebcccb6894, 0x3f91b85d6044e9ae), (0x38d23a2b392f494f, 0x3c37b38a223627b5, 0x3f93881a7b818f9e), (0xb87266701d45d395, 0x3c0521ad5fa98432, 0x3f9559bd2406c3ba), (0x38c07782809ecaf6, 0xbc29fc37c4e4e576, 0x3f972d4956ca2067), (0xb8d9f4886964e9f2, 0x3c3c830373882139, 0x3f9817c846828bbd), (0x38aa4fd0d6840595, 0x3c0be24ddca8b835, 0x3f99ee3a5e9f57e8), (0xb8a1f073a0185b5c, 0x3c0999ccc6d592f0, 0x3f9bc6a03117eb97), (0x38c1ba31ff0ebcf6, 0xbc34a65cdeb626ca, 0x3f9da0fde8038de9), (0xb8c2ae25e3c7af79, 0xbc29dc1111e3b44c, 0x3f9f7d57badb4ee8), (0x38e2862d635fc3a1, 0x3c47db4db93811b8, 0x3fa0362241e638ec), (0x38da4725a086a87e, 0xbc3f6975f23b8a99, 0x3fa125d0432ea20e), (0x38e747dcf984a4ce, 0x3c463610c66f42b2, 0x3fa21681b5c8c213), (0xb8ba8f5a9e1afc55, 0x3c3c756ef644213d, 0x3fa28f3c69912a74), (0x38b20caa6a9c4119, 0xbc11b16a272d4ddf, 0x3fa381772a00e604), (0x38c15a731b8c76f0, 0xbc2197beb0be1c78, 0x3fa474baeb77e904), (0xb89fcd308117f994, 0xbc0978c592e6c139, 0x3fa4eec0e2458f30), (0xb8c59c1417fe9b19, 0x3c2bb9cd2fb75402, 0x3fa5e3966b7e9295), (0x38c469a2211e96d7, 0x3c377b340fa390ec, 0x3fa6d97ab3ba5e10), (0x38d48e0de01f1b66, 0x3c3ea90ccf791593, 0x3fa754d31b1b179c), (0xb8d369beaa748363, 0x3c454596cc7150a8, 0x3fa84c51ebee8d15), (0xb8d20cdb1f079c35, 0xbc476df54932f73e, 0x3fa944e56a0d3450), (0x38cc0a24a6aece0c, 0xbc286148dd4cfbf5, 0x3fa9c197abf00dd7), (0x38c68fdc7ccadc86, 0xbc397d2cb982dac2, 0x3faabbcebd84fca0), (0x38ad7e11b8460553, 0x3c36591c969ff97b, 0x3fab39542ba23d73), (0xb8c42c09b578a1bb, 0xbc40859ccb55560e, 0x3fac3534628016dd), (0x38e912371677ce89, 0x3c4a5aca518d962e, 0x3facb38fccd8bfdb), (0x38cbad1cb83cff56, 0x3c396e1e0dda0b3d, 0x3fadb11ed766abf4), (0x38d5fbe0cd351aa2, 0x3c332de632195123, 0x3fae30531c76c34a), (0xb8cc92b7b45b9557, 0xbc23a73e99099cbd, 0x3faf2f96c6754aee), (0x38c78cf7437c1a1c, 0x3c262f731cfeb27b, 0x3fafafa6d397efdb), (0xb8ea24ca8acd4629, 0xbc4e0c43230184dc, 0x3fb0585283764178), (0xb8e8bbcb792f081a, 0x3c5466dc013d46a9, 0x3fb098c9ec61b3ff), (0xb8e5f8e913fb6a30, 0xbc5cae3496ce9852, 0x3fb11a294f2569f6), (0xb8fbd9f731f71bf6, 0xbc56a232c37f20c5, 0x3fb15b11a094a1aa), (0xb8d2ff33eb29a068, 0xbc4f587e7a233c80, 0x3fb1dd5460c8b16f), (0xb8e8dde97ac3bf82, 0x3c5a0dec3a5a500c, 0x3fb21eaf28f57941), (0x38b95b4fde7f0e0e, 0x3c585a155bb65408, 0x3fb2a1d86b49f1e2), (0x38d56074eaea7505, 0xbc5aef53f2ecddb9, 0x3fb2e3a740b7800f), (0x38f07fc540f1ffd6, 0xbc5de49ddb15fb04, 0x3fb367ba3aaa1883), (0xb8f3c847b2f2b20a, 0xbc5514fb6a33e70f, 0x3fb3a9febc60540a), (0x38f5b10bf359af28, 0x3c5c4c753d98645a, 0x3fb3ec6ad5407868), (0x38cc8292ede0aa76, 0x3c2ce8e795b6ed98, 0x3fb471ba8a7de2b7), (0xb8e4c088deea25e6, 0xbc54f0487863efe6, 0x3fb4b49e86b11e5f), (0x389fb62394a838a4, 0x3c4bc478d6071be0, 0x3fb53adfb462ce16), (0x38b8294b7967031c, 0xbc187decde1893f1, 0x3fb57e3d47c3af7b), (0x38dfaf3384ac8a3b, 0x3c481f647ea24688, 0x3fb5c1c3c5557799), (0xb8f02e1b4c45d28c, 0x3c5ad1738d96af06, 0x3fb6494c46ac6e4d), (0xb8c0efee9b397b5e, 0x3c54c74f6a7880e3, 0x3fb68d4eaf26d7ee), (0xb88bdf7c6a6a3fa8, 0xbc52a2d69cfac78f, 0x3fb6d17acb3e5f5e), (0xb8dfad5df4f01a6b, 0x3c4e4ba167ee73dd, 0x3fb75a50ebb1624a), (0x38effc4a2a1bc2cb, 0x3c57e469fe31a42f, 0x3fb79efb57b0f803), (0xb8accdbd86c1b5c3, 0xbc4d12e032a3b7af, 0x3fb7e3d04697b704), (0xb8e0e96abe790a21, 0xbc53f06091db6450, 0x3fb828cfed29a215), (0xb8e6b1083c5aa70b, 0x3c4da13d5c8cb232, 0x3fb8b350364c6257), (0x388318cf6f2052dc, 0x3be2034e6320e8c0, 0x3fb8f8d144557bdf), (0xb8f19142bff65cf6, 0xbc5d0d01941798b6, 0x3fb93e7de0fc3e80), (0xb8ff3ddeebf83378, 0xbc562d3ed69292b0, 0x3fb9ca5aa1729f45), (0xb8f46354ffa76f1d, 0x3c5ba75ea17687d3, 0x3fba108b33edb005), (0xb8beeaa25ea54d75, 0xbc3113a1fc340179, 0x3fba56e8325f5c87), (0x38d5b7ac1e1aef0c, 0xbc4f648977febad9, 0x3fba9d71d5258484), (0x38ceeebae16520f4, 0x3c45689de26b43ff, 0x3fbb2b0beb419ad0), (0xb886dbc50eaa6c95, 0xbc5a8267d18975f3, 0x3fbb721cd17157e3), (0xb8f10917d4228654, 0xbc5cb0a198331caf, 0x3fbbb95b41ab5ce6), (0xb8cdb7e880ea8bbb, 0xbc5b1e2e67b6f4bf, 0x3fbc00c7767225cb), (0xb8e783952280cc1c, 0xbc5b6b51fca7a9a5, 0x3fbc4861aab93a23), (0x38f01f84186661a4, 0xbc58f377e27bbe25, 0x3fbcd820ffd278f3), (0xb8f64617184a7a75, 0xbc5667bf89866cca, 0x3fbd204698cb42bd), (0xb885683b90b4f393, 0xbc1100072d011b81, 0x3fbd689b2193f133), (0x38dbad1cb83cff56, 0x3c496e1e0dda0b3d, 0x3fbdb11ed766abf4), (0xb8dbaceb968c6347, 0x3c55c6bc5d06e932, 0x3fbdf9d1f7f5b674), (0xb8fc9b4a9a70f158, 0xbc5e018e5642e2ef, 0x3fbe42b4c16caaf3), (0x38cefcd22b519828, 0xbc20a89525f3e005, 0x3fbed50a4a26eafc), (0xb8f06cab49f1568b, 0x3c50955b9d99c1b8, 0x3fbf1e7d882b689a), (0xb8d3723ccec39b76, 0xbc5c42f76e4345b0, 0x3fbf68216c9cc727), (0xb8cf28885cbbad03, 0xbc46749ac407ee87, 0x3fbfb1f6381856f4), (0xb8dd7ad76a7a7b71, 0x3c5d60df12c2e13d, 0x3fbffbfc2bbc7803), (0xb8d84e30bcb6c96c, 0x3c4ef8dd8b73f78d, 0x3fc02319c494f951), (0x38d7dcb3f42ceed7, 0x3c5f318aa3021710, 0x3fc0484e4942aa43), (0x390a877fa28d48a3, 0xbc6a12a1c0cb3d7f, 0x3fc093025a19976c), (0x38ff47213a55d67d, 0xbc609801174f88fd, 0x3fc0b88229b71227), (0x38f8cdc0d1c23d2c, 0x3c65b619c844d28b, 0x3fc0de1b56356b04), (0x38e4d94a39e28f45, 0x3c4dbdf176a1440a, 0x3fc103ce01fae223), (0xb8e86ff50e0d3676, 0xbc6ce6c847a6598d, 0x3fc1299a4fb3e306), (0x39030b6b1dc04f65, 0xbc61f5da9e930834, 0x3fc14f806253c3ed), (0x38f0cf7ad7cc99dc, 0x3c5ac676f20a87ab, 0x3fc175805d1587c1), (0x389beb9c10205d5f, 0xbc6e785b3b894bd7, 0x3fc19b9a637ca295), (0xb8ff10f27308fe1f, 0xbc5db924be9633b4, 0x3fc1c1ce9955c0c6), (0xb8fb96f43aca9222, 0x3c6db81c3374e59e, 0x3fc1e81d22b790d4), (0x390a3faccc5a1d64, 0xbc67299601268298, 0x3fc20e8624038fed), (0x38f3bb0b56ef561a, 0x3c6ea54c137b0aea, 0x3fc23509c1e6d937), (0x38ca3a8ffda52a42, 0x3c50349d03e16325, 0x3fc25ba8215af7fc), (0xb8d4ef96e017818e, 0x3c6557d4cdeffe3f, 0x3fc2826167a6bc9c), (0x38a1dc76a8836a07, 0xbc1f613823fd2a19, 0x3fc2a935ba5f1479), (0xb8c261e40d93238d, 0xbc63dda694b5fe22, 0x3fc2d0253f67e4cb), (0xb8eed469920e8a20, 0xbc4c7972ce5f8b57, 0x3fc2f7301cf4e87b), (0x38e43330d48115cd, 0x3c54b79d1957630a, 0x3fc31e56798a910a), (0x38ffcf787a5e0b91, 0xbc654fd6eb7d970e, 0x3fc345987bfeea91), ]; pxfm-0.1.23/src/logs/log1p.rs000064400000000000000000000642541046102023000140170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{EXP_MASK, get_exponent_f64}; use crate::common::{dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::dyadic_float::DyadicFloat128; use crate::logs::log1p_dd::log1p_dd; use crate::logs::log1p_dyadic::log1p_accurate; use crate::polyeval::f_polyeval4; // R1[i] = 2^-8 * nearestint( 2^8 / (1 + i * 2^-7) ) pub(crate) static R1: [u64; 129] = [ 0x3ff0000000000000, 0x3fefc00000000000, 0x3fef800000000000, 0x3fef400000000000, 0x3fef000000000000, 0x3feec00000000000, 0x3feea00000000000, 0x3fee600000000000, 0x3fee200000000000, 0x3fede00000000000, 0x3feda00000000000, 0x3fed800000000000, 0x3fed400000000000, 0x3fed000000000000, 0x3fece00000000000, 0x3feca00000000000, 0x3fec800000000000, 0x3fec400000000000, 0x3fec000000000000, 0x3febe00000000000, 0x3feba00000000000, 0x3feb800000000000, 0x3feb400000000000, 0x3feb200000000000, 0x3feb000000000000, 0x3feac00000000000, 0x3feaa00000000000, 0x3fea600000000000, 0x3fea400000000000, 0x3fea200000000000, 0x3fe9e00000000000, 0x3fe9c00000000000, 0x3fe9a00000000000, 0x3fe9800000000000, 0x3fe9400000000000, 0x3fe9200000000000, 0x3fe9000000000000, 0x3fe8e00000000000, 0x3fe8a00000000000, 0x3fe8800000000000, 0x3fe8600000000000, 0x3fe8400000000000, 0x3fe8200000000000, 0x3fe8000000000000, 0x3fe7e00000000000, 0x3fe7a00000000000, 0x3fe7800000000000, 0x3fe7600000000000, 0x3fe7400000000000, 0x3fe7200000000000, 0x3fe7000000000000, 0x3fe6e00000000000, 0x3fe6c00000000000, 0x3fe6a00000000000, 0x3fe6800000000000, 0x3fe6600000000000, 0x3fe6400000000000, 0x3fe6200000000000, 0x3fe6000000000000, 0x3fe5e00000000000, 0x3fe5c00000000000, 0x3fe5a00000000000, 0x3fe5800000000000, 0x3fe5800000000000, 0x3fe5600000000000, 0x3fe5400000000000, 0x3fe5200000000000, 0x3fe5000000000000, 0x3fe4e00000000000, 0x3fe4c00000000000, 0x3fe4a00000000000, 0x3fe4a00000000000, 0x3fe4800000000000, 0x3fe4600000000000, 0x3fe4400000000000, 0x3fe4200000000000, 0x3fe4200000000000, 0x3fe4000000000000, 0x3fe3e00000000000, 0x3fe3c00000000000, 0x3fe3c00000000000, 0x3fe3a00000000000, 0x3fe3800000000000, 0x3fe3600000000000, 0x3fe3600000000000, 0x3fe3400000000000, 0x3fe3200000000000, 0x3fe3000000000000, 0x3fe3000000000000, 0x3fe2e00000000000, 0x3fe2c00000000000, 0x3fe2c00000000000, 0x3fe2a00000000000, 0x3fe2800000000000, 0x3fe2800000000000, 0x3fe2600000000000, 0x3fe2400000000000, 0x3fe2400000000000, 0x3fe2200000000000, 0x3fe2000000000000, 0x3fe2000000000000, 0x3fe1e00000000000, 0x3fe1c00000000000, 0x3fe1c00000000000, 0x3fe1a00000000000, 0x3fe1a00000000000, 0x3fe1800000000000, 0x3fe1600000000000, 0x3fe1600000000000, 0x3fe1400000000000, 0x3fe1400000000000, 0x3fe1200000000000, 0x3fe1200000000000, 0x3fe1000000000000, 0x3fe0e00000000000, 0x3fe0e00000000000, 0x3fe0c00000000000, 0x3fe0c00000000000, 0x3fe0a00000000000, 0x3fe0a00000000000, 0x3fe0800000000000, 0x3fe0800000000000, 0x3fe0600000000000, 0x3fe0600000000000, 0x3fe0400000000000, 0x3fe0400000000000, 0x3fe0200000000000, 0x3fe0200000000000, 0x3fe0000000000000, ]; // Extra constants for exact range reduction when FMA instructions are not // available: // r * c - 1 for r = 2^-8 * nearestint( 2^8 / (1 + i * 2^-7)) // and c = 1 + i * 2^-7 // with i = 0..128. #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] pub(crate) static RCM1: [u64; 129] = [ 0x0000000000000000, 0xbf10000000000000, 0xbf30000000000000, 0xbf42000000000000, 0xbf50000000000000, 0xbf59000000000000, 0x3f5f000000000000, 0x3f52800000000000, 0x3f30000000000000, 0xbf49000000000000, 0xbf5f000000000000, 0x3f52000000000000, 0xbf30000000000000, 0xbf5c000000000000, 0x3f51000000000000, 0xbf45000000000000, 0x3f60000000000000, 0x3f10000000000000, 0xbf60000000000000, 0x3f3a000000000000, 0xbf5e000000000000, 0x3f38000000000000, 0xbf61000000000000, 0xbf00000000000000, 0x3f60000000000000, 0xbf4a000000000000, 0x3f51000000000000, 0xbf5f800000000000, 0xbf30000000000000, 0x3f56800000000000, 0xbf5f000000000000, 0xbf3c000000000000, 0x3f50000000000000, 0x3f63000000000000, 0xbf56000000000000, 0xbf24000000000000, 0x3f50000000000000, 0x3f60c00000000000, 0xbf60800000000000, 0xbf52000000000000, 0xbf30000000000000, 0x3f42000000000000, 0x3f55000000000000, 0x3f60000000000000, 0x3f65000000000000, 0xbf61c00000000000, 0xbf5c000000000000, 0xbf55800000000000, 0xbf50000000000000, 0xbf47000000000000, 0xbf40000000000000, 0xbf36000000000000, 0xbf30000000000000, 0xbf2c000000000000, 0xbf30000000000000, 0xbf36000000000000, 0xbf40000000000000, 0xbf47000000000000, 0xbf50000000000000, 0xbf55800000000000, 0xbf5c000000000000, 0xbf61c00000000000, 0xbf66000000000000, 0x3f65000000000000, 0x3f60000000000000, 0x3f55000000000000, 0x3f42000000000000, 0xbf30000000000000, 0xbf52000000000000, 0xbf60800000000000, 0xbf68800000000000, 0x3f60c00000000000, 0x3f50000000000000, 0xbf24000000000000, 0xbf56000000000000, 0xbf65400000000000, 0x3f63000000000000, 0x3f50000000000000, 0xbf3c000000000000, 0xbf5f000000000000, 0x3f68000000000000, 0x3f56800000000000, 0xbf30000000000000, 0xbf5f800000000000, 0x3f67000000000000, 0x3f51000000000000, 0xbf4a000000000000, 0xbf66000000000000, 0x3f60000000000000, 0xbf00000000000000, 0xbf61000000000000, 0x3f64800000000000, 0x3f38000000000000, 0xbf5e000000000000, 0x3f66000000000000, 0x3f3a000000000000, 0xbf60000000000000, 0x3f64800000000000, 0x3f10000000000000, 0xbf64000000000000, 0x3f60000000000000, 0xbf45000000000000, 0xbf6b000000000000, 0x3f51000000000000, 0xbf5c000000000000, 0x3f65400000000000, 0xbf30000000000000, 0xbf69c00000000000, 0x3f52000000000000, 0xbf5f000000000000, 0x3f63000000000000, 0xbf49000000000000, 0x3f6c000000000000, 0x3f30000000000000, 0xbf68800000000000, 0x3f52800000000000, 0xbf62000000000000, 0x3f5f000000000000, 0xbf59000000000000, 0x3f64c00000000000, 0xbf50000000000000, 0x3f69000000000000, 0xbf42000000000000, 0x3f6c400000000000, 0xbf30000000000000, 0x3f6e800000000000, 0xbf10000000000000, 0x3f6fc00000000000, 0x0000000000000000, ]; pub(crate) static LOG_R1_DD: [(u64, u64); 129] = [ (0x0000000000000000, 0x0000000000000000), (0xbd10c76b999d2be8, 0x3f80101575890000), (0xbd23dc5b06e2f7d2, 0x3f90205658938000), (0xbd2aa0ba325a0c34, 0x3f98492528c90000), (0x3d0111c05cf1d753, 0x3fa0415d89e74000), (0xbd2c167375bdfd28, 0x3fa466aed42e0000), (0xbd029efbec19afa2, 0x3fa67c94f2d4c000), (0x3d20fc1a353bb42e, 0x3faaaef2d0fb0000), (0xbd0e113e4fc93b7b, 0x3faeea31c006c000), (0xbd25325d560d9e9b, 0x3fb1973bd1466000), (0x3d2cc85ea5db4ed7, 0x3fb3bdf5a7d1e000), (0xbcf53a2582f4e1ef, 0x3fb4d3115d208000), (0x3cec1e8da99ded32, 0x3fb700d30aeac000), (0x3d23115c3abd47da, 0x3fb9335e5d594000), (0xbd0e42b6b94407c8, 0x3fba4e7640b1c000), (0x3d2646d1c65aacd3, 0x3fbc885801bc4000), (0x3d1a89401fa71733, 0x3fbda72763844000), (0xbd2534d64fa10afd, 0x3fbfe89139dbe000), (0x3d21ef78ce2d07f2, 0x3fc1178e8227e000), (0x3d2ca78e44389934, 0x3fc1aa2b7e23f000), (0x3d039d6ccb81b4a1, 0x3fc2d1610c868000), (0x3cc62fa8234b7289, 0x3fc365fcb0159000), (0x3d25837954fdb678, 0x3fc4913d8333b000), (0x3d2633e8e5697dc7, 0x3fc527e5e4a1b000), (0xbd127023eb68981c, 0x3fc5bf406b544000), (0xbd25118de59c21e1, 0x3fc6f0128b757000), (0xbd1c661070914305, 0x3fc7898d85445000), (0xbd073d54aae92cd1, 0x3fc8beafeb390000), (0x3d07f22858a0ff6f, 0x3fc95a5adcf70000), (0x3d29904d6865817a, 0x3fc9f6c407089000), (0xbd0c358d4eace1aa, 0x3fcb31d8575bd000), (0xbd2d4bc4595412b6, 0x3fcbd087383be000), (0xbcf1ec72c5962bd2, 0x3fcc6ffbc6f01000), (0xbd084a7e75b6f6e4, 0x3fcd1037f2656000), (0x3cc212276041f430, 0x3fce530effe71000), (0xbcca211565bb8e11, 0x3fcef5ade4dd0000), (0x3d1bcbecca0cdf30, 0x3fcf991c6cb3b000), (0xbd16f08c1485e94a, 0x3fd01eae5626c800), (0x3d27188b163ceae9, 0x3fd0c42d67616000), (0xbd2c210e63a5f01c, 0x3fd1178e8227e800), (0x3d2b9acdf7a51681, 0x3fd16b5ccbacf800), (0x3d2ca6ed5147bdb7, 0x3fd1bf99635a6800), (0x3d0a87deba46baea, 0x3fd214456d0eb800), (0x3d2c93c1df5bb3b6, 0x3fd269621134d800), (0x3d2a9cfa4a5004f4, 0x3fd2bef07cdc9000), (0x3d116ecdb0f177c8, 0x3fd36b6776be1000), (0x3d183b54b606bd5c, 0x3fd3c25277333000), (0x3d08e436ec90e09d, 0x3fd419b423d5e800), (0xbd2f27ce0967d675, 0x3fd4718dc271c800), (0xbd2e20891b0ad8a4, 0x3fd4c9e09e173000), (0x3d2ebe708164c759, 0x3fd522ae0738a000), (0x3d1fadedee5d40ef, 0x3fd57bf753c8d000), (0xbd0a0b2a08a465dc, 0x3fd5d5bddf596000), (0xbd2db623e731ae00, 0x3fd630030b3ab000), (0x3d20a0d32756eba0, 0x3fd68ac83e9c6800), (0x3d1721657c222d87, 0x3fd6e60ee6af1800), (0x3d2d8b0949dc60b3, 0x3fd741d876c67800), (0x3d29ec7d2efd1778, 0x3fd79e26687cf800), (0xbd272090c812566a, 0x3fd7fafa3bd81800), (0x3d2fd56f3333778a, 0x3fd85855776dc800), (0xbd205ae1e5e70470, 0x3fd8b639a88b3000), (0xbd1766b52ee6307d, 0x3fd914a8635bf800), (0xbd152313a502d9f0, 0x3fd973a343135800), (0xbd152313a502d9f0, 0x3fd973a343135800), (0xbd26279e10d0c0b0, 0x3fd9d32bea15f000), (0x3d23c6457f9d79f5, 0x3fda33440224f800), (0x3d1e36f2bea77a5d, 0x3fda93ed3c8ad800), (0xbd217cc552774458, 0x3fdaf5295248d000), (0x3d1095252d841995, 0x3fdb56fa04462800), (0x3d27d85bf40a666d, 0x3fdbb9611b80e000), (0x3d2cec807fe8e180, 0x3fdc1c60693fa000), (0x3d2cec807fe8e180, 0x3fdc1c60693fa000), (0xbd29b6ddc15249ae, 0x3fdc7ff9c7455800), (0xbd0797c33ec7a6b0, 0x3fdce42f18064800), (0x3d235bafe9a767a8, 0x3fdd490246def800), (0xbd1ea42d60dc616a, 0x3fddae75484c9800), (0xbd1ea42d60dc616a, 0x3fddae75484c9800), (0xbd1326b207322938, 0x3fde148a1a272800), (0xbd2465505372bd08, 0x3fde7b42c3ddb000), (0x3d2f27f45a470251, 0x3fdee2a156b41000), (0x3d2f27f45a470251, 0x3fdee2a156b41000), (0x3d12cde56f014a8b, 0x3fdf4aa7ee031800), (0x3d0085fa3c164935, 0x3fdfb358af7a4800), (0xbd053ba3b1727b1c, 0x3fe00e5ae5b20800), (0xbd053ba3b1727b1c, 0x3fe00e5ae5b20800), (0xbd04c45fe79539e0, 0x3fe04360be760400), (0x3d26812241edf5fd, 0x3fe078bf0533c400), (0x3d1f486b887e7e27, 0x3fe0ae76e2d05400), (0x3d1f486b887e7e27, 0x3fe0ae76e2d05400), (0x3d1c299807801742, 0x3fe0e4898611cc00), (0xbd258647bb9ddcb2, 0x3fe11af823c75c00), (0xbd258647bb9ddcb2, 0x3fe11af823c75c00), (0xbd2edd97a293ae49, 0x3fe151c3f6f29800), (0x3d14cc4ef8ab4650, 0x3fe188ee40f23c00), (0x3d14cc4ef8ab4650, 0x3fe188ee40f23c00), (0x3cccacdeed70e667, 0x3fe1c07849ae6000), (0xbd2a7242c9fe81d3, 0x3fe1f8635fc61800), (0xbd2a7242c9fe81d3, 0x3fe1f8635fc61800), (0x3d12fc066e48667b, 0x3fe230b0d8bebc00), (0xbd0b61f105226250, 0x3fe269621134dc00), (0xbd0b61f105226250, 0x3fe269621134dc00), (0x3d206d2be797882d, 0x3fe2a2786d0ec000), (0xbd17a6e507b9dc11, 0x3fe2dbf557b0e000), (0xbd17a6e507b9dc11, 0x3fe2dbf557b0e000), (0xbd274e93c5a0ed9c, 0x3fe315da44340800), (0xbd274e93c5a0ed9c, 0x3fe315da44340800), (0x3d10b83f9527e6ac, 0x3fe35028ad9d8c00), (0xbd218b7abb5569a4, 0x3fe38ae217197800), (0xbd218b7abb5569a4, 0x3fe38ae217197800), (0xbd02b7367cfe13c2, 0x3fe3c6080c36c000), (0xbd02b7367cfe13c2, 0x3fe3c6080c36c000), (0xbd26ce7930f0c74c, 0x3fe4019c2125cc00), (0xbd26ce7930f0c74c, 0x3fe4019c2125cc00), (0xbcfd984f481051f7, 0x3fe43d9ff2f92400), (0xbd22cb6af94d60aa, 0x3fe47a1527e8a400), (0xbd22cb6af94d60aa, 0x3fe47a1527e8a400), (0x3cef7115ed4c541c, 0x3fe4b6fd6f970c00), (0x3cef7115ed4c541c, 0x3fe4b6fd6f970c00), (0xbd2e6c516d93b8fb, 0x3fe4f45a835a5000), (0xbd2e6c516d93b8fb, 0x3fe4f45a835a5000), (0x3d05ccc45d257531, 0x3fe5322e26867800), (0x3d05ccc45d257531, 0x3fe5322e26867800), (0x3d09980bff3303dd, 0x3fe5707a26bb8c00), (0x3d09980bff3303dd, 0x3fe5707a26bb8c00), (0x3d2dfa63ac10c9fb, 0x3fe5af405c364800), (0x3d2dfa63ac10c9fb, 0x3fe5af405c364800), (0x3d2202380cda46be, 0x3fe5ee82aa241800), (0x3d2202380cda46be, 0x3fe5ee82aa241800), (0x0000000000000000, 0x0000000000000000), ]; #[inline] pub(crate) fn log1p_f64_dyadic(x: f64) -> DyadicFloat128 { let mut x_u = x.to_bits(); let mut x_dd = DoubleDouble::default(); let x_exp: u16 = ((x_u >> 52) & 0x7ff) as u16; if x_exp >= EXP_BIAS { // |x| >= 1 if x_u >= 0x4650_0000_0000_0000u64 { x_dd.hi = x; } else { x_dd = DoubleDouble::from_exact_add(x, 1.0); } } else { // |x| < 1 x_dd = DoubleDouble::from_exact_add(1.0, x); } const EXP_BIAS: u16 = (1u16 << (11 - 1u16)) - 1u16; // At this point, x_dd is the exact sum of 1 + x: // x_dd.hi + x_dd.lo = x + 1.0 exactly. // |x_dd.hi| >= 2^-54 // |x_dd.lo| < ulp(x_dd.hi) let xhi_bits = x_dd.hi.to_bits(); let xhi_frac = xhi_bits & ((1u64 << 52) - 1); x_u = xhi_bits; // Range reduction: // Find k such that |x_hi - k * 2^-7| <= 2^-8. let idx: i32 = ((xhi_frac.wrapping_add(1u64 << (52 - 8))) >> (52 - 7)) as i32; let x_e = (get_exponent_f64(f64::from_bits(xhi_bits)) as i32).wrapping_add(idx >> 7); // Scale x_dd by 2^(-xh_bits.get_exponent()). let s_u: i64 = (x_u & EXP_MASK) as i64 - (EXP_BIAS as i64).wrapping_shl(52); // Normalize arguments: // 1 <= m_dd.hi < 2 // |m_dd.lo| < 2^-52. // This is exact. let m_hi = 1f64.to_bits() | xhi_frac; let m_lo = if x_dd.lo.abs() > x_dd.hi * f64::from_bits(0x3800000000000000) { (x_dd.lo.to_bits() as i64).wrapping_sub(s_u) } else { 0 }; let m_dd = DoubleDouble::new(f64::from_bits(m_lo as u64), f64::from_bits(m_hi)); // Perform range reduction: // r * m - 1 = r * (m_dd.hi + m_dd.lo) - 1 // = (r * m_dd.hi - 1) + r * m_dd.lo // = v_hi + (v_lo.hi + v_lo.lo) // where: // v_hi = r * m_dd.hi - 1 (exact) // v_lo.hi + v_lo.lo = r * m_dd.lo (exact) // Bounds on the values: // -0x1.69000000000edp-8 < r * m - 1 < 0x1.7f00000000081p-8 // |v_lo.hi| <= |r| * |m_dd.lo| < 2^-52 // |v_lo.lo| < ulp(v_lo.hi) <= 2^(-52 - 53) = 2^(-105) let r = R1[idx as usize]; let v_hi; let v_lo = DoubleDouble::from_exact_mult(m_dd.lo, f64::from_bits(r)); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v_hi = f_fmla(f64::from_bits(r), m_dd.hi, -1.0); // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let c = f64::from_bits( (idx as u64) .wrapping_shl(52 - 7) .wrapping_add(0x3FF0_0000_0000_0000u64), ); v_hi = f_fmla( f64::from_bits(r), m_dd.hi - c, f64::from_bits(RCM1[idx as usize]), ); // Exact } // Range reduction output: // -0x1.69000000000edp-8 < v_hi + v_lo < 0x1.7f00000000081p-8 // |v_dd.lo| < ulp(v_dd.hi) <= 2^(-7 - 53) = 2^-60 let mut v_dd = DoubleDouble::from_exact_add(v_hi, v_lo.hi); v_dd.lo += v_lo.lo; log1p_accurate(x_e, idx as usize, v_dd) } /// Computes log(x+1) /// /// Max ULP 0.5 pub fn f_log1p(x: f64) -> f64 { let mut x_u = x.to_bits(); let mut x_dd = DoubleDouble::default(); let x_exp: u16 = ((x_u >> 52) & 0x7ff) as u16; const EXP_BIAS: u16 = (1u16 << (11 - 1u16)) - 1u16; let e = (((x_u >> 52) & 0x7ff) as i32).wrapping_sub(0x3ff); if e == 0x400 || x == 0. || x <= -1.0 { /* case NaN/Inf, +/-0 or x <= -1 */ if e == 0x400 && x.to_bits() != 0xfffu64 << 52 { /* NaN or + Inf*/ return x + x; } if x <= -1.0 /* we use the fact that NaN < -1 is false */ { /* log2p(x<-1) is NaN, log2p(-1) is -Inf and raises DivByZero */ return if x < -1.0 { f64::NAN } else { // x=-1 f64::NEG_INFINITY }; } return x + x; /* +/-0 */ } let ax = x_u.wrapping_shl(1); if ax < 0x7f60000000000000u64 { // |x| < 0.0625 // check case x tiny first to avoid spurious underflow in x*x if ax < 0x7940000000000000u64 { // |x| < 0x1p-53 if ax == 0 { return x; } /* we have underflow when |x| < 2^-1022, or when |x| = 2^-1022 and the result is smaller than 2^-1022 in absolute value */ let res = dyad_fmla(x.abs(), f64::from_bits(0xbc90000000000000), x); return res; } } if x_exp >= EXP_BIAS { // |x| >= 1 if x_u >= 0x4650_0000_0000_0000u64 { x_dd.hi = x; } else { x_dd = DoubleDouble::from_exact_add(x, 1.0); } } else { // |x| < 1 if x_exp < EXP_BIAS - 52 - 1 { // Quick return when |x| < 2^-53. // Since log(1 + x) = x - x^2/2 + x^3/3 - ..., // for |x| < 2^-53, // x > log(1 + x) > x - x^2 > x(1 - 2^-54) > x - ulp(x)/2 // Thus, // log(1 + x) = nextafter(x, -inf) for FE_DOWNWARD, or // FE_TOWARDZERO and x > 0, // = x otherwise. if x == 0.0 { return x + x; } let tp = 1.0f32; let tn = -1.0f32; let rdp = tp - f32::from_bits(0x3d594caf) != tp; let rdn = tn - f32::from_bits(0x33800000) != tn; if x > 0. && rdp { return f64::from_bits(x_u - 1); } if x < 0. && rdn { return f64::from_bits(x_u + 1); } return if x + x == 0.0 { x + x } else { x }; } x_dd = DoubleDouble::from_exact_add(1.0, x); } // At this point, x_dd is the exact sum of 1 + x: // x_dd.hi + x_dd.lo = x + 1.0 exactly. // |x_dd.hi| >= 2^-54 // |x_dd.lo| < ulp(x_dd.hi) let xhi_bits = x_dd.hi.to_bits(); let xhi_frac = xhi_bits & ((1u64 << 52) - 1); x_u = xhi_bits; // Range reduction: // Find k such that |x_hi - k * 2^-7| <= 2^-8. let idx: i32 = ((xhi_frac.wrapping_add(1u64 << (52 - 8))) >> (52 - 7)) as i32; let x_e = (get_exponent_f64(f64::from_bits(xhi_bits)) as i32).wrapping_add(idx >> 7); let e_x = x_e as f64; const LOG_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3d2ef35793c76730), f64::from_bits(0x3fe62e42fefa3800), ); // hi is exact // ulp(hi) = ulp(LOG_2_HI) = ulp(LOG_R1_DD[idx].hi) = 2^-43 let r_dd = LOG_R1_DD[idx as usize]; let hi = f_fmla(e_x, LOG_2.hi, f64::from_bits(r_dd.1)); // lo errors < |e_x| * ulp(LOG_2_LO) + ulp(LOG_R1[idx].lo) // <= 2^11 * 2^(-43-53) = 2^-85 let lo = f_fmla(e_x, LOG_2.lo, f64::from_bits(r_dd.0)); // Scale x_dd by 2^(-xh_bits.get_exponent()). let s_u: i64 = (x_u & EXP_MASK) as i64 - (EXP_BIAS as i64).wrapping_shl(52); // Normalize arguments: // 1 <= m_dd.hi < 2 // |m_dd.lo| < 2^-52. // This is exact. let m_hi = 1f64.to_bits() | xhi_frac; let m_lo = if x_dd.lo.abs() > x_dd.hi * f64::from_bits(0x3800000000000000) { (x_dd.lo.to_bits() as i64).wrapping_sub(s_u) } else { 0 }; let m_dd = DoubleDouble::new(f64::from_bits(m_lo as u64), f64::from_bits(m_hi)); // Perform range reduction: // r * m - 1 = r * (m_dd.hi + m_dd.lo) - 1 // = (r * m_dd.hi - 1) + r * m_dd.lo // = v_hi + (v_lo.hi + v_lo.lo) // where: // v_hi = r * m_dd.hi - 1 (exact) // v_lo.hi + v_lo.lo = r * m_dd.lo (exact) // Bounds on the values: // -0x1.69000000000edp-8 < r * m - 1 < 0x1.7f00000000081p-8 // |v_lo.hi| <= |r| * |m_dd.lo| < 2^-52 // |v_lo.lo| < ulp(v_lo.hi) <= 2^(-52 - 53) = 2^(-105) let r = R1[idx as usize]; let v_hi; let v_lo = DoubleDouble::from_exact_mult(m_dd.lo, f64::from_bits(r)); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v_hi = f_fmla(f64::from_bits(r), m_dd.hi, -1.0); // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let c = f64::from_bits( (idx as u64) .wrapping_shl(52 - 7) .wrapping_add(0x3FF0_0000_0000_0000u64), ); v_hi = f_fmla( f64::from_bits(r), m_dd.hi - c, f64::from_bits(RCM1[idx as usize]), ); // Exact } // Range reduction output: // -0x1.69000000000edp-8 < v_hi + v_lo < 0x1.7f00000000081p-8 // |v_dd.lo| < ulp(v_dd.hi) <= 2^(-7 - 53) = 2^-60 let mut v_dd = DoubleDouble::from_exact_add(v_hi, v_lo.hi); v_dd.lo += v_lo.lo; // Exact sum: // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u let r1 = DoubleDouble::from_exact_add(hi, v_dd.hi); // Degree-7 minimax polynomial log(1 + v) ~ v - v^2 / 2 + ... // generated by Sollya with: // > P = fpminimax(log(1 + x)/x, 6, [|1, 1, D...|], // [-0x1.69000000000edp-8, 0x1.7f00000000081p-8]); const P_COEFFS: [u64; 6] = [ 0xbfe0000000000000, 0x3fd5555555555166, 0xbfcfffffffdb7746, 0x3fc99999a8718a60, 0xbfc555874ce8ce22, 0x3fc24335555ddbe5, ]; // C * ulp(v_sq) + err_hi let v_sq = v_dd.hi * v_dd.hi; let p0 = f_fmla( v_dd.hi, f64::from_bits(P_COEFFS[1]), f64::from_bits(P_COEFFS[0]), ); let p1 = f_fmla( v_dd.hi, f64::from_bits(P_COEFFS[3]), f64::from_bits(P_COEFFS[2]), ); let p2 = f_fmla( v_dd.hi, f64::from_bits(P_COEFFS[5]), f64::from_bits(P_COEFFS[4]), ); let p = f_polyeval4(v_sq, (v_dd.lo + r1.lo) + lo, p0, p1, p2); const ERR_HI: [f64; 2] = [f64::from_bits(0x3aa0000000000000), 0.0]; let err_hi = ERR_HI[if hi == 0.0 { 1 } else { 0 }]; let err = f_fmla(v_sq, f64::from_bits(0x3ce0000000000000), err_hi); let left = r1.hi + (p - err); let right = r1.hi + (p + err); // Ziv's test to see if fast pass is accurate enough. if left == right { return left; } log1p_accurate_dd(x) } #[cold] fn log1p_accurate_dd(x: f64) -> f64 { log1p_dd(x).to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_log1p() { assert_eq!( f_log1p(-0.0000000000000003834186599935256), -0.00000000000000038341865999352564 ); assert_eq!(f_log1p(0.000032417476177515677), 0.000032416950742490306); assert_eq!(f_log1p(-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001866527236137164), -0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001866527236137164); assert_eq!(f_log1p(-0.0016481876264151651), -0.0016495473819346394); assert_eq!(f_log1p(-0.55), -0.7985076962177717); assert_eq!(f_log1p(-0.65), -1.0498221244986778); assert_eq!(f_log1p(1.65), 0.9745596399981308); assert!(f_log1p(-2.).is_nan()); } } pxfm-0.1.23/src/logs/log1p_dd.rs000064400000000000000000000226361046102023000144640ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::logs::log_dd::log_poly; use crate::logs::log_dd_coeffs::LOG_NEG_DD; use crate::polyeval::{f_polyeval3, f_polyeval6}; use crate::pow_tables::POW_INVERSE; #[inline(always)] pub(crate) fn log1p_tiny(z: f64) -> DoubleDouble { // See ./notes/log1p_tiny.sollya for generation const Q_1: [(u64, u64); 7] = [ (0xbc85555555555555, 0x3fd5555555555556), (0x0000000000000000, 0xbfd0000000000000), (0xbc6999999999999a, 0x3fc999999999999a), (0x3c75555555555555, 0xbfc5555555555556), (0x3c62492492492492, 0x3fc2492492492492), (0x0000000000000000, 0xbfc0000000000000), (0x3c5c71c71c71c71c, 0x3fbc71c71c71c71c), ]; let mut r = DoubleDouble::quick_mul_f64_add_f64( DoubleDouble::from_bit_pair(Q_1[6]), z, f64::from_bits(0xbfc0000000000000), ); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(Q_1[4])); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(Q_1[3])); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(Q_1[2])); r = DoubleDouble::quick_mul_f64_add_f64(r, z, f64::from_bits(0xbfd0000000000000)); r = DoubleDouble::quick_mul_f64_add(r, z, DoubleDouble::from_bit_pair(Q_1[0])); r = DoubleDouble::quick_mul_f64_add_f64(r, z, f64::from_bits(0xbfe0000000000000)); r = DoubleDouble::quick_mul_f64_add_f64(r, z, f64::from_bits(0x3ff0000000000000)); DoubleDouble::quick_mult_f64(r, z) } #[inline(always)] fn log1p_poly_fast(z: f64) -> DoubleDouble { // Polynomial generated by Sollya // d = [-0.0040283203125,0.0040283203125]; // f = log(1+x); // p0 = x-x^2/2; // w = 1; // pf = p0+fpminimax(f-p0, [|3,4,5,6,7,8,9|], [|107, D...|], d, absolute, floating); // See ./notes/dd_log1p_fast.sollya const Q: [f64; 6] = [ f64::from_bits(0xbfd0000000000002), f64::from_bits(0x3fc9999999996a6d), f64::from_bits(0xbfc5555555430087), f64::from_bits(0x3fc24924ea570eb6), f64::from_bits(0xbfc0001afd646804), f64::from_bits(0x3fbc12e04e0de219), ]; let x2 = DoubleDouble::from_exact_mult(z, z); let p = f_polyeval6(z, Q[0], Q[1], Q[2], Q[3], Q[4], Q[5]); let DoubleDouble { hi: h, lo: r } = DoubleDouble::from_exact_mult(z, p); let DoubleDouble { hi: p, lo: q } = DoubleDouble::add_f64( DoubleDouble::from_bit_pair((0x3c76235e52d6f15b, 0x3fd5555555555555)), h, ); let p = DoubleDouble::new(r + q, p); let mut t = DoubleDouble::quick_mult(x2, p); t = DoubleDouble::quick_mult_f64(t, z); DoubleDouble::mul_f64_add(x2, -0.5, t) } #[inline(always)] fn log1p_tiny_fast(z: f64) -> DoubleDouble { // Polynomial generated by Sollya // d = [-2^-12,2^-12]; // f = log(1+x); // p0 = x-x^2/2; // w = 1; // pf = p0+fpminimax(f-p0, [|3,4,5,6|], [|107, D...|], d, absolute, floating); // See ./notes/dd_log1p_tiny_fast.sollya let x2 = DoubleDouble::from_exact_mult(z, z); let p = f_polyeval3( z, f64::from_bits(0xbfcffffffffffff4), f64::from_bits(0x3fc99999b4d2481f), f64::from_bits(0xbfc55555714a3cb8), ); let DoubleDouble { hi: h, lo: r } = DoubleDouble::from_exact_mult(z, p); let DoubleDouble { hi: ph, lo: q } = DoubleDouble::add_f64( DoubleDouble::from_bit_pair((0xbc77e8068b994170, 0x3fd5555555555551)), h, ); let p = DoubleDouble::new(r + q, ph); let mut t = DoubleDouble::quick_mult(x2, p); t = DoubleDouble::quick_mult_f64(t, z); let f = DoubleDouble::f64_add(z, DoubleDouble::mul_f64_add(x2, -0.5, t)); DoubleDouble::from_exact_add(f.hi, f.lo) } #[inline] pub(crate) fn log1p_dd(z: f64) -> DoubleDouble { let ax = z.to_bits().wrapping_shl(1); if ax < 0x7e60000000000000u64 { // |x| < 0x1p-12 return log1p_tiny(z); } let dz = DoubleDouble::from_full_exact_add(z, 1.0); // We'll compute log((z+1)+1) as log(xh+xl) = log(xh) + log(1+xl/xh). // since xl/xh < ulp(xh) we'll use for log(1+xl/xh) // one taylor term what means that log(1+xl/xh) = log_lo + O(x^2) let log_lo = if dz.hi <= f64::from_bits(0x7fd0000000000000) || dz.lo.abs() >= 4.0 { dz.lo / dz.hi } else { 0. }; // avoid spurious underflow let x_u = dz.hi.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = DoubleDouble::from_bit_pair(LOG_NEG_DD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7abc9e3b39803f), f64::from_bits(0x3fe62e42fefa39ef), ); let tt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r); let v = DoubleDouble::full_add_f64(tt, z); let mut p = log_poly(z); // adding log(1+xl/xh) lower term p.lo += log_lo; DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)) } #[inline] pub(crate) fn log1p_fast_dd(z: f64) -> DoubleDouble { let ax = z.to_bits().wrapping_shl(1); if ax < 0x7e60000000000000u64 { // |x| < 2^-12 return log1p_tiny_fast(z); } let dz = DoubleDouble::from_full_exact_add(z, 1.0); // We'll compute log((z+1)+1) as log(xh+xl) = log(xh) + log(1+xl/xh). // since xl/xh < ulp(xh) we'll use for log(1+xl/xh) // one taylor term what means that log(1+xl/xh) = log_lo + O(x^2) let log_lo = if dz.hi <= f64::from_bits(0x7fd0000000000000) || dz.lo.abs() >= 4.0 { dz.lo / dz.hi } else { 0. }; // avoid spurious underflow let x_u = dz.hi.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = DoubleDouble::from_bit_pair(LOG_NEG_DD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7abc9e3b39803f), f64::from_bits(0x3fe62e42fefa39ef), ); let tt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r); let v = DoubleDouble::full_add_f64(tt, z); let mut p = log1p_poly_fast(z); // adding log(1+xl/xh) lower term p.lo += log_lo; DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)) } pxfm-0.1.23/src/logs/log1p_dyadic.rs000064400000000000000000000130221046102023000153170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log1p_dyadic_tables::{LOG1P_R1, LOG1P_R2, LOG1P_S2, LOG1P_S3, LOGP1_R3}; #[cold] pub(crate) fn log1p_accurate(e_x: i32, index: usize, m_x: DoubleDouble) -> DyadicFloat128 { // Minimax polynomial generated by Sollya with: // > P = fpminimax((log(1 + x) - x)/x^2, 3, [|1, 128...|], // [-0x1.01928p-22 , 0x1p-22]); // > P; // > dirtyinfnorm(log(1 + x)/x - 1 - x*P, [-0x1.01928p-22 , 0x1p-22]); // 0x1.ce1e...p-116 const BIG_COEFFS: [DyadicFloat128; 4] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xccccccd7_4818e397_7ed78465_d460315b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x80000000_000478b0_c6388a23_871ce156_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaaaaaaaa_aaaaaaaa_aa807bd8_67763262_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, ]; // log(2) with 128-bit precision generated by SageMath with: // def format_hex(value): // l = hex(value)[2:] // n = 4 // x = [l[i:i + n] for i in range(0, len(l), n)] // return "0x" + "_".join(x) + "_u128" // (s, m, e) = RealField(128)(2).log().sign_mantissa_exponent(); // print(format_hex(m)); const LOG_2: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb172_17f7_d1cf_79ab_c9e3_b398_03f2_f6af_u128, }; let e_x_f128 = DyadicFloat128::new_from_f64(e_x as f64); let mut sum = LOG_2 * e_x_f128; sum = sum + LOG1P_R1[index]; let mut v = DyadicFloat128::new_from_f64(m_x.hi) + DyadicFloat128::new_from_f64(m_x.lo); // Skip 2nd range reduction step if |m_x| <= 2^-15. if m_x.hi > f64::from_bits(0x3f00000000000000) || m_x.hi < f64::from_bits(0xbf00000000000000) { // Range reduction - Step 2. // For k such that: k * 2^-14 - 2^-15 <= m_x.hi < k * 2^-14 + 2^-15, // Let s_k = 2^-18 * round( 2^18 / (1 + k*2^-14) ) - 1 // Then the 2nd reduced argument is: // (1 + s_k) * (1 + m_x) - 1 = // = s_k + m_x + s_k * m_x // Output range: // -0x1.1037c00000040271p-15 <= v2.hi + v2.lo <= 0x1.108480000008096cp-15 let idx2: i32 = (f64::from_bits(0x40d0000000000000) * (m_x.hi + (91. * f64::from_bits(0x3f10000000000000) + f64::from_bits(0x3f00000000000000)))) as i32; sum = sum + LOG1P_R2[idx2 as usize]; let s2 = DyadicFloat128::new_from_f64(f64::from_bits(LOG1P_S2[idx2 as usize])); v = (v + s2) + (v * s2); } // Skip 3rd range reduction step if |v| <= 2^-22. if v.exponent > -150 { // Range reduction - Step 3. // For k such that: k * 2^-21 - 2^-22 <= v2.hi < k * 2^-21 + 2^-22, // Let s_k = 2^-21 * round( 2^21 / (1 + k*2^-21) ) - 1 // Then the 3rd reduced argument is: // v3.hi + v3.lo ~ (1 + s_k) * (1 + v2.hi + v2.lo) - 1 // Output range: // -0x1.012bb800000800114p-22 <= v3.hi + v3.lo <= 0x1p-22 let zv = v.fast_as_f64(); let idx3 = (f64::from_bits(0x4140000000000000) * (zv + (69. * f64::from_bits(0x3ea0000000000000) + f64::from_bits(0x3e90000000000000)))) as i32; sum = sum + LOGP1_R3[idx3 as usize]; let s3 = DyadicFloat128::new_from_f64(f64::from_bits(LOG1P_S3[idx3 as usize])); v = (v + s3) + (v * s3); } let mut p = v * BIG_COEFFS[0]; p = v * (p + BIG_COEFFS[1]); p = v * (p + BIG_COEFFS[2]); p = v * (p + BIG_COEFFS[3]); p = v + (v * p); sum + p } pxfm-0.1.23/src/logs/log1p_dyadic_tables.rs000064400000000000000000001722471046102023000166700ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; // Logarithm range reduction - Step 3: // s(k) = 2^-21 round( 2^21 / (1 + k*2^-21) ) - 1 for k = -69 .. 69 // Output range: // [-0x1.012bb800000800114p-22, 0x1p-22 ] pub(crate) static LOG1P_S3: [u64; 139] = [ 0x3f01400000000000, 0x3f01000000000000, 0x3f00c00000000000, 0x3f00800000000000, 0x3f00400000000000, 0x3f00000000000000, 0x3eff800000000000, 0x3eff000000000000, 0x3efe800000000000, 0x3efe000000000000, 0x3efd800000000000, 0x3efd000000000000, 0x3efc800000000000, 0x3efc000000000000, 0x3efb800000000000, 0x3efb000000000000, 0x3efa800000000000, 0x3efa000000000000, 0x3ef9800000000000, 0x3ef9000000000000, 0x3ef8800000000000, 0x3ef8000000000000, 0x3ef7800000000000, 0x3ef7000000000000, 0x3ef6800000000000, 0x3ef6000000000000, 0x3ef5800000000000, 0x3ef5000000000000, 0x3ef4800000000000, 0x3ef4000000000000, 0x3ef3800000000000, 0x3ef3000000000000, 0x3ef2800000000000, 0x3ef2000000000000, 0x3ef1800000000000, 0x3ef1000000000000, 0x3ef0800000000000, 0x3ef0000000000000, 0x3eef000000000000, 0x3eee000000000000, 0x3eed000000000000, 0x3eec000000000000, 0x3eeb000000000000, 0x3eea000000000000, 0x3ee9000000000000, 0x3ee8000000000000, 0x3ee7000000000000, 0x3ee6000000000000, 0x3ee5000000000000, 0x3ee4000000000000, 0x3ee3000000000000, 0x3ee2000000000000, 0x3ee1000000000000, 0x3ee0000000000000, 0x3ede000000000000, 0x3edc000000000000, 0x3eda000000000000, 0x3ed8000000000000, 0x3ed6000000000000, 0x3ed4000000000000, 0x3ed2000000000000, 0x3ed0000000000000, 0x3ecc000000000000, 0x3ec8000000000000, 0x3ec4000000000000, 0x3ec0000000000000, 0x3eb8000000000000, 0x3eb0000000000000, 0x3ea0000000000000, 0x0000000000000000, 0xbea0000000000000, 0xbeb0000000000000, 0xbeb8000000000000, 0xbec0000000000000, 0xbec4000000000000, 0xbec8000000000000, 0xbecc000000000000, 0xbed0000000000000, 0xbed2000000000000, 0xbed4000000000000, 0xbed6000000000000, 0xbed8000000000000, 0xbeda000000000000, 0xbedc000000000000, 0xbede000000000000, 0xbee0000000000000, 0xbee1000000000000, 0xbee2000000000000, 0xbee3000000000000, 0xbee4000000000000, 0xbee5000000000000, 0xbee6000000000000, 0xbee7000000000000, 0xbee8000000000000, 0xbee9000000000000, 0xbeea000000000000, 0xbeeb000000000000, 0xbeec000000000000, 0xbeed000000000000, 0xbeee000000000000, 0xbeef000000000000, 0xbef0000000000000, 0xbef0800000000000, 0xbef1000000000000, 0xbef1800000000000, 0xbef2000000000000, 0xbef2800000000000, 0xbef3000000000000, 0xbef3800000000000, 0xbef4000000000000, 0xbef4800000000000, 0xbef5000000000000, 0xbef5800000000000, 0xbef6000000000000, 0xbef6800000000000, 0xbef7000000000000, 0xbef7800000000000, 0xbef8000000000000, 0xbef8800000000000, 0xbef9000000000000, 0xbef9800000000000, 0xbefa000000000000, 0xbefa800000000000, 0xbefb000000000000, 0xbefb800000000000, 0xbefc000000000000, 0xbefc800000000000, 0xbefd000000000000, 0xbefd800000000000, 0xbefe000000000000, 0xbefe800000000000, 0xbeff000000000000, 0xbeff800000000000, 0xbf00000000000000, 0xbf00400000000000, 0xbf00800000000000, 0xbf00c00000000000, 0xbf01000000000000, 0xbf01400000000000, ]; // Logarithm range reduction - Step 2: // s(k) = 2^-18 round( 2^18 / (1 + k*2^-14) ) - 1 for k = -91 .. 96 // Output range: // [-0x1.1037c00000040271p-15 , 0x1.108480000008096cp-15] pub(crate) static LOG1P_S2: [u64; 188] = [ 0x3f76e00000000000, 0x3f76a00000000000, 0x3f76600000000000, 0x3f76200000000000, 0x3f75dc0000000000, 0x3f759c0000000000, 0x3f755c0000000000, 0x3f751c0000000000, 0x3f74dc0000000000, 0x3f749c0000000000, 0x3f74580000000000, 0x3f74180000000000, 0x3f73d80000000000, 0x3f73980000000000, 0x3f73580000000000, 0x3f73180000000000, 0x3f72d80000000000, 0x3f72940000000000, 0x3f72540000000000, 0x3f72140000000000, 0x3f71d40000000000, 0x3f71940000000000, 0x3f71540000000000, 0x3f71140000000000, 0x3f70d00000000000, 0x3f70900000000000, 0x3f70500000000000, 0x3f70100000000000, 0x3f6fa00000000000, 0x3f6f200000000000, 0x3f6ea00000000000, 0x3f6e200000000000, 0x3f6d980000000000, 0x3f6d180000000000, 0x3f6c980000000000, 0x3f6c180000000000, 0x3f6b980000000000, 0x3f6b180000000000, 0x3f6a980000000000, 0x3f6a180000000000, 0x3f69980000000000, 0x3f69100000000000, 0x3f68900000000000, 0x3f68100000000000, 0x3f67900000000000, 0x3f67100000000000, 0x3f66900000000000, 0x3f66100000000000, 0x3f65900000000000, 0x3f65100000000000, 0x3f64900000000000, 0x3f64100000000000, 0x3f63880000000000, 0x3f63080000000000, 0x3f62880000000000, 0x3f62080000000000, 0x3f61880000000000, 0x3f61080000000000, 0x3f60880000000000, 0x3f60080000000000, 0x3f5f100000000000, 0x3f5e100000000000, 0x3f5d100000000000, 0x3f5c100000000000, 0x3f5b100000000000, 0x3f5a100000000000, 0x3f59100000000000, 0x3f58100000000000, 0x3f57100000000000, 0x3f56000000000000, 0x3f55000000000000, 0x3f54000000000000, 0x3f53000000000000, 0x3f52000000000000, 0x3f51000000000000, 0x3f50000000000000, 0x3f4e000000000000, 0x3f4c000000000000, 0x3f4a000000000000, 0x3f48000000000000, 0x3f46000000000000, 0x3f44000000000000, 0x3f42000000000000, 0x3f40000000000000, 0x3f3c000000000000, 0x3f38000000000000, 0x3f34000000000000, 0x3f30000000000000, 0x3f28000000000000, 0x3f20000000000000, 0x3f10000000000000, 0x0000000000000000, 0xbf10000000000000, 0xbf20000000000000, 0xbf28000000000000, 0xbf30000000000000, 0xbf34000000000000, 0xbf38000000000000, 0xbf3c000000000000, 0xbf40000000000000, 0xbf42000000000000, 0xbf44000000000000, 0xbf46000000000000, 0xbf48000000000000, 0xbf4a000000000000, 0xbf4c000000000000, 0xbf4e000000000000, 0xbf50000000000000, 0xbf51000000000000, 0xbf52000000000000, 0xbf53000000000000, 0xbf54000000000000, 0xbf55000000000000, 0xbf56000000000000, 0xbf56f00000000000, 0xbf57f00000000000, 0xbf58f00000000000, 0xbf59f00000000000, 0xbf5af00000000000, 0xbf5bf00000000000, 0xbf5cf00000000000, 0xbf5df00000000000, 0xbf5ef00000000000, 0xbf5ff00000000000, 0xbf60780000000000, 0xbf60f80000000000, 0xbf61780000000000, 0xbf61f80000000000, 0xbf62780000000000, 0xbf62f80000000000, 0xbf63780000000000, 0xbf63f00000000000, 0xbf64700000000000, 0xbf64f00000000000, 0xbf65700000000000, 0xbf65f00000000000, 0xbf66700000000000, 0xbf66f00000000000, 0xbf67700000000000, 0xbf67f00000000000, 0xbf68700000000000, 0xbf68f00000000000, 0xbf69680000000000, 0xbf69e80000000000, 0xbf6a680000000000, 0xbf6ae80000000000, 0xbf6b680000000000, 0xbf6be80000000000, 0xbf6c680000000000, 0xbf6ce80000000000, 0xbf6d680000000000, 0xbf6de00000000000, 0xbf6e600000000000, 0xbf6ee00000000000, 0xbf6f600000000000, 0xbf6fe00000000000, 0xbf70300000000000, 0xbf70700000000000, 0xbf70b00000000000, 0xbf70f00000000000, 0xbf712c0000000000, 0xbf716c0000000000, 0xbf71ac0000000000, 0xbf71ec0000000000, 0xbf722c0000000000, 0xbf726c0000000000, 0xbf72ac0000000000, 0xbf72e80000000000, 0xbf73280000000000, 0xbf73680000000000, 0xbf73a80000000000, 0xbf73e80000000000, 0xbf74280000000000, 0xbf74640000000000, 0xbf74a40000000000, 0xbf74e40000000000, 0xbf75240000000000, 0xbf75640000000000, 0xbf75a40000000000, 0xbf75e00000000000, 0xbf76200000000000, 0xbf76600000000000, 0xbf76a00000000000, 0xbf76e00000000000, 0xbf77200000000000, 0xbf775c0000000000, 0xbf779c0000000000, 0xbf77dc0000000000, ]; //def format_hex(value): // l = hex(value)[2:] // n = 8 // x = [l[i:i + n] for i in range(0, len(l), n)] // return "0x" + "_".join(x) + "_u128" // for i in range(129): // r = 2^-8 * round( 2^8 / (1 + i*2^(-7)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("DyadicFloat {sign: DyadicDyadicSign::Pos, exponent: ", e, ",mantissa:", format_hex(m), "},"); #[rustfmt::skip] pub(crate) static LOG1P_R1: [DyadicFloat128; 129] = [ DyadicFloat128 {sign: DyadicSign::Pos,exponent: 0, mantissa: 0_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -134,mantissa: 0x8080abac_46f38946_662d417c_ed007a46_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -133,mantissa: 0x8102b2c4_9ac23a4f_91d082dc_e3ddcd38_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -133,mantissa: 0xc2492946_4655f45c_da5f3cc0_b3251dbd_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -132,mantissa: 0x820aec4f_3a222380_b9e3aea6_c444ef07_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -132,mantissa: 0xa33576a1_6f1f4c64_521016bd_904dc968_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -132,mantissa: 0xb3e4a796_a5dac208_27cca0bc_c06c2f92_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -132,mantissa: 0xd5779687_d887e0d1_a9dda170_56e45ed5_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -132,mantissa: 0xf7518e00_35c3dd83_606d8909_3278a939_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0x8cb9de8a_32ab368a_a7c98595_30a45153_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0x9defad3e_8f73217a_976d3b5b_45f6ca0b_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xa6988ae9_03f562ed_3e858f08_597b3a69_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xb8069857_560707a3_6a677b4c_8bec22e1_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xc99af2ea_ca4c4570_eaf51f66_692844ba_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xd273b205_8de1bd49_46bbf837_b4d320c6_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xe442c00d_e2591b47_196ab34c_e0bccd12_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xed393b1c_22351280_3f4e2e66_0317d55f_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -131,mantissa: 0xff4489ce_deab2ca6_c17bd40d_8d9291ec_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0x88bc7411_3f23def1_9c5a0fe3_96f40f1e_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0x8d515bf1_1fb94f1c_88713268_840cbcc0_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0x968b0864_3409ceb6_65c0da50_6a088484_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0x9b2fe580_ac80b17d_411a5b94_4aca8708_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xa489ec19_9dab06f2_a9fb6cf0_ecb411b7_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xa93f2f25_0dac67d1_cad2fb8d_48054ae0_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xadfa035a_a1ed8fdc_149767e4_10316d2c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xb780945b_ab55dce4_34c7bc3d_32750fde_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xbc4c6c2a_226399ef_8f6ebcfb_2016a439_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xc5f57f59_c7f46155_aa8b6997_a402bf30_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xcad2d6e7_b80bf914_2c507fb7_a3d0bf6a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xcfb62038_44b3209a_d0cb02f3_3f79c16c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xd98ec2ba_de71e539_58a98f2a_d65bee9b_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xde8439c1_dec56877_4d57da94_5b5d0aaa_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xe37fde37_807b84e3_4e9a750b_6b68781d_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xe881bf93_2af3dac0_c524848e_3443e040_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xf29877ff_38809091_3b020fa1_820c9492_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xf7ad6f26_e7ff2ef7_54d2238f_75f969b1_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -130,mantissa: 0xfcc8e365_9d9bcbec_ca0cdf30_1431b60f_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x80f572b1_363487b9_f5bd0b5b_3479d5f4_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x86216b3b_0b17188b_163ceae8_8f720f1e_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x88bc7411_3f23def1_9c5a0fe3_96f40f1e_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x8b5ae65d_67db9acd_f7a51681_26a58b9a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x8dfccb1a_d35ca6ed_5147bdb6_ddcaf59c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x90a22b68_75c6a1f7_ae91aeba_609c8877_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x934b1089_a6dc93c1_df5bb3b6_0554e152_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x95f783e6_e49a9cfa_4a5004f3_ef063313_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x9b5b3bb5_f088b766_d878bbe3_d392be25_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0x9e1293b9_998c1daa_5b035eae_273a855f_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xa0cda11e_af46390d_bb243827_3918db7e_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xa38c6e13_8e20d831_f698298a_dddd7f32_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xa64f04f0_b961df76_e4f5275c_2d15c21f_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xa9157039_c51ebe70_8164c759_686a2209_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xabdfba9e_468fd6f6_f72ea077_49ce6bd3_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xaeadeefa_caf97d35_7dd6e688_ebb13b03_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xb1801859_d56249dc_18ce51ff_f99479cd_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xb45641f4_e350a0d3_2756eba0_0bc33978_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xb7307735_78cb90b2_be1116c3_466beb6d_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xba0ec3b6_33dd8b09_49dc60b2_b059a60b_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xbcf13343_e7d9ec7d_2efd1778_1bb3afec_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xbfd7d1de_c0a8df6f_37eda996_244bccb0_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xc2c2abbb_6e5fd56f_33337789_d592e296_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xc5b1cd44_596fa51e_1a18fb8f_9f9ef280_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xc8a5431a_dfb44ca5_688ce7c1_a75e341a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xcb9d1a18_9ab56e76_2d7e9307_c70c0668_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xcb9d1a18_9ab56e76_2d7e9307_c70c0668_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xce995f50_af69d861_ef2f3f4f_861ad6a9_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xd19a2011_27d3c645_7f9d79f5_1dcc7301_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xd49f69e4_56cf1b79_5f53bd2e_406e66e7_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xd7a94a92_466e833a_ad88bba7_d0cee8e0_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xdab7d022_31484a92_96c20cca_6efe2ac5_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xddcb08dc_0717d85b_f40a666c_87842843_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xe0e30349_fd1cec80_7fe8e180_2aba24d6_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xe0e30349_fd1cec80_7fe8e180_2aba24d6_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xe3ffce3a_2aa64922_3eadb651_b49ac53a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xe72178c0_323a1a0f_304e1653_e71d9973_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xea481236_f7d35baf_e9a767a8_0d6d97e8_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xed73aa42_64b0ade9_4f91cf4b_33e42998_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xed73aa42_64b0ade9_4f91cf4b_33e42998_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xf0a450d1_39366ca6_fc66eb64_08ff6433_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xf3da161e_ed6b9aaf_ac8d42f7_8d3e65d3_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xf7150ab5_a09f27f4_5a470250_d40ebe90_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xf7150ab5_a09f27f4_5a470250_d40ebe90_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xfa553f70_18c966f2_b780a545_a1b54dcf_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -129,mantissa: 0xfd9ac57b_d244217e_8f05924d_258c14c5_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8072d72d_903d588b_89d1b09c_70c4010a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8072d72d_903d588b_89d1b09c_70c4010a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x821b05f3_b01d6774_030d58c3_f7e2ea1f_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x83c5f829_9e2b4091_20f6fafe_8fbb68b9_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8573b716_82a7d21a_e21f9f89_c1ab80b2_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8573b716_82a7d21a_e21f9f89_c1ab80b2_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x87244c30_8e670a66_01e005d0_6dbfa8f8_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x88d7c11e_3ad53cdc_223111a7_07b6de2c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x88d7c11e_3ad53cdc_223111a7_07b6de2c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8a8e1fb7_94b09134_2eb628db_a173c82d_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8c477207_91e53313_be2ad194_15fe25a5_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8c477207_91e53313_be2ad194_15fe25a5_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8e03c24d_73003959_bddae1cc_ce247838_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8fc31afe_30b2c6de_9b00bf16_7e95da67_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x8fc31afe_30b2c6de_9b00bf16_7e95da67_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x918586c5_f5e4bf01_9b92199e_d1a4bab1_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x934b1089_a6dc93c1_df5bb3b6_0554e152_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x934b1089_a6dc93c1_df5bb3b6_0554e152_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x9513c368_76083695_f3cbc416_a2418012_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x96dfaabd_86fa1646_be1188fb_c94e2f15_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x96dfaabd_86fa1646_be1188fb_c94e2f15_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x98aed221_a03458b6_1d2f8932_1647b358_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x98aed221_a03458b6_1d2f8932_1647b358_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x9a81456c_ec642e0f_e549f9aa_ea3cb5e1_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x9c5710b8_cbb73a42_a2554b2d_d4619e63_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x9c5710b8_cbb73a42_a2554b2d_d4619e63_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x9e304061_b5fda919_30603d87_b6df81ad_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0x9e304061_b5fda919_30603d87_b6df81ad_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa00ce109_2e5498c3_67879c5a_30cd1242_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa00ce109_2e5498c3_67879c5a_30cd1242_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa1ecff97_c91e267b_0b7efae0_8e597e16_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa3d0a93f_45169a4a_83594fab_088c0d65_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa3d0a93f_45169a4a_83594fab_088c0d65_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa5b7eb7c_b860fb88_af6a62a0_dec6e073_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa5b7eb7c_b860fb88_af6a62a0_dec6e073_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa7a2d41a_d270c9d7_49362382_a768847a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa7a2d41a_d270c9d7_49362382_a768847a_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa9917134_33c2b998_8ba4aea6_14d05701_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xa9917134_33c2b998_8ba4aea6_14d05701_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xab83d135_dc633301_7fe6607b_a902ef3c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xab83d135_dc633301_7fe6607b_a902ef3c_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xad7a02e1_b24efd31_d60864fd_949b4bd3_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xad7a02e1_b24efd31_d60864fd_949b4bd3_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xaf741551_20c9011c_066d235e_e63073dd_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: -128,mantissa: 0xaf741551_20c9011c_066d235e_e63073dd_u128}, DyadicFloat128 {sign: DyadicSign::Pos,exponent: 0, mantissa: 0_u128} ]; // -log(r) for the second step, generated by SageMath with: // def format_hex(value): // l = hex(value)[2:] // n = 8 // x = [l[i:i + n] for i in range(0, len(l), n)] // return "0x" + "_".join(x) + "_u128" // for i in range(-91, 97): // r = 2^-18 * round( 2^18 / (1 + i*2^(-14)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("{sign: DyadicDyadicSign::Pos," if (s == -1) else "{sign: DyadicDyadicSign::Neg, exponent: ", e, ", mantissa: " // format_hex(m), "},"); #[rustfmt::skip] pub(crate) static LOG1P_R2: [DyadicFloat128; 188] = [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xb67dab2a_1a5742a4_a0e061c5_f7431c5e_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xb4807f24_af682939_5d5bfe7b_969ed6ec_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xb2834b35_b4d54d5f_4d08702d_dfabc23f_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xb0860f5c_eba9be95_d4d36650_8b9953df_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xae68f71a_a09e8847_ac18a289_f8f214a9_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xac6baaee_d676e8f1_d5b42054_abb88c45_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xaa6e56d8_7cd632d6_09809d58_ee484964_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xa870fad7_54bb8791_b9e6fc7c_72f06d73_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xa67396eb_1f231892_6f78d6d0_105c00e2_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xa4762b13_9d0626e7_028f7126_29209148_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xa258dfd1_0aedaa67_c98d898e_f172df02_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0xa05b63a3_73e60a83_fcc37c3c_3062bfa1_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x9e5ddf89_cf42f501_3eb450db_05763c36_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x9c605383_ddf1b88c_7146a86f_d458b775_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x9a62bf91_60dcb286_c20a0c92_81474436_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x986523b2_18eb4ed6_cdc57316_ec4aebc3_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x96677fe5_c70207b9_c060dad7_4cef4273_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x9449f92d_2ff44633_ed8def1a_3e433499_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x924c4507_3220b5e0_3ce7a1f8_5c27b4fc_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x904e88f3_68fea63f_f2ca8934_49f7f2cb_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x8e50c4f1_956699ed_8d77d9fa_bd2853cf_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x8c52f901_782e20ec_93e828d7_5b58ded4_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x8a552522_d227d87a_9f9605b0_53c5acf0_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x88574955_64236ae0_62a14939_3bca7241_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x86398719_b66bac7c_aea6b56c_e89203d4_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x843b9aef_044e4dcc_0242bd86_d00609b2_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x823da6d4_c89c6927_daabf927_74bac84e_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x803faaca_c419abf2_a1c6f3fc_242ef8d0_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xfc834da1_6f0d9f57_a225ebc0_2e6d9dd4_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xf88735cc_c7433381_c33f6ad3_40ae18a9_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xf48b0e17_1249b6bc_70b2a4d3_8a242244_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xf08ed67f_d190e280_1d548190_48b811b0_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xec52ca07_ed95f236_9c21b650_afe9ede0_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xe85671ad_ecd28aac_935519c9_6d30e463_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xe45a0970_dc912ca7_ba88f6f2_e2672cfe_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xe05d9150_3e298bc8_0b1a8b84_657ae069_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xdc61094b_92ed70ef_ea3bff8d_197b20a1_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xd8647162_5c28b9e5_cdbb931d_6fecc249_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xd467c994_1b2158f5_d971d560_d5f00820_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xd06b11e0_51175493_75563561_244c090b_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xcc6e4a46_7f44c6fa_dc393c9a_3f3b380f_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xc831a4c6_f6fa709d_e6abe6e9_e4ee2096_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xc434bc61_24a0f16e_3ce3c822_8583a66e_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xc037c413_c61bfd93_b96a79f5_c5a4963a_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xbc3abbde_5c8d9bde_aaef2733_7008679f_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xb83da3c0_6911e509_a49a3fca_ddc8bc5a_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xb4407bb9_6cbf035a_e0254feb_785362fa_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xb04343c8_e8a53245_9893a4e2_5ab9dc95_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xac45fbee_5dcebe0b_5d8b0f40_a3708915_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xa848a429_4d40035d_5f4c11c2_c7a58c69_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xa44b3c79_37f76efd_b348cc5d_f706ffba_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xa04dc4dd_9eed7d60_9159f2c5_5a18befd_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x9c106456_3058bef3_bdfdee41_fe6a5a02_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x9812cbe3_46475a24_4580ddf8_9853254d_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x94152383_53489ffb_ac75e10d_61fc3ee8_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x90176b35_d83ce8e2_cad9b30b_29736155_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x8c19a2fa_55fe9b14_6f881deb_98fc45f3_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x881bcad0_4d622a3e_70a04b63_b7248c96_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x841de2b7_3f361722_b4823fb4_8035eddd_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x801feaae_ac42ef38_3364ccb5_b13cd47f_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xf843c56c_2a969897_e306977b_049f0ad5_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xf0479599_f617a843_e3c4d9e9_619bc045_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xe84b45e5_bc76702c_4356d525_b5e6432d_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xe04ed64e_7f14697a_7839dcd7_989339ab_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xd85246d3_3f47230b_4e21f045_ecb76f23_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xd0559772_fe5840b0_902e248d_d4ba9b28_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xc858c82c_bd857a72_a4444906_7ef92e01_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xc05bd8ff_7e009bd2_17926207_cc22e4e6_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xb85ec9ea_40ef8309_1c349622_f3fa5d82_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xafe1c6ec_e1a058dd_97fa2fd0_c9dc723e_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xa7e47606_048b1a65_983e8089_7cf1e60f_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x9fe70534_1d236102_7199cd06_ae5d39b3_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x97e97476_2c5e8f58_43cd18a7_2a051a96_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x8febc3cb_332616ff_7b6d1248_c3e1fd40_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x87edf332_325777c5_f5572a88_14c703af_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xffe00554_55887de0_26828c92_649a3a39_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xefe3e464_3a640cf3_82c550bd_1216d82a_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xdfe78392_14b4e8ae_da6959f7_f0e01bf0_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xcfeae2db_e5d6736d_da93e2fa_85a8f214_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xbfee023f_af0c2480_b47505bf_a5a03b06_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xaff0e1bb_718186ad_b1475a51_80a43520_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0x9ff3814d_2e4a36b2_a8740b91_c95df537_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0x8ff5e0f2_e661e1c6_57d895d3_5921b59c_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xfff00155_35588833_3c56c598_c659c2a3_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xdff3c0e4_97ea4eb1_2ef8ec33_ed9d782a_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xbff7008f_f5e0c257_379eba7e_6465ff63_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0x9ff9c053_5073a370_3f972b78_3fcab757_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -140, mantissa: 0xfff80055_51558885_de026e27_1ee0549d_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -140, mantissa: 0xbffb8023_febc0c25_eceb47ea_01f6c632_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -141, mantissa: 0xfffc0015_54d55888_7333c578_57e1ed52_u128}, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0xfffe0005_55455588_87dde026_fa704374_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0x80010002_aab2aac4_44999abe_2fe2cc65_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0x8002000a_aaeaac44_4eef3815_81464ccb_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0xc0048024_01440c26_dfeb4850_85f6f454_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0x8004002a_acaac445_99abe3be_3a1c6e93_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xa0064053_5a37a37a_6bc1e20e_ac8448b4_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xc0090090_0a20c275_979eedc0_64c242fd_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xe00c40e4_bd6e4efd_c72446cc_1bf728bd_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x800800aa_baac446e_f381b821_bbb569e5_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x900a20f3_19a3e273_569b26aa_a485ea5c_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xa00c814d_7c6a37f8_2dcf56c8_3c80b028_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xb00f21bb_e3e388ee_5f697682_84463b9b_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xc0120240_510c284c_b48ea6c0_5e2773a1_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xd01522dc_c4f87991_14d9d761_96d8043a_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xe0188393_40d4f241_e016a611_a4415d72_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xf01c2465_c5e61b6f_661e135f_49a47c40_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x801002ab_2ac4499a_be6bf0fa_435e8383_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x88121333_7898871e_9a31ba0c_bc030353_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x901443cc_cd362c9f_54b57dfe_0c4c840f_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x98169478_296fad41_7ad1e9c3_15328f7e_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xa0190536_8e2389b3_1f3f686c_f3d6be22_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xa81b9608_fc3c50ec_f105b66e_c4703ede_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xb01e46f0_74b0a0f3_610848c6_8df4d233_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xb7a0e9ed_7613acb0_2e0efddf_33a20464_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xbfa3d900_8e042ffb_c2cdb3c7_50f127b4_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xc7a6e82b_a36a7073_bd953378_6d3f4c49_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xcfaa176f_b76c8eb1_82e237c9_a4d450e3_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xd7ad66cd_cb3cbe14_c00b46a4_d0e3dfd0_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xdfb0d646_e0194584_ea999c0d_f8546710_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xe7b465db_f74c8032_cec6c2a9_ad974f4f_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xefb8158e_122cde5a_2d2045da_1570a07c_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xf7bbe55e_321ce603_6752e9b2_381e3edc_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xffbfd54d_588b33c5_3c1ed527_28e00e40_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x83e1f2ae_43793dc3_493b0d87_3fb9a340_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x87e40ac6_5f6cc4a0_29e38750_c9d26893_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x8be632ef_80e9a0df_aab9e832_7258ac3f_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x8fe86b2a_28bf51b3_28bc403d_8a5f3c63_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x93eab376_d7c36377_f720c1c9_7227fcdc_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x97ed0bd6_0ed17018_6ad9a3e3_d11b66c1_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x9bef7448_4ecb1f6c_edb27b79_c90b4019_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x9fb1c4cd_27012e19_a092a0d7_ab21722a_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xa3b44c65_b71c2d85_535d52f0_939a4d02_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xa7b6e412_cadcb3dc_90a57e11_edc1864e_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xabb98bd4_e33c4381_68e9c901_60031159_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xafbc43ac_813a6ea3_bf60594f_929adeb8_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xb3bf0b9a_25dcd7a2_8a421588_86775205_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xb7c1e39e_522f316d_1ab45417_663dee9e_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xbbc4cbb9_87433fe4_6c51ae3c_e1aea68a_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xbfc7c3ec_4630d83c_7c52ae8b_40ebabb7_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xc3cacc37_1015e15d_a857126f_7cfaaa67_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xc7cde49a_66165446_14d05662_cd29464a_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xcb90da16_44d29bb7_8379db06_ef3cd6bb_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xcf9411aa_99ddb7de_9025f4c6_7dd38bb6_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xd3975958_f681086d_d6f8a61c_892032ee_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xd79ab121_dbf8714c_9a2f20b4_e2332d47_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xdb9e1905_cb85ea59_3c767d61_f51d375b_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xdfa19105_46717fca_d4b2bd65_bb25493c_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xe3a51920_ce095292_c96c1254_a30ef91f_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xe7a8b158_e3a198be_73e324ce_0946b214_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xebac59ae_08949dd8_cacd125a_12bac62c_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xef6fd620_b2b7a503_cafdc272_27b71eaa_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xf3739daf_959aaafc_688d4282_f6026aa3_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xf777755d_03f4e0b6_e54e9e38_04464cdd_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xfb7b5d29_7f388a12_cb78b383_f4b59dce_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xff7f5515_88de024f_ee055fc5_15062c04_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x81c1ae90_d131de38_207812b4_3382acdd_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x83c3baa7_26a721cc_dc90c4c4_b61f3a87_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x85c5cece_05941dbc_1a03f13f_b2c978b1_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x87c7eb05_aec1304f_b36f282e_83a7dc36_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x89a9eccd_56a980c0_d82a4661_6d4c393f_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x8bac18a6_40185360_bc6ff847_13c9babd_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x8dae4c90_b22574f4_9f7942a5_16fc2d8a_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x8fb0888c_eda546ab_15e50cfd_9b29b427_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x91b2cc9b_336f3718_9f465296_ae7dd49a_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x93b518bb_c45dc268_b49c1eb9_b348e6e4_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x95b76cee_e14e728e_daa320cd_64c9d9c7_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9799a333_de49b963_75a91950_ffe1e3b5_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x999c070b_a32068cd_5c6abcbf_43f03f14_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9b9e72f6_b295ad4f_5a9e7f26_5d1ed157_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9da0e6f5_4d9318fd_efeb98d0_2a195c17_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9fa36307_b5054ca8_2aa503a3_110ab5a7_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa1a5e72e_29dbf808_d0fe7e05_869eb825_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa3884a68_a750cb10_e80a28f4_e1e500d2_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa58ade36_aeef9f0b_53106415_1ca6e30b_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa78d7a19_82c4b08f_27c01ffa_8e2e3c4b_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa9901e11_63cbbbf5_7ba9408d_c857d568_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xab92ca1e_93038d76_104d1e33_31d3b4fa_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xad957e41_516e0158_9343c846_fcdf9137_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xaf780e79_b2514889_3977e89a_ec59bfa2_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb17ad246_ef3713bc_913d4e3d_c55c3e6e_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb37d9e2a_7a56b09d_777b52a9_e70d8bcc_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb5807224_94be0c91_55de916f_d30591de_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb7834e35_7f7e2600_e79cfb37_be2861e4_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb986325d_7bab0c89_90983104_d3805389_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbb68ef9c_254aa378_59e3b2ec_71ce64f4_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbd6be371_8c77636f_e83183bf_3dd612ef_u128}, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbf6edf5e_c44d9d35_c4e3b0ac_2fd52b7f_u128}, ]; // -log(r) for the third step, generated by SageMath with: // // for i in range(-69, 70): // r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("{sign: DyadicDyadicSign::Pos," if (s == -1) else "{sign: DyadicDyadicSign::Neg, exponent: ", e, ", mantissa:" // format_hex(m), "},"); #[rustfmt::skip] pub(crate) static LOGP1_R3: [DyadicFloat128; 139] =[ DyadicFloat128 {sign: DyadicSign::Neg, exponent: -142, mantissa: 0x89ff6b38_d5de2622_e39d3faf_42340ed7_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -142, mantissa: 0x87ff6f80_ccb40f16_7ff33266_82c02485_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -142, mantissa: 0x85ff73b8_c3cdf731_5caf4fbe_343cf928_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -142, mantissa: 0x83ff77e0_bb2ade79_cdb6e554_348f7fe8_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -142, mantissa: 0x81ff7bf8_b2c9c4f6_0ef009c2_457de25d_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xffff0001_55535558_8883333c_57b57c74_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xfbff07f1_45931f44_f32668f3_9c70d183_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xf7ff0fc1_3650e7bd_459a73c6_a6486fe3_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xf3ff1771_278aaecd_37b18cca_7dd3a29f_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xefff1f01_193e7480_513f610d_21bcfc78_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xebff2671_0b6a38e1_ea190b95_c0690b7b_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xe7ff2dc0_fe0bfbfd_2a150f64_f0ad1743_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xe3ff34f0_f121bddd_090b5174_e995e9d1_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xdfff3c00_e4a97e8c_4ed512b9_b93ea2bf_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xdbff42f0_d8a13e15_934cea21_7ab794a2_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xd7ff49c0_cd06fc83_3e4ebe94_8afd2c76_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xd3ff5070_c1d8b9df_87b7c0f5_bcfee2e1_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xcfff5700_b7147634_77666622_8cb6371b_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xcbff5d70_acb8318b_e53a60f3_514db358_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xc7ff63c0_a2c1ebef_79149c3b_6e57fa86_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xc3ff69f0_992fa568_aad734c9_8416df2a_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xbfff7000_8fff5e00_c2657367_9ed28334_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xbbff75f0_872f15c0_d7a3c6db_6540809f_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xb7ff7bc0_7ebcccb1_d277bde6_45fb1aad_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xb3ff8170_76a682dc_6ac80145_a4087793_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xafff8700_6eea3849_287c4db3_0271e265_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xabff8c70_6785ed00_637d6de4_2eeb151e_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xa7ff91c0_6077a10a_43b5348b_6b898a8c_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0xa3ff96f0_59bd546e_c10e7657_978bd7f6_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x9fff9c00_53550735_a37503f4_57310e59_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x9bffa0f0_4d3cb966_82d5a40a_3aa022ff_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x97ffa5c0_47726b08_c71e0d3e_e3df5f4d_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x93ffaa70_41f41c23_a83ce035_2bdbd79b_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x8fffaf00_3cbfccbe_2e21a18d_4680e8e4_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x8bffb370_37d37cdf_30bcb3e4_e5dfbd28_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x87ffb7c0_332d2c8d_57ff51d7_5c66d64a_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -143, mantissa: 0x83ffbbf0_2ecadbcf_1bdb87fd_be299f43_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xffff8000_55551555_88885dde_02700703_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xf7ff87e0_4d94724c_d259ca80_3a0c1870_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xefff8f80_464fce8f_e5141308_51c7070a_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xe7ff96e0_3f832a2a_30a16898_f3073a64_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xdfff9e00_392a8526_c4ed6451_7b2949ce_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xd7ffa4e0_3341df90_51e4fb4e_32cf6350_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xcfffab80_2dc53971_277672a8_8350bcce_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xc7ffb1e0_28b092d3_35915377_2a490f06_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xbfffb800_23ffebc0_0c265ece_6b481a0e_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xb7ffbde0_1faf4440_db2781c0_3fa132f6_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xafffc380_1bba9c5e_7287c95c_845ada33_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0xa7ffc8e0_181df421_423b56b1_263e5a77_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0x9fffce00_14d54b91_5a3752ca_4c076fa3_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0x97ffd2e0_11dca2b6_6a71e2b2_7eb3f573_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0x8fffd780_0f2ff997_c2e21b72_cff39d8f_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -144, mantissa: 0x87ffdbe0_0ccb503c_537ff612_feb7ac9e_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0xffffc000_15554d55_58888733_33c57c18_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0xefffc7c0_1193f9d1_fa514218_42311c42_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0xdfffcf00_0e4aa5fa_2c4ed6de_475b942c_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0xcfffd5c0_0b7151d8_ce77678c_bb6fcb88_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0xbfffdc00_08fffd78_00c26629_a679ed3b_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0xafffe1c0_06eea8e1_23287cb9_d3072728_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0x9fffe700_0535541c_d5a37540_fd057315_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -145, mantissa: 0x8fffebc0_03cbff32_f82e21c1_fce36810_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -146, mantissa: 0xffffe000_05555455_5588887d_dde02702_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -146, mantissa: 0xdfffe780_0392aa14_9ac4ed72_adf5b295_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -146, mantissa: 0xbfffee00_023fffaf_000c2664_8066b482_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -146, mantissa: 0x9ffff380_014d552e_455a3754_b292c077_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -147, mantissa: 0xfffff000_01555535_55588888_33333c58_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -147, mantissa: 0xbffff700_008ffff5_e000c266_5736679f_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -148, mantissa: 0xfffff800_00555551_55558888_85ddde02_u128}, DyadicFloat128 {sign: DyadicSign::Neg, exponent: -149, mantissa: 0xfffffc00_00155554_d5555888_88733334_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: 0, mantissa: 0_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -148, mantissa: 0x80000200_000aaaaa_eaaaac44_444eeeef_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -147, mantissa: 0x80000400_002aaaac_aaaac444_459999ac_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -147, mantissa: 0xc0000900_0090000a_2000c266_7596679f_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -146, mantissa: 0x80000800_00aaaaba_aaac4444_6eeef381_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -146, mantissa: 0xa0000c80_014d557c_655a3755_f81815cc_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -146, mantissa: 0xc0001200_02400051_000c2668_4c66b482_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -146, mantissa: 0xe0001880_0392ab40_bac4ed7c_40fb07eb_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0x80001000_02aaab2a_aac44449_999abe2c_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0x90001440_03cc00cd_082e21d7_9cbb6812_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0xa0001900_0535568d_d5a37569_adb01dc3_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0xb0001e40_06eeac74_33287d01_e8c9d1d9_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0xc0002400_09000288_00c266a3_2679ed48_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0xd0002a40_0b7158d1_de776851_22b2764b_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0xe0003100_0e4aaf5b_2c4ed810_a8063f03_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -145, mantissa: 0xf0003840_1194062e_0a5143e7_be891c8f_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0x80002000_0aaaaeaa_ac4444ee_ef3813a1_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0x88002420_0ccb5a6e_5b7ff7fe_1339025b_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0x90002880_0f300668_42e21e26_caf39e33_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0x98002d20_11dcb29e_f271e66f_a5554bc6_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xa0003200_14d55f19_5a3757e0_615cc676_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xa8003720_181e0bde_ca3b5d82_10ca5cab_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xb0003c80_1bbab8f6_f287d25f_3cb032bb_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xb8004220_1faf6669_e3278d84_0be28cdb_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xc0004800_24001440_0c266dfe_6b482076_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xc8004e20_28b0c282_3d9166de_380a6d3d_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xd0005480_2dc57139_a7768b35_6ba61e4b_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xd8005b20_3342206f_d9e51a18_49db73c1_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xe0006200_392ad02e_c4ed8a9d_907eb521_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xe8006920_3f838080_b8a197de_a928acd7_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xf0007080_46503170_65144cf7_dcc72d3b_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -144, mantissa: 0xf8007820_4d94e308_da5a1108_890d9f6a_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x80004000_2aaacaaa_c4445999_abe2ce2c_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x84004410_2ecb2431_1fdbbb4f_3bffc832_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x88004840_332d7e1d_97ff8f39_ec91b4ee_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x8c004c90_37d3d876_74bcfcf0_b3f0a95d_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x90005100_3cc03342_2e21f80c_a6813aff_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x94005590_41f48e87_6c3d4629_170ce87f_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x98005a40_4772ea4d_071e84e3_b80a8881_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0x9c005f10_4d3d469a_06d62fdc_bdd6bec3_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xa0006400_5355a375_a375a6b7_01dc77c0_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xa4006910_59be00e7_450f3318_26ad6b05_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xa8006e40_60785ef6_83b60ea8_bd0aa459_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xac007390_6786bdab_277e6914_69dd13f5_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xb0007900_6eeb1d0d_287d6e0a_0d1e25eb_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xb4007e90_76a77d24_aec94b3b_e9b060f5_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xb8008440_7ebdddfa_1279365f_ce280cce_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xbc008a10_87303f95_dba5732f_3e83e04a_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc0009000_9000a200_c2675967_9ed5b754_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc4009610_99310543_aed95aca_5edb5109_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc8009c40_a2c36967_b917091d_2687160f_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xcc00a290_acb9ce76_293d1c2a_0378e75d_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd000a900_b7163478_776977bf_9766f5a7_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd400af90_c1da9b78_4bbb31b1_4776a18b_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd800b640_cd09037f_7e5297d7_6c8564ba_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xdc00bd10_d8a36c98_1751360f_8461c447_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xe000c400_e4abd6cc_4ed9dc3c_63f44c41_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xe400cb10_f1244226_8d10a446_6a5894d5_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xe800d240_fe0eaeb1_6a1af81b_b4e6510e_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xec00d991_0b6d1c77_ae1f97b0_542a677a_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xf000e101_19418b84_51469efe_81d014cc_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xf400e891_278dfbe2_7bb98c06_d77a18b4_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xf800f041_36546d9d_85a344d0_868bed17_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -143, mantissa: 0xfc00f811_4596e0c0_f7301d69_90e307cc_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -142, mantissa: 0x80008000_aaabaaac_4446eef3_8140138f_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -142, mantissa: 0x82008408_b2cbe5b8_10f5e432_96105497_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -142, mantissa: 0x84008820_bb2d2189_edbd4f83_ef63f730_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -142, mantissa: 0x86008c48_c3d05e27_feb654fd_541c638e_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -142, mantissa: 0x88009080_ccb69b98_7ffadeb8_882f7674_u128}, DyadicFloat128 {sign: DyadicSign::Pos, exponent: -142, mantissa: 0x8a0094c8_d5e0d9e1_c5a59fd3_6bd44397_u128}, ]; pxfm-0.1.23/src/logs/log1pf.rs000064400000000000000000000146321046102023000141600ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::logs::{LOG_R_DD, LOG_RANGE_REDUCTION}; use crate::polyeval::{f_estrin_polyeval8, f_polyeval6}; #[cold] pub(crate) fn special_logf(x: f32) -> f32 { let t = x.to_bits(); if t == 0xbf800000u32 { // +0.0 return f32::NEG_INFINITY; } if t == 0x7f800000u32 { return x; } // +inf let ax: u32 = t.wrapping_shl(1); if ax > 0xff000000u32 { return x + x; } // nan f32::NAN } #[inline] pub(crate) fn core_logf(x: f64) -> f64 { let x_u = x.to_bits(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut x_e: i32 = -(E_BIAS as i32); // log2(x) = log2(2^x_e * x_m) // = x_e + log2(x_m) // Range reduction for log2(x_m): // For each x_m, we would like to find r such that: // -2^-8 <= r * x_m - 1 < 2^-7 let shifted = (x_u >> 45) as i32; let index = shifted & 0x7F; let r = f64::from_bits(LOG_RANGE_REDUCTION[index as usize]); // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are // all 1's. x_e = x_e.wrapping_add(x_u.wrapping_add(1u64 << 45).wrapping_shr(52) as i32); let e_x = x_e as f64; const LOG_2_HI: f64 = f64::from_bits(0x3fe62e42fefa3800); const LOG_2_LO: f64 = f64::from_bits(0x3d2ef35793c76730); let log_r_dd = LOG_R_DD[index as usize]; // hi is exact let hi = f_fmla(e_x, LOG_2_HI, f64::from_bits(log_r_dd.1)); let lo = f_fmla(e_x, LOG_2_LO, f64::from_bits(log_r_dd.0)); // Set m = 1.mantissa. let x_m = (x_u & 0x000F_FFFF_FFFF_FFFFu64) | 0x3FF0_0000_0000_0000u64; let m = f64::from_bits(x_m); let u; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { u = f_fmla(r, m, -1.0); // exact } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::LOG_CD; let c_m = x_m & 0x3FFF_E000_0000_0000u64; let c = f64::from_bits(c_m); u = f_fmla(r, m - c, f64::from_bits(LOG_CD[index as usize])); // exact } let r1 = hi; // Polynomial for log(1+x)/x generated in Sollya: // d = [-2^-8, 2^-7]; // f_log = log(1 + x)/x; // Q = fpminimax(f_log, 5, [|D...|], d); // See ./notes/log1pf_core.sollya let p = f_polyeval6( u, f64::from_bits(0x3fefffffffffffff), f64::from_bits(0xbfdffffffffff3e6), f64::from_bits(0x3fd5555555626b74), f64::from_bits(0xbfd0000026aeecc8), f64::from_bits(0x3fc9999114d16c06), f64::from_bits(0xbfc51e433a85278a), ); f_fmla(p, u, r1) + lo } /// Computes log(x+1) /// /// Max ULP 0.5 #[inline] pub fn f_log1pf(x: f32) -> f32 { let ax = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; if !x.is_normal() { if x.is_nan() { return x + x; } if x.is_infinite() { return if x.is_sign_positive() { f32::INFINITY } else { f32::NAN }; } if x == 0. { return x; } } // Use log1p(x) = log(1 + x) for |x| > 2^-6; if ax > 0x3c80_0000u32 { if x == -1. { return f32::NEG_INFINITY; } let x1p = xd + 1.; if x1p <= 0. { if x1p == 0. { return f32::NEG_INFINITY; } return f32::NAN; } return core_logf(x1p) as f32; } // log(1+x) is expected to be used near zero // Polynomial generated by Sollya: // d = [-2^-6; 2^-6]; // f_log1pf = log(1+x)/x; // Q = fpminimax(f_log1pf, 7, [|0, D...|], d); // See ./notes/log1pf.sollya let p = f_estrin_polyeval8( xd, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfe0000000000000), f64::from_bits(0x3fd5555555556aad), f64::from_bits(0xbfd000000000181a), f64::from_bits(0x3fc999998998124e), f64::from_bits(0xbfc55555452e2a2b), f64::from_bits(0x3fc24adb8cde4aa7), f64::from_bits(0xbfc0019db915ef6f), ) * xd; p as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn log1pf_works() { assert!(f_log1pf(f32::from_bits(0xffefb9a7)).is_nan()); assert!(f_log1pf(f32::NAN).is_nan()); assert_eq!(f_log1pf(f32::from_bits(0x41078feb)), 2.2484074); assert_eq!(f_log1pf(-0.0000014305108), -0.0000014305118); assert_eq!(f_log1pf(0.0), 0.0); assert_eq!(f_log1pf(2.0), 1.0986123); assert_eq!(f_log1pf(-0.7), -1.2039728); assert_eq!(f_log1pf(-0.0000000000043243), -4.3243e-12); } } pxfm-0.1.23/src/logs/log1pmx.rs000064400000000000000000000317621046102023000143620ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{EXP_MASK, get_exponent_f64}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::logs::log1p::{LOG_R1_DD, R1}; use crate::logs::log1p_dd; use crate::polyeval::{f_estrin_polyeval8, f_polyeval4, f_polyeval5}; #[cold] fn tiny_hard(x: f64) -> f64 { // d = [-2^-10; 2^-10]; // f_log1pf = (log(1+x) - x)/x^2; // Q = fpminimax(f_log1pf, 7, [|0, 107...|], d); // See ./notes/log1pmx_at_zero_hard.sollya let x2 = DoubleDouble::from_exact_mult(x, x); const C: [(u64, u64); 7] = [ (0x3c755555555129de, 0x3fd5555555555555), (0xbbd333352fe28400, 0xbfd0000000000000), (0xbc698cb3ef1ea2dd, 0x3fc999999999999a), (0x3c4269700b3f95d0, 0xbfc55555555546ef), (0x3c61290e9261823e, 0x3fc2492492491565), (0x3c6fb0a243c2a59c, 0xbfc000018af8cb7e), (0x3c3b271ceb5c60a0, 0x3fbc71ca10b30518), ]; let mut r = DoubleDouble::mul_f64_add( DoubleDouble::from_bit_pair(C[6]), x, DoubleDouble::from_bit_pair(C[5]), ); r = DoubleDouble::mul_f64_add(r, x, DoubleDouble::from_bit_pair(C[4])); r = DoubleDouble::mul_f64_add(r, x, DoubleDouble::from_bit_pair(C[3])); r = DoubleDouble::mul_f64_add(r, x, DoubleDouble::from_bit_pair(C[2])); r = DoubleDouble::mul_f64_add(r, x, DoubleDouble::from_bit_pair(C[1])); r = DoubleDouble::mul_f64_add(r, x, DoubleDouble::from_bit_pair(C[0])); r = DoubleDouble::mul_f64_add_f64(r, x, f64::from_bits(0xbfe0000000000000)); r = DoubleDouble::quick_mult(r, x2); r.to_f64() } fn log1pmx_big(x: f64) -> f64 { let mut x_u = x.to_bits(); let mut x_dd = DoubleDouble::default(); let x_exp: u16 = ((x_u >> 52) & 0x7ff) as u16; const EXP_BIAS: u16 = (1u16 << (11 - 1u16)) - 1u16; if x_exp >= EXP_BIAS { // |x| >= 1 if x_u >= 0x4650_0000_0000_0000u64 { x_dd.hi = x; } else { x_dd = DoubleDouble::from_exact_add(x, 1.0); } } else { // |x| < 1 x_dd = DoubleDouble::from_exact_add(1.0, x); } // At this point, x_dd is the exact sum of 1 + x: // x_dd.hi + x_dd.lo = x + 1.0 exactly. // |x_dd.hi| >= 2^-54 // |x_dd.lo| < ulp(x_dd.hi) let xhi_bits = x_dd.hi.to_bits(); let xhi_frac = xhi_bits & ((1u64 << 52) - 1); x_u = xhi_bits; // Range reduction: // Find k such that |x_hi - k * 2^-7| <= 2^-8. let idx: i32 = ((xhi_frac.wrapping_add(1u64 << (52 - 8))) >> (52 - 7)) as i32; let x_e = (get_exponent_f64(f64::from_bits(xhi_bits)) as i32).wrapping_add(idx >> 7); let e_x = x_e as f64; const LOG_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3d2ef35793c76730), f64::from_bits(0x3fe62e42fefa3800), ); // hi is exact // ulp(hi) = ulp(LOG_2_HI) = ulp(LOG_R1_DD[idx].hi) = 2^-43 let r_dd = LOG_R1_DD[idx as usize]; let hi = f_fmla(e_x, LOG_2.hi, f64::from_bits(r_dd.1)); // lo errors < |e_x| * ulp(LOG_2_LO) + ulp(LOG_R1[idx].lo) // <= 2^11 * 2^(-43-53) = 2^-85 let lo = f_fmla(e_x, LOG_2.lo, f64::from_bits(r_dd.0)); // Scale x_dd by 2^(-xh_bits.get_exponent()). let s_u: i64 = (x_u & EXP_MASK) as i64 - (EXP_BIAS as i64).wrapping_shl(52); // Normalize arguments: // 1 <= m_dd.hi < 2 // |m_dd.lo| < 2^-52. // This is exact. let m_hi = 1f64.to_bits() | xhi_frac; let m_lo = if x_dd.lo.abs() > x_dd.hi * f64::from_bits(0x3800000000000000) { (x_dd.lo.to_bits() as i64).wrapping_sub(s_u) } else { 0 }; let m_dd = DoubleDouble::new(f64::from_bits(m_lo as u64), f64::from_bits(m_hi)); // Perform range reduction: // r * m - 1 = r * (m_dd.hi + m_dd.lo) - 1 // = (r * m_dd.hi - 1) + r * m_dd.lo // = v_hi + (v_lo.hi + v_lo.lo) // where: // v_hi = r * m_dd.hi - 1 (exact) // v_lo.hi + v_lo.lo = r * m_dd.lo (exact) // Bounds on the values: // -0x1.69000000000edp-8 < r * m - 1 < 0x1.7f00000000081p-8 // |v_lo.hi| <= |r| * |m_dd.lo| < 2^-52 // |v_lo.lo| < ulp(v_lo.hi) <= 2^(-52 - 53) = 2^(-105) let r = R1[idx as usize]; let v_hi; let v_lo = DoubleDouble::from_exact_mult(m_dd.lo, f64::from_bits(r)); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v_hi = f_fmla(f64::from_bits(r), m_dd.hi, -1.0); // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log1p::RCM1; let c = f64::from_bits( (idx as u64) .wrapping_shl(52 - 7) .wrapping_add(0x3FF0_0000_0000_0000u64), ); v_hi = f_fmla( f64::from_bits(r), m_dd.hi - c, f64::from_bits(RCM1[idx as usize]), ); // Exact } // Range reduction output: // -0x1.69000000000edp-8 < v_hi + v_lo < 0x1.7f00000000081p-8 // |v_dd.lo| < ulp(v_dd.hi) <= 2^(-7 - 53) = 2^-60 let mut v_dd = DoubleDouble::from_exact_add(v_hi, v_lo.hi); v_dd.lo += v_lo.lo; // Exact sum: // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u let mut r1 = DoubleDouble::from_exact_add(hi, v_dd.hi); // Degree-7 minimax polynomial log(1 + v) ~ v - v^2 / 2 + ... // generated by Sollya with: // > P = fpminimax(log(1 + x)/x, 6, [|1, 1, D...|], // [-0x1.69000000000edp-8, 0x1.7f00000000081p-8]); const P_COEFFS: [u64; 6] = [ 0xbfe0000000000000, 0x3fd5555555555166, 0xbfcfffffffdb7746, 0x3fc99999a8718a60, 0xbfc555874ce8ce22, 0x3fc24335555ddbe5, ]; // C * ulp(v_sq) + err_hi let v_sq = v_dd.hi * v_dd.hi; let p0 = f_fmla( v_dd.hi, f64::from_bits(P_COEFFS[1]), f64::from_bits(P_COEFFS[0]), ); let p1 = f_fmla( v_dd.hi, f64::from_bits(P_COEFFS[3]), f64::from_bits(P_COEFFS[2]), ); let p2 = f_fmla( v_dd.hi, f64::from_bits(P_COEFFS[5]), f64::from_bits(P_COEFFS[4]), ); let p = f_polyeval4(v_sq, (v_dd.lo + r1.lo) + lo, p0, p1, p2); const ERR_HI: [f64; 2] = [f64::from_bits(0x3aa0000000000000), 0.0]; let err_hi = ERR_HI[if hi == 0.0 { 1 } else { 0 }]; let err = f_fmla(v_sq, f64::from_bits(0x3ce0000000000000), err_hi); r1.lo = p; r1 = DoubleDouble::from_exact_add(r1.hi, r1.lo); r1 = DoubleDouble::full_add_f64(r1, -x); let left = r1.hi + (r1.lo - err); let right = r1.hi + (r1.lo + err); // Ziv's test to see if fast pass is accurate enough. if left == right { return left; } log1pmx_accurate_dd(x) } #[cold] fn log1pmx_accurate_dd(x: f64) -> f64 { let r = log1p_dd(x); DoubleDouble::full_add_f64(r, -x).to_f64() } /// Computes log(1+x) - x /// /// ulp 0.5 pub fn f_log1pmx(x: f64) -> f64 { let ax = x.to_bits() & 0x7fff_ffff_ffff_ffffu64; let x_e = (x.to_bits() >> 52) & 0x7ff; if !x.is_normal() { if x.is_nan() { return x + x; } if x.is_infinite() { return f64::NAN; } if x == 0. { return x; } } if ax > 0x3f90000000000000u64 { // |x| > 2^-6 if x <= -1. { if x == -1. { return f64::NEG_INFINITY; } return f64::NAN; } return log1pmx_big(x); } const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; // log(1+x) is expected to be used near zero if x_e < E_BIAS - 10 { if x_e < E_BIAS - 100 { // |x| < 2^-100 // taylor series log(1+x) - x ~ -x^2/2 + x^3/3 let x2 = x * x; let dx2 = f_fmla(x, x, -x2); let rl = dx2 * -0.5; return f_fmla(x2, -0.5, rl); } // Polynomial generated by Sollya in form log(1+x) - x = x^2 * R(x): // d = [-2^-10; 2^-10]; // f_log1pf = (log(1+x) - x)/x^2; // Q = fpminimax(f_log1pf, 7, [|0, 107, 107, D...|], d); // See ./notes/log1pmx_at_zero.sollya let p = f_polyeval5( x, f64::from_bits(0x3fc999999999999a), f64::from_bits(0xbfc55555555546ef), f64::from_bits(0x3fc24924923d3abf), f64::from_bits(0xbfc000018af7f637), f64::from_bits(0x3fbc72984db24b6a), ); let x2 = DoubleDouble::from_exact_mult(x, x); let mut r = DoubleDouble::f64_mul_f64_add( x, p, DoubleDouble::from_bit_pair((0xbbd3330899095800, 0xbfd0000000000000)), ); r = DoubleDouble::mul_f64_add( r, x, DoubleDouble::from_bit_pair((0x3c75555538509407, 0x3fd5555555555555)), ); r = DoubleDouble::mul_f64_add_f64(r, x, f64::from_bits(0xbfe0000000000000)); r = DoubleDouble::quick_mult(r, x2); const ERR: f64 = f64::from_bits(0x3af0000000000000); // 2^-80 let ub = r.hi + (r.lo + ERR); let lb = r.hi + (r.lo - ERR); if lb == ub { return r.to_f64(); } return tiny_hard(x); } // Polynomial generated by Sollya in form log(1+x) - x = x^2 * R(x): // d = [-2^-6; 2^-6]; // f_log1pf = (log(1+x) - x)/x^2; // Q = fpminimax(f_log1pf, 10, [|0, 107, 107, D...|], d); // See ./notes/log1pmx.sollya let p = f_estrin_polyeval8( x, f64::from_bits(0x3fc9999999999997), f64::from_bits(0xbfc5555555555552), f64::from_bits(0x3fc249249249fb64), f64::from_bits(0xbfc000000000f450), f64::from_bits(0x3fbc71c6e2591149), f64::from_bits(0xbfb999995cf14d86), f64::from_bits(0x3fb7494eb6c2c544), f64::from_bits(0xbfb558bf05690e85), ); let x2 = DoubleDouble::from_exact_mult(x, x); let mut r = DoubleDouble::f64_mul_f64_add( x, p, DoubleDouble::from_bit_pair((0xbb9d89dc15a38000, 0xbfd0000000000000)), ); r = DoubleDouble::mul_f64_add( r, x, DoubleDouble::from_bit_pair((0x3c7555a15a94e505, 0x3fd5555555555555)), ); r = DoubleDouble::mul_f64_add_f64(r, x, f64::from_bits(0xbfe0000000000000)); r = DoubleDouble::quick_mult(r, x2); r.to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_log1pmx() { assert_eq!( f_log1pmx(0.00000000000000005076835735015165), -0.0000000000000000000000000000000012887130540163486 ); assert_eq!(f_log1pmx(5.), -3.208240530771945); assert_eq!(f_log1pmx(-0.99), -3.6151701859880907); assert_eq!(f_log1pmx(-1.), f64::NEG_INFINITY); assert_eq!( f_log1pmx(1.0000000000008708e-13), -0.0000000000000000000000000050000000000083744 ); assert_eq!( f_log1pmx(1.0000000000008708e-26), -0.00000000000000000000000000000000000000000000000000005000000000008707 ); assert_eq!(f_log1pmx(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012890176556069385), -0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830783258233204); } } pxfm-0.1.23/src/logs/log1pmxf.rs000064400000000000000000000067321046102023000145270ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::polyeval::f_estrin_polyeval7; /// Computes log(1+x) - x /// /// ulp 0.5 pub fn f_log1pmxf(x: f32) -> f32 { let ax = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; if !x.is_normal() { if x.is_nan() { return x + x; } if x.is_infinite() { return f32::NAN; } if x == 0. { return x; } } // Use log1p(x) = log(1 + x) for |x| > 2^-6; if ax > 0x3c80_0000u32 { if x == -1. { return f32::NEG_INFINITY; } let x1p = xd + 1.; if x1p <= 0. { if x1p == 0. { return f32::NEG_INFINITY; } return f32::NAN; } return (crate::logs::log1pf::core_logf(x1p) - xd) as f32; } // log(1+x) is expected to be used near zero // Polynomial generated by Sollya in form log(1+x) - x = x^2 * R(x): // d = [-2^-6; 2^-6]; // f_log1pf = (log(1+x) - x)/x^2; // Q = fpminimax(f_log1pf, 6, [|0, D...|], d); // See ./notes/log1pmxf.sollya let xd_sqr = xd * xd; let p = f_estrin_polyeval7( xd, f64::from_bits(0xbfe0000000000000), f64::from_bits(0x3fd55555555561c8), f64::from_bits(0xbfd0000000000f5a), f64::from_bits(0x3fc999998d26deab), f64::from_bits(0xbfc555554878739c), f64::from_bits(0x3fc24ab2e3c10eca), f64::from_bits(0xbfc0017973fafec4), ) * xd_sqr; p as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_log1pmxfm() { assert_eq!(f_log1pmxf(-0.0000014305108), -1.0231815e-12); assert_eq!(f_log1pmxf(0.0), 0.0); assert_eq!(f_log1pmxf(2.0), -0.9013877); assert_eq!(f_log1pmxf(-0.7), -0.50397277); assert_eq!( f_log1pmxf(-0.0000000000043243), -0.000000000000000000000009349785 ); } } pxfm-0.1.23/src/logs/log2.rs000064400000000000000000000502421046102023000136300ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, min_normal_f64}; use crate::double_double::DoubleDouble; use crate::logs::log2dd::log2_dd; use crate::logs::log2td::log2_td; use crate::polyeval::f_polyeval6; pub(crate) static LOG_RANGE_REDUCTION: [u64; 128] = [ 0x3ff0000000000000, 0x3fefc00000000000, 0x3fef800000000000, 0x3fef400000000000, 0x3fef000000000000, 0x3feec00000000000, 0x3fee800000000000, 0x3fee400000000000, 0x3fee000000000000, 0x3fede00000000000, 0x3feda00000000000, 0x3fed600000000000, 0x3fed400000000000, 0x3fed000000000000, 0x3fecc00000000000, 0x3feca00000000000, 0x3fec600000000000, 0x3fec400000000000, 0x3fec000000000000, 0x3febe00000000000, 0x3feba00000000000, 0x3feb800000000000, 0x3feb400000000000, 0x3feb200000000000, 0x3feae00000000000, 0x3feac00000000000, 0x3fea800000000000, 0x3fea600000000000, 0x3fea400000000000, 0x3fea000000000000, 0x3fe9e00000000000, 0x3fe9c00000000000, 0x3fe9800000000000, 0x3fe9600000000000, 0x3fe9400000000000, 0x3fe9200000000000, 0x3fe9000000000000, 0x3fe8c00000000000, 0x3fe8a00000000000, 0x3fe8800000000000, 0x3fe8600000000000, 0x3fe8400000000000, 0x3fe8000000000000, 0x3fe7e00000000000, 0x3fe7c00000000000, 0x3fe7a00000000000, 0x3fe7800000000000, 0x3fe7600000000000, 0x3fe7400000000000, 0x3fe7200000000000, 0x3fe7000000000000, 0x3fe6e00000000000, 0x3fe6c00000000000, 0x3fe6a00000000000, 0x3fe6800000000000, 0x3fe6600000000000, 0x3fe6400000000000, 0x3fe6200000000000, 0x3fe6000000000000, 0x3fe5e00000000000, 0x3fe5c00000000000, 0x3fe5a00000000000, 0x3fe5800000000000, 0x3fe5600000000000, 0x3fe5400000000000, 0x3fe5400000000000, 0x3fe5200000000000, 0x3fe5000000000000, 0x3fe4e00000000000, 0x3fe4c00000000000, 0x3fe4a00000000000, 0x3fe4a00000000000, 0x3fe4800000000000, 0x3fe4600000000000, 0x3fe4400000000000, 0x3fe4200000000000, 0x3fe4000000000000, 0x3fe4000000000000, 0x3fe3e00000000000, 0x3fe3c00000000000, 0x3fe3a00000000000, 0x3fe3a00000000000, 0x3fe3800000000000, 0x3fe3600000000000, 0x3fe3400000000000, 0x3fe3400000000000, 0x3fe3200000000000, 0x3fe3000000000000, 0x3fe3000000000000, 0x3fe2e00000000000, 0x3fe2c00000000000, 0x3fe2c00000000000, 0x3fe2a00000000000, 0x3fe2800000000000, 0x3fe2800000000000, 0x3fe2600000000000, 0x3fe2400000000000, 0x3fe2400000000000, 0x3fe2200000000000, 0x3fe2000000000000, 0x3fe2000000000000, 0x3fe1e00000000000, 0x3fe1c00000000000, 0x3fe1c00000000000, 0x3fe1a00000000000, 0x3fe1a00000000000, 0x3fe1800000000000, 0x3fe1600000000000, 0x3fe1600000000000, 0x3fe1400000000000, 0x3fe1400000000000, 0x3fe1200000000000, 0x3fe1000000000000, 0x3fe1000000000000, 0x3fe0e00000000000, 0x3fe0e00000000000, 0x3fe0c00000000000, 0x3fe0c00000000000, 0x3fe0a00000000000, 0x3fe0a00000000000, 0x3fe0800000000000, 0x3fe0800000000000, 0x3fe0600000000000, 0x3fe0600000000000, 0x3fe0400000000000, 0x3fe0400000000000, 0x3fe0200000000000, 0x3fe0000000000000, ]; /** Generated by SageMath: ```python values = LOG_RANGE_REDUCTION R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] real_array = [R(hex_to_float(h)) for h in values] for r in real_array: print_double_double("", -RealField(180)(r).log2()) ``` **/ static LOG2_DD: [(u64, u64); 128] = [ (0x0, 0x0), (0x3c26d746128b1857, 0x3f872c7ba20f7327), (0x3c2b2a41b08fbe06, 0x3f9743ee861f3556), (0x3c3491f06c085bc2, 0x3fa184b8e4c56af8), (0x3c477970e03f821c, 0x3fa77394c9d958d5), (0x3c0155660710eb2a, 0x3fad6ebd1f1febfe), (0x3c298c5452bbce74, 0x3fb1bb32a600549d), (0x3c2c141e66faaaad, 0x3fb4c560fe68af88), (0x3c59ced1447e30ad, 0x3fb7d60496cfbb4c), (0xbc321ba488a62577, 0x3fb960caf9abb7ca), (0xbc17936311889913, 0x3fbc7b528b70f1c5), (0xbc36cd4d2ae3a2f6, 0x3fbf9c95dc1d1165), (0x3c55d243efd93259, 0x3fc097e38ce60649), (0xbc5696e2866c718e, 0x3fc22dadc2ab3497), (0xbc67a6ed4e1b0936, 0x3fc3c6fb650cde51), (0xbc61562d61af73f8, 0x3fc494f863b8df35), (0x3c354fae008fbb59, 0x3fc633a8bf437ce1), (0xbc60798d1aa21694, 0x3fc7046031c79f85), (0x3c699aa6df8b7d83, 0x3fc8a8980abfbd32), (0xbc6e95734abd2fcc, 0x3fc97c1cb13c7ec1), (0xbc6cc865b3dd0dbb, 0x3fcb2602497d5346), (0x3c2bc0af7b82e7d7, 0x3fcbfc67a7fff4cc), (0xbc0ba8b1f646ab12, 0x3fcdac22d3e441d3), (0xbc6086fce864a1f6, 0x3fce857d3d361368), (0x3c7768994400ca0a, 0x3fd01d9bbcfa61d4), (0xbc53d56efe4338fe, 0x3fd08bce0d95fa38), (0x3c7c8d43e017579b, 0x3fd169c05363f158), (0x3c6ae9804237ec8e, 0x3fd1d982c9d52708), (0x3c734107c0e54aed, 0x3fd249cd2b13cd6c), (0x3c7968925e378d68, 0x3fd32bfee370ee68), (0x3c7fcad2f4710e00, 0x3fd39de8e1559f6f), (0xbc7c658d602e66b0, 0x3fd4106017c3eca3), (0x3c7e393a16b94b52, 0x3fd4f6fbb2cec598), (0xbc78d86531d55da2, 0x3fd56b22e6b578e5), (0x3c710b5b643a6ecb, 0x3fd5dfdcf1eeae0e), (0x3c7ac9080333c605, 0x3fd6552b49986277), (0x3c2b6d40900b2502, 0x3fd6cb0f6865c8ea), (0x3c68f89e2eb553b2, 0x3fd7b89f02cf2aad), (0x3c651d58525aad39, 0x3fd8304d90c11fd3), (0x3c799aa6df8b7d83, 0x3fd8a8980abfbd32), (0x3c7fdc46af571993, 0x3fd921800924dd3b), (0x3c7bca36fd02def0, 0x3fd99b072a96c6b2), (0x3c5817fd3b7d7e5d, 0x3fda8ff971810a5e), (0xbc45e13b838eba7d, 0x3fdb0b67f4f46810), (0xbc501d98c3531027, 0x3fdb877c57b1b070), (0x3c7edf515c63dd87, 0x3fdc043859e2fdb3), (0x3c6c4aec56233279, 0x3fdc819dc2d45fe4), (0x3c78a38b4175d665, 0x3fdcffae611ad12b), (0xbc6e15a52a31604a, 0x3fdd7e6c0abc3579), (0x3c438c8946414c6a, 0x3fddfdd89d586e2b), (0x3c73bed456b24ed1, 0x3fde7df5fe538ab3), (0x3c76d261f1753e0b, 0x3fdefec61b011f85), (0xbc79ca1a3202b3d7, 0x3fdf804ae8d0cd02), (0xbc87398fe685f171, 0x3fe0014332be0033), (0xbc89c32630008a1f, 0x3fe042bd4b9a7c99), (0xbc7f47806a0e4105, 0x3fe08494c66b8ef0), (0xbc48a33c25e8e226, 0x3fe0c6caaf0c5597), (0xbc73aec658457c41, 0x3fe1096015dee4da), (0xbc8fc7d7c3320aab, 0x3fe14c560fe68af9), (0xbc892ba145dcf40b, 0x3fe18fadb6e2d3c2), (0xbc7f9fb952bbbccc, 0x3fe1d368296b5255), (0xbc8568859c64022e, 0x3fe217868b0c37e8), (0xbc84828ddf1fb145, 0x3fe25c0a0463beb0), (0xbc8c348e4aab18b8, 0x3fe2a0f3c340705c), (0xbc83af881af2f3d9, 0x3fe2e644fac04fd8), (0xbc83af881af2f3d9, 0x3fe2e644fac04fd8), (0x3c8968925e378d68, 0x3fe32bfee370ee68), (0xbc869656a0ad70d4, 0x3fe37222bb70747c), (0x3c76d266d6cdc959, 0x3fe3b8b1c68fa6ed), (0xbc69575b04fa6fbd, 0x3fe3ffad4e74f1d6), (0x3c5b90132aeddb58, 0x3fe44716a2c08262), (0x3c5b90132aeddb58, 0x3fe44716a2c08262), (0xbc75e35482d13dc1, 0x3fe48eef19317991), (0xbc8ca44f1db913d3, 0x3fe4d7380dcc422d), (0x3c7817fd3b7d7e5d, 0x3fe51ff2e30214bc), (0x3c804613e33c06c9, 0x3fe5692101d9b4a6), (0xbc8fc9257edfe9b6, 0x3fe5b2c3da19723b), (0xbc8fc9257edfe9b6, 0x3fe5b2c3da19723b), (0x3c8149a1977b5b99, 0x3fe5fcdce2727ddb), (0xbc8b32266d92c0fe, 0x3fe6476d98ad990a), (0x3c821d90b84e7218, 0x3fe6927781d932a8), (0x3c821d90b84e7218, 0x3fe6927781d932a8), (0x3c7f6e91ad16ecff, 0x3fe6ddfc2a78fc63), (0xbc74a31ce1b7e328, 0x3fe729fd26b707c8), (0x3c6a7b47d2c352d9, 0x3fe7767c12967a45), (0x3c6a7b47d2c352d9, 0x3fe7767c12967a45), (0x3c821f9cb2cc5575, 0x3fe7c37a9227e7fb), (0x3c8dc572667587b1, 0x3fe810fa51bf65fd), (0x3c8dc572667587b1, 0x3fe810fa51bf65fd), (0xbc78f93e7aa3bdf8, 0x3fe85efd062c656d), (0x3c5b85a54d7ee2fd, 0x3fe8ad846cf369a4), (0x3c5b85a54d7ee2fd, 0x3fe8ad846cf369a4), (0x3c8bf1d926766301, 0x3fe8fc924c89ac84), (0x3c401ee1343fe7ca, 0x3fe94c287492c4db), (0x3c401ee1343fe7ca, 0x3fe94c287492c4db), (0x3c7fa0a62e6add1b, 0x3fe99c48be2063c8), (0x3c8022ddb71189c5, 0x3fe9ecf50bf43f13), (0x3c8022ddb71189c5, 0x3fe9ecf50bf43f13), (0x3c7ac7fc60a51031, 0x3fea3e2f4ac43f60), (0x3c6817fd3b7d7e5d, 0x3fea8ff971810a5e), (0x3c6817fd3b7d7e5d, 0x3fea8ff971810a5e), (0xbc83138e941643f7, 0x3feae255819f022d), (0x3c8e0ae0d3f8a58b, 0x3feb35458761d479), (0x3c8e0ae0d3f8a58b, 0x3feb35458761d479), (0x3c742b7579f0f8d4, 0x3feb88cb9a2ab521), (0x3c742b7579f0f8d4, 0x3feb88cb9a2ab521), (0x3c6a7610e40bd6ab, 0x3febdce9dcc96187), (0xbc80e5edaecee150, 0x3fec31a27dd00b4a), (0xbc80e5edaecee150, 0x3fec31a27dd00b4a), (0xbc831d962d3728cc, 0x3fec86f7b7ea4a89), (0xbc831d962d3728cc, 0x3fec86f7b7ea4a89), (0xbc857391924a6d9d, 0x3fecdcebd2373995), (0x3c78333ac7d9ebbb, 0x3fed338120a6dd9d), (0x3c78333ac7d9ebbb, 0x3fed338120a6dd9d), (0xbc86c0268890da53, 0x3fed8aba045b01c8), (0xbc86c0268890da53, 0x3fed8aba045b01c8), (0xbc859e7ba5d5ccc9, 0x3fede298ec0bac0d), (0xbc859e7ba5d5ccc9, 0x3fede298ec0bac0d), (0x3c60b07079619c47, 0x3fee3b20546f554a), (0x3c60b07079619c47, 0x3fee3b20546f554a), (0xbc8cc4d81bc25adf, 0x3fee9452c8a71028), (0xbc8cc4d81bc25adf, 0x3fee9452c8a71028), (0xbc776c0a2827d49a, 0x3feeee32e2aeccbf), (0xbc776c0a2827d49a, 0x3feeee32e2aeccbf), (0xbc8314dc4fc42302, 0x3fef48c34bd1e96f), (0xbc8314dc4fc42302, 0x3fef48c34bd1e96f), (0xbc817f8e37b00179, 0x3fefa406bd2443df), (0x0, 0x0), ]; #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] pub(crate) static LOG_CD: [u64; 128] = [ 0x0000000000000000, 0xbf10000000000000, 0xbf30000000000000, 0xbf42000000000000, 0xbf50000000000000, 0xbf59000000000000, 0xbf62000000000000, 0xbf68800000000000, 0xbf70000000000000, 0xbf49000000000000, 0xbf5f000000000000, 0xbf69c00000000000, 0xbf30000000000000, 0xbf5c000000000000, 0xbf6b000000000000, 0xbf45000000000000, 0xbf64000000000000, 0x3f10000000000000, 0xbf60000000000000, 0x3f3a000000000000, 0xbf5e000000000000, 0x3f38000000000000, 0xbf61000000000000, 0xbf00000000000000, 0xbf66000000000000, 0xbf4a000000000000, 0xbf6e000000000000, 0xbf5f800000000000, 0xbf30000000000000, 0xbf6c000000000000, 0xbf5f000000000000, 0xbf3c000000000000, 0xbf70000000000000, 0xbf65400000000000, 0xbf56000000000000, 0xbf24000000000000, 0x3f50000000000000, 0xbf68800000000000, 0xbf60800000000000, 0xbf52000000000000, 0xbf30000000000000, 0x3f42000000000000, 0xbf70000000000000, 0xbf6ac00000000000, 0xbf66000000000000, 0xbf61c00000000000, 0xbf5c000000000000, 0xbf55800000000000, 0xbf50000000000000, 0xbf47000000000000, 0xbf40000000000000, 0xbf36000000000000, 0xbf30000000000000, 0xbf2c000000000000, 0xbf30000000000000, 0xbf36000000000000, 0xbf40000000000000, 0xbf47000000000000, 0xbf50000000000000, 0xbf55800000000000, 0xbf5c000000000000, 0xbf61c00000000000, 0xbf66000000000000, 0xbf6ac00000000000, 0xbf70000000000000, 0x3f55000000000000, 0x3f42000000000000, 0xbf30000000000000, 0xbf52000000000000, 0xbf60800000000000, 0xbf68800000000000, 0x3f60c00000000000, 0x3f50000000000000, 0xbf24000000000000, 0xbf56000000000000, 0xbf65400000000000, 0xbf70000000000000, 0x3f50000000000000, 0xbf3c000000000000, 0xbf5f000000000000, 0xbf6c000000000000, 0x3f56800000000000, 0xbf30000000000000, 0xbf5f800000000000, 0xbf6e000000000000, 0x3f51000000000000, 0xbf4a000000000000, 0xbf66000000000000, 0x3f60000000000000, 0xbf00000000000000, 0xbf61000000000000, 0x3f64800000000000, 0x3f38000000000000, 0xbf5e000000000000, 0x3f66000000000000, 0x3f3a000000000000, 0xbf60000000000000, 0x3f64800000000000, 0x3f10000000000000, 0xbf64000000000000, 0x3f60000000000000, 0xbf45000000000000, 0xbf6b000000000000, 0x3f51000000000000, 0xbf5c000000000000, 0x3f65400000000000, 0xbf30000000000000, 0xbf69c00000000000, 0x3f52000000000000, 0xbf5f000000000000, 0x3f63000000000000, 0xbf49000000000000, 0xbf70000000000000, 0x3f30000000000000, 0xbf68800000000000, 0x3f52800000000000, 0xbf62000000000000, 0x3f5f000000000000, 0xbf59000000000000, 0x3f64c00000000000, 0xbf50000000000000, 0x3f69000000000000, 0xbf42000000000000, 0x3f6c400000000000, 0xbf30000000000000, 0x3f6e800000000000, 0xbf10000000000000, 0xbf70000000000000, ]; pub(crate) const LOG_COEFFS: [u64; 6] = [ 0xbfdfffffffffffff, 0x3fd5555555554a9b, 0xbfd0000000094567, 0x3fc99999dcc9823c, 0xbfc55550ac2e537a, 0x3fc21a02c4e624d7, ]; /// Log2(x) /// /// Max found ULP 0.5 pub fn f_log2(x: f64) -> f64 { let mut x_u = x.to_bits(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut x_e: i64 = -(E_BIAS as i64); const MAX_NORMAL: u64 = f64::to_bits(f64::MAX); if x_u == 1f64.to_bits() { // log2(1.0) = +0.0 return 0.0; } if x_u < min_normal_f64().to_bits() || x_u > MAX_NORMAL { if x == 0.0 { return f64::NEG_INFINITY; } if x < 0. || x.is_nan() { return f64::NAN; } if x.is_infinite() || x.is_nan() { return x + x; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4330000000000000)).to_bits(); x_e -= 52; } // log2(x) = log2(2^x_e * x_m) // = x_e + log2(x_m) // Range reduction for log2(x_m): // For each x_m, we would like to find r such that: // -2^-8 <= r * x_m - 1 < 2^-7 let shifted = (x_u >> 45) as i64; let index = shifted & 0x7F; // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are // all 1's. x_e = x_e.wrapping_add(x_u.wrapping_add(1u64 << 45).wrapping_shr(52) as i64); let e_x = x_e as f64; // Set m = 1.mantissa. let x_m = (x_u & 0x000F_FFFF_FFFF_FFFFu64) | 0x3FF0_0000_0000_0000u64; let m = f64::from_bits(x_m); let u; let r = f64::from_bits(LOG_RANGE_REDUCTION[index as usize]); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { u = f_fmla(r, m, -1.0); // exact } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let c_m = x_m & 0x3FFF_E000_0000_0000u64; let c = f64::from_bits(c_m); u = f_fmla(r, m - c, f64::from_bits(LOG_CD[index as usize])); // exact } // Exact sum: let log_vals = DoubleDouble::from_bit_pair(LOG2_DD[index as usize]); /* Poly generated in Sollya; d = [-2^-8, 2^-7]; f = (log2(1 + x))/x; pf = fpminimax(f, 5, [|D...|], [-2^-8, 2^-7]); See ./notes/log2.sollya */ const C: [u64; 6] = [ 0x3ff71547652b82fe, 0xbfe71547652b7a07, 0x3fdec709dc458db1, 0xbfd715479c2266c9, 0x3fd2776ae1ddf8f0, 0xbfce7b2178870157, ]; // Degree-7 minimax polynomial let p = f_fmla( f_polyeval6( u, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), f64::from_bits(C[5]), ), u, log_vals.lo, ); // log2(x) = e + log2(r) + log2(index) let rr = DoubleDouble::from_full_exact_add(log_vals.hi, e_x); let r3 = DoubleDouble::add_f64(rr, p); let err = f_fmla( r3.hi, f64::from_bits(0x3bf0000000000000), // 2^-64 f64::from_bits(0x3c60000000000000), // 2^-57 ); // Lower bound from the result let left = r3.hi + (r3.lo - err); // Upper bound from the result let right = r3.hi + (r3.lo + err); // Ziv's test if fast pass is accurate enough. if left == right { return left; } log2_hard(x) } #[cold] #[inline(never)] fn log2_hard(x: f64) -> f64 { let r = log2_dd(x); let err = f_fmla( r.hi, f64::from_bits(0x3b50000000000000), // 2^-74 f64::from_bits(0x3990000000000000), // 2^-102 ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { return r.to_f64(); } log2_hard_slow(x) } #[cold] #[inline(never)] fn log2_hard_slow(x: f64) -> f64 { log2_td(x).to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_log2d() { assert_eq!(f_log2(0.7500000000000461), -0.4150374992787552); assert_eq!(f_log2(1.99999999779061), 0.999999998406262); assert_eq!(f_log2(0.7812499981882864), -0.35614381357087554); assert_eq!(f_log2(0.5937499997089616), -0.7520724872635803); assert_eq!(f_log2(0.9983015060407214), -0.0024524921736992287); assert_eq!(f_log2(0.2284926469437778), -2.129780355811612); assert_eq!(f_log2(24.), 4.584962500721156181453738943); assert!((f_log2(0.35) - 0.35f64.log2()).abs() < 1e-8); assert!((f_log2(0.9) - 0.9f64.log2()).abs() < 1e-8); assert_eq!(f_log2(0.), f64::NEG_INFINITY); assert!(f_log2(-1.).is_nan()); assert!(f_log2(f64::NAN).is_nan()); assert!(f_log2(f64::NEG_INFINITY).is_nan()); assert_eq!(f_log2(f64::INFINITY), f64::INFINITY); } #[test] fn test_log2_control_values() { assert_eq!( f_log2(f64::from_bits(0x3ff1406d79e1b574)), 0.10866415915666149 ); assert_eq!( f_log2(f64::from_bits(0x3ffb4ebe40c95a01)), 0.7712301192941611 ); assert_eq!( f_log2(f64::from_bits(0x3ff0b541b6746bd1)), 0.062470074690080965 ); assert_eq!( f_log2(f64::from_bits(0x3ff68d778f076021)), 0.4952222169409832 ); assert_eq!( f_log2(f64::from_bits(0x3ff67eaf07ce24d1)), 0.4915233709893074 ); assert_eq!( f_log2(f64::from_bits(0x3ff0b53197bd66c8)), 0.062448835548542664 ); assert_eq!( f_log2(f64::from_bits(0x3fe6b015f8d9a784)), -0.496152942566177 ); assert_eq!( f_log2(f64::from_bits(0x3ff160732376ad7f)), 0.11908694357502585 ); assert_eq!( f_log2(f64::from_bits(0x3ff0b53f741fb8c4)), 0.062467098188572705 ); } } pxfm-0.1.23/src/logs/log2dd.rs000064400000000000000000000111751046102023000141420ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::logs::log2dd_coeffs::LOG2_NEG_DD; use crate::pow_tables::POW_INVERSE; #[inline(always)] fn log2_poly(z: f64) -> DoubleDouble { /* See ./notes/dd_log2.sollya */ const P: [(u64, u64); 10] = [ (0x3c7777d0ffdb7a88, 0x3ff71547652b82fe), (0xbc6777d0fff4382c, 0xbfe71547652b82fe), (0x3c7d27ad39ed5b3e, 0x3fdec709dc3a03fd), (0xbc57748c64010a70, 0xbfd71547652b82fe), (0x3c771aed4208f9c1, 0x3fd2776c50ef9c06), (0x3c6dd0178c438bee, 0xbfcec709dc3a041c), (0x3c6054a5812d9fc4, 0x3fca61762a515608), (0x3c5662d846baea2e, 0xbfc7154764f1db89), (0x3c66b62df1fd3c4b, 0x3fc484dddfe20481), (0xbc6b16c93b93c1e3, 0xbfc2779d6a07c6b3), ]; let mut t = DoubleDouble::from_bit_pair(P[9]); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[8])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[7])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[6])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[5])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[4])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[3])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[2])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[1])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[0])); DoubleDouble::quick_mult_f64(t, z) } #[inline] pub(crate) fn log2_dd(x: f64) -> DoubleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log2(x) = log2(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let idx = (i - 181) as usize; let r = f64::from_bits(POW_INVERSE[idx]); let log_r = DoubleDouble::from_bit_pair(LOG2_NEG_DD[idx]); let z = f64::mul_add(r, t, -1.0); let v = DoubleDouble::full_add_f64(log_r, be as f64); let p = log2_poly(z); let z0 = DoubleDouble::new(v.lo + p.lo, p.hi); DoubleDouble::full_add_f64(z0, v.hi) } #[cfg(test)] mod tests { use super::*; #[test] fn log2dd_test() { assert_eq!(log2_dd(0.0040283203125 / 2.).to_f64(), -8.955605880641546); } } pxfm-0.1.23/src/logs/log2dd_coeffs.rs000064400000000000000000000241701046102023000154660ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by Sage: from POW_INV ```python R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] real_array = [R(hex_to_float(h)) for h in values] for r in real_array: print_double_double("", -RealField(120)(r).log2()) ``` **/ pub(crate) static LOG2_NEG_DD: [(u64, u64); 182] = [ (0xbc61d46ccc53c278, 0xbfdfbc16b902680a), (0x3c6780e41697a095, 0xbfdf38c567bcc541), (0xbc74f9727980f5ed, 0xbfdeb4b847d15bce), (0xbc4be44aae7442ab, 0xbfde2fed3d097298), (0xbc1274a5715611b7, 0xbfddaa6222064fb9), (0xbc74856fb52a53d2, 0xbfdd2414c80bf27d), (0x3c6b517ae88c2fd3, 0xbfdce0a4923a587d), (0xbc7f9fb952bbbccc, 0xbfdc592fad295b56), (0x3c752ef4c737fba5, 0xbfdbd0f2e9e79031), (0x3c76fae441c09d76, 0xbfdb47ebf73882a1), (0x3c5e5b8daaa73a43, 0xbfdabe18797f1f49), (0x3c78a0efca1a184f, 0xbfda33760a7f6051), (0x3c7dc938c18e544d, 0xbfd9edd6759b25e0), (0x3c7cc298a148e6ca, 0xbfd961f90527409c), (0x3c7530bdb6949302, 0xbfd8d54673b5c372), (0x3c76d266d6cdc959, 0xbfd88e9c72e0b226), (0xbc69575b04fa6fbd, 0xbfd800a563161c54), (0x3c5b90132aeddb58, 0xbfd771d2ba7efb3c), (0xbc75e35482d13dc1, 0xbfd6e221cd9d0cde), (0xbc7a3152150d2dbf, 0xbfd699f5248cd4b8), (0x3c7a43fc62b7e690, 0xbfd608f1b42948ae), (0x3c7817fd3b7d7e5d, 0xbfd5c01a39fbd688), (0xbc7f73d83987f26d, 0xbfd52dbdfc4c96b3), (0x3c1b6d40900b2502, 0xbfd49a784bcd1b8b), (0x3c7aca97d800ce47, 0xbfd4507cfedd4fc4), (0x3c7a9f3c8bc9672e, 0xbfd3bbd3a0a1dcfb), (0x3c63376649b4fc09, 0xbfd37124cea4cded), (0xbc7bc4de8f631bcf, 0xbfd2db10fc4d9aaf), (0xbc78c0e85a908be6, 0xbfd28fab35b32683), (0xbc65f43469fbe6ea, 0xbfd1f825f6d88e13), (0xbc74a31ce1b7e328, 0xbfd1ac05b291f070), (0x3c6a7b47d2c352d9, 0xbfd11307dad30b76), (0x3c76c13816f9f480, 0xbfd0c62975542a8f), (0xbc7bc0c69a675517, 0xbfd0790adbb03009), (0xbc51d46ccc53c278, 0xbfcfbc16b902680a), (0xbc61dd4a99cc633b, 0xbfcf205339208f27), (0x3c4e41bd8c32e1be, 0xbfcde73fe3b1480f), (0x3c5b85a54d7ee2fd, 0xbfcd49ee4c325970), (0x3c6a4ecd69d3b872, 0xbfccac163c770dc9), (0xbc6afb63338bed1f, 0xbfcb6ecf175f95e9), (0x3c401ee1343fe7ca, 0xbfcacf5e2db4ec94), (0x3c5ae3bd6c6d42f0, 0xbfca2f632320b86b), (0x3c628caf799ad993, 0xbfc8edcae8352b6c), (0x3c116edb88c4e2b5, 0xbfc84c2bd02f03b3), (0x3c3d0364be23e873, 0xbfc7a9fec7d05ddf), (0xbc6f3314e0985116, 0xbfc663f6fac91316), (0x3c6817fd3b7d7e5d, 0xbfc5c01a39fbd688), (0xbc622c022616fdff, 0xbfc51bab907a5c8a), (0xbc589c74a0b21fb6, 0xbfc476a9f983f74d), (0xbc4f51f2c075a74c, 0xbfc32ae9e278ae1a), (0x3c6ca25d54d6f775, 0xbfc284294b07a640), (0xbc67a9150c1e0e58, 0xbfc1dcd197552b7b), (0x3bf94b7dfe0d99a5, 0xbfc134e1b489062e), (0x3c5becb2e71abdc8, 0xbfbfc66a0f0b00a5), (0xbc3cbdb5d9dc29f2, 0xbfbe72ec117fa5b2), (0xbc5342ce3cc8f2f9, 0xbfbd1e34e35b82da), (0xbc58ecb169b9465f, 0xbfbbc84240adabba), (0x3c34bba7e1c43d2c, 0xbfba7111df348494), (0x3c5463736dac9317, 0xbfb918a16e46335b), (0xbc5f3314e0985116, 0xbfb663f6fac91316), (0x3c458696424b2e96, 0xbfb507b836033bb7), (0x3c43fd9776f25acf, 0xbfb3aa2fdd27f1c3), (0x3c5d974c32ba8269, 0xbfb24b5b7e135a3d), (0x3c530c22d15199b8, 0xbfb0eb389fa29f9b), (0x3c478cbe51121a94, 0xbfaf1389833253a0), (0x3c160e0f2c3388f0, 0xbfac4dfab90aab5f), (0xbc482838ed43de84, 0xbfa985bfc3495194), (0xbc389b03784b5be1, 0xbfa6bad3758efd87), (0xbc3013a5b81fc494, 0xbfa3ed3094685a26), (0x3c227ebafb056cb9, 0xbfa11cd1d5133413), (0xbc399ba03dc5d34f, 0xbf9c9363ba850f86), (0x3c3d6476077b9fbd, 0xbf96e79685c2d22a), (0xbc32ed069b244452, 0xbf91363117a97b0c), (0xbc2fe38dec005e54, 0xbf86fe50b6ef0851), (0x0000000000000000, 0x0000000000000000), (0x0000000000000000, 0x0000000000000000), (0x3c0456006875bd76, 0x3f815cfe8eaec830), (0x3c2ae48169cf4cdb, 0x3f8cfee70c5ce5dc), (0x3c37910667a9b5f8, 0x3f94564a62192834), (0xbc361176ce5d0a51, 0x3f9a330fd028f75f), (0xbc493cced296b87d, 0x3fa00ae7f502c1c4), (0xbc4c3f1d5c0cfec8, 0x3fa2ff4b77413dcb), (0x3c2c62a2f6e13b06, 0x3fa5f6b8a11c3c61), (0x3c477970e03f821c, 0x3fa77394c9d958d5), (0xbc486446a6eb19b1, 0x3faa6f9c377dd31b), (0x3c0155660710eb2a, 0x3fad6ebd1f1febfe), (0xbc57de9078d157a3, 0x3fb0387efbca869e), (0x3c298c5452bbce74, 0x3fb1bb32a600549d), (0xbc3e20375a3220ba, 0x3fb33f7cde14cf5a), (0xbc4e40a005e7a3e0, 0x3fb4023b7b26ac9e), (0x3c5a489c555db4a8, 0x3fb588edd4d1ceaa), (0xbc524e45ed01d67c, 0x3fb7113f3259e07a), (0x3c34ea44821c1dc2, 0x3fb89b33091d6fe8), (0xbc5d9af608a7a4d8, 0x3fba26ccd9981853), (0x3c540238de7ea9f1, 0x3fbaed391ab6674e), (0xbc17936311889913, 0x3fbc7b528b70f1c5), (0x3c592ce9636c90a0, 0x3fbe0b1ae8f2fd56), (0xbc56fb7d020ef0e0, 0x3fbed3a1d4cdbebb), (0x3c3905c241a252f9, 0x3fc032fbbaee6d65), (0xbc61d536b72e64f7, 0x3fc0fd02a03727ea), (0xbc5df0fdbc295d19, 0x3fc162593186da70), (0xbc5696e2866c718e, 0x3fc22dadc2ab3497), (0xbc6978b98f7dedf9, 0x3fc2f9e32d5bfdd1), (0xbc4b5ac8d9739e01, 0x3fc36052d01c3dd7), (0x3c648a7168f01501, 0x3fc42ddd2ba1b4a9), (0x3c67c2c3172b86af, 0x3fc4fc4d4d9bb313), (0x3c390e41bca6ef96, 0x3fc563dc29ffacb2), (0x3c354fae008fbb59, 0x3fc633a8bf437ce1), (0x3c6a1981a877433e, 0x3fc69be6fbb3aa6f), (0x3c6519f7ed9559d4, 0x3fc76d14a4601225), (0x3c69ced1447e30ad, 0x3fc7d60496cfbb4c), (0x3c699aa6df8b7d83, 0x3fc8a8980abfbd32), (0xbc40b273219ed335, 0x3fc9123c1528c6ce), (0xbc45359413e77d86, 0x3fc9e63a24971f46), (0x3c6013b6eaceb921, 0x3fca5094b54d2828), (0xbc6cc865b3dd0dbb, 0x3fcb2602497d5346), (0x3c569a95f528f2c7, 0x3fcb9115db83a3dd), (0xbc4fab00c0500189, 0x3fcc67f7f770a67e), (0x3c592eeaf409cc88, 0x3fccd3c712d31109), (0xbc0ba8b1f646ab12, 0x3fcdac22d3e441d3), (0x3c29bf75f08df8fb, 0x3fce18b00e13123d), (0x3c506313e79cf1dc, 0x3fcef28aacd72231), (0xbc6bdc0426c3c274, 0x3fcf5fd8a9063e35), (0x3c7768994400ca0a, 0x3fd01d9bbcfa61d4), (0x3c7fdee226b2d7aa, 0x3fd054a474bf0eb7), (0xbc53d56efe4338fe, 0x3fd08bce0d95fa38), (0x3c40de07b685556f, 0x3fd0fa848044b351), (0x3c790ea4cc5a44e3, 0x3fd13211a9b38424), (0x3c7a3174c8d0586b, 0x3fd1a190a5d674a0), (0x3c6ae9804237ec8e, 0x3fd1d982c9d52708), (0xbc7343f87991ca1f, 0x3fd21196e87473d1), (0xbc57154f4085d044, 0x3fd28225bb5e64a4), (0xbc50132ae5e417cd, 0x3fd2baa0c34be1ec), (0xbc7bc5dc0ebe6308, 0x3fd2f33e6d2120f2), (0xbc687bf1007a1695, 0x3fd364e2511cc821), (0x3c7fcad2f4710e00, 0x3fd39de8e1559f6f), (0xbc69cee46ebe3a2d, 0x3fd3d712bf9c9def), (0xbc7c658d602e66b0, 0x3fd4106017c3eca3), (0xbc75759f8091112d, 0x3fd48365e695d797), (0xbc75e341793e8e12, 0x3fd4bd1eb680e548), (0x3c7e393a16b94b52, 0x3fd4f6fbb2cec598), (0xbc78d86531d55da2, 0x3fd56b22e6b578e5), (0x3c7885b23dbdaaf1, 0x3fd5a56d7a370ded), (0x3c710b5b643a6ecb, 0x3fd5dfdcf1eeae0e), (0x3c515f01e8fdf6ad, 0x3fd61a717cac1983), (0x3c3d3cd794eee08b, 0x3fd6900a8836d0d5), (0x3c2b6d40900b2502, 0x3fd6cb0f6865c8ea), (0x3c6cbc6f17205b76, 0x3fd7063a1a5fb4f2), (0xbc726bfff0133975, 0x3fd7418acebbf18f), (0xbc76d8d6e54d428b, 0x3fd77d01b66fbd37), (0x3c6412d04e355531, 0x3fd7f462e58e1688), (0x3c651d58525aad39, 0x3fd8304d90c11fd3), (0xbc71660ad9487503, 0x3fd86c5f36dea3dc), (0x3c799aa6df8b7d83, 0x3fd8a8980abfbd32), (0xbc740df0e173c574, 0x3fd8e4f83fa145ee), (0x3c7fdc46af571993, 0x3fd921800924dd3b), (0x3c7bca36fd02def0, 0x3fd99b072a96c6b2), (0xbc7cf91d2080a35b, 0x3fd9d806ebc9921c), (0xbc64278cd1699312, 0x3fda152f142981b4), (0x3c6b56b1d743ac01, 0x3fda527fd95fd8ff), (0x3c5817fd3b7d7e5d, 0x3fda8ff971810a5e), (0x3c77061311743a68, 0x3fdacd9c130dd53f), (0xbc45e13b838eba7d, 0x3fdb0b67f4f46810), (0xbc501d98c3531027, 0x3fdb877c57b1b070), (0xbc78a87a168550fe, 0x3fdbc5c5489254cc), (0x3c7edf515c63dd87, 0x3fdc043859e2fdb3), (0xbc687a4c86c71df7, 0x3fdc42d5c4c688b4), (0x3c6c4aec56233279, 0x3fdc819dc2d45fe4), (0x3c5d3c79567f954e, 0x3fdcc0908e19b7bd), (0x3c78a38b4175d665, 0x3fdcffae611ad12b), (0xbc4e2b378ff59cbb, 0x3fdd3ef776d43ff4), (0xbc6e15a52a31604a, 0x3fdd7e6c0abc3579), (0xbc76a568b022e9a3, 0x3fddbe0c58c3cff2), (0x3c438c8946414c6a, 0x3fddfdd89d586e2b), (0xbc63aeabca24fd25, 0x3fde3dd1156507de), (0x3c73bed456b24ed1, 0x3fde7df5fe538ab3), (0x3c7ff93949a1897d, 0x3fdebe47960e3c08), (0x3c76d261f1753e0b, 0x3fdefec61b011f85), (0xbc7f4c8f8f9cbfe1, 0x3fdf3f71cc1b629c), (0xbc79ca1a3202b3d7, 0x3fdf804ae8d0cd02), (0x3c5b9a81085cd3b3, 0x3fdfc151b11b3640), (0xbc87398fe685f171, 0x3fe0014332be0033), ]; pxfm-0.1.23/src/logs/log2f.rs000064400000000000000000000257421046102023000140050ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf, set_exponent_f32}; use crate::polyeval::f_polyeval3; pub(crate) static LOG2_R: [u64; 128] = [ 0x0000000000000000, 0x3f872c7ba20f7327, 0x3f9743ee861f3556, 0x3fa184b8e4c56af8, 0x3fa77394c9d958d5, 0x3fad6ebd1f1febfe, 0x3fb1bb32a600549d, 0x3fb4c560fe68af88, 0x3fb7d60496cfbb4c, 0x3fb960caf9abb7ca, 0x3fbc7b528b70f1c5, 0x3fbf9c95dc1d1165, 0x3fc097e38ce60649, 0x3fc22dadc2ab3497, 0x3fc3c6fb650cde51, 0x3fc494f863b8df35, 0x3fc633a8bf437ce1, 0x3fc7046031c79f85, 0x3fc8a8980abfbd32, 0x3fc97c1cb13c7ec1, 0x3fcb2602497d5346, 0x3fcbfc67a7fff4cc, 0x3fcdac22d3e441d3, 0x3fce857d3d361368, 0x3fd01d9bbcfa61d4, 0x3fd08bce0d95fa38, 0x3fd169c05363f158, 0x3fd1d982c9d52708, 0x3fd249cd2b13cd6c, 0x3fd32bfee370ee68, 0x3fd39de8e1559f6f, 0x3fd4106017c3eca3, 0x3fd4f6fbb2cec598, 0x3fd56b22e6b578e5, 0x3fd5dfdcf1eeae0e, 0x3fd6552b49986277, 0x3fd6cb0f6865c8ea, 0x3fd7b89f02cf2aad, 0x3fd8304d90c11fd3, 0x3fd8a8980abfbd32, 0x3fd921800924dd3b, 0x3fd99b072a96c6b2, 0x3fda8ff971810a5e, 0x3fdb0b67f4f46810, 0x3fdb877c57b1b070, 0x3fdc043859e2fdb3, 0x3fdc819dc2d45fe4, 0x3fdcffae611ad12b, 0x3fdd7e6c0abc3579, 0x3fddfdd89d586e2b, 0x3fde7df5fe538ab3, 0x3fdefec61b011f85, 0x3fdf804ae8d0cd02, 0x3fe0014332be0033, 0x3fe042bd4b9a7c99, 0x3fe08494c66b8ef0, 0x3fe0c6caaf0c5597, 0x3fe1096015dee4da, 0x3fe14c560fe68af9, 0x3fe18fadb6e2d3c2, 0x3fe1d368296b5255, 0x3fe217868b0c37e8, 0x3fe25c0a0463beb0, 0x3fe2a0f3c340705c, 0x3fe2e644fac04fd8, 0x3fe2e644fac04fd8, 0x3fe32bfee370ee68, 0x3fe37222bb70747c, 0x3fe3b8b1c68fa6ed, 0x3fe3ffad4e74f1d6, 0x3fe44716a2c08262, 0x3fe44716a2c08262, 0x3fe48eef19317991, 0x3fe4d7380dcc422d, 0x3fe51ff2e30214bc, 0x3fe5692101d9b4a6, 0x3fe5b2c3da19723b, 0x3fe5b2c3da19723b, 0x3fe5fcdce2727ddb, 0x3fe6476d98ad990a, 0x3fe6927781d932a8, 0x3fe6927781d932a8, 0x3fe6ddfc2a78fc63, 0x3fe729fd26b707c8, 0x3fe7767c12967a45, 0x3fe7767c12967a45, 0x3fe7c37a9227e7fb, 0x3fe810fa51bf65fd, 0x3fe810fa51bf65fd, 0x3fe85efd062c656d, 0x3fe8ad846cf369a4, 0x3fe8ad846cf369a4, 0x3fe8fc924c89ac84, 0x3fe94c287492c4db, 0x3fe94c287492c4db, 0x3fe99c48be2063c8, 0x3fe9ecf50bf43f13, 0x3fe9ecf50bf43f13, 0x3fea3e2f4ac43f60, 0x3fea8ff971810a5e, 0x3fea8ff971810a5e, 0x3feae255819f022d, 0x3feb35458761d479, 0x3feb35458761d479, 0x3feb88cb9a2ab521, 0x3feb88cb9a2ab521, 0x3febdce9dcc96187, 0x3fec31a27dd00b4a, 0x3fec31a27dd00b4a, 0x3fec86f7b7ea4a89, 0x3fec86f7b7ea4a89, 0x3fecdcebd2373995, 0x3fed338120a6dd9d, 0x3fed338120a6dd9d, 0x3fed8aba045b01c8, 0x3fed8aba045b01c8, 0x3fede298ec0bac0d, 0x3fede298ec0bac0d, 0x3fee3b20546f554a, 0x3fee3b20546f554a, 0x3fee9452c8a71028, 0x3fee9452c8a71028, 0x3feeee32e2aeccbf, 0x3feeee32e2aeccbf, 0x3fef48c34bd1e96f, 0x3fef48c34bd1e96f, 0x3fefa406bd2443df, 0x3ff0000000000000, ]; /// Logarithm of base 2 /// /// Max found ULP 0.4999996 #[inline] pub fn f_log2f(x: f32) -> f32 { let mut x_u = x.to_bits(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; let mut m = -(E_BIAS as i32); if x_u < f32::MIN_POSITIVE.to_bits() || x_u > f32::MAX.to_bits() { if x == 0.0 { return f32::NEG_INFINITY; } if x_u == 0x80000000u32 { return f32::NEG_INFINITY; } if x.is_sign_negative() && !x.is_nan() { return f32::NAN + x; } // x is +inf or nan if x.is_nan() || x.is_infinite() { return x + x; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4160000000000000) as f32).to_bits(); m -= 23; } m = m.wrapping_add(x_u.wrapping_shr(23) as i32); let mant = x_u & 0x007F_FFFF; let index = mant.wrapping_shr(16); x_u = set_exponent_f32(x_u, 0x7F); let v; let u = f32::from_bits(x_u); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::logs::logf::LOG_REDUCTION_F32; v = f_fmlaf(u, f32::from_bits(LOG_REDUCTION_F32.0[index as usize]), -1.0) as f64; // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::LOG_RANGE_REDUCTION; v = f_fmla( u as f64, f64::from_bits(LOG_RANGE_REDUCTION[index as usize]), -1.0, ); // Exact } // Degree-5 polynomial approximation of log2 generated by Sollya with: // > P = fpminimax(log2(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); let extra_factor = m as f64 + f64::from_bits(LOG2_R[index as usize]); const COEFFS: [u64; 5] = [ 0x3ff71547652b8133, 0xbfe71547652d1e33, 0x3fdec70a098473de, 0xbfd7154c5ccdf121, 0x3fd2514fd90a130a, ]; let v2 = v * v; // Exact let c0 = f_fmla(v, f64::from_bits(COEFFS[0]), extra_factor); let c1 = f_fmla(v, f64::from_bits(COEFFS[2]), f64::from_bits(COEFFS[1])); let c2 = f_fmla(v, f64::from_bits(COEFFS[4]), f64::from_bits(COEFFS[3])); let r = f_polyeval3(v2, c0, c1, c2); r as f32 } /// Natural logarithm using FMA /// /// Max found ULP 0.4999996 #[inline(always)] #[allow(dead_code)] pub(crate) fn f_log2fx(x: f32) -> f64 { let mut x_u = x.to_bits(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; let mut m = -(E_BIAS as i32); if x_u == 0x3f80_0000u32 { return 0.0; } if x_u < f32::MIN_POSITIVE.to_bits() || x_u > f32::MAX.to_bits() { if x == 0.0 { return f64::NEG_INFINITY; } if x_u == 0x80000000u32 { return f64::NEG_INFINITY; } if x.is_sign_negative() && !x.is_nan() { return f64::NAN + x as f64; } // x is +inf or nan if x.is_nan() || x.is_infinite() { return (x + x) as f64; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4160000000000000) as f32).to_bits(); m -= 23; } m = m.wrapping_add(x_u.wrapping_shr(23) as i32); let mant = x_u & 0x007F_FFFF; let index = mant.wrapping_shr(16); x_u = set_exponent_f32(x_u, 0x7F); let v; let u = f32::from_bits(x_u); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::logs::logf::LOG_REDUCTION_F32; v = f_fmlaf(u, f32::from_bits(LOG_REDUCTION_F32.0[index as usize]), -1.0) as f64; // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log2::LOG_RANGE_REDUCTION; v = f_fmla( u as f64, f64::from_bits(LOG_RANGE_REDUCTION[index as usize]), -1.0, ); // Exact } // Degree-5 polynomial approximation of log2 generated by Sollya with: // > P = fpminimax(log2(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); let extra_factor = m as f64 + f64::from_bits(LOG2_R[index as usize]); const COEFFS: [u64; 5] = [ 0x3ff71547652b8133, 0xbfe71547652d1e33, 0x3fdec70a098473de, 0xbfd7154c5ccdf121, 0x3fd2514fd90a130a, ]; let v2 = v * v; // Exact let c0 = f_fmla(v, f64::from_bits(COEFFS[0]), extra_factor); let c1 = f_fmla(v, f64::from_bits(COEFFS[2]), f64::from_bits(COEFFS[1])); let c2 = f_fmla(v, f64::from_bits(COEFFS[4]), f64::from_bits(COEFFS[3])); f_polyeval3(v2, c0, c1, c2) } /// Dirty log2 using FMA #[inline(always)] #[allow(dead_code)] pub(crate) fn dirty_log2f(d: f32) -> f32 { let mut ix = d.to_bits(); /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix = ix.wrapping_add(0x3f800000 - 0x3f3504f3); let n = (ix >> 23) as i32 - 0x7f; ix = (ix & 0x007fffff).wrapping_add(0x3f3504f3); let a = f32::from_bits(ix); let x = (a - 1.) / (a + 1.); let x2 = x * x; let mut u = 0.4121985850084821691e+0; u = f_fmlaf(u, x2, 0.5770780163490337802e+0); u = f_fmlaf(u, x2, 0.9617966939259845749e+0); f_fmlaf(x2 * x, u, f_fmlaf(x, 0.2885390081777926802e+1, n as f32)) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log2f() { assert!((f_log2f(0.35f32) - 0.35f32.log2()).abs() < 1e-5); assert!((f_log2f(0.9f32) - 0.9f32.log2()).abs() < 1e-5); assert_eq!(f_log2f(0.), f32::NEG_INFINITY); assert_eq!(f_log2f(1.0), 0.0); assert!(f_log2f(-1.).is_nan()); assert!(f_log2f(f32::NAN).is_nan()); assert!(f_log2f(f32::NEG_INFINITY).is_nan()); assert_eq!(f_log2f(f32::INFINITY), f32::INFINITY); } #[test] fn test_dirty_log2f() { assert!((dirty_log2f(0.35f32) - 0.35f32.log2()).abs() < 1e-5); assert!((dirty_log2f(0.9f32) - 0.9f32.log2()).abs() < 1e-5); } } pxfm-0.1.23/src/logs/log2p1.rs000064400000000000000000000552401046102023000140740ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{biased_exponent_f64, get_exponent_f64, mantissa_f64}; use crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::logs::log2p1_dyadic_tables::{LOG2P1_F128_POLY, LOG2P1_INVERSE_2, LOG2P1_LOG_INV_2}; use crate::logs::log2p1_tables::{LOG2P1_EXACT, LOG2P1_INVERSE, LOG2P1_LOG_DD_INVERSE}; /* put in h+l a double-double approximation of log(z)-z for |z| < 0.03125, with absolute error bounded by 2^-67.14 (see analyze_p1a(-0.03125,0.03125) from log1p.sage) */ #[inline] pub(crate) fn log_p_1a(z: f64) -> DoubleDouble { let z2: DoubleDouble = if z.abs() >= f64::from_bits(0x3000000000000000) { DoubleDouble::from_exact_mult(z, z) } else { // avoid spurious underflow DoubleDouble::default() }; let z4h = z2.hi * z2.hi; /* The following is a degree-11 polynomial generated by Sollya approximating log(1+x) for |x| < 0.03125, with absolute error < 2^-73.441 and relative error < 2^-67.088 (see file Pabs_a.sollya). The polynomial is P[0]*x + P[1]*x^2 + ... + P[10]*x^11. The algorithm assumes that the degree-1 coefficient P[0] is 1 and the degree-2 coefficient P[1] is -0.5. */ const PA: [u64; 11] = [ 0x3ff0000000000000, 0xbfe0000000000000, 0x3fd5555555555555, 0xbfcffffffffffe5f, 0x3fc999999999aa82, 0xbfc555555583a8c8, 0x3fc2492491c359e6, 0xbfbffffc728edeea, 0x3fbc71c961f34980, 0xbfb9a82ac77c05f4, 0x3fb74b40dd1707d3, ]; let p910 = dd_fmla(f64::from_bits(PA[10]), z, f64::from_bits(PA[9])); let p78 = dd_fmla(f64::from_bits(PA[8]), z, f64::from_bits(PA[7])); let p56 = dd_fmla(f64::from_bits(PA[6]), z, f64::from_bits(PA[5])); let p34 = dd_fmla(f64::from_bits(PA[4]), z, f64::from_bits(PA[3])); let p710 = dd_fmla(p910, z2.hi, p78); let p36 = dd_fmla(p56, z2.hi, p34); let mut ph = dd_fmla(p710, z4h, p36); ph = dd_fmla(ph, z, f64::from_bits(PA[2])); ph *= z2.hi; let mut p = DoubleDouble::from_exact_add(-0.5 * z2.hi, ph * z); p.lo += -0.5 * z2.lo; p } /* put in h+l a double-double approximation of log(z)-z for |z| < 0.00212097167968735, with absolute error bounded by 2^-78.25 (see analyze_p1(-0.00212097167968735,0.00212097167968735) from accompanying file log1p.sage, which also yields |l| < 2^-69.99) */ #[inline] fn p_1(z: f64) -> DoubleDouble { const P: [u64; 7] = [ 0x3ff0000000000000, 0xbfe0000000000000, 0x3fd5555555555550, 0xbfcfffffffff572d, 0x3fc999999a2d7868, 0xbfc5555c0d31b08e, 0x3fc2476b9058e396, ]; let z2 = DoubleDouble::from_exact_mult(z, z); let p56 = dd_fmla(f64::from_bits(P[6]), z, f64::from_bits(P[5])); let p34 = dd_fmla(f64::from_bits(P[4]), z, f64::from_bits(P[3])); let mut ph = dd_fmla(p56, z2.hi, p34); /* ph approximates P[3]+P[4]*z+P[5]*z^2+P[6]*z^3 */ ph = dd_fmla(ph, z, f64::from_bits(P[2])); /* ph approximates P[2]+P[3]*z+P[4]*z^2+P[5]*z^3+P[6]*z^4 */ ph *= z2.hi; /* ph approximates P[2]*z^2+P[3]*z^3+P[4]*z^4+P[5]*z^5+P[6]*z^6 */ let mut p = DoubleDouble::from_exact_add(-0.5 * z2.hi, ph * z); p.lo += -0.5 * z2.lo; p } #[inline] pub(crate) fn log_fast(e: i32, v_u: u64) -> DoubleDouble { let m: u64 = 0x10000000000000u64.wrapping_add(v_u & 0xfffffffffffff); /* x = m/2^52 */ /* if x > sqrt(2), we divide it by 2 to avoid cancellation */ let c: i32 = if m >= 0x16a09e667f3bcd { 1 } else { 0 }; let e = e.wrapping_add(c); /* now -1074 <= e <= 1024 */ static CY: [f64; 2] = [1.0, 0.5]; static CM: [u32; 2] = [43, 44]; let i: i32 = (m >> CM[c as usize]) as i32; let y = f64::from_bits(v_u) * CY[c as usize]; const OFFSET: i32 = 362; let r = f64::from_bits(LOG2P1_INVERSE[(i - OFFSET) as usize]); let log2_inv_dd = LOG2P1_LOG_DD_INVERSE[(i - OFFSET) as usize]; let l1 = f64::from_bits(log2_inv_dd.1); let l2 = f64::from_bits(log2_inv_dd.0); let z = dd_fmla(r, y, -1.0); /* exact */ /* evaluate P(z), for |z| < 0.00212097167968735 */ let p = p_1(z); /* Add e*log(2) to (h,l), where -1074 <= e <= 1023, thus e has at most 11 bits. log2_h is an integer multiple of 2^-42, so that e*log2_h is exact. */ const LOG2_H: f64 = f64::from_bits(0x3fe62e42fefa3800); const LOG2_L: f64 = f64::from_bits(0x3d2ef35793c76730); /* |log(2) - (h+l)| < 2^-102.01 */ /* let hh = e * log2_h: hh is an integer multiple of 2^-42, with |hh| <= 1074*log2_h = 3274082061039582*2^-42. l1 is also an integer multiple of 2^-42, with |l1| <= 1524716581803*2^-42. Thus hh+l1 is an integer multiple of 2^-42, with 2^42*|hh+l1| <= 3275606777621385 < 2^52, thus hh+l1 is exactly representable. */ let ee = e as f64; let mut vl = DoubleDouble::from_exact_add(f_fmla(ee, LOG2_H, l1), z); /* here |hh+l1|+|z| <= 3275606777621385*2^-42 + 0.0022 < 745 thus |h| < 745, and the additional error from the fast_two_sum() call is bounded by 2^-105*745 < 2^-95.4. */ /* add ph + pl + l2 to l */ vl.lo = p.hi + (vl.lo + (l2 + p.lo)); /* here |ph| < 2.26e-6, |l| < ulp(h) = 2^-43, |l2| < 2^-43 and |pl| < 2^-69.99, thus |l2 + pl| < 2^-42 and |*l + l2 + pl| < 2^-41.99, and the rounding error on l2 + pl is bounded by 2^-95 (l2 + pl cannot be > 2^-42), and that on *l + (...) by 2^-94. Now |ph + (*l + (l2 + pl))| < 2.26e-6 + 2^-41.99 < 2^-18.7, thus the rounding error on ph + ... is bounded by ulp(2^-18.7) = 2^-71, which yields a cumulated error bound of 2^-71 + 2^-95 + 2^-94 < 2^-70.99. */ vl.lo = dd_fmla(ee, LOG2_L, vl.lo); /* let l_in be the input value of *l, and l_out the output value. We have |l_in| < 2^-18.7 (from above) and |e*log2_l| <= 1074*0x1.ef35793c7673p-45 thus |l_out| < 2^-18.69 and err(l_out) <= ulp(2^-18.69) = 2^-71 */ /* The absolute error on h + l is bounded by: 2^-78.25 from the error in the Sollya polynomial plus the rounding errors in p_1 (&ph, &pl, z) 2^-91.94 for the maximal difference |e*(log(2)-(log2_h + log2_l))| (|e| <= 1074 and |log(2)-(log2_h + log2_l)| < 2^-102.01) 2^-97 for the maximal difference |l1 + l2 - (-log(r))| 2^-95.4 from the fast_two_sum call 2^-70.99 from the *l = ph + (*l + l2) instruction 2^-71 from the last __builtin_fma call. This gives an absolute error bounded by < 2^-69.99. */ vl } const INV_LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7777d0ffda0d24), f64::from_bits(0x3ff71547652b82fe), ); fn log2p1_accurate_small(x: f64) -> f64 { static P_ACC: [u64; 24] = [ 0x3ff71547652b82fe, 0x3c7777d0ffda0d24, 0xbfe71547652b82fe, 0xbc6777d0ffd9ddb8, 0x3fdec709dc3a03fd, 0x3c7d27f055481523, 0xbfd71547652b82fe, 0xbc5777d1456a14c4, 0x3fd2776c50ef9bfe, 0x3c7e4b2a04f81513, 0xbfcec709dc3a03fd, 0xbc6d2072e751087a, 0x3fca61762a7aded9, 0x3c5f90f4895378ac, 0xbfc71547652b8301, 0x3fc484b13d7c02ae, 0xbfc2776c50ef7591, 0x3fc0c9a84993cabb, 0xbfbec709de7b1612, 0x3fbc68f56ba73fd1, 0xbfba616c83da87e7, 0x3fb89f3042097218, 0xbfb72b376930a3fa, 0x3fb5d0211d5ab530, ]; /* for degree 11 or more, ulp(c[d]*x^d) < 2^-105.5*|log2p1(x)| where c[d] is the degree-d coefficient of Pacc, thus we can compute with a double only */ let mut h = dd_fmla(f64::from_bits(P_ACC[23]), x, f64::from_bits(P_ACC[22])); // degree 16 for i in (11..=15).rev() { h = dd_fmla(h, x, f64::from_bits(P_ACC[(i + 6) as usize])); // degree i } let mut l = 0.; for i in (8..=10).rev() { let mut p = DoubleDouble::quick_f64_mult(x, DoubleDouble::new(l, h)); l = p.lo; p = DoubleDouble::from_exact_add(f64::from_bits(P_ACC[(i + 6) as usize]), p.hi); h = p.hi; l += p.lo; } for i in (1..=7).rev() { let mut p = DoubleDouble::quick_f64_mult(x, DoubleDouble::new(l, h)); l = p.lo; p = DoubleDouble::from_exact_add(f64::from_bits(P_ACC[(2 * i - 2) as usize]), p.hi); h = p.hi; l += p.lo + f64::from_bits(P_ACC[(2 * i - 1) as usize]); } let pz = DoubleDouble::quick_f64_mult(x, DoubleDouble::new(l, h)); pz.to_f64() } /* deal with |x| < 2^-900, then log2p1(x) ~ x/log(2) */ #[cold] fn log2p1_accurate_tiny(x: f64) -> f64 { // exceptional values if x.abs() == f64::from_bits(0x0002c316a14459d8) { return if x > 0. { dd_fmla( f64::from_bits(0x1a70000000000000), f64::from_bits(0x1a70000000000000), f64::from_bits(0x0003fc1ce8b1583f), ) } else { dd_fmla( f64::from_bits(0x9a70000000000000), f64::from_bits(0x1a70000000000000), f64::from_bits(0x8003fc1ce8b1583f), ) }; } /* first scale x to avoid truncation of l in the underflow region */ let sx = x * f64::from_bits(0x4690000000000000); let mut zh = DoubleDouble::quick_f64_mult(sx, INV_LOG2_DD); let res = zh.to_f64() * f64::from_bits(0x3950000000000000); // expected result zh.lo += dd_fmla(-res, f64::from_bits(0x4690000000000000), zh.hi); // the correction to apply to res is l*2^-106 /* For all rounding modes, we have underflow for |x| <= 0x1.62e42fefa39eep-1023 */ dyad_fmla(zh.lo, f64::from_bits(0x3950000000000000), res) } /* Given x > -1, put in (h,l) a double-double approximation of log2(1+x), and return a bound err on the maximal absolute error so that: |h + l - log2(1+x)| < err. We have x = m*2^e with 1 <= m < 2 (m = v.f) and -1074 <= e <= 1023. This routine is adapted from cr_log1p_fast. */ #[inline] fn log2p1_fast(x: f64, e: i32) -> (DoubleDouble, f64) { if e < -5 /* e <= -6 thus |x| < 2^-5 */ { if e <= -969 { /* then |x| might be as small as 2^-969, thus h=x/log(2) might in the binade [2^-969,2^-968), with ulp(h) = 2^-1021, and if |l| < ulp(h), then l.ulp() might be smaller than 2^-1074. We defer that case to the accurate path. */ // *h = *l = 0; // return 1; let ax = x.abs(); let result = if ax < f64::from_bits(0x3960000000000000) { log2p1_accurate_tiny(x) } else { log2p1_accurate_small(x) }; return (DoubleDouble::new(0.0, result), 0.0); } let mut p = log_p_1a(x); let p_lo = p.lo; p = DoubleDouble::from_exact_add(x, p.hi); p.lo += p_lo; /* from analyze_x_plus_p1a(rel=true,Xmax=2^-5.) in the accompanying file log1p.sage, the relative error is bounded by 2^-61.14 with respect to h. We use the fact that we don't need the return value err to be positive, since we add/subtract it in the rounding test. We also get that the ratio |l/h| is bounded by 2^-50.96. */ /* now we multiply h+l by 1/log(2) */ p = DoubleDouble::quick_mult(p, INV_LOG2_DD); /* the d_mul() call decomposes into: a_mul (h_out, l1, h, INVLOG2H) l2 = __builtin_fma (h, INVLOG2L, l1) l_out = __builtin_fma (l, INVLOG2H, l2) we have |l1| <= ulp(h_out) since |INVLOG2L/INVLOG2H| < 2^-55, then |h*INVLOG2L| <= 2^-55*|h_out| and since |x| < 2^53*ulp(x): |h*INVLOG2L| <= ulp(h_out)/4 thus |l2| <= 5/4*ulp(h_out). Now since |l/h| < 2^-50.96, |l*INVLOG2H| < 2^-50.96*|h*INVLOG2H| < 2^-50.96*(1+2^-52)*|h_out| < 2^-50.95*|h_out| < 4.15*ulp(h_out), thus |l_out| < o(4.15*ulp(h_out)+5/4*ulp(h_out)) < 5.5*ulp(h_out). The rounding errors are bounded by ulp(l2)+ulp(l_out) <= ulp(5/4*ulp(h_out)) + ulp(5.5*ulp(h_out)) <= 2^-52*(5/4*ulp(h_out)+5.5*ulp(h_out)) [using ulp(x) <= 2^-52*|x|] <= 2^-49.2*ulp(h_out) We also have to take into account the ignored term l*INVLOG2L: |l*INVLOG2L| < 2^-50.96*|h|*2^-55.97*|INVLOG2H| < 2^-106.93*(1+2^-52)*|h_out| < 2^-106.92*|h_out| < 2^-51.92*ulp(h_out) [using |x| < 2^53*ulp(x)] and the approximation error in INVLOG2H+INVLOG2L: |INVLOG2H + INVLOG2L - 1/log(2)| < 2^-110/log(2) The total error of d_mul() is thus bounded by: (2^-49.2+2^-51.92)*ulp(h_out) < 2^-48.99*ulp(h_out) < 2^-100.99*|h_out|, using again ulp(x) <= 2^-52*|x|. The relative error is thus bounded by (1+2^-61.14)*(1+2^-100.99)*(1+2^-110)-1 < 2^-61.13 */ return (p, f64::from_bits(0x3c1d400000000000) * p.hi); /* 2^-61.13 < 0x1.d4p-62 */ } /* (xh,xl) <- 1+x */ let zx = DoubleDouble::from_full_exact_add(1.0, x); let mut v_u = zx.hi.to_bits(); let e = ((v_u >> 52) as i32).wrapping_sub(0x3ff); v_u = (0x3ffu64 << 52) | (v_u & 0xfffffffffffff); let mut p = log_fast(e, v_u); /* log(xh+xl) = log(xh) + log(1+xl/xh) */ let c = if zx.hi <= f64::from_bits(0x7fd0000000000000) || zx.lo.abs() >= 4.0 { zx.lo / zx.hi } else { 0. }; // avoid spurious underflow /* Since |xl| < ulp(xh), we have |xl| < 2^-52 |xh|, thus |c| < 2^-52, and since |log(1+x)-x| < x^2 for |x| < 0.5, we have |log(1+c)-c)| < c^2 < 2^-104. */ p.lo += c; /* Since |l_in| < 2^-18.69 (from the analysis of cr_log_fast, see file ../log/log.c), and |c| < 2^-52, we have |l| < 2^-18.68, thus the rounding error in *l += c is bounded by ulp(2^-18.68) = 2^-71. The total absolute error is thus bounded by: 0x1.b6p-69 + 2^-104 + 2^-71 < 2^-68.02. */ /* now multiply h+l by 1/log(2) */ p = DoubleDouble::quick_mult(p, INV_LOG2_DD); /* the d_mul() call decomposes into: a_mul (h_out, l1, h, INVLOG2H) l2 = __builtin_fma (h, INVLOG2L, l1) l_out = __builtin_fma (l, INVLOG2H, l2) We have three errors: * the rounding error in l2 = __builtin_fma (h, INVLOG2L, l1) * the rounding error in l_out = __builtin_fma (l, INVLOG2H, l2) * the ignored term l * INVLOG2L We have |h| < 745 thus |h*INVLOG2H| < 1075 thus |h_out| <= 1075 and |l1| <= ulp(h_out) <= 2^-42. Then |h*INVLOG2L+l1| <= 745*INVLOG2L+2^-42 < 2^-41.9 thus |l2| < 2^-41.9*(1+2^-52) < 2^-41.8 and the first rounding error is bounded by ulp(2^-41.8) = 2^-94. Now |l*INVLOG2H+l2| < 2^-18.68*INVLOG2H+2^-41.8 < 2^-18.1 thus |l_out| < 2^-18.1*(1+2^-52) < 2^-18.09 and the second rounding error is bounded by ulp(2^-18.09) = 2^-71. The ignored term is bounded by |l*INVLOG2L| < 2^-18.68*INVLOG2L < 2^-74.1. Thus, the absolute error from d_mul() is bounded by: 2^-94 + 2^-71 + 2^-74.1 < 2^-70.84. Adding to the maximal absolute error of 2^-68.02 before d_mul(), we get 2^-68.02 + 2^-70.84 < 2^-67.82. */ (p, f64::from_bits(0x3bb2300000000000)) /* 2^-67.82 < 0x1.23p-68 */ } fn log_dyadic_taylor_poly(x: DyadicFloat128) -> DyadicFloat128 { let mut r = LOG2P1_F128_POLY[12]; for i in (0..12).rev() { r = x * r + LOG2P1_F128_POLY[i]; } r * x } pub(crate) fn log2_dyadic(d: DyadicFloat128, x: f64) -> DyadicFloat128 { let biased_exp = biased_exponent_f64(x); let e = get_exponent_f64(x); let base_mant = mantissa_f64(x); let mant = base_mant + if biased_exp != 0 { 1u64 << 52 } else { 0 }; let lead = mant.leading_zeros(); let kk = e - (if lead > 11 { lead - 12 } else { 0 }) as i64; let mut fe: i16 = kk as i16; let adjusted_mant = mant << lead; // Find the lookup index let mut i: i16 = (adjusted_mant >> 55) as i16; if adjusted_mant > 0xb504f333f9de6484 { fe = fe.wrapping_add(1); i >>= 1; } let mut x = d; x.exponent = x.exponent.wrapping_sub(fe); let inverse_2 = LOG2P1_INVERSE_2[(i - 128) as usize]; let mut z = x * inverse_2; const F128_MINUS_ONE: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }; z = z + F128_MINUS_ONE; const LOG2: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb172_17f7_d1cf_79ab_c9e3_b398_03f2_f6af_u128, }; // E·log(2) let r = LOG2.mul_int64(fe as i64); let mut p = log_dyadic_taylor_poly(z); p = LOG2P1_LOG_INV_2[(i - 128) as usize] + p; p + r } #[cold] fn log2p1_accurate(x: f64) -> f64 { let ax = x.abs(); if ax < f64::from_bits(0x3fa0000000000000) { return if ax < f64::from_bits(0x3960000000000000) { log2p1_accurate_tiny(x) } else { log2p1_accurate_small(x) }; } let dx = if x > 1.0 { DoubleDouble::from_exact_add(x, 1.0) } else { DoubleDouble::from_exact_add(1.0, x) }; /* log2p1(x) is exact when 1+x = 2^e, thus when 2^e-1 is exactly representable. This can only occur when xl=0 here. */ let mut t: u64 = x.to_bits(); if dx.lo == 0. { /* check if xh is a power of two */ t = dx.hi.to_bits(); if (t.wrapping_shl(12)) == 0 { let e = ((t >> 52) as i32).wrapping_sub(0x3ff); return e as f64; } } /* if x=2^e, the accurate path will fail for directed roundings */ if (t.wrapping_shl(12)) == 0 { let e: i32 = ((t >> 52) as i32).wrapping_sub(0x3ff); // x = 2^e /* for e >= 49, log2p1(x) rounds to e for rounding to nearest; for e >= 48, log2p1(x) rounds to e for rounding toward zero; for e >= 48, log2p1(x) rounds to nextabove(e) for rounding up; for e >= 48, log2p1(x) rounds to e for rounding down. */ if e >= 49 { return e as f64 + f64::from_bits(0x3cf0000000000000); // 0x1p-48 = 1/2 ulp(49) } } let x_d = DyadicFloat128::new_from_f64(dx.hi); let mut y = log2_dyadic(x_d, dx.hi); let mut c = DyadicFloat128::from_div_f64(dx.lo, dx.hi); let mut bx = c * c; /* multiply X by -1/2 */ bx.exponent -= 1; bx.sign = DyadicSign::Neg; /* C <- C - C^2/2 */ c = c + bx; /* |C-log(1+xl/xh)| ~ 2e-64 */ y = y + c; const LOG2_INV: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xb8aa_3b29_5c17_f0bb_be87_fed0_691d_3e89_u128, }; y = y * LOG2_INV; y.exponent -= 12; y.fast_as_f64() } /// Computes log2(x+1) /// /// Max ULP 0.5 pub fn f_log2p1(x: f64) -> f64 { let x_u = x.to_bits(); let e = (((x_u >> 52) & 0x7ff) as i32).wrapping_sub(0x3ff); if e == 0x400 || x == 0. || x <= -1.0 { /* case NaN/Inf, +/-0 or x <= -1 */ if e == 0x400 && x.to_bits() != 0xfffu64 << 52 { /* NaN or + Inf*/ return x + x; } if x <= -1.0 /* we use the fact that NaN < -1 is false */ { /* log2p(x<-1) is NaN, log2p(-1) is -Inf and raises DivByZero */ return if x < -1.0 { f64::NAN } else { // x=-1 f64::NEG_INFINITY }; } return x + x; /* +/-0 */ } /* now x > -1 */ /* check x=2^n-1 for 0 <= n <= 53, where log2p1(x) is exact, and we shouldn't raise the inexact flag */ if 0 <= e && e <= 52 { /* T[e]=2^(e+1)-1, i.e., the unique value of the form 2^n-1 in the interval [2^e, 2^(e+1)). */ if x == f64::from_bits(LOG2P1_EXACT[e as usize]) { return (e + 1) as f64; } } /* For x=2^k-1, -53 <= k <= -1, log2p1(x) = k is also exact. */ if e == -1 && x < 0. { // -1 < x <= -1/2 let w = (1.0 + x).to_bits(); // 1+x is exact if w.wrapping_shl(12) == 0 { // 1+x = 2^k let k: i32 = ((w >> 52) as i32).wrapping_sub(0x3ff); return k as f64; } } /* now x = m*2^e with 1 <= m < 2 (m = v.f) and -1074 <= e <= 1023 */ let (p, err) = log2p1_fast(x, e); let left = p.hi + (p.lo - err); let right = p.hi + (p.lo + err); if left == right { return left; } log2p1_accurate(x) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log2p1() { assert_eq!(f_log2p1(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008344095884546873), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012037985753337781); assert_eq!(f_log2p1(0.00006669877554532304), 0.00009622278377734607); assert_eq!(f_log2p1(1.00006669877554532304), 1.0000481121941047); assert_eq!(f_log2p1(-0.90006669877554532304), -3.322890675865049); } } pxfm-0.1.23/src/logs/log2p1_dyadic_tables.rs000064400000000000000000002231331046102023000167410ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; pub(crate) static LOG2P1_F128_POLY: [DyadicFloat128; 13] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ebd8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaaaa_aaaa_aaaa_aaaa_aaaa_aaaa_a5c4_8b54_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xffff_ffff_ffff_ffff_ffff_ff22_4582_3ae0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xcccc_cccc_cccc_cccc_ccc2_ca18_b08f_e343_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xaaaa_aaaa_aaaa_aaaa_6637_fd4b_1974_3eec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9249_2492_4924_911d_862b_c3d3_3abb_3649_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xffff_ffff_fff9_24cc_05b3_08e3_9fa7_dfb5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe38e_38e3_807c_fa4b_c976_e6cb_d22e_203f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xcccc_ccb9_ec01_7492_f934_e28d_924e_76d4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xba2e_7a1e_af85_6174_70e5_c5a5_ebbe_0226_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xaaa0_2d43_f696_c3e4_4dbe_7546_67b6_bc48_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x99df_88a0_4308_13ca_a1cf_fb6e_966a_70f6_u128, }, ]; pub(crate) static LOG2P1_INVERSE_2: [DyadicFloat128; 240] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xfe03_f80f_e03f_80ff_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xfc0f_c0fc_0fc0_fc10_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xfa23_2cf2_5213_8ac0_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf83e_0f83_e0f8_3e10_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf660_3d98_0f66_03da_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf489_8d5f_85bb_3951_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf2b9_d648_0f2b_9d65_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf0f0_f0f0_f0f0_f0f1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xef2e_b71f_c434_5239_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xed73_03b5_cc0e_d731_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xebbd_b2a5_c161_9c8c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xea0e_a0ea_0ea0_ea0f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe865_ac7b_7603_a197_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe6c2_b448_1cd8_568a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe525_982a_f70c_880f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe38e_38e3_8e38_e38f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe1fc_780e_1fc7_80e2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe070_381c_0e07_0382_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xdee9_5c4c_a037_ba58_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xdd67_c8a6_0dd6_7c8b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xdbeb_61ee_d19c_5958_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xda74_0da7_40da_740e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd901_b203_6406_c80e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd794_35e5_0d79_435f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd62b_80d6_2b80_d62c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd4c7_7b03_531d_ec0e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd368_0d36_80d3_680e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd20d_20d2_0d20_d20e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd0b6_9fcb_d258_0d0c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xcf64_74a8_819e_c8ea_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xce16_8a77_2508_0ce2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xcccc_cccc_cccc_cccd_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xcb87_27c0_65c3_93e1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xca45_87e6_b74f_032a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc907_da4e_8711_46ad_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc7ce_0c7c_e0c7_ce0d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc698_0c69_80c6_980d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc565_c87b_5f9d_4d1c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc437_2f85_5d82_4ca6_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc30c_30c3_0c30_c30d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc1e4_bbd5_95f6_e948_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc0c0_c0c0_c0c0_c0c1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbfa0_2fe8_0bfa_02ff_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbe82_fa0b_e82f_a0bf_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbd69_1047_0766_1aa3_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbc52_640b_c526_40bd_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbb3e_e721_a54d_880c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xba2e_8ba2_e8ba_2e8c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb921_43fa_36f5_e02f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb817_02e0_5c0b_8171_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb70f_bb5a_19be_3659_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb60b_60b6_0b60_b60c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb509_e68a_9b94_8220_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb40b_40b4_0b40_b40c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb30f_6352_8917_c80c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb216_42c8_590b_2165_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb11f_d3b8_0b11_fd3c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb02c_0b02_c0b0_2c0c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xaf3a_ddc6_80af_3ade_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xae4c_415c_9882_b932_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xad60_2b58_0ad6_02b6_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xac76_9184_0ac7_6919_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xab8f_69e2_8359_cd12_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xaaaa_aaaa_aaaa_aaab_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa9c8_4a47_a07f_5638_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa8e8_3f57_17c0_a8e9_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa80a_80a8_0a80_a80b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa72f_0539_7829_cbc2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa655_c439_2d7b_73a8_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa57e_b502_95fa_d40b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa4a9_cf1d_9683_3752_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa3d7_0a3d_70a3_d70b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa306_5e3f_ae7c_d0e1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa237_c32b_16cf_d773_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa16b_312e_a8fc_377d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa0a0_a0a0_a0a0_a0a1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9fd8_09fd_809f_d80a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9f11_65e7_2548_13e3_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9e4c_ad23_dd5f_3a21_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9d89_d89d_89d8_9d8a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9cc8_e160_c3fb_19b9_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9c09_c09c_09c0_9c0a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9b4c_6f9e_f03a_3caa_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9a90_e7d9_5bc6_09aa_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x99d7_22da_bde5_8f07_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x991f_1a51_5885_fb38_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9868_c809_868c_8099_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x97b4_25ed_097b_425f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9701_2e02_5c04_b80a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x964f_da6c_0964_fda7_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x95a0_2568_095a_0257_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x94f2_094f_2094_f20a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9445_8094_4580_9446_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x939a_85c4_0939_a85d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x92f1_1384_0497_889d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9249_2492_4924_924a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x91a2_b3c4_d5e6_f80a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x90fd_bc09_0fdb_c091_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x905a_3863_3e06_c43b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8fb8_23ee_08fb_823f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8f17_79d9_fdc3_a219_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8e78_356d_1408_e784_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8dda_5202_3769_4809_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8d3d_cb08_d3dc_b08e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8ca2_9c04_6514_e024_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8c08_c08c_08c0_8c09_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8b70_344a_139b_c75b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8ad8_f2fb_a938_6823_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8a42_f870_5669_db47_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x89ae_4089_ae40_89af_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x891a_c73a_e981_9b51_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8888_8888_8888_8889_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x87f7_8087_f780_87f8_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8767_ab5f_34e4_7ef2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x86d9_0544_7a34_acc7_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x864b_8a7d_e6d1_d609_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x85bf_3761_2cee_3c9b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8534_0853_4085_3409_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x84a9_f9c8_084a_9f9d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8421_0842_1084_2109_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8399_3052_3fbe_3368_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8312_6e97_8d4f_df3c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x828c_bfbe_b9a0_20a4_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8208_2082_0820_8209_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8184_8da8_faf0_d278_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8102_0408_1020_4082_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xff00_ff00_ff00_ff02_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfe03_f80f_e03f_80ff_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfd08_e550_0fd0_8e56_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfc0f_c0fc_0fc0_fc11_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfb18_8565_06dd_aba7_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfa23_2cf2_5213_8ac1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf92f_b221_1855_a866_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf83e_0f83_e0f8_3e11_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf74e_3fc2_2c70_0f76_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf660_3d98_0f66_03db_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf574_03d5_d00f_5741_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf489_8d5f_85bb_3951_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf3a0_d52c_ba87_2337_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf2b9_d648_0f2b_9d66_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf1d4_8bce_e0d3_99fb_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf0f0_f0f0_f0f0_f0f2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf00f_00f0_0f00_f010_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xef2e_b71f_c434_5239_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xee50_0ee5_00ee_5010_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xed73_03b5_cc0e_d731_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xec97_9118_f3fc_4da3_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xebbd_b2a5_c161_9c8d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xeae5_6403_ab95_9010_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xea0e_a0ea_0ea0_ea10_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe939_651f_e2d8_d35d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe865_ac7b_7603_a198_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe793_72e2_25fe_30da_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe6c2_b448_1cd8_568a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe5f3_6cb0_0e5f_36cc_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe525_982a_f70c_880f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe459_32d7_dc52_100f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe38e_38e3_8e38_e38f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe2c4_a688_6a4c_2e11_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe1fc_780e_1fc7_80e3_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe135_a9c9_7500_e137_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe070_381c_0e07_0383_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdfac_1f74_346c_5760_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdee9_5c4c_a037_ba58_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xde27_eb2c_41f3_d9d2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdd67_c8a6_0dd6_7c8b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdca8_f158_c7f9_1ab9_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdbeb_61ee_d19c_5959_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdb2f_171d_f770_291a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xda74_0da7_40da_740f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd9ba_4256_c036_6e92_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd901_b203_6406_c80f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd84a_598e_c915_1f44_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd794_35e5_0d79_435f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd6df_43fc_a482_f00e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd62b_80d6_2b80_d62d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd578_e97c_3f5f_e552_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd4c7_7b03_531d_ec0e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd417_3289_870a_c52f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd368_0d36_80d3_680e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd2ba_083b_4452_50ac_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd20d_20d2_0d20_d20e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd161_543e_28e5_0275_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd0b6_9fcb_d258_0d0c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd00d_00d0_0d00_d00e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcf64_74a8_819e_c8ea_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcebc_f8bb_5b41_69cc_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xce16_8a77_2508_0ce2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcd71_2752_a886_d243_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcccc_cccc_cccc_ccce_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcc29_786c_7607_f9a0_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcb87_27c0_65c3_93e1_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcae5_d85f_1bbd_6c96_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xca45_87e6_b74f_032a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc9a6_33fc_d967_300e_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc907_da4e_8711_46ae_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc86a_7890_0c86_a78a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc7ce_0c7c_e0c7_ce0d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc732_93d7_89b9_f839_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc698_0c69_80c6_980d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc5fe_7403_17f9_d00d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc565_c87b_5f9d_4d1d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc4ce_07b0_0c4c_e07c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc437_2f85_5d82_4ca7_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc3a1_3de6_0495_c774_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc30c_30c3_0c30_c30d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc278_0613_c030_9e03_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc1e4_bbd5_95f6_e948_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc152_500c_1525_00c2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc0c0_c0c0_c0c0_c0c2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc030_0c03_00c0_300d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbfa0_2fe8_0bfa_0300_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbf11_2a8a_d278_e8de_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbe82_fa0b_e82f_a0c0_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbdf5_9c91_700b_df5b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbd69_1047_0766_1aa4_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbcdd_535d_b1cc_5b7c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbc52_640b_c526_40bd_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbbc8_408c_d630_69a2_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbb3e_e721_a54d_880d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbab6_5610_0bab_6562_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xba2e_8ba2_e8ba_2e8d_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb9a7_862a_0ff4_6589_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb921_43fa_36f5_e02f_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb89b_c36c_e3e0_453b_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb817_02e0_5c0b_8171_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb793_00b7_9300_b794_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb70f_bb5a_19be_365a_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb68d_3134_0e43_07d9_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb60b_60b6_0b60_b60c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb58a_4855_18d1_e7e5_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb509_e68a_9b94_8220_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb48a_39d4_4685_fe98_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb40b_40b4_0b40_b40c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb38c_f9b0_0b38_cf9c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb30f_6352_8917_c80c_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb292_7c29_da55_19d0_0000_0000_0000_0000_u128, }, ]; pub(crate) static LOG2P1_LOG_INV_2: [DyadicFloat128; 240] = [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xb172_17f7_d1cf_79ab_c9e3_b398_03f2_f6af_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xaf74_1551_20c9_011d_046d_235e_e630_73dc_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xad7a_02e1_b24e_fd32_1608_64fd_949b_4bd3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xab83_d135_dc63_3301_ffe6_607b_a902_ef3b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xa991_7134_33c2_b999_0ba4_aea6_14d0_5700_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xa7a2_d41a_d270_c9d7_cd36_2382_a768_8479_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xa5b7_eb7c_b860_fb89_7b6a_62a0_dec6_e072_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xa3d0_a93f_4516_9a4b_0959_4fab_088c_0d64_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xa1ec_ff97_c91e_267b_1b7e_fae0_8e59_7e16_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0xa00c_e109_2e54_98c4_6987_9c5a_30cd_1241_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x9e30_4061_b5fd_a91a_0460_3d87_b6df_81ac_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x9c57_10b8_cbb7_3a42_aa55_4b2d_d461_9e63_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x9a81_456c_ec64_2e10_4d49_f9aa_ea3c_b5e0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x98ae_d221_a034_58b6_732f_8932_1647_b358_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x96df_aabd_86fa_1647_d611_88fb_c94e_2f14_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x9513_c368_7608_3696_b5cb_c416_a241_8011_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x934b_1089_a6dc_93c2_bf5b_b3b6_0554_e151_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x9185_86c5_f5e4_bf01_9f92_199e_d1a4_bab0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8fc3_1afe_30b2_c6de_e300_bf16_7e95_da66_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8e03_c24d_7300_395a_cdda_e1cc_ce24_7837_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8c47_7207_91e5_3314_762a_d194_15fe_25a5_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8a8e_1fb7_94b0_9134_9eb6_28db_a173_c82d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x88d7_c11e_3ad5_3cdc_8a31_11a7_07b6_de2c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8724_4c30_8e67_0a66_85e0_05d0_6dbf_a8f7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8573_b716_82a7_d21b_b21f_9f89_c1ab_80b2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x83c5_f829_9e2b_4091_b8f6_fafe_8fbb_68b8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x821b_05f3_b01d_6774_db0d_58c3_f7e2_ea1e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x8072_d72d_903d_588c_7dd1_b09c_70c4_0109_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xfd9a_c57b_d244_2180_af05_924d_258c_14c4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xfa55_3f70_18c9_66f4_2780_a545_a1b5_4dce_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xf715_0ab5_a09f_27f6_0a47_0250_d40e_be8e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xf3da_161e_ed6b_9ab1_248d_42f7_8d3e_65d2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xf0a4_50d1_3936_6ca7_7c66_eb64_08ff_6432_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xed73_aa42_64b0_adeb_5391_cf4b_33e4_2996_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xea48_1236_f7d3_5bb2_39a7_67a8_0d6d_97e6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xe721_78c0_323a_1a0f_cc4e_1653_e71d_9973_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xe3ff_ce3a_2aa6_4923_8ead_b651_b49a_c539_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xe0e3_0349_fd1c_ec82_03e8_e180_2aba_24d5_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xddcb_08dc_0717_d85c_940a_666c_8784_2842_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xdab7_d022_3148_4a93_bec2_0cca_6efe_2ac4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xd7a9_4a92_466e_833c_cd88_bba7_d0ce_e8df_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xd49f_69e4_56cf_1b7b_7f53_bd2e_406e_66e6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xd19a_2011_27d3_c646_279d_79f5_1dcc_7301_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xce99_5f50_af69_d863_432f_3f4f_861a_d6a8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xcb9d_1a18_9ab5_6e77_7d7e_9307_c70c_0667_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xc8a5_431a_dfb4_4ca6_048c_e7c1_a75e_341a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xc5b1_cd44_596f_a51f_f218_fb8f_9f9e_f27f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xc2c2_abbb_6e5f_d570_0333_7789_d592_e296_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xbfd7_d1de_c0a8_df70_37ed_a996_244b_ccaf_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xbcf1_3343_e7d9_ec7f_2afd_1778_1bb3_afea_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xba0e_c3b6_33dd_8b0b_91dc_60b2_b059_a609_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xb730_7735_78cb_90b3_aa11_16c3_466b_eb6c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xb456_41f4_e350_a0d4_e756_eba0_0bc3_3976_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xb180_1859_d562_49de_98ce_51ff_f994_79cb_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xaead_eefa_caf9_7d37_9dd6_e688_ebb1_3b01_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xabdf_ba9e_468f_d6f9_472e_a077_49ce_6bd1_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xa915_7039_c51e_be72_e164_c759_686a_2207_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xa64f_04f0_b961_df78_54f5_275c_2d15_c21e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xa38c_6e13_8e20_d834_d698_298a_dddd_7f30_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xa0cd_a11e_af46_390e_6324_3827_3918_db7d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x9e12_93b9_998c_1dad_3b03_5eae_273a_855c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x9b5b_3bb5_f088_b768_5078_bbe3_d392_be24_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x98a7_8f0e_9ae7_1d87_64de_c347_8470_7838_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x95f7_83e6_e49a_9cfc_0250_04f3_ef06_3312_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x934b_1089_a6dc_93c2_df5b_b3b6_0554_e151_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x90a2_2b68_75c6_a1f8_8e91_aeba_609c_8876_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x8dfc_cb1a_d35c_a6ef_9947_bdb6_ddca_f59a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x8b5a_e65d_67db_9acf_7ba5_1681_26a5_8b99_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x88bc_7411_3f23_def3_bc5a_0fe3_96f4_0f1c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x8621_6b3b_0b17_188c_363c_eae8_8f72_0f1d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x8389_c302_6ac3_139d_6add_a9d2_270f_a1f3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0x80f5_72b1_3634_87bc_edbd_0b5b_3479_d5f2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xfcc8_e365_9d9b_cbf1_8a0c_df30_1431_b60b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xf7ad_6f26_e7ff_2efc_9cd2_238f_75f9_69ad_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xf298_77ff_3880_9097_2b02_0fa1_820c_948d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xed89_ed86_a44a_01ab_09d4_9f96_cb88_317a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xe881_bf93_2af3_dac3_2524_848e_3443_e03f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xe37f_de37_807b_84e3_5e9a_750b_6b68_781c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xde84_39c1_dec5_687c_9d57_da94_5b5d_0aa6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xd98e_c2ba_de71_e53e_d0a9_8f2a_d65b_ee96_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xd49f_69e4_56cf_1b7a_5f53_bd2e_406e_66e7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xcfb6_2038_44b3_209b_18cb_02f3_3f79_c16b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xcad2_d6e7_b80b_f915_cc50_7fb7_a3d0_bf69_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xc5f5_7f59_c7f4_6156_9a8b_6997_a402_bf30_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xc11e_0b2a_8d1e_0de1_da63_1e83_0fd3_08fe_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xbc4c_6c2a_2263_99f6_276e_bcfb_2016_a433_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xb780_945b_ab55_dcea_b4c7_bc3d_3275_0fd9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xb2ba_75f4_6099_cf8f_243c_2e77_904a_fa76_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xadfa_035a_a1ed_8fdd_5497_67e4_1031_6d2b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xa93f_2f25_0dac_67d5_9ad2_fb8d_4805_4add_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xa489_ec19_9dab_06f4_59fb_6cf0_ecb4_11b7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x9fda_2d2c_c946_5c52_6b2b_9565_f535_5180_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x9b2f_e580_ac80_b182_011a_5b94_4aca_8705_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x968b_0864_3409_ceb9_d5c0_da50_6a08_8482_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x91eb_8952_4e10_0d28_bfd3_df5c_52d6_7e77_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x8d51_5bf1_1fb9_4f22_a071_3268_840c_bcbb_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x88bc_7411_3f23_def7_9c5a_0fe3_96f4_0f19_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x842c_c5ac_f1d0_344b_6fec_dfa8_19b9_6092_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xff44_89ce_deab_2ca6_e17b_d40d_8d92_91ec_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xf639_cc18_5088_fe62_5066_e87f_2c0f_733d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xed39_3b1c_2235_1281_ff4e_2e66_0317_d55f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xe442_c00d_e259_1b4c_e96a_b34c_e0bc_cd10_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xdb56_446d_6ad8_df09_2811_2e35_a60e_636f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xd273_b205_8de1_bd4b_36bb_f837_b4d3_20c6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xc99a_f2ea_ca4c_457b_eaf5_1f66_6928_44b2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xc0cb_f17a_071f_80e9_396f_fdf7_6a14_7cc2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xb806_9857_5607_07a7_0a67_7b4c_8bec_22e0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xaf4a_d26c_bc8e_5bef_9e8b_8b88_a14f_f0c9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0xa698_8ae9_03f5_62f1_7e85_8f08_597b_3a68_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x9def_ad3e_8f73_2186_476d_3b5b_45f6_ca02_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x9550_2522_38bd_2468_658e_5a0b_811c_596d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x8cb9_de8a_32ab_3694_97c9_8595_30a4_514c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -131, mantissa: 0x842c_c5ac_f1d0_344c_1fec_dfa8_19b9_6094_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xf751_8e00_35c3_dd92_606d_8909_3278_a931_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xe65b_9e6e_ed96_5c4f_609f_5fe2_058d_5ff2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xd577_9687_d887_e0ee_49dd_a170_56e4_5ebb_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xc4a5_50a4_fd9a_19bb_3e97_660a_23cc_5402_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xb3e4_a796_a5da_c213_07cc_a0bc_c06c_2f8e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0xa335_76a1_6f1f_4c79_1210_16bd_904d_c95a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0x9297_997c_68c1_f4e6_610d_b3d4_dd42_3bc9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -132, mantissa: 0x820a_ec4f_3a22_2397_b9e3_aea6_c444_eef6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -133, mantissa: 0xe31e_9760_a557_8c6d_f9eb_2f28_4f31_c35a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -133, mantissa: 0xc249_2946_4655_f482_da5f_3cc0_b325_1da6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -133, mantissa: 0xa195_492c_c066_0519_4a18_dff7_cdb4_ae33_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -133, mantissa: 0x8102_b2c4_9ac2_3a86_91d0_82dc_e3dd_cd08_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -134, mantissa: 0xc122_451c_4515_5150_b161_37f0_9a00_2b0e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -134, mantissa: 0x8080_abac_46f3_89c4_662d_417c_ed00_79c9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xff80_5515_885e_014e_435a_b4da_6a5b_b50f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xff01_5358_833c_4762_bb48_1c8e_e141_6999_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xbee2_3afc_0853_b6a8_a897_82c2_0df3_50c2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xfe05_4587_e01f_1e2b_f6d3_a69b_d5ea_b72f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x9e75_221a_352b_a751_452b_7ea6_2f21_98ea_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xbdc8_d83e_ad88_d518_7faa_638b_5e00_ee90_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xdcfe_013d_7c8c_bfc5_632d_bac4_6f30_d009_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xfc14_d873_c198_0236_c7e0_9e3d_e453_f5fc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x8d86_cc49_1ecb_fe03_f177_6453_b7e8_2558_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x9cf4_3dcf_f5ea_fd2f_2ad9_0155_c8a7_236a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xac52_dd7e_4726_a456_a47a_963a_91bb_3018_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xbba2_c7b1_96e7_e224_e795_0f72_52c1_63cf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xcae4_1876_471f_5bde_91d0_0a41_7e33_0f8e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xda16_eb88_cb8d_f5fb_28a6_3ecf_b66e_94c0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe93b_5c56_d85a_9083_ce29_92bf_ea38_e76b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xf851_8600_8b15_32f9_e64b_8b77_5997_8998_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x83ac_c1ac_c723_8978_5a53_33c4_5b7f_442e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x8b29_b775_1bd7_073b_02e0_b9ee_992f_2372_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x929f_b178_50a0_b7be_5b4d_3807_6605_16a4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9a0e_bcb0_de8e_848e_2c1b_b082_689b_a814_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa176_e5f5_3237_81d2_dcf9_3599_6c92_e8d4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xa8d8_39f8_30c1_fb40_4c73_4351_7c8a_c264_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb032_c549_ba86_1d83_774e_27bc_92ce_3373_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb786_9457_2b5a_5cd3_24cd_cf68_cdb2_067c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xbed3_b36b_d896_6419_7c06_44d7_d9ed_08b4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc61a_2eb1_8cd9_07a1_e5a1_532f_6d5a_1ac1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xcd5a_1231_019d_66d7_761e_3e7b_171e_44b2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xd493_69d2_56ab_1b1f_9e91_54e1_d526_3cda_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xdbc6_415d_876d_0839_3e33_c0c9_f882_4f54_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe2f2_a47a_de3a_18a8_a0bf_7c0b_0d8b_b4ef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xea18_9eb3_659a_eaeb_93b2_a3b2_1f44_8259_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xf138_3b71_5797_2f48_543f_ff0f_f4f0_aaf1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xf851_8600_8b15_3302_5e4b_8b77_5997_8993_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xff64_898e_df55_d548_428c_cfc9_9271_dffa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x8338_a896_52cb_714a_b247_eb86_498c_2ce7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x86bb_f3e6_8472_cb2f_0b8b_d206_1574_7126_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x8a3c_2c23_3a15_6341_9027_c74f_e0e6_f64f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x8db9_56a9_7b3d_0143_f023_472c_d739_f9e1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9133_78c8_52d6_5be6_977e_3013_d10f_7525_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x94aa_97c0_ffa9_1a5d_4ee3_880f_b7d3_4429_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x981e_b8c7_23fe_97f2_1f1c_134f_b702_d433_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9b8f_e100_f47b_a1d8_04b6_2af1_89fc_ba0d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9efe_1587_6631_4e4f_4d71_827e_fe89_2fc8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa269_5b66_5be8_f338_4eca_87c3_f0f0_6211_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa5d1_b79c_d2af_2aca_8837_986c_eabf_bed6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa937_2f1d_0da1_bd10_580e_b71e_58cd_36e5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xac99_c6cc_c104_2e94_3dd5_5752_8315_838d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xaff9_8385_3c9e_9e40_5f10_5039_091d_d7f5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb356_6a13_956a_86f4_471b_1e15_74d9_fd55_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb6b0_7f38_ce90_e463_7bb2_e265_d0de_37e1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xba07_c7aa_01bd_2648_43f9_d57b_324b_d05f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xbd5c_4810_86c8_48db_bb59_6b50_3040_3242_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc0ae_050a_1abf_56ad_2f7f_8c5f_a9c5_0d76_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc3fd_0329_0648_847d_3048_0bee_4cbb_d698_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc749_46f4_436a_054e_f4f5_cb53_1201_c0d3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xca92_d4e7_a2b5_a3ad_c983_a9c5_c4b3_b135_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xcdd9_b173_efdc_1aaa_8863_e007_c184_a1e7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd11d_e0ff_15ab_18c6_d88d_83d4_cc61_3f21_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd45f_67e4_4178_c612_5486_e73c_6151_58b4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd79e_4a74_05ff_96c3_1300_c9be_67ae_5da0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xdada_8cf4_7dad_236d_dffb_833c_3409_ee7e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xde14_33a1_6c66_b14c_de74_4870_f54f_0f18_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xe14b_42ac_60c6_0512_4e38_eb80_92a0_1f06_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xe47f_be3c_d4d1_0d5b_2ec0_f797_fdcd_125c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xe7b1_aa70_4e2e_e240_b40f_aab6_d2ad_0841_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xeae1_0b5a_7ddc_8ad8_806b_2fc9_a803_8790_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xee0d_e505_5f63_eb01_90a3_3316_df83_ba5a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xf138_3b71_5797_2f4a_b43f_ff0f_f4f0_aaf1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xf460_1295_52d2_ff41_e62e_3201_bb2b_bdce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xf785_6e5e_e2c9_b28a_76f2_a1b8_4190_a7dc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xfaa8_52b2_5bd9_b833_a6db_fa03_186e_0666_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xfdc8_c36a_f1f1_5468_0a33_61bc_a696_504a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8073_622d_6a80_e631_e897_0090_1531_6073_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8201_2ca5_a682_06d5_8fde_85af_dd2b_c88a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x838d_c2fe_6ac8_68e7_1a3f_cbde_f401_00cb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8519_2713_9c87_1af8_67bd_00c3_8061_c51f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x86a3_5abc_d5ba_5901_5481_c3cb_d925_ccd2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x882c_5fcd_7256_a8c1_3905_5a65_98e7_c29e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x89b4_3814_9d45_82f5_3453_1dba_493e_b5a6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8b3a_e55d_5d30_701a_c63e_ab88_3717_0480_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8cc0_696e_a11b_7b36_9436_1c9a_28d3_8a6a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8e44_c60b_4ccf_d7dc_1473_aa01_c777_8679_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8fc7_fcf2_4517_946a_380c_be76_9f2c_6793_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x914a_0fde_7bcb_2d0e_c429_ed3a_ea19_7a60_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x92cb_0086_fbb1_cf75_a29d_47c5_0b11_82d0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x944a_d09e_f435_1af1_a498_27e0_81cb_16ba_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x95c9_81d5_c4e9_24ea_4540_4f5a_a577_d6b4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9747_15d7_08e9_84dd_6648_d428_40d9_e6fb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x98c3_8e4a_a20c_27d2_8467_67ec_990d_7333_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9a3e_ecd4_c3ea_a6ae_db3a_7f6e_6087_b947_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9bb9_3315_fec2_d790_7f58_9fba_0865_790f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9d32_62ab_4a2f_4e37_a1ae_6ba0_6846_fae0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9eaa_7d2e_0fb8_7c35_ff47_2bc6_ce64_8a7d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa021_8434_353f_1de4_d493_efa6_3253_0acc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa197_7950_2740_9daa_1dd1_d4a6_df96_0357_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa30c_5e10_e2f6_13e4_9bd9_bd99_e39a_20b3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa480_3402_004e_865c_31cb_e0e8_8241_16cd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa5f2_fcab_bbc5_06d8_68ca_4fb7_ec32_3d74_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa764_b993_0013_4d79_0d04_d104_7430_1862_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa8d5_6c39_6fc1_684c_01eb_067d_578c_4756_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaa45_161d_6e93_167b_9b08_1cf7_2249_f5b2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xabb3_b8ba_2ad3_62a1_1db6_506c_c17a_01f5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xad21_5587_a67f_0cdf_e890_422c_b86b_7cb1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xae8d_edfa_c04e_5282_ac70_7b8f_fc22_b3e8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaff9_8385_3c9e_9e3f_c510_5039_091d_d7f8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb164_1795_ce3c_a978_faf9_1530_0e51_7393_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb2cd_ab98_1f0f_940b_c857_c77d_c1df_600f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb436_40f4_d8a5_761f_f5f0_80a7_1c34_b25d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb59d_d911_aca1_ec48_1d26_64cf_09a0_c1bf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb704_7551_5d0f_1c5e_4c98_c6b8_be17_818d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb86a_1713_c491_aeaa_d37e_e287_2a6f_1cd6_u128, }, ]; pxfm-0.1.23/src/logs/log2p1_tables.rs000064400000000000000000000702071046102023000154260ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ pub(crate) static LOG2P1_EXACT: [u64; 53] = [ 0x3ff0000000000000, 0x4008000000000000, 0x401c000000000000, 0x402e000000000000, 0x403f000000000000, 0x404f800000000000, 0x405fc00000000000, 0x406fe00000000000, 0x407ff00000000000, 0x408ff80000000000, 0x409ffc0000000000, 0x40affe0000000000, 0x40bfff0000000000, 0x40cfff8000000000, 0x40dfffc000000000, 0x40efffe000000000, 0x40fffff000000000, 0x410ffff800000000, 0x411ffffc00000000, 0x412ffffe00000000, 0x413fffff00000000, 0x414fffff80000000, 0x415fffffc0000000, 0x416fffffe0000000, 0x417ffffff0000000, 0x418ffffff8000000, 0x419ffffffc000000, 0x41affffffe000000, 0x41bfffffff000000, 0x41cfffffff800000, 0x41dfffffffc00000, 0x41efffffffe00000, 0x41fffffffff00000, 0x420ffffffff80000, 0x421ffffffffc0000, 0x422ffffffffe0000, 0x423fffffffff0000, 0x424fffffffff8000, 0x425fffffffffc000, 0x426fffffffffe000, 0x427ffffffffff000, 0x428ffffffffff800, 0x429ffffffffffc00, 0x42affffffffffe00, 0x42bfffffffffff00, 0x42cfffffffffff80, 0x42dfffffffffffc0, 0x42efffffffffffe0, 0x42fffffffffffff0, 0x430ffffffffffff8, 0x431ffffffffffffc, 0x432ffffffffffffe, 0x433fffffffffffff, ]; /* For 362 <= i <= 724, r[i] = LOG2P1_INVERSE[i-362] is a 10-bit approximation of 1/x[i], where i*2^-9 <= x[i] < (i+1)*2^-9. More precisely r[i] is a 10-bit value such that r[i]*y-1 is representable exactly on 53 bits for any y, i*2^-9 <= y < (i+1)*2^-9. Moreover |r[i]*y-1| <= 0.00212097167968735. */ pub(crate) static LOG2P1_INVERSE: [u64; 363] = [ 0x3ff6980000000000, 0x3ff6880000000000, 0x3ff6780000000000, 0x3ff6680000000000, 0x3ff6580000000000, 0x3ff6480000000000, 0x3ff6380000000000, 0x3ff6300000000000, 0x3ff6200000000000, 0x3ff6100000000000, 0x3ff6000000000000, 0x3ff5f00000000000, 0x3ff5e00000000000, 0x3ff5d00000000000, 0x3ff5c00000000000, 0x3ff5b00000000000, 0x3ff5a80000000000, 0x3ff5980000000000, 0x3ff5880000000000, 0x3ff5780000000000, 0x3ff5680000000000, 0x3ff5600000000000, 0x3ff5500000000000, 0x3ff5400000000000, 0x3ff5300000000000, 0x3ff5200000000000, 0x3ff5180000000000, 0x3ff5080000000000, 0x3ff4f80000000000, 0x3ff4f00000000000, 0x3ff4e00000000000, 0x3ff4d00000000000, 0x3ff4c00000000000, 0x3ff4b80000000000, 0x3ff4a80000000000, 0x3ff4a00000000000, 0x3ff4900000000000, 0x3ff4800000000000, 0x3ff4780000000000, 0x3ff4680000000000, 0x3ff4580000000000, 0x3ff4500000000000, 0x3ff4400000000000, 0x3ff4300000000000, 0x3ff4280000000000, 0x3ff4180000000000, 0x3ff4100000000000, 0x3ff4000000000000, 0x3ff3f80000000000, 0x3ff3e80000000000, 0x3ff3e00000000000, 0x3ff3d00000000000, 0x3ff3c00000000000, 0x3ff3b80000000000, 0x3ff3a80000000000, 0x3ff3a00000000000, 0x3ff3900000000000, 0x3ff3880000000000, 0x3ff3780000000000, 0x3ff3700000000000, 0x3ff3600000000000, 0x3ff3580000000000, 0x3ff3500000000000, 0x3ff3400000000000, 0x3ff3380000000000, 0x3ff3280000000000, 0x3ff3200000000000, 0x3ff3100000000000, 0x3ff3080000000000, 0x3ff3000000000000, 0x3ff2f00000000000, 0x3ff2e80000000000, 0x3ff2d80000000000, 0x3ff2d00000000000, 0x3ff2c80000000000, 0x3ff2b80000000000, 0x3ff2b00000000000, 0x3ff2a00000000000, 0x3ff2980000000000, 0x3ff2900000000000, 0x3ff2800000000000, 0x3ff2780000000000, 0x3ff2700000000000, 0x3ff2600000000000, 0x3ff2580000000000, 0x3ff2500000000000, 0x3ff2400000000000, 0x3ff2380000000000, 0x3ff2300000000000, 0x3ff2280000000000, 0x3ff2180000000000, 0x3ff2100000000000, 0x3ff2080000000000, 0x3ff2000000000000, 0x3ff1f00000000000, 0x3ff1e80000000000, 0x3ff1e00000000000, 0x3ff1d00000000000, 0x3ff1c80000000000, 0x3ff1c00000000000, 0x3ff1b80000000000, 0x3ff1b00000000000, 0x3ff1a00000000000, 0x3ff1980000000000, 0x3ff1900000000000, 0x3ff1880000000000, 0x3ff1800000000000, 0x3ff1700000000000, 0x3ff1680000000000, 0x3ff1600000000000, 0x3ff1580000000000, 0x3ff1500000000000, 0x3ff1400000000000, 0x3ff1380000000000, 0x3ff1300000000000, 0x3ff1280000000000, 0x3ff1200000000000, 0x3ff1180000000000, 0x3ff1100000000000, 0x3ff1000000000000, 0x3ff0f80000000000, 0x3ff0f00000000000, 0x3ff0e80000000000, 0x3ff0e00000000000, 0x3ff0d80000000000, 0x3ff0d00000000000, 0x3ff0c80000000000, 0x3ff0c00000000000, 0x3ff0b00000000000, 0x3ff0a80000000000, 0x3ff0a00000000000, 0x3ff0980000000000, 0x3ff0900000000000, 0x3ff0880000000000, 0x3ff0800000000000, 0x3ff0780000000000, 0x3ff0700000000000, 0x3ff0680000000000, 0x3ff0600000000000, 0x3ff0580000000000, 0x3ff0500000000000, 0x3ff0480000000000, 0x3ff0400000000000, 0x3ff0380000000000, 0x3ff0300000000000, 0x3ff0280000000000, 0x3ff0200000000000, 0x3ff0180000000000, 0x3ff0100000000000, 0x3ff0080000000000, 0x3feff80000000000, 0x3fefe80000000000, 0x3fefd80000000000, 0x3fefc80000000000, 0x3fefb80000000000, 0x3fefa80000000000, 0x3fef980000000000, 0x3fef880000000000, 0x3fef780000000000, 0x3fef680000000000, 0x3fef580000000000, 0x3fef500000000000, 0x3fef400000000000, 0x3fef300000000000, 0x3fef200000000000, 0x3fef100000000000, 0x3fef000000000000, 0x3feef00000000000, 0x3feee00000000000, 0x3feed00000000000, 0x3feec80000000000, 0x3feeb80000000000, 0x3feea80000000000, 0x3fee980000000000, 0x3fee880000000000, 0x3fee780000000000, 0x3fee700000000000, 0x3fee600000000000, 0x3fee500000000000, 0x3fee400000000000, 0x3fee300000000000, 0x3fee280000000000, 0x3fee180000000000, 0x3fee080000000000, 0x3fedf80000000000, 0x3fedf00000000000, 0x3fede00000000000, 0x3fedd00000000000, 0x3fedc00000000000, 0x3fedb80000000000, 0x3feda80000000000, 0x3fed980000000000, 0x3fed900000000000, 0x3fed800000000000, 0x3fed700000000000, 0x3fed600000000000, 0x3fed580000000000, 0x3fed480000000000, 0x3fed380000000000, 0x3fed300000000000, 0x3fed200000000000, 0x3fed100000000000, 0x3fed080000000000, 0x3fecf80000000000, 0x3fece80000000000, 0x3fece00000000000, 0x3fecd00000000000, 0x3fecc80000000000, 0x3fecb80000000000, 0x3feca80000000000, 0x3feca00000000000, 0x3fec900000000000, 0x3fec880000000000, 0x3fec780000000000, 0x3fec680000000000, 0x3fec600000000000, 0x3fec500000000000, 0x3fec480000000000, 0x3fec380000000000, 0x3fec300000000000, 0x3fec200000000000, 0x3fec180000000000, 0x3fec080000000000, 0x3febf80000000000, 0x3febf00000000000, 0x3febe00000000000, 0x3febd80000000000, 0x3febc80000000000, 0x3febc00000000000, 0x3febb00000000000, 0x3feba80000000000, 0x3feb980000000000, 0x3feb900000000000, 0x3feb800000000000, 0x3feb780000000000, 0x3feb680000000000, 0x3feb600000000000, 0x3feb580000000000, 0x3feb480000000000, 0x3feb400000000000, 0x3feb300000000000, 0x3feb280000000000, 0x3feb180000000000, 0x3feb100000000000, 0x3feb000000000000, 0x3feaf80000000000, 0x3feaf00000000000, 0x3feae00000000000, 0x3fead80000000000, 0x3feac80000000000, 0x3feac00000000000, 0x3feab80000000000, 0x3feaa80000000000, 0x3feaa00000000000, 0x3fea900000000000, 0x3fea880000000000, 0x3fea800000000000, 0x3fea700000000000, 0x3fea680000000000, 0x3fea600000000000, 0x3fea500000000000, 0x3fea480000000000, 0x3fea400000000000, 0x3fea300000000000, 0x3fea280000000000, 0x3fea200000000000, 0x3fea100000000000, 0x3fea080000000000, 0x3fea000000000000, 0x3fe9f00000000000, 0x3fe9e80000000000, 0x3fe9e00000000000, 0x3fe9d00000000000, 0x3fe9c80000000000, 0x3fe9c00000000000, 0x3fe9b00000000000, 0x3fe9a80000000000, 0x3fe9a00000000000, 0x3fe9980000000000, 0x3fe9880000000000, 0x3fe9800000000000, 0x3fe9780000000000, 0x3fe9680000000000, 0x3fe9600000000000, 0x3fe9580000000000, 0x3fe9500000000000, 0x3fe9400000000000, 0x3fe9380000000000, 0x3fe9300000000000, 0x3fe9280000000000, 0x3fe9200000000000, 0x3fe9100000000000, 0x3fe9080000000000, 0x3fe9000000000000, 0x3fe8f80000000000, 0x3fe8e80000000000, 0x3fe8e00000000000, 0x3fe8d80000000000, 0x3fe8d00000000000, 0x3fe8c80000000000, 0x3fe8b80000000000, 0x3fe8b00000000000, 0x3fe8a80000000000, 0x3fe8a00000000000, 0x3fe8980000000000, 0x3fe8880000000000, 0x3fe8800000000000, 0x3fe8780000000000, 0x3fe8700000000000, 0x3fe8680000000000, 0x3fe8600000000000, 0x3fe8500000000000, 0x3fe8480000000000, 0x3fe8400000000000, 0x3fe8380000000000, 0x3fe8300000000000, 0x3fe8280000000000, 0x3fe8200000000000, 0x3fe8100000000000, 0x3fe8080000000000, 0x3fe8000000000000, 0x3fe7f80000000000, 0x3fe7f00000000000, 0x3fe7e80000000000, 0x3fe7e00000000000, 0x3fe7d80000000000, 0x3fe7c80000000000, 0x3fe7c00000000000, 0x3fe7b80000000000, 0x3fe7b00000000000, 0x3fe7a80000000000, 0x3fe7a00000000000, 0x3fe7980000000000, 0x3fe7900000000000, 0x3fe7880000000000, 0x3fe7800000000000, 0x3fe7780000000000, 0x3fe7700000000000, 0x3fe7600000000000, 0x3fe7580000000000, 0x3fe7500000000000, 0x3fe7480000000000, 0x3fe7400000000000, 0x3fe7380000000000, 0x3fe7300000000000, 0x3fe7280000000000, 0x3fe7200000000000, 0x3fe7180000000000, 0x3fe7100000000000, 0x3fe7080000000000, 0x3fe7000000000000, 0x3fe6f80000000000, 0x3fe6f00000000000, 0x3fe6e80000000000, 0x3fe6e00000000000, 0x3fe6d80000000000, 0x3fe6d00000000000, 0x3fe6c80000000000, 0x3fe6c00000000000, 0x3fe6b80000000000, 0x3fe6b00000000000, 0x3fe6a80000000000, 0x3fe6a00000000000, ]; pub(crate) static LOG2P1_LOG_DD_INVERSE: [(u64, u64); 363] = [ (0xbd13c7ca90bc04b2, 0xbfd615ddb4bec000), (0xbd3527d18f7738fa, 0xbfd5e87b20c29000), (0x3d339ae8f873fa41, 0xbfd5baf846aa2000), (0xbd2791f30a795215, 0xbfd58d54f86e0000), (0x3d11e64778df4a62, 0xbfd55f9107a44000), (0xbd3df83b7d931501, 0xbfd531ac457ee000), (0x3d2a68c8f16f9b5d, 0xbfd503a682cb2000), (0xbd234d7aaf04d104, 0xbfd4ec9732600000), (0x3d3d7c92cd9ad824, 0xbfd4be5f95778000), (0x3d38bccffe1a0f8c, 0xbfd4900680401000), (0x3d13d82f484c84cc, 0xbfd4618bc21c6000), (0x3d3fb129931715ad, 0xbfd432ef2a04f000), (0xbd3f8ef43049f7d3, 0xbfd404308686a000), (0xbd3c3e1cd9a395e3, 0xbfd3d54fa5c1f000), (0xbd37a71cbcd735d0, 0xbfd3a64c55694000), (0x3d3e9436ac53b023, 0xbfd3772662bfe000), (0x3d3b07de4ea1a54a, 0xbfd35f865c933000), (0xbd36217dc2a3e08b, 0xbfd3302c16586000), (0xbd342f568b75fcac, 0xbfd300aead063000), (0xbd360c61f7088353, 0xbfd2d10dec508000), (0x3d30dbbf51f3aadc, 0xbfd2a1499f763000), (0xbd3a8d7ad24c13f0, 0xbfd2895a13de8000), (0xbd38e7bc224ea3e3, 0xbfd2596010df7000), (0x3d3a6976f5eb0963, 0xbfd22941fbcf8000), (0xbd27946c040cbe77, 0xbfd1f8ff9e48a000), (0x3d381410e5c62aff, 0xbfd1c898c169a000), (0x3d32dd466dc55e2d, 0xbfd1b05791f08000), (0x3d3a8a8ba74a2684, 0xbfd17fb98e151000), (0x3d3e97a65dfc9794, 0xbfd14ef67f887000), (0x3d3d3e8499d67123, 0xbfd136870293b000), (0x3d34ab9d817d52cd, 0xbfd1058bf9ae5000), (0xbd3d2c81f640e1e6, 0xbfd0d46b579ab000), (0xbd0c6bee7ef4030e, 0xbfd0a324e2739000), (0xbd3ebc1d40c5a329, 0xbfd08a73667c5000), (0x3d30e866bcd236ad, 0xbfd058f3c703f000), (0xbcf036b89ef42d7f, 0xbfd0402594b4d000), (0xbcdcc68d52e01203, 0xbfd00e6c45ad5000), (0x3d0d572aab993c87, 0xbfcfb9186d5e4000), (0x3d3f75fd6a526efe, 0xbfcf871b28956000), (0x3d3f454f1417e41f, 0xbfcf22e5e72f2000), (0x3d23d45330fdca4d, 0xbfcebe61f4dd8000), (0x3d26805b80e8e6ff, 0xbfce8c0252aa6000), (0x3d3a342c2af0003c, 0xbfce27076e2b0000), (0xbd38fac1a628ccc6, 0xbfcdc1bca0abe000), (0x3d15105fc364c784, 0xbfcd8ef91af32000), (0x3d383270128aaa5f, 0xbfcd293581b6c000), (0xbd2771239a07d55b, 0xbfccf6354e09c000), (0x3d27794f689f8434, 0xbfcc8ff7c79aa000), (0xbd20929decb454fc, 0xbfcc5cba543ae000), (0xbd2386a947c378b5, 0xbfcbf601bb0e4000), (0xbd39ac53f39d121c, 0xbfcbc286742d8000), (0x3d34b722ec011f31, 0xbfcb5b519e8fc000), (0x3cba4e633fcd9066, 0xbfcaf3c94e80c000), (0x3d3b68f5395f139d, 0xbfcabfe5ae462000), (0xbd3b99c8ca1d9abb, 0xbfca57df28244000), (0x3d3539cd91dc9f0b, 0xbfca23bc1fe2c000), (0x3d21f2a8a1ce0ffc, 0xbfc9bb362e7e0000), (0xbcf93b564dd44000, 0xbfc986d322818000), (0xbd37bc6abddeff46, 0xbfc91dcc8c340000), (0xbd3a8154b13d72d5, 0xbfc8e928de886000), (0xbd322120401202fc, 0xbfc87fa06520c000), (0x3d3d8daadf4e2bd2, 0xbfc84abb75866000), (0x3d302a52f9201ce8, 0xbfc815c0a1436000), (0x3d2bdb9072534a58, 0xbfc7ab890210e000), (0xbd0274903479e3d1, 0xbfc7764c128f2000), (0xbd34ea64f6a95bef, 0xbfc70b8f97a1a000), (0x3d3bc6e557134767, 0xbfc6d60fe719e000), (0xbd3aa1bdbfc6c785, 0xbfc66acd4272a000), (0xbd2d5ec0ab8163af, 0xbfc6350a28aaa000), (0x3d38586f183bebf2, 0xbfc5ff3070a7a000), (0xbcf0ba68b7555d4a, 0xbfc59338d9982000), (0xbd3add94dda647e8, 0xbfc55d1ad4232000), (0x3d3e9bf2fafeaf27, 0xbfc4f099f4a24000), (0x3d34354bb3f219e5, 0xbfc4ba36f39a6000), (0xbd1eea52723f6369, 0xbfc483bccce6e000), (0x3d210047081f849d, 0xbfc41682bf728000), (0xbd28a72a62b8c13f, 0xbfc3dfc2b0ecc000), (0xbd3ee8779b2d8abc, 0xbfc371fc201e8000), (0xbd3c9ecca2fe72a5, 0xbfc33af575770000), (0x3cd680b5ce3ecb05, 0xbfc303d718e48000), (0x3d35b967f4471dfc, 0xbfc29552f8200000), (0xbd35a3854f176449, 0xbfc25ded0abc6000), (0x3d24d20ab840e7f6, 0xbfc2266f190a6000), (0xbd2e80a41811a396, 0xbfc1b72ad52f6000), (0xbd2843fad093c8dc, 0xbfc17f6458fca000), (0xbd1563451027c750, 0xbfc1478584674000), (0xbd3cb2cd2ee2f482, 0xbfc0d77e7cd08000), (0x3d28f3057157d1a8, 0xbfc09f561ee72000), (0x3d2a47579cdc0a3d, 0xbfc0671512ca6000), (0x3d15a8fa5ce00e5d, 0xbfc02ebb42bf4000), (0x3d010987e897ed01, 0xbfbf7b79fec38000), (0x3d3d599e83368e91, 0xbfbf0a30c0118000), (0xbd34677489c50e97, 0xbfbe98b549670000), (0x3d2a342c2af0003c, 0xbfbe27076e2b0000), (0x3d29454379135713, 0xbfbd4313d66cc000), (0xbd33e14db50dd743, 0xbfbcd0cdbf8c0000), (0xbd1d0c57585fbe06, 0xbfbc5e548f5bc000), (0x3d325ef7bc3987e7, 0xbfbb78c82bb10000), (0xbd0ff22c18f84a5e, 0xbfbb05b49bee4000), (0xbd3563650bd22a9c, 0xbfba926d3a4ac000), (0xbd3cd4176df97bcb, 0xbfba1ef1d8060000), (0x3d28a64826787061, 0xbfb9ab4246204000), (0xbd3b20f5acb42a66, 0xbfb8c345d6318000), (0x3d37d5cd246977c9, 0xbfb84ef898e84000), (0xbd32cc844480c89b, 0xbfb7da766d7b0000), (0x3cfecbc035c4256a, 0xbfb765bf23a6c000), (0x3d34b4641b664613, 0xbfb6f0d28ae58000), (0xbd30c3b1dee9c4f8, 0xbfb60658a9374000), (0xbd3c284f5722abaa, 0xbfb590cafdf00000), (0xbd383f69278e686a, 0xbfb51b073f060000), (0x3d2f7fe1308973e2, 0xbfb4a50d3aa1c000), (0xbd1bc0eeea7c9acd, 0xbfb42edcbea64000), (0xbd31d09299837610, 0xbfb341d7961bc000), (0xbd3e1ee2ca657021, 0xbfb2cb0283f5c000), (0xbd3416f8fb69a701, 0xbfb253f62f0a0000), (0xbd39444f5e9e8981, 0xbfb1dcb263db0000), (0x3d147c5e768fa309, 0xbfb16536eea38000), (0x3d3901f46d48abb4, 0xbfb0ed839b554000), (0x3d3b8ecfe4b59987, 0xbfb0759835990000), (0x3d2d599e83368e91, 0xbfaf0a30c0118000), (0x3d2fea4664629e86, 0xbfae19070c278000), (0xbd16a423c78a64b0, 0xbfad276b8adb0000), (0xbd2f2ccc9abf8388, 0xbfac355dd0920000), (0x3d1c827ae5d6704c, 0xbfab42dd71198000), (0x3d36e584a0402925, 0xbfaa4fe9ffa40000), (0x3d2c148297c5feb8, 0xbfa95c830ec90000), (0x3d12623a134ac693, 0xbfa868a830840000), (0x3d3181dce586af09, 0xbfa77458f6330000), (0x3d2b2b739570ad39, 0xbfa58a5bafc90000), (0xbd211c78a56fd247, 0xbfa494acc34d8000), (0xbd3eafd480ad9015, 0xbfa39e87b9fe8000), (0x3d278ce77a9163fe, 0xbfa2a7ec22150000), (0x3d33401e9ae889bb, 0xbfa1b0d989240000), (0x3d2e89896f022783, 0xbfa0b94f7c198000), (0xbd2980267c7e09e4, 0xbf9f829b0e780000), (0xbd2e61f1658cfb9a, 0xbf9d91a66c540000), (0x3d3b9a010ae6922a, 0xbf9b9fc027b00000), (0x3d2d75d97ec7c410, 0xbf99ace7551d0000), (0x3d33b955b602ace4, 0xbf97b91b07d60000), (0x3d263bb6216d87d8, 0xbf95c45a51b90000), (0x3d36a2c432d6a40b, 0xbf93cea443470000), (0x3d14193a83fcc7a6, 0xbf91d7f7eb9f0000), (0xbcdf1e7cf6d3a69c, 0xbf8fc0a8b0fc0000), (0xbd1c25e097bd9771, 0xbf8bcf712c740000), (0x3d3eb1245b5da1f5, 0xbf87dc475f820000), (0x3d2609c1ff29a114, 0xbf83e7295d260000), (0xbd19e23f0dda40e4, 0xbf7fe02a6b100000), (0xbd0749d3c2d23a07, 0xbf77ee11ebd80000), (0xbd20bc04a086b56a, 0xbf6ff00aa2b00000), (0x3d33bc661d61c5eb, 0xbf5ff802a9b00000), (0x3d356224cd5f35f8, 0x3f50020055600000), (0x3d285c0696a70c0c, 0x3f68090482880000), (0x3d1e3871df070002, 0x3f740c8a74780000), (0xbd3d805512588560, 0x3f7c189cbb100000), (0x3d3e3d1238c4ea00, 0x3f82145e939e0000), (0xbd38073eeaf8eaf3, 0x3f861e77e8b60000), (0xbd3f73bc4d6d3472, 0x3f8a2a9c6c180000), (0xbd39de88a3da281a, 0x3f8e38ce30340000), (0x3d3fdbe5fed4b393, 0x3f912487a5500000), (0x3d2710cb130895fc, 0x3f932db0ea130000), (0x3d2ab259d2d7f253, 0x3f9537e3f45f0000), (0x3d07abf389596542, 0x3f963d6178690000), (0xbd2aa0ba325a0c34, 0x3f98492528c90000), (0xbd2de0709f2d03c9, 0x3f9a55f548c60000), (0xbd35439ce030a687, 0x3f9c63d2ec150000), (0xbd28d75149774d47, 0x3f9e72bf28140000), (0xbd3dddc7f461c516, 0x3fa0415d89e78000), (0xbd32b98a9a4168fd, 0x3fa149e3e4008000), (0x3d283e9ae021b67b, 0x3fa252f32f8d0000), (0x3d38357d5ef9eb35, 0x3fa35c8bfaa10000), (0x3d3748ed3f6e378e, 0x3fa3e18c1ca08000), (0xbd2d9150f73be773, 0x3fa4ebf4334a0000), (0xbd20485a8012494c, 0x3fa5f6e730790000), (0xbd2888df11fd5ce7, 0x3fa70265a5510000), (0xbd399dc16f28bf45, 0x3fa80e7023d90000), (0xbd19d7c53f76ca96, 0x3fa91b073efd8000), (0xbd30c22e4ec4d90d, 0x3fa9a187b5740000), (0x3d20fc1a353bb42e, 0x3faaaef2d0fb0000), (0xbd17bf868c317c2a, 0x3fabbcebfc690000), (0x3d3965c36e09f5fe, 0x3faccb73cddd8000), (0xbd21b1ac64d9e42f, 0x3fadda8adc680000), (0xbd30f25c74676689, 0x3fae624c4a0b8000), (0xbd3d6eb0dd5610d3, 0x3faf723b51800000), (0x3d1111c05cf1d753, 0x3fb0415d89e74000), (0x3d2c2da80974d976, 0x3fb0c9e615ac4000), (0xbd37cf69284a3465, 0x3fb10e45b3cb0000), (0x3d3566d154f930b3, 0x3fb1973bd1464000), (0x3d349d8cfc10c7bf, 0x3fb2207b5c784000), (0x3d37a48ba8b1cb41, 0x3fb2aa04a4470000), (0x3d08081edd77c860, 0x3fb2eee507b40000), (0x3d37141128f1faca, 0x3fb378dd7f748000), (0x3d26fd84aa8157c0, 0x3fb403207b414000), (0x3d3fad46e8d26ab7, 0x3fb4485e03dbc000), (0xbcf53a2582f4e1ef, 0x3fb4d3115d208000), (0x3d0c1d740c53c72e, 0x3fb55e10050e0000), (0x3d31cb7ce1d17171, 0x3fb5e95a4d978000), (0xbd2179957ed63c4e, 0x3fb62f1be7d78000), (0x3d0daf3cc08926ae, 0x3fb6bad83c188000), (0xbd3126d16e1e21d2, 0x3fb746e100228000), (0x3d069b5794b69fb7, 0x3fb78d02263d8000), (0xbd3c0fe460d20041, 0x3fb8197e2f410000), (0x3d3c28c0af9bd6df, 0x3fb8a6477a91c000), (0xbd222f39be67f7aa, 0x3fb8ecc933aec000), (0xbcf8bcc1732093ce, 0x3fb97a07024cc000), (0xbd0a9ce6c9ad51bf, 0x3fba0792e9278000), (0xbd0e42b6b94407c8, 0x3fba4e7640b1c000), (0xbd3573b209c31904, 0x3fbadc77ee5b0000), (0xbceff64eea137079, 0x3fbb23965a530000), (0xbd368ba835459b8e, 0x3fbbb20e936d8000), (0x3d3cb1121d1930dd, 0x3fbc40d6425a4000), (0x3d2646d1c65aacd3, 0x3fbc885801bc4000), (0x3d336433b5efbeed, 0x3fbd179788218000), (0x3d30e239cc185469, 0x3fbd5f5565920000), (0xbd324750412e9a74, 0x3fbdef0d8d468000), (0xbd32c1c59bc77bfa, 0x3fbe7f1691a34000), (0x3d311fcba80cdd10, 0x3fbec739830a0000), (0x3d176a6c9ea8b04e, 0x3fbf57bc7d900000), (0xbd08f351fa48a730, 0x3fbfa01c9db58000), (0x3d03f9651cff9dfe, 0x3fc0188d2ecf6000), (0x3d381a9cf169fc5c, 0x3fc03cdc0a51e000), (0xbd27e5dd7009902c, 0x3fc08598b59e4000), (0xbd345519d7032129, 0x3fc0aa0691268000), (0xbd3e09b441ae86c5, 0x3fc0f301717d0000), (0xbd2cf5fdd94f6509, 0x3fc13c2605c3a000), (0x3d2ec2d2a9009e3d, 0x3fc160c8024b2000), (0xbd31ac38dde3b366, 0x3fc1aa2b7e240000), (0xbd315c1c39192af9, 0x3fc1ceed09854000), (0xbd3b3a1e7f50c701, 0x3fc2188fd9808000), (0x3d100d238fd3df5c, 0x3fc23d712a49c000), (0x3d37494e359302e6, 0x3fc28753bc11a000), (0xbd1d3466d0c6c8a8, 0x3fc2ac55095f6000), (0x3d352b302160f40d, 0x3fc2f677cbbc0000), (0x3d3f098ee3a50810, 0x3fc31b994d3a4000), (0xbd3fd3a0afb9691b, 0x3fc365fcb015a000), (0xbd370ef0545c17f9, 0x3fc38b3e9e028000), (0x3d13fb2f85096c4b, 0x3fc3d5e3126bc000), (0x3d319713c0cae559, 0x3fc3fb45a5992000), (0xbd116282c85a0884, 0x3fc420b327410000), (0xbd1249cd0790841a, 0x3fc46baf0f9f6000), (0xbd353e43558124c4, 0x3fc4913d8333c000), (0x3d0c79b60ae1ff0f, 0x3fc4dc7b897bc000), (0x3d348a05ff36a25b, 0x3fc5022b292f6000), (0x3d2746fee5c8d0d8, 0x3fc54dabc2610000), (0x3d39baa7a6b887f6, 0x3fc5737cc9018000), (0xbd127023eb68981c, 0x3fc5bf406b544000), (0xbd31ce0bf3b290ea, 0x3fc5e533144c2000), (0xbd371456c988f814, 0x3fc60b3100b0a000), (0xbd398c1d34f0f462, 0x3fc6574ebe8c2000), (0xbd311e8830a706d3, 0x3fc67d6e9d786000), (0xbcdc73fafd9b2dca, 0x3fc6c9d07d204000), (0x3d3577390d31ef0f, 0x3fc6f0128b756000), (0x3ce51b157cec3838, 0x3fc716600c914000), (0xbd25e77dc7c5f3e1, 0x3fc7631d82936000), (0x3d38e67be3dbaf3f, 0x3fc7898d85444000), (0xbd24c06b17c301d7, 0x3fc7d6903caf6000), (0xbd158bebf457b7d2, 0x3fc7fd22ff59a000), (0x3d1e0ddb9a631e83, 0x3fc823c16551a000), (0x3d3328eb42f9af75, 0x3fc871213750e000), (0xbd296b37380cbe9e, 0x3fc897e2b17b2000), (0xbd073d54aae92cd1, 0x3fc8beafeb390000), (0xbd1935f57718d7ca, 0x3fc90c6db9fcc000), (0x3d33115c3abd47da, 0x3fc9335e5d594000), (0x3d07f22858a0ff6f, 0x3fc95a5adcf70000), (0x3d3470fa3efec390, 0x3fc9a8778deba000), (0x3d3d862f10c414e3, 0x3fc9cf97cdce0000), (0xbd3337d94bcd3f43, 0x3fc9f6c40708a000), (0x3d360a77c81f7171, 0x3fca454082e6a000), (0xbd3f63b7f037b0c6, 0x3fca6c90d44b8000), (0xbd28724350562169, 0x3fca93ed3c8ae000), (0x3d37a8d5ae54f550, 0x3fcae2ca6f672000), (0xbd22e72d5c3998ed, 0x3fcb0a4b48fc2000), (0x3d3c794e562a63cb, 0x3fcb31d8575bc000), (0x3d1e90683b9cd768, 0x3fcb811730b82000), (0x3d3a32e7f44432da, 0x3fcba8c90ae4a000), (0xbd2d4bc4595412b6, 0x3fcbd087383be000), (0xbd292e0ee55c7ac6, 0x3fcc2028ab180000), (0x3d39a294d5e44e76, 0x3fcc480c0005c000), (0x3d3ee138d3a69d43, 0x3fcc6ffbc6f00000), (0x3d23b161a8c6e6c5, 0x3fcc97f8079d4000), (0xbd29e0aba2099515, 0x3fcce816157f2000), (0xbd084a7e75b6f6e4, 0x3fcd1037f2656000), (0xbd373650b38932bc, 0x3fcd386668720000), (0xbd375f280234bf51, 0x3fcd88e93fb30000), (0x3d32806a847527e6, 0x3fcdb13db0d48000), (0xbd302ec669c756eb, 0x3fcdd99edaf6e000), (0xbd252b00adb91424, 0x3fce020cc6236000), (0xbd3fdbdbb13f7c18, 0x3fce530effe72000), (0xbd0d5eee23793649, 0x3fce7ba35eb78000), (0x3d35e91663732a36, 0x3fcea4449f04a000), (0xbd3bec63a3e75640, 0x3fceccf2c8fea000), (0xbcca211565bb8e11, 0x3fcef5ade4dd0000), (0xbd3bae49f1df7b5e, 0x3fcf474b134e0000), (0xbd10819516673e23, 0x3fcf702d36778000), (0xbd390d04cd7cc834, 0x3fcf991c6cb3c000), (0x3d34bba46f1cf6a0, 0x3fcfc218be620000), (0x3d31cd8d688b9e18, 0x3fd00a1c6adda000), (0x3d3a43dcfade85ae, 0x3fd01eae5626c000), (0x3cf89ff8a966395c, 0x3fd03346e0106000), (0x3d2dbdf10d397f3c, 0x3fd047e60cde8000), (0x3d2ad0f1c77ccb58, 0x3fd05c8be0d96000), (0x3d3e5d513f45fe7b, 0x3fd085eb8f8ae000), (0x3d3b50a1e1734342, 0x3fd09aa572e6c000), (0x3d23c7c3f528d80a, 0x3fd0af660eb9e000), (0x3d27188b163ceae9, 0x3fd0c42d67616000), (0x3d1ee8c88753fa35, 0x3fd0d8fb813eb000), (0xbd2f1fbddfdfd686, 0x3fd102ac0a35d000), (0x3d31ef78ce2d07f2, 0x3fd1178e8227e000), (0x3d13b2948a11f797, 0x3fd12c77cd007000), (0x3d3e0c07824daaf5, 0x3fd14167ef367000), (0xbcee75adfb6aba25, 0x3fd1565eed456000), (0xbd323299042d74bf, 0x3fd16b5ccbad0000), (0x3d27d2f73ad1aa14, 0x3fd1956d3b9bc000), (0x3d29f60a9616f7a0, 0x3fd1aa7fd638d000), (0xbd31ac89575c2125, 0x3fd1bf99635a7000), (0x3d222a667c42e56d, 0x3fd1d4b9e796c000), (0xbd382eaed3c8b65e, 0x3fd1e9e16788a000), (0x3d3e9d5b513ff0c1, 0x3fd1ff0fe7cf4000), (0xbd3caf0428b728a3, 0x3fd214456d0ec000), (0xbd36dbe448a2e522, 0x3fd23ec5991ec000), (0x3d3b1d7ac0ef77f2, 0x3fd25410494e5000), (0xbd31b61f10522625, 0x3fd269621134e000), (0xbd2b198800b4bda7, 0x3fd27ebaf58d9000), (0xbd3210c2b730e28b, 0x3fd2941afb187000), (0xbd22058e557285cf, 0x3fd2a982269a4000), (0x3d2a9cfa4a5004f4, 0x3fd2bef07cdc9000), (0xbd288d0ddcd54196, 0x3fd2d46602add000), (0xbd38aed2541e6e2e, 0x3fd2ff66b04eb000), (0xbd28e27ad3213cb8, 0x3fd314f1e1d36000), (0x3d04f928139af5d6, 0x3fd32a8456512000), (0xbd317c73556e291d, 0x3fd3401e12aed000), (0xbd2ba99b8964f0e8, 0x3fd355bf1bd83000), (0x3d116ecdb0f177c8, 0x3fd36b6776be1000), (0xbd2a71e493a0702b, 0x3fd3811728565000), (0xbd05839c5663663d, 0x3fd396ce359bc000), (0xbd2d0befbc02be4a, 0x3fd3ac8ca38e6000), (0x3d183b54b606bd5c, 0x3fd3c25277333000), (0xbd222c7c2a9d37a4, 0x3fd3d81fb5947000), (0xbd3f067c297f2c3f, 0x3fd3edf463c17000), (0xbd3ce379226de3ec, 0x3fd419b423d5f000), (0x3d3906440f7d3354, 0x3fd42f9f3ff62000), (0xbd06e95892923d88, 0x3fd44591e053a000), (0xbd0d9120e7d0a853, 0x3fd45b8c0a17e000), (0x3d306c18fb4c14c5, 0x3fd4718dc271c000), (0x3d3dc1b8465cf25f, 0x3fd487970e958000), (0x3d307b334daf4b9a, 0x3fd49da7f3bcc000), (0xbd165b4681052b9f, 0x3fd4b3c077268000), (0xbd2e20891b0ad8a4, 0x3fd4c9e09e173000), (0xbd34d692a1e44788, 0x3fd4e0086dd8c000), (0xbd3fc158cb3124b9, 0x3fd4f637ebbaa000), (0xbd3a0e6b7e827c2c, 0x3fd50c6f1d11c000), (0x3d2ebe708164c759, 0x3fd522ae0738a000), (0x3d27ec02e45547ce, 0x3fd538f4af8f7000), (0x3d1a8954c0910952, 0x3fd54f431b7be000), (0x3d14c5fd2badc774, 0x3fd5659950695000), (0x3d1fadedee5d40ef, 0x3fd57bf753c8d000), (0xbd369bf5a7a56f34, 0x3fd5925d2b113000), (0xbcf7c79b0af7ecf8, 0x3fd5a8cadbbee000), (0xbd227023eb68981c, 0x3fd5bf406b544000), (0xbd0a0b2a08a465dc, 0x3fd5d5bddf596000), (0x3d36b71a1229d17f, 0x3fd5ec433d5c3000), (0x3d1ebe9176df3f65, 0x3fd602d08af09000), (0xbd2f08ad603c488e, 0x3fd61965cdb03000), (0xbd2db623e731ae00, 0x3fd630030b3ab000), ]; pxfm-0.1.23/src/logs/log2p1f.rs000064400000000000000000000325641046102023000142460ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use std::hint::black_box; static IX: [u64; 129] = [ 0x3ff0000000000000, 0x3fefc07f01fc0000, 0x3fef81f81f820000, 0x3fef44659e4a0000, 0x3fef07c1f07c0000, 0x3feecc07b3020000, 0x3fee9131abf00000, 0x3fee573ac9020000, 0x3fee1e1e1e1e0000, 0x3fede5d6e3f80000, 0x3fedae6076ba0000, 0x3fed77b654b80000, 0x3fed41d41d420000, 0x3fed0cb58f6e0000, 0x3fecd85689040000, 0x3feca4b3055e0000, 0x3fec71c71c720000, 0x3fec3f8f01c40000, 0x3fec0e0703820000, 0x3febdd2b89940000, 0x3febacf914c20000, 0x3feb7d6c3dda0000, 0x3feb4e81b4e80000, 0x3feb2036406c0000, 0x3feaf286bca20000, 0x3feac5701ac60000, 0x3fea98ef606a0000, 0x3fea6d01a6d00000, 0x3fea41a41a420000, 0x3fea16d3f97a0000, 0x3fe9ec8e95100000, 0x3fe9c2d14ee40000, 0x3fe99999999a0000, 0x3fe970e4f80c0000, 0x3fe948b0fcd60000, 0x3fe920fb49d00000, 0x3fe8f9c18f9c0000, 0x3fe8d3018d300000, 0x3fe8acb90f6c0000, 0x3fe886e5f0ac0000, 0x3fe8618618620000, 0x3fe83c977ab20000, 0x3fe8181818180000, 0x3fe7f405fd020000, 0x3fe7d05f417e0000, 0x3fe7ad2208e00000, 0x3fe78a4c81780000, 0x3fe767dce4340000, 0x3fe745d1745e0000, 0x3fe724287f460000, 0x3fe702e05c0c0000, 0x3fe6e1f76b440000, 0x3fe6c16c16c20000, 0x3fe6a13cd1540000, 0x3fe6816816820000, 0x3fe661ec6a520000, 0x3fe642c8590c0000, 0x3fe623fa77020000, 0x3fe6058160580000, 0x3fe5e75bb8d00000, 0x3fe5c9882b940000, 0x3fe5ac056b020000, 0x3fe58ed230820000, 0x3fe571ed3c500000, 0x3fe5555555560000, 0x3fe5390948f40000, 0x3fe51d07eae20000, 0x3fe5015015020000, 0x3fe4e5e0a7300000, 0x3fe4cab887260000, 0x3fe4afd6a0520000, 0x3fe49539e3b20000, 0x3fe47ae147ae0000, 0x3fe460cbc7f60000, 0x3fe446f865620000, 0x3fe42d6625d60000, 0x3fe4141414140000, 0x3fe3fb013fb00000, 0x3fe3e22cbce40000, 0x3fe3c995a47c0000, 0x3fe3b13b13b20000, 0x3fe3991c2c180000, 0x3fe3813813820000, 0x3fe3698df3de0000, 0x3fe3521cfb2c0000, 0x3fe33ae45b580000, 0x3fe323e34a2c0000, 0x3fe30d1901300000, 0x3fe2f684bda20000, 0x3fe2e025c04c0000, 0x3fe2c9fb4d820000, 0x3fe2b404ad020000, 0x3fe29e4129e40000, 0x3fe288b012880000, 0x3fe27350b8820000, 0x3fe25e2270800000, 0x3fe24924924a0000, 0x3fe23456789a0000, 0x3fe21fb781220000, 0x3fe20b470c680000, 0x3fe1f7047dc20000, 0x3fe1e2ef3b400000, 0x3fe1cf06ada20000, 0x3fe1bb4a40460000, 0x3fe1a7b9611a0000, 0x3fe19453808c0000, 0x3fe1811811820000, 0x3fe16e0689420000, 0x3fe15b1e5f760000, 0x3fe1485f0e0a0000, 0x3fe135c811360000, 0x3fe12358e75e0000, 0x3fe1111111120000, 0x3fe0fef010fe0000, 0x3fe0ecf56be60000, 0x3fe0db20a8900000, 0x3fe0c9714fbc0000, 0x3fe0b7e6ec260000, 0x3fe0a6810a680000, 0x3fe0953f39020000, 0x3fe0842108420000, 0x3fe073260a480000, 0x3fe0624dd2f20000, 0x3fe05197f7d80000, 0x3fe0410410420000, 0x3fe03091b5200000, 0x3fe0204081020000, 0x3fe0101010100000, 0x3fe0000000000000, ]; static LIX: [u64; 129] = [ 0x0000000000000000, 0xbf86fe50b6f1eafa, 0xbf96e79685c160d5, 0xbfa11cd1d51955ba, 0xbfa6bad37591e030, 0xbfac4dfab908ddb5, 0xbfb0eb389fab4795, 0xbfb3aa2fdd26ae99, 0xbfb663f6faca846b, 0xbfb918a16e4cb157, 0xbfbbc84240a78a13, 0xbfbe72ec1181cfb1, 0xbfc08c588cd964e4, 0xbfc1dcd19759f2e3, 0xbfc32ae9e27627c6, 0xbfc476a9f989a58a, 0xbfc5c01a39fa6533, 0xbfc70742d4eed455, 0xbfc84c2bd02d6434, 0xbfc98edd077e9f0a, 0xbfcacf5e2db31eea, 0xbfcc0db6cddaa82d, 0xbfcd49ee4c33121a, 0xbfce840be751d775, 0xbfcfbc16b9003e0b, 0xbfd0790adbae3fc0, 0xbfd11307dad465b5, 0xbfd1ac05b2924cc5, 0xbfd24407ab0cc410, 0xbfd2db10fc4ea424, 0xbfd37124cea58697, 0xbfd406463b1d455d, 0xbfd49a784bcbaa37, 0xbfd52dbdfc4f341d, 0xbfd5c01a39ff2c9b, 0xbfd6518fe46abaa5, 0xbfd6e221cd9d6933, 0xbfd771d2ba7f5791, 0xbfd800a56315ee2a, 0xbfd88e9c72df8611, 0xbfd91bba891d495f, 0xbfd9a8023920fa4d, 0xbfda33760a7fbca6, 0xbfdabe18797d2eff, 0xbfdb47ebf734b923, 0xbfdbd0f2e9eb2b84, 0xbfdc592fad2be1aa, 0xbfdce0a4923cf5e6, 0xbfdd6753e02f4ebc, 0xbfdded3fd445af00, 0xbfde726aa1e558fe, 0xbfdef6d67325ba38, 0xbfdf7a8568c8aea6, 0xbfdffd799a81be87, 0x3fdf804ae8d33c40, 0x3fdefec61b04af4e, 0x3fde7df5fe572606, 0x3fddfdd89d5b0009, 0x3fdd7e6c0abbd924, 0x3fdcffae611a74d6, 0x3fdc819dc2d8578c, 0x3fdc043859e5bdbc, 0x3fdb877c57b47c04, 0x3fdb0b67f4f29a66, 0x3fda8ff97183ed07, 0x3fda152f14293c74, 0x3fd99b072a9289ca, 0x3fd921800927e284, 0x3fd8a8980ac41130, 0x3fd8304d90c2859d, 0x3fd7b89f02cbd49a, 0x3fd7418aceb84ab1, 0x3fd6cb0f68656c95, 0x3fd6552b49993dc2, 0x3fd5dfdcf1eacd7b, 0x3fd56b22e6b97c18, 0x3fd4f6fbb2ce6943, 0x3fd48365e6957b42, 0x3fd4106017c0dbcf, 0x3fd39de8e15727d9, 0x3fd32bfee37489bc, 0x3fd2baa0c34989c3, 0x3fd249cd2b177fd5, 0x3fd1d982c9d50468, 0x3fd169c0536677ac, 0x3fd0fa848045f67b, 0x3fd08bce0d9a7c60, 0x3fd01d9bbcf66a2c, 0x3fcf5fd8a90e2d85, 0x3fce857d3d3af1e5, 0x3fcdac22d3ec5f4e, 0x3fccd3c712db459a, 0x3fcbfc67a7ff3c22, 0x3fcb2602497678f4, 0x3fca5094b555a1f8, 0x3fc97c1cb136b96f, 0x3fc8a8980ac8652d, 0x3fc7d60496c83f66, 0x3fc7046031c7cdaf, 0x3fc633a8bf460335, 0x3fc563dc2a08b102, 0x3fc494f863bbc1de, 0x3fc3c6fb6507a37e, 0x3fc2f9e32d5257ec, 0x3fc22dadc2a627ef, 0x3fc1625931802e49, 0x3fc097e38cef9519, 0x3fbf9c95dc138295, 0x3fbe0b1ae90505f6, 0x3fbc7b528b5fcffa, 0x3fbaed391abb17a1, 0x3fb960caf9bd35ea, 0x3fb7d60496e3edeb, 0x3fb64ce26bf2108e, 0x3fb4c560fe5b573b, 0x3fb33f7cde24adfb, 0x3fb1bb32a5ed9353, 0x3fb0387efbd3006e, 0x3fad6ebd1f1d0955, 0x3faa6f9c37a8beab, 0x3fa77394c9d6762c, 0x3fa47aa07358e1a4, 0x3fa184b8e4d490ef, 0x3f9d23afc4d95c78, 0x3f9743ee8678a7cb, 0x3f916a21e243bf78, 0x3f872c7ba20c907e, 0x3f7720d9c0536e17, 0x0000000000000000, ]; // |x| < 1.3862943452718848 #[cold] fn log2p1f_small(z: f64, ax: u32, ux: u32) -> f32 { let z2 = z * z; let z4 = z2 * z2; if ax < 0x3b9d9d34u32 { // |x| < 0x1.3b3a68p-8 if ax < 0x39638a7eu32 { // |x| < 0x1.c714fcp-13 if ax < 0x329c5639u32 { // |x| < 0x1.38ac72p-26 const C: [u64; 2] = [0x3ff71547652b82fe, 0xbfe71547652b82ff]; let res = z * f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); res as f32 } else { if ux == 0x32ff7045u32 { return black_box(f32::from_bits(0x3338428d)) - black_box(f32::from_bits(0x17c00000)); } if ux == 0xb395efbbu32 { return black_box(f32::from_bits(0xb3d85005)) + black_box(f32::from_bits(0x19800000)); } if ux == 0x35a14df7u32 { return black_box(f32::from_bits(0x35e8b690)) + black_box(f32::from_bits(0x1b800000)); } if ux == 0x3841cb81u32 { return black_box(f32::from_bits(0x388bca4f)) + black_box(f32::from_bits(0x1e000000)); } const C: [u64; 4] = [ 0x3ff71547652b82fe, 0xbfe71547652b82fd, 0x3fdec709ead0c9a7, 0xbfd7154773c1cb29, ]; let zxf0 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let zxf1 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let zxf = z * f_fmla(z2, zxf0, zxf1); zxf as f32 } } else { if ux == 0xbac9363du32 { return black_box(f32::from_bits(0xbb114155)) + black_box(f32::from_bits(0x21000000)); } const C: [u64; 6] = [ 0x3ff71547652b82fe, 0xbfe71547652b8300, 0x3fdec709dc28f51b, 0xbfd7154765157748, 0x3fd2778a510a3682, 0xbfcec745df1551fc, ]; let zxf0 = f_fmla(z, f64::from_bits(C[5]), f64::from_bits(C[4])); let zxf1 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let zxf2 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let zw0 = f_fmla(z2, zxf1, zxf2); let zxf = z * f_fmla(z4, zxf0, zw0); zxf as f32 } } else { const C: [u64; 8] = [ 0x3ff71547652b82fe, 0xbfe71547652b82fb, 0x3fdec709dc3b6a73, 0xbfd71547652dc090, 0x3fd2776c1a889010, 0xbfcec7095bd4d208, 0x3fca66bec7fc8f70, 0xbfc71a900fc3f3f9, ]; let zxf0 = f_fmla(z, f64::from_bits(C[7]), f64::from_bits(C[6])); let zxf1 = f_fmla(z, f64::from_bits(C[5]), f64::from_bits(C[4])); let zxf2 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let zxf3 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let zw0 = f_fmla(z2, zxf0, zxf1); let zw1 = f_fmla(z2, zxf2, zxf3); let zxf = z * f_fmla(z4, zw0, zw1); zxf as f32 } } /// Computes log2(x+1) /// /// Max ULP 0.5 #[inline] pub fn f_log2p1f(x: f32) -> f32 { let mut z = x as f64; let t = x.to_bits(); let ux = t; let ax = ux & 0x7fff_ffff; if ux >= 0x17fu32 << 23 { // x <= -1 if ux == (0x17fu32 << 23) { return f32::NEG_INFINITY; // -1.0 } if ux > (0x1ffu32 << 23) { return x + x; } // nan f32::NAN // x < -1 } else if ax >= (0xff << 23) { // +inf, nan if ax > (0xff << 23) { return x + x; } // nan f32::INFINITY } else if ax < 0x3cb7aa26u32 { // |x| < 1.3862943452718848 log2p1f_small(z, ax, ux) } else { // |x| >= 0x1.6f544cp-6 if ux == 0x4ebd09e3u32 { let h = f32::from_bits(0x41f48013); let l = f32::from_bits(0x35780000); return black_box(h) + black_box(l); } let tp = (z + 1.0).to_bits(); let m = tp & 0x000fffffffffffff; let mut e: i32 = (tp >> 52).wrapping_sub(0x3ff) as i32; let j: i32 = ((m as i64).wrapping_add(1i64 << (52 - 8)) >> (52 - 7)) as i32; let k = if j > 53 { 1 } else { 0 }; e += k; let xd = m | 0x3ffu64 << 52; z = f_fmla(f64::from_bits(xd), f64::from_bits(IX[j as usize]), -1.0); const C: [u64; 6] = [ 0x3ff71547652b82fe, 0xbfe71547652b82ff, 0x3fdec709dc32988b, 0xbfd715476521ec2b, 0x3fd277801a1ad904, 0xbfcec731704d6a88, ]; let z2 = z * z; let mut c0 = f_fmla(z, f64::from_bits(C[1]), f64::from_bits(C[0])); let c2 = f_fmla(z, f64::from_bits(C[3]), f64::from_bits(C[2])); let c4 = f_fmla(z, f64::from_bits(C[5]), f64::from_bits(C[4])); let zv0 = f_fmla(z2, c4, c2); c0 = f_fmla(z2, zv0, c0); let res = f_fmla(z, c0, -f64::from_bits(LIX[j as usize])) + e as f64; res as f32 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_log2p1f() { assert_eq!(f_log2p1f(0.0), 0.0); assert_eq!(f_log2p1f(1.0), 1.0); assert_eq!(f_log2p1f(-0.0432432), -0.063775845); assert_eq!(f_log2p1f(-0.009874634), -0.01431689); assert_eq!(f_log2p1f(1.2443), 1.1662655); assert!(f_log2p1f(-1.0432432).is_nan()); } } pxfm-0.1.23/src/logs/log2td.rs000064400000000000000000000116511046102023000141610ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::logs::log2td_coeffs::LOG2_NEG_TD; use crate::pow_tables::POW_INVERSE; use crate::triple_double::TripleDouble; #[inline(always)] fn log2_poly(z: f64) -> TripleDouble { /* See ./notes/dd_log.sollya */ const P: [(u64, u64, u64); 11] = [ (0x38cb46674646bfff, 0x3c7777d0ffda0d23, 0x3ff71547652b82fe), (0xb90ea6e2f55cd900, 0xbc6777d0ffe87198, 0xbfe71547652b82fe), (0x391e004d54467330, 0x3c7d27f0556d8546, 0x3fdec709dc3a03fd), (0xb8b2d21aeeb27bff, 0xbc5775b3aa82c433, 0xbfd71547652b82fe), (0xb9164a4a186a0c00, 0x3c7e49c9bdb8b680, 0x3fd2776c50ef9bfe), (0xb8efe23702b5a940, 0x3c6195ba6326b1bf, 0xbfcec709dc3a0414), (0x38d7695a46fb4b00, 0x3c6f82e7add9bb4d, 0x3fca61762a7adf00), (0xb8c00e9d3285e000, 0x3c2caf76a9ee1e78, 0xbfc7154764fba5e4), (0xb8d1ff2b356eee80, 0xbc3f6102bc5ddc49, 0x3fc484b13d3bbed8), (0xb8edd22b4add09c0, 0x3c4c1da4a1a32f3b, 0xbfc2779952952c26), (0x388875bd65660001, 0x3c58e09839d588dd, 0x3fc0c9d962b39a7d), ]; let mut t = TripleDouble::from_bit_pair(P[10]); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[9])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[8])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[7])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[6])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[5])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[4])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[3])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[2])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[1])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[0])); TripleDouble::quick_mult_f64(t, z) } #[inline] pub(crate) fn log2_td(x: f64) -> TripleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log2(x) = log2(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = TripleDouble::from_bit_pair(LOG2_NEG_TD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); let v = TripleDouble::add_f64(be as f64, log_r); let p = log2_poly(z); TripleDouble::add_f64(v.hi, TripleDouble::new(v.lo + p.lo, v.mid + p.mid, p.hi)) } #[cfg(test)] mod tests { use crate::logs::log2td::log2_td; #[test] fn log2td_test() { assert_eq!(log2_td(0.0040283203125 / 2.).to_f64(), -8.955605880641546); } } pxfm-0.1.23/src/logs/log2td_coeffs.rs000064400000000000000000000332761046102023000155150ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by SageMath: ```python values = POW_INV R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] real_array = [R(hex_to_float(h)) for h in values] for r in real_array: print_triple_double("", -RealField(180)(r).log2()) ``` **/ pub(crate) static LOG2_NEG_TD: [(u64, u64, u64); 182] = [ (0x390941b6615224a5, 0xbc61d46ccc53c278, 0xbfdfbc16b902680a), (0x38f07da8aa70916c, 0x3c6780e41697a095, 0xbfdf38c567bcc541), (0x391d3c8f5fd3dc67, 0xbc74f9727980f5ed, 0xbfdeb4b847d15bce), (0xb8e739d205efb04e, 0xbc4be44aae7442ab, 0xbfde2fed3d097298), (0x3898c9127b6c16fb, 0xbc1274a5715611b7, 0xbfddaa6222064fb9), (0xb9196a462f40def6, 0xbc74856fb52a53d2, 0xbfdd2414c80bf27d), (0x390bea8fdeb55632, 0x3c6b517ae88c2fd3, 0xbfdce0a4923a587d), (0xb908a7815661988f, 0xbc7f9fb952bbbccc, 0xbfdc592fad295b56), (0xb8e453488bf5b6cc, 0x3c752ef4c737fba5, 0xbfdbd0f2e9e79031), (0x38fc548eb57fa11c, 0x3c76fae441c09d76, 0xbfdb47ebf73882a1), (0xb8fc786e3d2aafcf, 0x3c5e5b8daaa73a43, 0xbfdabe18797f1f49), (0xb91b1fdcc00753ce, 0x3c78a0efca1a184f, 0xbfda33760a7f6051), (0x38fa1959f815466e, 0x3c7dc938c18e544d, 0xbfd9edd6759b25e0), (0xb9153e596854d8d8, 0x3c7cc298a148e6ca, 0xbfd961f90527409c), (0xb8ebb343d8cce6ac, 0x3c7530bdb6949302, 0xbfd8d54673b5c372), (0x38f53bc13892380d, 0x3c76d266d6cdc959, 0xbfd88e9c72e0b226), (0xb90911b0bd8dfc92, 0xbc69575b04fa6fbd, 0xbfd800a563161c54), (0x38ac786dcf6b587c, 0x3c5b90132aeddb58, 0xbfd771d2ba7efb3c), (0x38edde6c0edf5f9b, 0xbc75e35482d13dc1, 0xbfd6e221cd9d0cde), (0x390079b0d8796cf7, 0xbc7a3152150d2dbf, 0xbfd699f5248cd4b8), (0xb9015c2742b99e22, 0x3c7a43fc62b7e690, 0xbfd608f1b42948ae), (0x38f48bb6c3065717, 0x3c7817fd3b7d7e5d, 0xbfd5c01a39fbd688), (0xb912cbbddfbc3c96, 0xbc7f73d83987f26d, 0xbfd52dbdfc4c96b3), (0x38b2cc9a4ea80721, 0x3c1b6d40900b2502, 0xbfd49a784bcd1b8b), (0x390e110ddda53ed5, 0x3c7aca97d800ce47, 0xbfd4507cfedd4fc4), (0xb91d40a85c203c0a, 0x3c7a9f3c8bc9672e, 0xbfd3bbd3a0a1dcfb), (0xb8f186e41376f461, 0x3c63376649b4fc09, 0xbfd37124cea4cded), (0xb90b8ee38b380b8c, 0xbc7bc4de8f631bcf, 0xbfd2db10fc4d9aaf), (0x391f0463d2dc68ee, 0xbc78c0e85a908be6, 0xbfd28fab35b32683), (0x390dfcf160587090, 0xbc65f43469fbe6ea, 0xbfd1f825f6d88e13), (0xb91a061db1cd272d, 0xbc74a31ce1b7e328, 0xbfd1ac05b291f070), (0xb903f833b9cd87fa, 0x3c6a7b47d2c352d9, 0xbfd11307dad30b76), (0xb90ea304fc9566d2, 0x3c76c13816f9f480, 0xbfd0c62975542a8f), (0x38f4999ebc7b5be1, 0xbc7bc0c69a675517, 0xbfd0790adbb03009), (0x38f941b6615224a5, 0xbc51d46ccc53c278, 0xbfcfbc16b902680a), (0x390b074c63fc2e10, 0xbc61dd4a99cc633b, 0xbfcf205339208f27), (0x38bd01b29154c9bc, 0x3c4e41bd8c32e1be, 0xbfcde73fe3b1480f), (0x38f77c80fa9696aa, 0x3c5b85a54d7ee2fd, 0xbfcd49ee4c325970), (0xb902de32e0e76d80, 0x3c6a4ecd69d3b872, 0xbfccac163c770dc9), (0x38bfcd52b1405dd8, 0xbc6afb63338bed1f, 0xbfcb6ecf175f95e9), (0xb8da5a90415f750a, 0x3c401ee1343fe7ca, 0xbfcacf5e2db4ec94), (0xb8edc57adc0d07e5, 0x3c5ae3bd6c6d42f0, 0xbfca2f632320b86b), (0xb8fbd5bde9064fc5, 0x3c628caf799ad993, 0xbfc8edcae8352b6c), (0x38b1e10526896a05, 0x3c116edb88c4e2b5, 0xbfc84c2bd02f03b3), (0x38d23d3d07963ee8, 0x3c3d0364be23e873, 0xbfc7a9fec7d05ddf), (0x38f4a786b5f060aa, 0xbc6f3314e0985116, 0xbfc663f6fac91316), (0x38e48bb6c3065717, 0x3c6817fd3b7d7e5d, 0xbfc5c01a39fbd688), (0x390a35613d82ada7, 0xbc622c022616fdff, 0xbfc51bab907a5c8a), (0xb8c3eeadb3c7c4e9, 0xbc589c74a0b21fb6, 0xbfc476a9f983f74d), (0x38e66c9ab03b4ece, 0xbc4f51f2c075a74c, 0xbfc32ae9e278ae1a), (0xb8d9632ea3495efa, 0x3c6ca25d54d6f775, 0xbfc284294b07a640), (0xb90575a87dd48ab4, 0xbc67a9150c1e0e58, 0xbfc1dcd197552b7b), (0x38536121d3d82a7d, 0x3bf94b7dfe0d99a5, 0xbfc134e1b489062e), (0x38f9009af5640e65, 0x3c5becb2e71abdc8, 0xbfbfc66a0f0b00a5), (0xb893a950ee2d9c26, 0xbc3cbdb5d9dc29f2, 0xbfbe72ec117fa5b2), (0xb8f8af0cb05a0a5c, 0xbc5342ce3cc8f2f9, 0xbfbd1e34e35b82da), (0x38f47869be3af7ef, 0xbc58ecb169b9465f, 0xbfbbc84240adabba), (0x38d3b67d8a9115c0, 0x3c34bba7e1c43d2c, 0xbfba7111df348494), (0x38d737dca6ec6478, 0x3c5463736dac9317, 0xbfb918a16e46335b), (0x38e4a786b5f060aa, 0xbc5f3314e0985116, 0xbfb663f6fac91316), (0xb8d0a7b1e526a7c3, 0x3c458696424b2e96, 0xbfb507b836033bb7), (0xb8dda9b52342f8f1, 0x3c43fd9776f25acf, 0xbfb3aa2fdd27f1c3), (0x38ff4924636e235a, 0x3c5d974c32ba8269, 0xbfb24b5b7e135a3d), (0xb8f7066b9150f3c8, 0x3c530c22d15199b8, 0xbfb0eb389fa29f9b), (0xb8decbebcad152bd, 0x3c478cbe51121a94, 0xbfaf1389833253a0), (0xb8b42bd2b182fdab, 0x3c160e0f2c3388f0, 0xbfac4dfab90aab5f), (0xb8d5c7c92fd4f7f3, 0xbc482838ed43de84, 0xbfa985bfc3495194), (0x38dedbe726436947, 0xbc389b03784b5be1, 0xbfa6bad3758efd87), (0xb8dea50c8ba63a79, 0xbc3013a5b81fc494, 0xbfa3ed3094685a26), (0xb8c4bcdabff7514c, 0x3c227ebafb056cb9, 0xbfa11cd1d5133413), (0x38ce9f581ff32546, 0xbc399ba03dc5d34f, 0xbf9c9363ba850f86), (0x38d06b9f56890d24, 0x3c3d6476077b9fbd, 0xbf96e79685c2d22a), (0xb8b1b179cc231c2a, 0xbc32ed069b244452, 0xbf91363117a97b0c), (0x38b777c664136e1b, 0xbc2fe38dec005e54, 0xbf86fe50b6ef0851), (0x0000000000000000, 0x0000000000000000, 0x8000000000000000), (0x0000000000000000, 0x0000000000000000, 0x8000000000000000), (0xb8a7dbe5813706e0, 0x3c0456006875bd76, 0x3f815cfe8eaec830), (0x38c7f9509188db9f, 0x3c2ae48169cf4cdb, 0x3f8cfee70c5ce5dc), (0xb8d79e2d0f7ae4d0, 0x3c37910667a9b5f8, 0x3f94564a62192834), (0xb8d813d8377012b5, 0xbc361176ce5d0a51, 0x3f9a330fd028f75f), (0xb8d685445ab0c8b5, 0xbc493cced296b87d, 0x3fa00ae7f502c1c4), (0xb8ebcdc68a46e891, 0xbc4c3f1d5c0cfec8, 0x3fa2ff4b77413dcb), (0x38a63b39766a5ce1, 0x3c2c62a2f6e13b06, 0x3fa5f6b8a11c3c61), (0x38ed757f27c1c5b2, 0x3c477970e03f821c, 0x3fa77394c9d958d5), (0x38d0bf5248279df2, 0xbc486446a6eb19b1, 0x3faa6f9c377dd31b), (0x387223b831459354, 0x3c0155660710eb2a, 0x3fad6ebd1f1febfe), (0x38f423e28c15d772, 0xbc57de9078d157a3, 0x3fb0387efbca869e), (0xb8c9cfd3de88693e, 0x3c298c5452bbce74, 0x3fb1bb32a600549d), (0xb8d9456e30e04c8b, 0xbc3e20375a3220ba, 0x3fb33f7cde14cf5a), (0xb8dd9b5327c61668, 0xbc4e40a005e7a3e0, 0x3fb4023b7b26ac9e), (0xb8d8302738bd7244, 0x3c5a489c555db4a8, 0x3fb588edd4d1ceaa), (0x38d15de8817f9652, 0xbc524e45ed01d67c, 0x3fb7113f3259e07a), (0xb8c297cc436527f1, 0x3c34ea44821c1dc2, 0x3fb89b33091d6fe8), (0xb8d163823d724b8c, 0xbc5d9af608a7a4d8, 0x3fba26ccd9981853), (0xb8f030b03172242b, 0x3c540238de7ea9f1, 0x3fbaed391ab6674e), (0xb898fd98ad57a6d5, 0xbc17936311889913, 0x3fbc7b528b70f1c5), (0xb8f80f8712f10464, 0x3c592ce9636c90a0, 0x3fbe0b1ae8f2fd56), (0x38ec0a4d34a2fd5c, 0xbc56fb7d020ef0e0, 0x3fbed3a1d4cdbebb), (0xb8b8adf1dbb4847f, 0x3c3905c241a252f9, 0x3fc032fbbaee6d65), (0xb903fe7b94dd3deb, 0xbc61d536b72e64f7, 0x3fc0fd02a03727ea), (0xb8f06547268dda91, 0xbc5df0fdbc295d19, 0x3fc162593186da70), (0x38e31c1f44f6723a, 0xbc5696e2866c718e, 0x3fc22dadc2ab3497), (0x38fd32863d2685d2, 0xbc6978b98f7dedf9, 0x3fc2f9e32d5bfdd1), (0x38ec6ccb73071d8f, 0xbc4b5ac8d9739e01, 0x3fc36052d01c3dd7), (0xb90321b9c961872d, 0x3c648a7168f01501, 0x3fc42ddd2ba1b4a9), (0x390f41f9b48ee641, 0x3c67c2c3172b86af, 0x3fc4fc4d4d9bb313), (0xb8b9b5bedec4594c, 0x3c390e41bca6ef96, 0x3fc563dc29ffacb2), (0x38dd601656701a20, 0x3c354fae008fbb59, 0x3fc633a8bf437ce1), (0xb905adb0d2530905, 0x3c6a1981a877433e, 0x3fc69be6fbb3aa6f), (0xb90f3e5eefe085d3, 0x3c6519f7ed9559d4, 0x3fc76d14a4601225), (0x38fc9f6eab582c70, 0x3c69ced1447e30ad, 0x3fc7d60496cfbb4c), (0x3902bdc639cad5c0, 0x3c699aa6df8b7d83, 0x3fc8a8980abfbd32), (0xb8ca47539e091f76, 0xbc40b273219ed335, 0x3fc9123c1528c6ce), (0xb8cd48f7f45b5018, 0xbc45359413e77d86, 0x3fc9e63a24971f46), (0xb8b73b65f96477cb, 0x3c6013b6eaceb921, 0x3fca5094b54d2828), (0xb9055f0f3a28066a, 0xbc6cc865b3dd0dbb, 0x3fcb2602497d5346), (0x38f53cf448ae828c, 0x3c569a95f528f2c7, 0x3fcb9115db83a3dd), (0xb8e2102812a3d1b1, 0xbc4fab00c0500189, 0x3fcc67f7f770a67e), (0x38fa40fe032a2c66, 0x3c592eeaf409cc88, 0x3fccd3c712d31109), (0xb887c5ffe75deb96, 0xbc0ba8b1f646ab12, 0x3fcdac22d3e441d3), (0xb8811c83ec58557f, 0x3c29bf75f08df8fb, 0x3fce18b00e13123d), (0x38ea7fea131ac432, 0x3c506313e79cf1dc, 0x3fcef28aacd72231), (0xb9084b9b76dd9f57, 0xbc6bdc0426c3c274, 0x3fcf5fd8a9063e35), (0x3902c0ac2d3510c7, 0x3c7768994400ca0a, 0x3fd01d9bbcfa61d4), (0xb90ead7402dbb16c, 0x3c7fdee226b2d7aa, 0x3fd054a474bf0eb7), (0x38f7ea4900b7ca9f, 0xbc53d56efe4338fe, 0x3fd08bce0d95fa38), (0xb8ef4d89ee4185a6, 0x3c40de07b685556f, 0x3fd0fa848044b351), (0xb918d4aa56ccb3b2, 0x3c790ea4cc5a44e3, 0x3fd13211a9b38424), (0x38fa379cb518805e, 0x3c7a3174c8d0586b, 0x3fd1a190a5d674a0), (0xb90af38b63e590a5, 0x3c6ae9804237ec8e, 0x3fd1d982c9d52708), (0x3907a7fd81201c43, 0xbc7343f87991ca1f, 0x3fd21196e87473d1), (0x38fc178bd3a1edca, 0xbc57154f4085d044, 0x3fd28225bb5e64a4), (0x38e7ab84f442d263, 0xbc50132ae5e417cd, 0x3fd2baa0c34be1ec), (0x39026a2436846fab, 0xbc7bc5dc0ebe6308, 0x3fd2f33e6d2120f2), (0xb9047b4beb18bc59, 0xbc687bf1007a1695, 0x3fd364e2511cc821), (0xb919992a2440dc93, 0x3c7fcad2f4710e00, 0x3fd39de8e1559f6f), (0x38ead80ac1494e37, 0xbc69cee46ebe3a2d, 0x3fd3d712bf9c9def), (0xb9134ed7c8d82134, 0xbc7c658d602e66b0, 0x3fd4106017c3eca3), (0x38f81bffac5a3040, 0xbc75759f8091112d, 0x3fd48365e695d797), (0x390122141b6e6cce, 0xbc75e341793e8e12, 0x3fd4bd1eb680e548), (0xb90844a77a231cf3, 0x3c7e393a16b94b52, 0x3fd4f6fbb2cec598), (0x390784ce0b08724e, 0xbc78d86531d55da2, 0x3fd56b22e6b578e5), (0x38fdb88067f0d789, 0x3c7885b23dbdaaf1, 0x3fd5a56d7a370ded), (0x391c3aeac5cdb196, 0x3c710b5b643a6ecb, 0x3fd5dfdcf1eeae0e), (0x38f9a8ddc498a5b0, 0x3c515f01e8fdf6ad, 0x3fd61a717cac1983), (0x38d9002dddd7f2ce, 0x3c3d3cd794eee08b, 0x3fd6900a8836d0d5), (0x38c2cc9a4ea80721, 0x3c2b6d40900b2502, 0x3fd6cb0f6865c8ea), (0x38cf01842d4b2f59, 0x3c6cbc6f17205b76, 0x3fd7063a1a5fb4f2), (0xb915071dd6fa27c2, 0xbc726bfff0133975, 0x3fd7418acebbf18f), (0xb914f2a5689dd709, 0xbc76d8d6e54d428b, 0x3fd77d01b66fbd37), (0xb8e0b434dd18e7de, 0x3c6412d04e355531, 0x3fd7f462e58e1688), (0x38f6527e7e840122, 0x3c651d58525aad39, 0x3fd8304d90c11fd3), (0x38e516a4b1855739, 0xbc71660ad9487503, 0x3fd86c5f36dea3dc), (0x3912bdc639cad5c0, 0x3c799aa6df8b7d83, 0x3fd8a8980abfbd32), (0xb91995b025e39b60, 0xbc740df0e173c574, 0x3fd8e4f83fa145ee), (0x38f93dd58663d90f, 0x3c7fdc46af571993, 0x3fd921800924dd3b), (0xb8f0939e6edc060c, 0x3c7bca36fd02def0, 0x3fd99b072a96c6b2), (0xb91659657a3f4cd6, 0xbc7cf91d2080a35b, 0x3fd9d806ebc9921c), (0x390d166fe5d876b2, 0xbc64278cd1699312, 0x3fda152f142981b4), (0xb8fec39dceb08f82, 0x3c6b56b1d743ac01, 0x3fda527fd95fd8ff), (0x38d48bb6c3065717, 0x3c5817fd3b7d7e5d, 0x3fda8ff971810a5e), (0xb8e711410d392f17, 0x3c77061311743a68, 0x3fdacd9c130dd53f), (0x38c45703d2c5dcbe, 0xbc45e13b838eba7d, 0x3fdb0b67f4f46810), (0xb8fd917ff9c35ae9, 0xbc501d98c3531027, 0x3fdb877c57b1b070), (0x3907193712b6e51c, 0xbc78a87a168550fe, 0x3fdbc5c5489254cc), (0x391d391561769b34, 0x3c7edf515c63dd87, 0x3fdc043859e2fdb3), (0xb905c1e916668206, 0xbc687a4c86c71df7, 0x3fdc42d5c4c688b4), (0x38efe382a72aa9a4, 0x3c6c4aec56233279, 0x3fdc819dc2d45fe4), (0xb8ff56b5607ee8e4, 0x3c5d3c79567f954e, 0x3fdcc0908e19b7bd), (0x390e73e7b9e3ba70, 0x3c78a38b4175d665, 0x3fdcffae611ad12b), (0x38ef3d2624494be1, 0xbc4e2b378ff59cbb, 0x3fdd3ef776d43ff4), (0xb90611295daec3b0, 0xbc6e15a52a31604a, 0x3fdd7e6c0abc3579), (0x38f6dcd082b5ed11, 0xbc76a568b022e9a3, 0x3fddbe0c58c3cff2), (0x38c4b12ca495197c, 0x3c438c8946414c6a, 0x3fddfdd89d586e2b), (0x38f9351168f2db59, 0xbc63aeabca24fd25, 0x3fde3dd1156507de), (0x38eeaaf81af2c453, 0x3c73bed456b24ed1, 0x3fde7df5fe538ab3), (0x391a697a348a408c, 0x3c7ff93949a1897d, 0x3fdebe47960e3c08), (0xb8fe170ccb0f7762, 0x3c76d261f1753e0b, 0x3fdefec61b011f85), (0xb900da9304567477, 0xbc7f4c8f8f9cbfe1, 0x3fdf3f71cc1b629c), (0x391c1a6aa9135b96, 0xbc79ca1a3202b3d7, 0x3fdf804ae8d0cd02), (0xb8f5b4fa1d9fe122, 0x3c5b9a81085cd3b3, 0x3fdfc151b11b3640), (0x391dd3a12d527b9c, 0xbc87398fe685f171, 0x3fe0014332be0033), ]; pxfm-0.1.23/src/logs/log_dd.rs000064400000000000000000000166111046102023000142170ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::logs::log_dd_coeffs::LOG_NEG_DD; use crate::polyeval::f_polyeval7; use crate::pow_tables::POW_INVERSE; #[inline(always)] pub(crate) fn log_poly(z: f64) -> DoubleDouble { /* See ./notes/dd_log.sollya */ const P: [(u64, u64); 9] = [ (0x3c755555556a4311, 0x3fd5555555555555), (0x3b8ffa82859b4000, 0xbfd0000000000000), (0xbc699b6b44796cd4, 0x3fc999999999999a), (0x3c489642b3424250, 0xbfc5555555555563), (0x3c60e3ef2c7fc443, 0x3fc24924924924ad), (0x3c535269fe0ce5df, 0xbfbfffffffc0b25c), (0x3c24f14f55e95858, 0x3fbc71c71c187ea4), (0x3c5b15951c5e1a17, 0xbfb999d71e5042d5), (0x3c5ecb0133e43410, 0x3fb74615b842a94d), ]; let x2 = DoubleDouble::from_exact_mult(z, z); let mut t = DoubleDouble::quick_mul_f64_add( DoubleDouble::from_bit_pair(P[8]), z, DoubleDouble::from_bit_pair(P[7]), ); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[6])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[5])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[4])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[3])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[2])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[1])); t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[0])); t = DoubleDouble::quick_mult(t, x2); t = DoubleDouble::quick_mult_f64(t, z); DoubleDouble::mul_f64_add(x2, -0.5, t) } #[inline(always)] pub(crate) fn log_poly_fast(z: f64) -> DoubleDouble { /* See ./notes/dd_log_fast.sollya */ let x2 = DoubleDouble::from_exact_mult(z, z); let r = f_polyeval7( z, f64::from_bits(0xbfc5555555555555), f64::from_bits(0x3fc24924924924aa), f64::from_bits(0xbfc000000000bc96), f64::from_bits(0x3fbc71c71c202bf0), f64::from_bits(0xbfb9999839f1aa36), f64::from_bits(0x3fb74612adef67e0), f64::from_bits(0xbfb5cb6ab20b8efa), ); let mut p = DoubleDouble::f64_mul_f64_add( z, r, DoubleDouble::from_bit_pair((0xbc699b293fa3344b, 0x3fc999999999999a)), ); p = DoubleDouble::mul_f64_add( p, z, DoubleDouble::from_bit_pair((0xbb3b08905e500000, 0xbfd0000000000000)), ); p = DoubleDouble::mul_f64_add( p, z, DoubleDouble::from_bit_pair((0x3c7555555567a1b0, 0x3fd5555555555555)), ); let mut t = DoubleDouble::quick_mult(x2, p); t = DoubleDouble::quick_mult_f64(t, z); DoubleDouble::mul_f64_add(x2, -0.5, t) } #[inline] pub(crate) fn log_dd(x: f64) -> DoubleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = DoubleDouble::from_bit_pair(LOG_NEG_DD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7abc9e3b39803f), f64::from_bits(0x3fe62e42fefa39ef), ); let tt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r); let v = DoubleDouble::full_add_f64(tt, z); let p = log_poly(z); DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)) } #[inline] pub(crate) fn log_dd_fast(x: f64) -> DoubleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = DoubleDouble::from_bit_pair(LOG_NEG_DD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c7abc9e3b39803f), f64::from_bits(0x3fe62e42fefa39ef), ); let tt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r); let v = DoubleDouble::full_add_f64(tt, z); let p = log_poly_fast(z); DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log_dd() { assert_eq!(log_dd(std::f64::consts::E).to_f64(), 1.); } } pxfm-0.1.23/src/logs/log_dd_coeffs.rs000064400000000000000000000241661046102023000155500ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by Sage: from POW_INV ```python R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] real_array = [R(hex_to_float(h)) for h in values] for r in real_array: print_double_double("", -RealField(120)(r).log()) ``` **/ pub(crate) static LOG_NEG_DD: [(u64, u64); 182] = [ (0x3c6bc60efafc6f6e, 0xbfd5ff3070a793d4), (0x3c78ebcb7dee9a3d, 0xbfd5a42ab0f4cfe2), (0x3c6819cf7e308ddb, 0xbfd548a2c3add263), (0x3c742a87d977dc5e, 0xbfd4ec973260026a), (0x3c69ffc341f177dc, 0xbfd49006804009d1), (0x3c729931715ac903, 0xbfd432ef2a04e814), (0x3c70bcfb6082ce6d, 0xbfd404308686a7e4), (0x3c6c68651945f97c, 0xbfd3a64c556945ea), (0x3c64dd4c580919f8, 0xbfd347dd9a987d55), (0x3c78f4cdb95ebdf9, 0xbfd2e8e2bae11d31), (0xbc77ad24c13f040e, 0xbfd2895a13de86a3), (0x3c776f5eb09628af, 0xbfd22941fbcf7966), (0x3c7c9fdf9a0c4b07, 0xbfd1f8ff9e48a2f3), (0xbc79d3d1b0e4d147, 0xbfd1980d2dd4236f), (0xbc77b66298edd24a, 0xbfd136870293a8b0), (0xbc589fa0ab4cb31d, 0xbfd1058bf9ae4ad5), (0xbc77dcfde8061c03, 0xbfd0a324e27390e3), (0x3c628ec217a5022d, 0xbfd0402594b4d041), (0x3c6caaae64f21acb, 0xbfcfb9186d5e3e2b), (0xbc2c5f6dfd018c37, 0xbfcf550a564b7b37), (0x3c46e03a39bfc89b, 0xbfce8c0252aa5a60), (0x3c461578001e0162, 0xbfce27076e2af2e6), (0xbc66e443597e4d40, 0xbfcd5c216b4fbb91), (0x3c64f689f8434012, 0xbfcc8ff7c79a9a22), (0x3c673dee38a3fb6b, 0xbfcc2968558c18c1), (0xbc6ba27fdc19e1a0, 0xbfcb5b519e8fb5a4), (0x3c5398cff3641985, 0xbfcaf3c94e80bff3), (0xbc493711b07a998c, 0xbfca23bc1fe2b563), (0xbc6575e31f003e0c, 0xbfc9bb362e7dfb83), (0x3c6569d851a56770, 0xbfc8e928de886d41), (0x3c6bf7fdbfa08d9a, 0xbfc87fa06520c911), (0xbc4be36b2d6a0608, 0xbfc7ab890210d909), (0x3c5b264062a84cdb, 0xbfc740f8f54037a5), (0x3c6caae268ecd179, 0xbfc6d60fe719d21d), (0x3c5bc60efafc6f6e, 0xbfc5ff3070a793d4), (0x3c565d22aa8ad7cf, 0xbfc59338d9982086), (0xbc668981bcc36756, 0xbfc4ba36f39a55e5), (0xbc69f4f6543e1f88, 0xbfc44d2b6ccb7d1e), (0x3c5ab3a8e7d81017, 0xbfc3dfc2b0ecc62a), (0x3c06b9c7d96091fa, 0xbfc303d718e47fd3), (0xbc6301771c407dbf, 0xbfc29552f81ff523), (0xbc6f547bf1809e88, 0xbfc2266f190a5acb), (0xbc6a28813e3a7f07, 0xbfc14785846742ac), (0xbc69a5dc5e9030ac, 0xbfc0d77e7cd08e59), (0xbc550c647eb86499, 0xbfc0671512ca596e), (0xbc585f325c5bbacd, 0xbfbf0a30c01162a6), (0x3c361578001e0162, 0xbfbe27076e2af2e6), (0xbc5790dd951d90fa, 0xbfbd4313d66cb35d), (0xbc35d617ef8161b1, 0xbfbc5e548f5bc743), (0xbc5942f48aa70ea9, 0xbfba926d3a4ad563), (0x3c42099e1c184e8e, 0xbfb9ab42462033ad), (0x3c24a697ab3424a9, 0xbfb8c345d6319b21), (0x3c5eeedfcdd94131, 0xbfb7da766d7b12cd), (0x3c5388458ec21b6a, 0xbfb60658a93750c4), (0xbc5a49e39a1a8be4, 0xbfb51b073f06183f), (0xbc4ddd4f935996c9, 0xbfb42edcbea646f0), (0x3c5b599f227becbb, 0xbfb341d7961bd1d1), (0x3c1c125963fc4cfd, 0xbfb253f62f0a1417), (0x3c379da3e8c22cda, 0xbfb16536eea37ae1), (0xbc485f325c5bbacd, 0xbfaf0a30c01162a6), (0xbc21e3c53257fd47, 0xbfad276b8adb0b52), (0x3c3eb9759c130499, 0xbfab42dd711971bf), (0xbc4f5a0e80520bf2, 0xbfa95c830ec8e3eb), (0xbc418d3ca87b9296, 0xbfa77458f632dcfc), (0x3c4ce55c2b4e2b72, 0xbfa58a5bafc8e4d5), (0x3c45bfa937f551bb, 0xbfa39e87b9febd60), (0x3c3e9ae889bac481, 0xbfa1b0d98923d980), (0xbc333e3f04f1ef23, 0xbf9f829b0e783300), (0x3bf0ae69229dc868, 0xbf9b9fc027af9198), (0x3c35b602ace3a510, 0xbf97b91b07d5b11b), (0x3c10cb5a902b3a1c, 0xbf93cea44346a575), (0x3c183092c59642a1, 0xbf8fc0a8b0fc03e4), (0x3c116d7687d3df21, 0xbf87dc475f810a77), (0x3bce44b7e3711ebf, 0xbf7fe02a6b106789), (0x0000000000000000, 0x0000000000000000), (0x0000000000000000, 0x0000000000000000), (0x3bec14b9f9377a1d, 0x3f78121214586b54), (0xbc2c5517f64bc223, 0x3f841929f96832f0), (0x3c2806208c04c220, 0x3f8c317384c75f06), (0xbc2cd7b66e01c26d, 0x3f9228fb1fea2e28), (0xbbf8ed4d357c9c97, 0x3f963d6178690bd6), (0x3c1ec1a5f86d41f9, 0x3f9a55f548c5c43f), (0x3c375b44595cab18, 0x3f9e72bf2813ce51), (0x3c4c05cf1d753622, 0x3fa0415d89e74444), (0xbc4947f792615916, 0x3fa252f32f8d183f), (0xbc4cdd6f7f4a137e, 0x3fa466aed42de3ea), (0x3c40413e6505e603, 0x3fa67c94f2d4bb58), (0x3c3a8be97660a23d, 0x3fa894aa149fb343), (0x3c2a353bb42e0add, 0x3faaaef2d0fb10fc), (0x3c3e5cf3a0f56f72, 0x3fabbcebfc68f420), (0x3c44e6c986f44c55, 0x3fadda8adc67ee4e), (0xbc4cd9f1f95c2eed, 0x3faffa6911ab9301), (0xbc5a4a128d192686, 0x3fb10e45b3cae831), (0xbc5cc0fbce104eaa, 0x3fb2207b5c78549e), (0xbc5d15d38d2fa3f7, 0x3fb2aa04a44717a5), (0x3c47a976d3b5b45f, 0x3fb3bdf5a7d1ee64), (0x3c5769f42c7842cc, 0x3fb4d3115d207eac), (0xbc545f9d61c68c1b, 0x3fb55e10050e0384), (0xbc59acd8b33f8fdc, 0x3fb674f089365a7a), (0x3c5abca5b4fdb880, 0x3fb78d02263d82d3), (0x3c3b9f2dffbeed43, 0x3fb8197e2f40e3f0), (0xbc5478a85704ccb7, 0x3fb9335e5d594989), (0xbc55b5ca203e4259, 0x3fba4e7640b1bc38), (0x3c537d8f39bee659, 0x3fbadc77ee5aea8c), (0xbc4cdc9f6f5f38c7, 0x3fbbf968769fca11), (0x3c49daf7df76ad2a, 0x3fbd179788219364), (0x3c5401fa71733019, 0x3fbda727638446a2), (0xbc4a2bf991780d3f, 0x3fbec739830a1120), (0xbc59361574fb24e2, 0x3fbf57bc7d9005db), (0x3c639e2d3f8b7d10, 0x3fc03cdc0a51ec0d), (0xbc6dd7009902bf32, 0x3fc08598b59e3a07), (0xbc50e63a5f01c691, 0x3fc1178e8227e47c), (0xbc62d56ff61c2bfb, 0x3fc160c8024b27b1), (0x3c462c9ef939ac5d, 0x3fc1f3b925f25d41), (0xbc66e38161051d69, 0x3fc23d712a49c202), (0xbc5499a3f25af95f, 0x3fc2d1610c86813a), (0xbc5c4716bdfc0cc9, 0x3fc31b994d3a4f85), (0x3c370d6cdf05266c, 0x3fc3b08b6757f2a9), (0xbc6d87e6a354d056, 0x3fc3fb45a59928cc), (0xbc50d5604930f135, 0x3fc4913d8333b561), (0xbc6927d47803c5f4, 0x3fc4dc7b897bc1c8), (0x3c64f4d710fec38e, 0x3fc5737cc9018cdd), (0xbc21f5b44c0df7e7, 0x3fc5bf406b543db2), (0xbc3d34f0f4621bed, 0x3fc6574ebe8c133a), (0x3c696332bd4b341f, 0x3fc6a399dabbd383), (0xbc68de59c21e166c, 0x3fc6f0128b756abc), (0x3c5ef8f6ebcfb201, 0x3fc7898d85444c73), (0xbc4ac5f0c075b847, 0x3fc7d6903caf5ad0), (0x3c6d685f35eea2a0, 0x3fc871213750e994), (0x3c555aa8b6997a40, 0x3fc8beafeb38fe8c), (0x3c6054473941ad99, 0x3fc90c6db9fcbcd9), (0x3c6f47dfd871f87f, 0x3fc9a8778debaa38), (0x3c435a19605e67ef, 0x3fc9f6c407089664), (0x3c5df207dc5c34c6, 0x3fca454082e6ab05), (0x3c6ab5ca9eaa088a, 0x3fcae2ca6f672bd4), (0xbc66353ab386a94d, 0x3fcb31d8575bce3d), (0x3c3a0ee735d9f0ec, 0x3fcb811730b823d2), (0x3c3dd355f6a516d7, 0x3fcbd087383bd8ad), (0xbc68e58b2c57a4a5, 0x3fcc6ffbc6f00f71), (0x3c653d154280394f, 0x3fccc000c9db3c52), (0x3c660629242471a2, 0x3fcd1037f2655e7b), (0x3c5aa11d49f96cb9, 0x3fcdb13db0d48940), (0x3c5fea48dd7b81d1, 0x3fce020cc6235ab5), (0x3c42276041f43042, 0x3fce530effe71012), (0xbc6d33919ab94074, 0x3fcea4449f04aaf5), (0xbc527c77ded76aad, 0x3fcf474b134df229), (0x3c6f665066f980a2, 0x3fcf991c6cb3b379), (0x3c28de00938b4c40, 0x3fcfeb2233ea07cd), (0xbc418290bd2932e2, 0x3fd01eae5626c691), (0xbc70779634061cbc, 0x3fd047e60cde83b8), (0x3c643c2e68684d53, 0x3fd09aa572e6c6d4), (0x3c5162c79d5d11ee, 0x3fd0c42d676162e3), (0xbc692b49ef282b09, 0x3fd0edd060b78081), (0xbc60e63a5f01c691, 0x3fd1178e8227e47c), (0x3c1e0936abd4fa6e, 0x3fd14167ef367783), (0x3c766fbd28b40935, 0x3fd16b5ccbacfb73), (0xbc612aeb84249223, 0x3fd1bf99635a6b95), (0x3c7512c3749a1e4e, 0x3fd1e9e1678899f4), (0x3c6f7ae91aeba60a, 0x3fd214456d0eb8d4), (0x3c3bb75d1addf870, 0x3fd23ec5991eba49), (0x3c7e0efadd9db02b, 0x3fd269621134db92), (0xbc6856e61c515740, 0x3fd2941afb186b7c), (0xbc782dad7fd86088, 0x3fd2bef07cdc9354), (0xbc73d69909e5c3dc, 0x3fd314f1e1d35ce4), (0xbc5cd55b8a4746c0, 0x3fd3401e12aecba1), (0xbc5324f0e883858e, 0x3fd36b6776be1117), (0xbc5ce2b31b31e8b0, 0x3fd396ce359bbf54), (0xbc72ad27e50a8ec6, 0x3fd3c25277333184), (0x3c783d680d3c1084, 0x3fd3edf463c1683e), (0x3c60dbb243827392, 0x3fd419b423d5e8c7), (0xbc72b125247b0fa5, 0x3fd44591e0539f49), (0x3c38fb4c14c56eef, 0x3fd4718dc271c41b), (0xbc69964a168ccaca, 0x3fd49da7f3bcc41f), (0xbc5123615b147a5d, 0x3fd4c9e09e172c3c), (0xbc758cb3124b9245, 0x3fd4f637ebba9810), (0xbc68f7e9b38a6979, 0x3fd522ae0738a3d8), (0xbc7aacfdbbdab914, 0x3fd54f431b7be1a9), (0xbc60908d15f88b63, 0x3fd57bf753c8d1fb), (0xbc5e6c2bdfb3e037, 0x3fd5a8cadbbedfa1), (0xbc76541148cbb8a2, 0x3fd5d5bddf595f30), (0xbc56e8920c09b73f, 0x3fd602d08af091ec), (0x3c6dc18ce51fff99, 0x3fd630030b3aac49), ]; pxfm-0.1.23/src/logs/log_dyadic.rs000064400000000000000000003063541046102023000150730ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; pub(crate) static LOG_STEP_1: [DyadicFloat128; 128] = [ // -log(r) with 128-bit precision generated by SageMath with: // for i in range(128): // r = 2^-8 * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("{RationalSign::Pos,", e, ", format_hex(m), "},"); /* .step_1= */ DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x8080abac_46f38946_662d417c_ed007a46_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0x8102b2c4_9ac23a4f_91d082dc_e3ddcd38_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc2492946_4655f45c_da5f3cc0_b3251dbd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0x820aec4f_3a222380_b9e3aea6_c444ef07_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xa33576a1_6f1f4c64_521016bd_904dc968_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc4a550a4_fd9a19a8_be97660a_23cc540d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xe65b9e6e_ed965c36_e09f5fe2_058d6006_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x842cc5ac_f1d03445_1fecdfa8_19b96098_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x8cb9de8a_32ab368a_a7c98595_30a45153_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9defad3e_8f73217a_976d3b5b_45f6ca0b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xaf4ad26c_bc8e5be7_0e8b8b88_a14ff0ce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xb8069857_560707a3_6a677b4c_8bec22e1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc99af2ea_ca4c4570_eaf51f66_692844ba_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xdb56446d_6ad8deff_a8112e35_a60e6375_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe442c00d_e2591b47_196ab34c_e0bccd12_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xf639cc18_5088fe5d_4066e87f_2c0f7340_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xff4489ce_deab2ca6_c17bd40d_8d9291ec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x88bc7411_3f23def1_9c5a0fe3_96f40f1e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x8d515bf1_1fb94f1c_88713268_840cbcc0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x968b0864_3409ceb6_65c0da50_6a088484_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9b2fe580_ac80b17d_411a5b94_4aca8708_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa489ec19_9dab06f2_a9fb6cf0_ecb411b7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xa93f2f25_0dac67d1_cad2fb8d_48054ae0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb2ba75f4_6099cf8b_2c3c2e77_904afa78_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xb780945b_ab55dce4_34c7bc3d_32750fde_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc11e0b2a_8d1e0ddb_9a631e83_0fd30904_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc5f57f59_c7f46155_aa8b6997_a402bf30_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xcad2d6e7_b80bf914_2c507fb7_a3d0bf6a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd49f69e4_56cf1b79_5f53bd2e_406e66e7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xd98ec2ba_de71e539_58a98f2a_d65bee9b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xde8439c1_dec56877_4d57da94_5b5d0aaa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xe881bf93_2af3dac0_c524848e_3443e040_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xed89ed86_a44a01aa_11d49f96_cb88317b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xf29877ff_38809091_3b020fa1_820c9492_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xf7ad6f26_e7ff2ef7_54d2238f_75f969b1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xfcc8e365_9d9bcbec_ca0cdf30_1431b60f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8389c302_6ac3139b_62dda9d2_270fa1f4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x86216b3b_0b17188b_163ceae8_8f720f1e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x88bc7411_3f23def1_9c5a0fe3_96f40f1e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8b5ae65d_67db9acd_f7a51681_26a58b9a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8dfccb1a_d35ca6ed_5147bdb6_ddcaf59c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x934b1089_a6dc93c1_df5bb3b6_0554e152_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x95f783e6_e49a9cfa_4a5004f3_ef063313_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x98a78f0e_9ae71d85_2cdec347_84707839_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9b5b3bb5_f088b766_d878bbe3_d392be25_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9e1293b9_998c1daa_5b035eae_273a855f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa0cda11e_af46390d_bb243827_3918db7e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa38c6e13_8e20d831_f698298a_dddd7f32_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa64f04f0_b961df76_e4f5275c_2d15c21f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa9157039_c51ebe70_8164c759_686a2209_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xabdfba9e_468fd6f6_f72ea077_49ce6bd3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaeadeefa_caf97d35_7dd6e688_ebb13b03_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb1801859_d56249dc_18ce51ff_f99479cd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb45641f4_e350a0d3_2756eba0_0bc33978_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb7307735_78cb90b2_be1116c3_466beb6d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xba0ec3b6_33dd8b09_49dc60b2_b059a60b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xbcf13343_e7d9ec7d_2efd1778_1bb3afec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xbfd7d1de_c0a8df6f_37eda996_244bccb0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xc2c2abbb_6e5fd56f_33337789_d592e296_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xc5b1cd44_596fa51e_1a18fb8f_9f9ef280_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xc8a5431a_dfb44ca5_688ce7c1_a75e341a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcb9d1a18_9ab56e76_2d7e9307_c70c0668_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xce995f50_af69d861_ef2f3f4f_861ad6a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xd19a2011_27d3c645_7f9d79f5_1dcc7301_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xd19a2011_27d3c645_7f9d79f5_1dcc7301_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xd49f69e4_56cf1b79_5f53bd2e_406e66e7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xd7a94a92_466e833a_ad88bba7_d0cee8e0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xdab7d022_31484a92_96c20cca_6efe2ac5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xddcb08dc_0717d85b_f40a666c_87842843_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe0e30349_fd1cec80_7fe8e180_2aba24d6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe0e30349_fd1cec80_7fe8e180_2aba24d6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe3ffce3a_2aa64922_3eadb651_b49ac53a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe72178c0_323a1a0f_304e1653_e71d9973_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xea481236_f7d35baf_e9a767a8_0d6d97e8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xed73aa42_64b0ade9_4f91cf4b_33e42998_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf0a450d1_39366ca6_fc66eb64_08ff6433_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf0a450d1_39366ca6_fc66eb64_08ff6433_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf3da161e_ed6b9aaf_ac8d42f7_8d3e65d3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf7150ab5_a09f27f4_5a470250_d40ebe90_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xfa553f70_18c966f2_b780a545_a1b54dcf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xfa553f70_18c966f2_b780a545_a1b54dcf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xfd9ac57b_d244217e_8f05924d_258c14c5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8072d72d_903d588b_89d1b09c_70c4010a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x821b05f3_b01d6774_030d58c3_f7e2ea1f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x821b05f3_b01d6774_030d58c3_f7e2ea1f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x83c5f829_9e2b4091_20f6fafe_8fbb68b9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8573b716_82a7d21a_e21f9f89_c1ab80b2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8573b716_82a7d21a_e21f9f89_c1ab80b2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x87244c30_8e670a66_01e005d0_6dbfa8f8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x88d7c11e_3ad53cdc_223111a7_07b6de2c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x88d7c11e_3ad53cdc_223111a7_07b6de2c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8a8e1fb7_94b09134_2eb628db_a173c82d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8c477207_91e53313_be2ad194_15fe25a5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8c477207_91e53313_be2ad194_15fe25a5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8e03c24d_73003959_bddae1cc_ce247838_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8fc31afe_30b2c6de_9b00bf16_7e95da67_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8fc31afe_30b2c6de_9b00bf16_7e95da67_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x918586c5_f5e4bf01_9b92199e_d1a4bab1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x934b1089_a6dc93c1_df5bb3b6_0554e152_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x934b1089_a6dc93c1_df5bb3b6_0554e152_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9513c368_76083695_f3cbc416_a2418012_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x96dfaabd_86fa1646_be1188fb_c94e2f15_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x96dfaabd_86fa1646_be1188fb_c94e2f15_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x98aed221_a03458b6_1d2f8932_1647b358_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x98aed221_a03458b6_1d2f8932_1647b358_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9a81456c_ec642e0f_e549f9aa_ea3cb5e1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9c5710b8_cbb73a42_a2554b2d_d4619e63_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9c5710b8_cbb73a42_a2554b2d_d4619e63_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9e304061_b5fda919_30603d87_b6df81ad_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9e304061_b5fda919_30603d87_b6df81ad_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa00ce109_2e5498c3_67879c5a_30cd1242_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa1ecff97_c91e267b_0b7efae0_8e597e16_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa1ecff97_c91e267b_0b7efae0_8e597e16_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa3d0a93f_45169a4a_83594fab_088c0d65_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa3d0a93f_45169a4a_83594fab_088c0d65_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa5b7eb7c_b860fb88_af6a62a0_dec6e073_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa5b7eb7c_b860fb88_af6a62a0_dec6e073_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa7a2d41a_d270c9d7_49362382_a768847a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa7a2d41a_d270c9d7_49362382_a768847a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa9917134_33c2b998_8ba4aea6_14d05701_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa9917134_33c2b998_8ba4aea6_14d05701_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xab83d135_dc633301_7fe6607b_a902ef3c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xab83d135_dc633301_7fe6607b_a902ef3c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xad7a02e1_b24efd31_d60864fd_949b4bd3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xad7a02e1_b24efd31_d60864fd_949b4bd3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xaf741551_20c9011c_066d235e_e63073dd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0_u128, }, ]; pub(crate) static LOG_STEP_2: [DyadicFloat128; 193] = // -log(r) for the second step, generated by SageMath with: // // for i in range(-2^6, 2^7 + 1): // r = 2^-16 * round( 2^16 / (1 + i*2^(-14)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("{RationalSign::Pos," if s == -1 else "{RationalSign::Neg,", e, ", // format_hex(m), "},"); /* .step_2 = */ [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -135, mantissa: 0x803faaca_c419abf2_a1c6f3fc_242ef8d0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xfc834da1_6f0d9f57_a225ebc0_2e6d9dd4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xf88735cc_c7433381_c33f6ad3_40ae18a9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xf48b0e17_1249b6bc_70b2a4d3_8a242244_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xf08ed67f_d190e280_1d548190_48b811b0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xec928f06_86828706_aee59837_01d2a02b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xe89637aa_b2828aed_40abb8ab_72afa2d2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xe499d06b_d6eeead5_deb547a0_d4a26ef9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xe09d5949_751fb909_39c5bdfb_cf6087a0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xdca0d243_0e671d18_53ea9bf1_52de635f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xd8a43b58_2411537e_25b82043_6f5f4352_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xd4a79488_3764ad41_3c2d13ea_1d0be058_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xd0aaddd2_c9a18f95_4f3cfa62_bcb3ce3a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xccae1737_5c02737c_d0fff6cd_f14a86c7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xc8b140b5_6fbbe56a_7587b5f0_453ac3d2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xc4b45a4c_85fc84e2_b358ad16_dfd0d085_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xc0b763fc_1fed041d_3c86fdce_5dbe7314_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xbcba5dc3_beb027a6_70764e46_ac18a96d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xb8bd47a2_e362c600_c63be62b_8f285882_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xb3c0d59a_244325a4_72e7b5a3_86e5e31b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xafc39bac_66434f27_c3ea2cd9_3f316b34_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xabc651d4_91a7b438_1dfb11a7_cc892843_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xa7c8f812_2773f38d_fc679a28_e9d9f212_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0xa3cb8e64_a8a5bbe6_e7bc977e_eec42254_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x9fce14cb_9634cba6_b20f215b_d3b58c61_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x9bd08b46_7112f078_abe28625_08d67a98_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x97d2f1d4_ba2c06f0_d1aacedc_efe9d377_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x93d54875_f265fa2c_f1eb25e7_7d05f58d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x8fd78f29_9aa0c375_cbef6fac_33691e95_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x8bd9c5ef_33b669e0_27206404_62a0f8ad_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x87dbecc6_3e7b01ed_e2f17751_34c8da75_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -136, mantissa: 0x83de03ae_3bbcad2e_ff67e201_c8c50d67_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xffc0154d_588733c5_3c742a7c_76356396_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xf7c4035e_21a4052f_f90dd6b2_4aa686ec_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xefc7d18d_d4485b9e_ca47c52b_7d7ffce2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xe7cb7fdb_71e0db36_3703617a_d3d8311f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xdfcf0e45_fbce3e80_7e4cfbd8_30393b88_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xd7d27ccc_736555af_4f7a29cf_0fc2c38e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xcfd5cb6d_d9ef05dd_7370ae83_f9e72748_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xc7d8fa29_30a84850_671486eb_4cd76f65_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xbfdc08fd_78c229b9_e6dbb624_f9739782_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xb7def7e9_b361c979_6b866e09_e57d9079_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xafe1c6ec_e1a058dd_97fa2fd0_c9dc723e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xa7e47606_048b1a65_983e8089_7cf1e60f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x9fe70534_1d236102_7199cd06_ae5d39b3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x97e97476_2c5e8f58_43cd18a7_2a051a96_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x8febc3cb_332616ff_7b6d1248_c3e1fd40_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0x87edf332_325777c5_f5572a88_14c703af_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xffe00554_55887de0_26828c92_649a3a39_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xefe3e464_3a640cf3_82c550bd_1216d82a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xdfe78392_14b4e8ae_da6959f7_f0e01bf0_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xcfeae2db_e5d6736d_da93e2fa_85a8f214_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xbfee023f_af0c2480_b47505bf_a5a03b06_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0xaff0e1bb_718186ad_b1475a51_80a43520_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0x9ff3814d_2e4a36b2_a8740b91_c95df537_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -138, mantissa: 0x8ff5e0f2_e661e1c6_57d895d3_5921b59c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xfff00155_35588833_3c56c598_c659c2a3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xdff3c0e4_97ea4eb1_2ef8ec33_ed9d782a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0xbff7008f_f5e0c257_379eba7e_6465ff63_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -139, mantissa: 0x9ff9c053_5073a370_3f972b78_3fcab757_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -140, mantissa: 0xfff80055_51558885_de026e27_1ee0549d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -140, mantissa: 0xbffb8023_febc0c25_eceb47ea_01f6c632_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -141, mantissa: 0xfffc0015_54d55888_7333c578_57e1ed52_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0xfffe0005_55455588_87dde026_fa704374_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: 0, mantissa: 0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -141, mantissa: 0x80010002_aab2aac4_44999abe_2fe2cc65_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0x8002000a_aaeaac44_4eef3815_81464ccb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0xc0048024_01440c26_dfeb4850_85f6f454_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0x8004002a_acaac445_99abe3be_3a1c6e93_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xa0064053_5a37a37a_6bc1e20e_ac8448b4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xc0090090_0a20c275_979eedc0_64c242fd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -139, mantissa: 0xe00c40e4_bd6e4efd_c72446cc_1bf728bd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x800800aa_baac446e_f381b821_bbb569e5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x900a20f3_19a3e273_569b26aa_a485ea5c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xa00c814d_7c6a37f8_2dcf56c8_3c80b028_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xb00f21bb_e3e388ee_5f697682_84463b9b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xc0120240_510c284c_b48ea6c0_5e2773a1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xd01522dc_c4f87991_14d9d761_96d8043a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xe0188393_40d4f241_e016a611_a4415d72_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0xf01c2465_c5e61b6f_661e135f_49a47c40_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x801002ab_2ac4499a_be6bf0fa_435e8383_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x88121333_7898871e_9a31ba0c_bc030353_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x901443cc_cd362c9f_54b57dfe_0c4c840f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0x98169478_296fad41_7ad1e9c3_15328f7e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xa0190536_8e2389b3_1f3f686c_f3d6be22_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xa81b9608_fc3c50ec_f105b66e_c4703ede_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xb01e46f0_74b0a0f3_610848c6_8df4d233_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xb82117ed_f8832797_d6aef30c_d312169a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xc0240902_88c2a339_f3ac3796_08053d9d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xc8271a2f_2689e388_e6e2acf8_f4d4c24a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xd02a4b74_d2ffca44_ce6ae474_d860359f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xd82d9cd4_8f574c00_28bb3cd9_f2a65fb5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xe0310e4f_5ccf70e1_54f30dbe_f38a8066_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xe8349fe6_3cb35564_224a96f5_a7471c46_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xf038519a_305a2b1b_6ea92059_1aa02e1b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xf83c236c_39273972_d462b637_56c87e80_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x80200aae_ac44ef38_338f7760_5fe77f2a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x842213b7_47fec7bb_3ff51287_882500ed_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x88242cd0_7084ed02_cc394b3e_f0ebeb12_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x8c2655fa_a6a1323f_1ab9679b_55f78a6b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x90288f36_6b237771_7025697d_10af0436_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x942ad884_3ee1a9cd_17e4b7ac_6c600cb4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x982d31e4_a2b7c418_7013925a_9a8da7f3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0x9c2f9b58_1787cf0d_fd1a09c8_48e3950e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xa03214df_1e39e1bd_84dd2de6_e3d90a37_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xa4349e7a_37bc21ed_318b2ddd_9d0a33b4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xa8373829_e502c47a_bc031e6f_5acfd4a8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xac39e1ee_a7080dbc_9dd91e52_c79fd070_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xb03c9bc8_fecc51e3_4af78fa1_cb48a12d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xb43f65b9_6d55f55a_72de1d99_ce252efd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xb74187bc_8ccffa84_efb1dbe7_21934877_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xbb446dd4_d9bca499_b4b080f2_30c87598_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xbf476404_a05f88f2_da6a7cd1_9c7fa4f2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xc34a6a4c_61d5cc3c_df00e378_3b50ecfb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xc74d80ac_9f42a52d_da2e5e02_ab4e183c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xcb50a725_d9cf5ce6_ea5f6ee9_9d30c626_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xcf53ddb8_92ab4f55_a96d5956_531d7d8b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xd3572465_4b0beb95_a8fc636e_b36afa75_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xd75a7b2c_842cb451_f67e2b82_7bfc4421_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xdb5de20e_bf4f4026_a6d8c817_516303e6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xdf61590c_7dbb3a02_69b36ae5_962e85f4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xe364e026_40be6188_24693eec_2a831cc3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xe768775c_89ac8b70_94a339d5_6a55ab4a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xeb6c1eaf_d9dfa1eb_fa9998fb_f9703bf4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xef6fd620_b2b7a503_cafdc272_27b71eaa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xf3739daf_959aaafc_688d4282_f6026aa3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xf777755d_03f4e0b6_e54e9e38_04464cdd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xfb7b5d29_7f388a12_cb78b383_f4b59dce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xff7f5515_88de024f_ee055fc5_15062c04_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x81c1ae90_d131de38_207812b4_3382acdd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x83c3baa7_26a721cc_dc90c4c4_b61f3a87_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x85c5cece_05941dbc_1a03f13f_b2c978b1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x87c7eb05_aec1304f_b36f282e_83a7dc36_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x89ca0f4e_62f9c476_6ad14c3d_fa414391_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x8bcc3ba8_630c51f4_e8dd4ea0_d48b88e5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x8dce7013_efca5d96_c02515af_e8caeb90_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x8fd0ac91_4a08795f_741ceaf3_349f3cf1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x91d2f120_b29e44bb_83f7cd49_29d2c28c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x93d53dc2_6a666cb1_795d03eb_c2fd03fa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x95d79276_b23eac12_faf74f1d_1ad16acc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x97d9ef3d_cb07cbad_e2de134f_72fee429_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x99dc5417_f5a5a27d_58d8dba6_cadac5d5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9bdec105_72ff15da_f07d90bc_5aae40a4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9d609804_6659ea6b_1deaf79d_9fc40374_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0x9f631314_50b07988_7ba63e67_69b81999_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa1659638_404d5f92_59ebfc93_35094e59_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa3682170_7622f97a_16aae012_b5026f71_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa56ab4bd_3326b378_ff5d4f2c_0e4b9cae_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa76d501e_b8510941_855838b5_119dcb28_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xa96ff395_469d8630_75f70cbb_e9cf1603_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xab729f21_1f0ac57e_36a53ad4_d5541cc9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xad7552c2_829a7270_04c5934e_c32d20d9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xaf780e79_b2514889_3977e89a_ec59bfa2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb17ad246_ef3713bc_913d4e3d_c55c3e6e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb37d9e2a_7a56b09d_777b52a9_e70d8bcc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb5807224_94be0c91_55de916f_d30591de_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb7834e35_7f7e2600_e79cfb37_be2861e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xb986325d_7bab0c89_90983104_d3805389_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbb891e9c_ca5be12e_b860504b_aa6f984d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbd8c12f3_acaad68b_29178d6f_f5712b96_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xbf8f0f62_63b53102_7236fa47_ba19a198_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xc19213e9_309b46f2_4f34d64c_afcc50e3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xc3952088_548080e4_120cc62e_b0a8db3e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xc5983540_108b59be_11aa5084_779060e3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xc79b5210_a5e55ef5_1c35fd62_36c8dcf1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xc99e76fa_55bb30bd_ed4576a7_e4b878fe_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xcb20d7fa_3a336081_6caf4bb8_fd2c1131_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xcd240b10_753e78de_3f24a6cb_b09c654f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xcf274640_7e0ff09f_78bc003b_b81e40f3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd12a898a_95dff002_56647301_edfd8e8b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd32dd4ee_fde9b2ef_28fe1c4d_04ca4ed9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd531286d_f76b892a_e1ea9ea6_cbf57379_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd7348407_c3a6d688_a3832028_141a5cc2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xd937e7bc_a3e0131b_557421dd_379d3ead_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xdb3b538c_d95ecb67_3cff8e87_a99bcaf0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xdd3ec778_a56da093_99255ef3_4bd0801f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xdf424380_495a489c_42b33220_abfa15cd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xe145c7a4_06758e83_503b378f_aa97dbc0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xe34953e4_1e135282_bdf2ca00_6f59b544_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xe54ce840_d18a8a3e_1979190a_f37ed16f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xe75084ba_623540f4_31863ff7_cf898c9c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xe9542951_117097b0_c983284f_60293647_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xeb57d605_209cc57e_510a969e_be03f804_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xed5b8ad6_d11d1797_9f53bffc_6d23fe30_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xef5f47c6_6457f199_b286c6e1_13337886_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf0e21acd_d6e7d412_b6ed8085_2ae6fd63_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf2e5e5f2_5450c5a2_df437fb0_f616082d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf4e9b935_685dbe0b_f237cff1_acb306b3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf6ed9497_5480b696_52dbfafb_4121a092_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xf8f17818_5a2ebfd9_0d816482_49cece4c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xfaf563b8_bae001eb_ad95e6b0_b96903d3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xfcf95778_b80fbc98_176cd568_87ac7fe9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -135, mantissa: 0xfefd5358_933c478c_65f4c739_7f1f478d_u128, }, ]; pub(crate) static LOG_STEP_3: [DyadicFloat128; 161] = // -log(r) for the third step, generated by SageMath with: // // for i in range(-80, 81): // r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("{RationalSign::Pos," if (s == -1) else "{RationalSign::Neg,", e, ", // format_hex(m), "},"); /* .step_3 = */ [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x9fff3801_4d52e45a_374b2940_76d669c3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x9dff3cf9_40fad85a_7f6f05dc_dbeb776e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x9bff41e1_34f1cb36_3d55e21d_41bbadf9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x99ff46b9_2936bcf4_ccdba2d5_4aadbc5c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x97ff4b81_1dc8ad9d_71dd16d3_073f79b2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x95ff5039_12a69d37_5837f3df_1a58dd48_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x93ff54e1_07cf8bc9_93cad3bc_dd26fd6d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x91ff5978_fd42795b_2075312a_827f14fa_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x8fff5e00_f2fe65f2_e21764e1_39c98f60_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x8dff6278_e9025197_a492a295_51751b4c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x8bff66e0_df4d3c50_1bc8f5f6_58f1c3a2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x89ff6b38_d5de2622_e39d3faf_42340ed7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x87ff6f80_ccb40f16_7ff33266_82c02485_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x85ff73b8_c3cdf731_5caf4fbe_343cf928_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x83ff77e0_bb2ade79_cdb6e554_348f7fe8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -142, mantissa: 0x81ff7bf8_b2c9c4f6_0ef009c2_457de25d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xffff0001_55535558_8883333c_57b57c74_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xfbff07f1_45931f44_f32668f3_9c70d183_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xf7ff0fc1_3650e7bd_459a73c6_a6486fe3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xf3ff1771_278aaecd_37b18cca_7dd3a29f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xefff1f01_193e7480_513f610d_21bcfc78_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xebff2671_0b6a38e1_ea190b95_c0690b7b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xe7ff2dc0_fe0bfbfd_2a150f64_f0ad1743_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xe3ff34f0_f121bddd_090b5174_e995e9d1_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xdfff3c00_e4a97e8c_4ed512b9_b93ea2bf_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xdbff42f0_d8a13e15_934cea21_7ab794a2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xd7ff49c0_cd06fc83_3e4ebe94_8afd2c76_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xd3ff5070_c1d8b9df_87b7c0f5_bcfee2e1_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xcfff5700_b7147634_77666622_8cb6371b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xcbff5d70_acb8318b_e53a60f3_514db358_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xc7ff63c0_a2c1ebef_79149c3b_6e57fa86_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xc3ff69f0_992fa568_aad734c9_8416df2a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xbfff7000_8fff5e00_c2657367_9ed28334_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xbbff75f0_872f15c0_d7a3c6db_6540809f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xb7ff7bc0_7ebcccb1_d277bde6_45fb1aad_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xb3ff8170_76a682dc_6ac80145_a4087793_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xafff8700_6eea3849_287c4db3_0271e265_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xabff8c70_6785ed00_637d6de4_2eeb151e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xa7ff91c0_6077a10a_43b5348b_6b898a8c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0xa3ff96f0_59bd546e_c10e7657_978bd7f6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x9fff9c00_53550735_a37503f4_57310e59_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x9bffa0f0_4d3cb966_82d5a40a_3aa022ff_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x97ffa5c0_47726b08_c71e0d3e_e3df5f4d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x93ffaa70_41f41c23_a83ce035_2bdbd79b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x8fffaf00_3cbfccbe_2e21a18d_4680e8e4_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x8bffb370_37d37cdf_30bcb3e4_e5dfbd28_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x87ffb7c0_332d2c8d_57ff51d7_5c66d64a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -143, mantissa: 0x83ffbbf0_2ecadbcf_1bdb87fd_be299f43_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xffff8000_55551555_88885dde_02700703_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xf7ff87e0_4d94724c_d259ca80_3a0c1870_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xefff8f80_464fce8f_e5141308_51c7070a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xe7ff96e0_3f832a2a_30a16898_f3073a64_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xdfff9e00_392a8526_c4ed6451_7b2949ce_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xd7ffa4e0_3341df90_51e4fb4e_32cf6350_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xcfffab80_2dc53971_277672a8_8350bcce_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xc7ffb1e0_28b092d3_35915377_2a490f06_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xbfffb800_23ffebc0_0c265ece_6b481a0e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xb7ffbde0_1faf4440_db2781c0_3fa132f6_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xafffc380_1bba9c5e_7287c95c_845ada33_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0xa7ffc8e0_181df421_423b56b1_263e5a77_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0x9fffce00_14d54b91_5a3752ca_4c076fa3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0x97ffd2e0_11dca2b6_6a71e2b2_7eb3f573_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0x8fffd780_0f2ff997_c2e21b72_cff39d8f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -144, mantissa: 0x87ffdbe0_0ccb503c_537ff612_feb7ac9e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0xffffc000_15554d55_58888733_33c57c18_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0xefffc7c0_1193f9d1_fa514218_42311c42_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0xdfffcf00_0e4aa5fa_2c4ed6de_475b942c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0xcfffd5c0_0b7151d8_ce77678c_bb6fcb88_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0xbfffdc00_08fffd78_00c26629_a679ed3b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0xafffe1c0_06eea8e1_23287cb9_d3072728_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0x9fffe700_0535541c_d5a37540_fd057315_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -145, mantissa: 0x8fffebc0_03cbff32_f82e21c1_fce36810_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -146, mantissa: 0xffffe000_05555455_5588887d_dde02702_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -146, mantissa: 0xdfffe780_0392aa14_9ac4ed72_adf5b295_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -146, mantissa: 0xbfffee00_023fffaf_000c2664_8066b482_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -146, mantissa: 0x9ffff380_014d552e_455a3754_b292c077_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -147, mantissa: 0xfffff000_01555535_55588888_33333c58_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -147, mantissa: 0xbffff700_008ffff5_e000c266_5736679f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -148, mantissa: 0xfffff800_00555551_55558888_85ddde02_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -149, mantissa: 0xfffffc00_00155554_d5555888_88733334_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -148, mantissa: 0x80000200_000aaaaa_eaaaac44_444eeeef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -147, mantissa: 0x80000400_002aaaac_aaaac444_459999ac_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -147, mantissa: 0xc0000900_0090000a_2000c266_7596679f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0x80000800_00aaaaba_aaac4444_6eeef381_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0xa0000c80_014d557c_655a3755_f81815cc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0xc0001200_02400051_000c2668_4c66b482_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0xe0001880_0392ab40_bac4ed7c_40fb07eb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0x80001000_02aaab2a_aac44449_999abe2c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0x90001440_03cc00cd_082e21d7_9cbb6812_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xa0001900_0535568d_d5a37569_adb01dc3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xb0001e40_06eeac74_33287d01_e8c9d1d9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xc0002400_09000288_00c266a3_2679ed48_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xd0002a40_0b7158d1_de776851_22b2764b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xe0003100_0e4aaf5b_2c4ed810_a8063f03_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -145, mantissa: 0xf0003840_1194062e_0a5143e7_be891c8f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0x80002000_0aaaaeaa_ac4444ee_ef3813a1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0x88002420_0ccb5a6e_5b7ff7fe_1339025b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0x90002880_0f300668_42e21e26_caf39e33_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0x98002d20_11dcb29e_f271e66f_a5554bc6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xa0003200_14d55f19_5a3757e0_615cc676_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xa8003720_181e0bde_ca3b5d82_10ca5cab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xb0003c80_1bbab8f6_f287d25f_3cb032bb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xb8004220_1faf6669_e3278d84_0be28cdb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xc0004800_24001440_0c266dfe_6b482076_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xc8004e20_28b0c282_3d9166de_380a6d3d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xd0005480_2dc57139_a7768b35_6ba61e4b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xd8005b20_3342206f_d9e51a18_49db73c1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xe0006200_392ad02e_c4ed8a9d_907eb521_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xe8006920_3f838080_b8a197de_a928acd7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xf0007080_46503170_65144cf7_dcc72d3b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -144, mantissa: 0xf8007820_4d94e308_da5a1108_890d9f6a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x80004000_2aaacaaa_c4445999_abe2ce2c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x84004410_2ecb2431_1fdbbb4f_3bffc832_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x88004840_332d7e1d_97ff8f39_ec91b4ee_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x8c004c90_37d3d876_74bcfcf0_b3f0a95d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x90005100_3cc03342_2e21f80c_a6813aff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x94005590_41f48e87_6c3d4629_170ce87f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x98005a40_4772ea4d_071e84e3_b80a8881_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0x9c005f10_4d3d469a_06d62fdc_bdd6bec3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xa0006400_5355a375_a375a6b7_01dc77c0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xa4006910_59be00e7_450f3318_26ad6b05_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xa8006e40_60785ef6_83b60ea8_bd0aa459_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xac007390_6786bdab_277e6914_69dd13f5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xb0007900_6eeb1d0d_287d6e0a_0d1e25eb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xb4007e90_76a77d24_aec94b3b_e9b060f5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xb8008440_7ebdddfa_1279365f_ce280cce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xbc008a10_87303f95_dba5732f_3e83e04a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc0009000_9000a200_c2675967_9ed5b754_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc4009610_99310543_aed95aca_5edb5109_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xc8009c40_a2c36967_b917091d_2687160f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xcc00a290_acb9ce76_293d1c2a_0378e75d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd000a900_b7163478_776977bf_9766f5a7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd400af90_c1da9b78_4bbb31b1_4776a18b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd800b640_cd09037f_7e5297d7_6c8564ba_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xdc00bd10_d8a36c98_1751360f_8461c447_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xe000c400_e4abd6cc_4ed9dc3c_63f44c41_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xe400cb10_f1244226_8d10a446_6a5894d5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xe800d240_fe0eaeb1_6a1af81b_b4e6510e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xec00d991_0b6d1c77_ae1f97b0_542a677a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xf000e101_19418b84_51469efe_81d014cc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xf400e891_278dfbe2_7bb98c06_d77a18b4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xf800f041_36546d9d_85a344d0_868bed17_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xfc00f811_4596e0c0_f7301d69_90e307cc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x80008000_aaabaaac_4446eef3_8140138f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x82008408_b2cbe5b8_10f5e432_96105497_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x84008820_bb2d2189_edbd4f83_ef63f730_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x86008c48_c3d05e27_feb654fd_541c638e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x88009080_ccb69b98_7ffadeb8_882f7674_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x8a0094c8_d5e0d9e1_c5a59fd3_6bd44397_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x8c009920_df50190a_3bd21770_1b27dddb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x8e009d88_e9055918_669c93b5_0e4a2595_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9000a200_f3019a12_e22234cd_39f29cd4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9200a688_fd45dc00_6280efe8_307d41d9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9400ab21_07d31ee7_b3d7923a_436f6fc4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9600afc9_12aa62cf_ba45c3fc_a574c5a0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9800b481_1dcca7bf_71ec0b6d_8cd413d1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9a00b949_293aedbd_eeebcfd0_565c5006_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9c00be21_34f634d2_5d675c6d_a8c98fc3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0x9e00c309_40ff7d04_0181e393_98a2099a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -142, mantissa: 0xa000c801_4d57c65a_375f8195_cc8b1d29_u128, }, ]; pub(crate) static LOG_STEP_4: [DyadicFloat128; 130] = // -log(r) for the fourth step, generated by SageMath with: // // for i in range(-65, 65): // r = 2^-28 * round( 2^28 / (1 + i*2^(-28)) ); // s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); // print("{RationalSign::Pos," if (s == -1) else "{RationalSign::Neg,", e, ", // format_hex(m), "},"); /* .step_4 = */ [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -149, mantissa: 0x81fffef7_f002cb2b_4cd24d68_ff2f11ae_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xfffffe00_00055555_45555588_8887ddde_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xfbfffe0f_e0051653_f0fa101f_52b3971f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xf7fffe1f_8004d94a_9c9329d6_59ed3734_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xf3fffe2e_e0049e31_4821006d_9b58462e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xeffffe3e_000464ff_f3a3f025_142f8c21_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xebfffe4c_e0042dae_9f1c53bc_c1c4b11c_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xe7fffe5b_8003f835_4a8a8474_a17fdd30_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xe3fffe69_e003c48b_f5eeda0c_b0df586d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xdffffe78_000392aa_a149aac4_ed772adf_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xdbfffe85_e0036289_4c9b4b5d_54f0bc96_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xd7fffe93_8003341f_f7e40f15_e50a759f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xd3fffea0_e0030766_a32447ae_9b975e05_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xcffffeae_0002dc55_4e5c4567_767ebdd5_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xcbfffeba_e002b2e3_f98c5700_73bbbd19_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xc7fffec7_80028b0a_a4b4c9b9_915d03dd_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xc3fffed3_e00264c1_4fd5e952_cd845a28_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xbffffee0_00023fff_faf0000c_26664806_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xbbfffeeb_e0021cbe_a60356a5_9a49b57f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xb7fffef7_8001faf5_5110345f_27878a9b_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xb3ffff02_e001da9b_fc16def8_cc8a4f61_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xafffff0e_0001bbaa_a7179ab2_87cdcbd8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xabffff18_e0019e19_5212aa4c_57dea809_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xa7ffff23_800181df_fd084f06_3b5a0bf8_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0xa3ffff2d_e00166f6_a7f8c8a0_30ed3fab_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x9fffff38_00014d55_52e4555a_37554b29_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x9bffff41_e00134f3_fdcb31f4_4d5e9676_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x97ffff4b_80011dca_a8ad99ae_71e48997_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x93ffff54_e00107d1_538bc648_a3d12c90_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x8fffff5e_0000f2ff_fe65f002_e21cc765_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x8bffff66_e000df4e_a93c4d9d_2bcd821a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x87ffff6f_8000ccb5_540f1457_7ff704b2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -150, mantissa: 0x83ffff77_e000bb2b_fede77f1_ddba1731_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xffffff00_00015555_53555558_88888333_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xf7ffff0f_c0013652_a8e7ba8d_659ed7dc_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xefffff1f_0001193f_fe747e02_5142fc61_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xe7ffff2d_c000fe0d_53fbfb37_4a1800c7_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xdfffff3c_0000e4aa_a97e8aac_4ed77513_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xd7ffff49_c000cd07_fefc81e1_5e50a947_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xcfffff57_0000b715_54763356_7767ed66_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xc7ffff63_c000a2c2_a9ebee8b_9915d174_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xbfffff70_00008fff_ff5e0000_c2666573_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xb7ffff7b_c0007ebd_54ccb135_f2787966_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xafffff87_00006eea_aa3848ab_287cdd4e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0xa7ffff91_c0006077_ffa109e0_63b5a12d_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0x9fffff9c_00005355_55073555_a3755504_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0x97ffffa5_c0004772_aa6b088a_e71e48d5_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0x8fffffaf_00003cbf_ffccbe00_2e21cca2_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -151, mantissa: 0x87ffffb7_c000332d_552c8d35_77ff706a_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0xffffff80_00005555_55155555_8888885e_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0xefffff8f_8000464f_ffce8fc0_25142fe3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0xdfffff9e_0000392a_aa8526aa_c4ed7764_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0xcfffffab_80002dc5_55397115_67767ee3_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0xbfffffb8_000023ff_ffebc000_0c26665f_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0xafffffc3_80001bba_aa9c5e6a_b287cdd9_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0x9fffffce_000014d5_554b9155_5a375553_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -152, mantissa: 0x8fffffd7_80000f2f_fff997c0_02e21ccb_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -153, mantissa: 0xffffffc0_00001555_554d5555_58888887_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -153, mantissa: 0xdfffffcf_00000e4a_aaa5fa2a_ac4ed777_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -153, mantissa: 0xbfffffdc_000008ff_fffd7800_00c26666_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -153, mantissa: 0x9fffffe7_00000535_55541cd5_55a37555_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -154, mantissa: 0xffffffe0_00000555_55545555_55888888_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -154, mantissa: 0xbfffffee_0000023f_ffffaf00_000c2666_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -155, mantissa: 0xfffffff0_00000155_55553555_55588889_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -156, mantissa: 0xfffffff8_00000055_55555155_55558889_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -155, mantissa: 0x80000004_0000002a_aaaaacaa_aaaac444_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -154, mantissa: 0x80000008_000000aa_aaaabaaa_aaac4444_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -154, mantissa: 0xc0000012_00000240_00005100_000c2666_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -153, mantissa: 0x80000010_000002aa_aaab2aaa_aac44444_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -153, mantissa: 0xa0000019_00000535_55568dd5_55a37555_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -153, mantissa: 0xc0000024_00000900_00028800_00c26667_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -153, mantissa: 0xe0000031_00000e4a_aaaf5b2a_ac4ed778_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0x80000020_00000aaa_aaaeaaaa_ac444445_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0x90000028_80000f30_00066840_02e21cce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0xa0000032_000014d5_555f1955_5a375558_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0xb000003c_80001bba_aab8f6ea_b287cde2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0xc0000048_00002400_00144000_0c26666e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0xd0000054_80002dc5_55713995_67767efb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0xe0000062_0000392a_aad02eaa_c4ed778b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -152, mantissa: 0xf0000070_80004650_00317040_2514301d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0x80000040_00002aaa_aacaaaaa_c444445a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0x88000048_4000332d_557e1d75_77ff70a7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0x90000051_00003cc0_00334200_2e21ccf8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0x9800005a_40004772_aaea4cca_e71e494d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xa0000064_00005355_55a37555_a37555a7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xa800006e_40006078_005ef620_63b5a207_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xb0000079_00006eea_ab1d0cab_287cde6e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xb8000084_40007ebd_55ddf975_f2787ade_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xc0000090_00009000_00a20000_c2666759_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xc800009c_4000a2c2_ab6966cb_9915d3e1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xd00000a9_0000b715_56347756_7767f078_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xd80000b6_4000cd08_01037e21_5e50ad20_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xe00000c4_0000e4aa_abd6caac_4ed779dc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xe80000d2_4000fe0d_56aeaf77_4a1806b0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xf00000e1_00011940_018b8202_5143039f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -151, mantissa: 0xf80000f0_40013652_ac6d9acd_659ee0ad_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x80000080_0000aaaa_abaaaaac_444446ef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x84000088_2000bb2c_01218811_ddba1d9b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x88000090_8000ccb5_569b9657_7ff70c5f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x8c000099_2000df4e_ac1907bd_2bcd8b3b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x900000a2_0000f300_019a1002_e21cd235_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x940000ab_200107d1_571ee468_a3d1394e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x980000b4_80011dca_aca7bbae_71e4988b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0x9c0000be_200134f4_0234ce14_4d5ea7f0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xa00000c8_00014d55_57c6555a_37555f82_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xa40000d2_200166f6_ad5c8cc0_30ed5744_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xa80000dc_800181e0_02f7b106_3b5a273b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xac0000e7_20019e19_5898006c_57dec76f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xb00000f2_0001bbaa_ae3dbab2_87cdefe3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xb40000fd_2001da9c_03e92118_cc8a789f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xb8000108_8001faf5_599a765f_2787b9aa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xbc000114_20021cbe_af51fec5_9a49eb0a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xc0000120_00024000_0510000c_266684c6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xc400012c_200264c1_5ad4c172_cd849ee9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xc8000138_80028b0a_b0a08bb9_915d5179_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xcc000145_2002b2e4_0673a920_73bc1480_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xd0000152_0002dc55_5c4e6567_767f2009_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xd400015f_20030766_b2310dce_9b97cc1d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xd800016c_80033420_081bf115_e50af0c7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xdc00017a_20036289_5e0f5f7d_54f14614_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xe0000188_000392aa_b40baac4_ed77c410_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xe4000196_2003c48c_0a11262c_b0e002c7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xe80001a4_8003f835_60202674_a1809a47_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xec0001b3_20042dae_b63901dc_c1c582a0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xf00001c2_00046500_0c5c1025_143073df_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xf40001d1_20049e31_6289aa8d_9b594616_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xf80001e0_8004d94a_b8c22bd6_59ee5155_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -150, mantissa: 0xfc0001f0_20051654_0f05f03f_52b4cdae_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -149, mantissa: 0x80000100_0002aaaa_b2aaaac4_4444999a_u128, }, ]; pxfm-0.1.23/src/logs/log_range_reduction.rs000064400000000000000000000206251046102023000170000ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; // Logarithm range reduction - Step 3: // r(k) = 2^-21 round(2^21 / (1 + k*2^-21)) for k = -80 .. 80. // Output range: // [-0x1.01928p-22 , 0x1p-22] // We store S[i] = 2^21 (r(i - 80) - 1). static S3: [i32; 161] = [ 0x50, 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, -0x1, -0x2, -0x3, -0x4, -0x5, -0x6, -0x7, -0x8, -0x9, -0xa, -0xb, -0xc, -0xd, -0xe, -0xf, -0x10, -0x11, -0x12, -0x13, -0x14, -0x15, -0x16, -0x17, -0x18, -0x19, -0x1a, -0x1b, -0x1c, -0x1d, -0x1e, -0x1f, -0x20, -0x21, -0x22, -0x23, -0x24, -0x25, -0x26, -0x27, -0x28, -0x29, -0x2a, -0x2b, -0x2c, -0x2d, -0x2e, -0x2f, -0x30, -0x31, -0x32, -0x33, -0x34, -0x35, -0x36, -0x37, -0x38, -0x39, -0x3a, -0x3b, -0x3c, -0x3d, -0x3e, -0x3f, -0x40, -0x41, -0x42, -0x43, -0x44, -0x45, -0x46, -0x47, -0x48, -0x49, -0x4a, -0x4b, -0x4c, -0x4d, -0x4e, -0x4f, -0x50, ]; // Logarithm range reduction - Step 4 // r(k) = 2^-28 round(2^28 / (1 + k*2^-28)) for k = -65 .. 64. // Output range: // [-0x1.0002143p-29 , 0x1p-29] // We store S[i] = 2^28 (r(i - 65) - 1). static S4: [i32; 130] = [ 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, -0x1, -0x2, -0x3, -0x4, -0x5, -0x6, -0x7, -0x8, -0x9, -0xa, -0xb, -0xc, -0xd, -0xe, -0xf, -0x10, -0x11, -0x12, -0x13, -0x14, -0x15, -0x16, -0x17, -0x18, -0x19, -0x1a, -0x1b, -0x1c, -0x1d, -0x1e, -0x1f, -0x20, -0x21, -0x22, -0x23, -0x24, -0x25, -0x26, -0x27, -0x28, -0x29, -0x2a, -0x2b, -0x2c, -0x2d, -0x2e, -0x2f, -0x30, -0x31, -0x32, -0x33, -0x34, -0x35, -0x36, -0x37, -0x38, -0x39, -0x3a, -0x3b, -0x3c, -0x3d, -0x3e, -0x3f, -0x40, ]; // Logarithm range reduction - Step 2: // r(k) = 2^-16 round(2^16 / (1 + k*2^-14)) for k = -2^6 .. 2^7. // Output range: // [-0x1.3ffcp-15, 0x1.3e3dp-15] // We store S2[i] = 2^16 (r(i - 2^6) - 1). static S2: [i32; 193] = [ 0x101, 0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1, 0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1, 0xbd, 0xb9, 0xb4, 0xb0, 0xac, 0xa8, 0xa4, 0xa0, 0x9c, 0x98, 0x94, 0x90, 0x8c, 0x88, 0x84, 0x80, 0x7c, 0x78, 0x74, 0x70, 0x6c, 0x68, 0x64, 0x60, 0x5c, 0x58, 0x54, 0x50, 0x4c, 0x48, 0x44, 0x40, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0xc, 0x8, 0x4, 0x0, -0x4, -0x8, -0xc, -0x10, -0x14, -0x18, -0x1c, -0x20, -0x24, -0x28, -0x2c, -0x30, -0x34, -0x38, -0x3c, -0x40, -0x44, -0x48, -0x4c, -0x50, -0x54, -0x58, -0x5c, -0x60, -0x64, -0x68, -0x6c, -0x70, -0x74, -0x78, -0x7c, -0x80, -0x84, -0x88, -0x8c, -0x90, -0x94, -0x98, -0x9c, -0xa0, -0xa4, -0xa8, -0xac, -0xb0, -0xb4, -0xb7, -0xbb, -0xbf, -0xc3, -0xc7, -0xcb, -0xcf, -0xd3, -0xd7, -0xdb, -0xdf, -0xe3, -0xe7, -0xeb, -0xef, -0xf3, -0xf7, -0xfb, -0xff, -0x103, -0x107, -0x10b, -0x10f, -0x113, -0x117, -0x11b, -0x11f, -0x123, -0x127, -0x12b, -0x12f, -0x133, -0x137, -0x13a, -0x13e, -0x142, -0x146, -0x14a, -0x14e, -0x152, -0x156, -0x15a, -0x15e, -0x162, -0x166, -0x16a, -0x16e, -0x172, -0x176, -0x17a, -0x17e, -0x182, -0x186, -0x18a, -0x18e, -0x192, -0x195, -0x199, -0x19d, -0x1a1, -0x1a5, -0x1a9, -0x1ad, -0x1b1, -0x1b5, -0x1b9, -0x1bd, -0x1c1, -0x1c5, -0x1c9, -0x1cd, -0x1d1, -0x1d5, -0x1d9, -0x1dd, -0x1e0, -0x1e4, -0x1e8, -0x1ec, -0x1f0, -0x1f4, -0x1f8, -0x1fc, ]; // Perform logarithm range reduction steps 2-4. // Inputs from the first step of range reduction: // m_x : the reduced argument after the first step of range reduction // satisfying -2^-8 <= m_x < 2^-7 and ulp(m_x) >= 2^-60. // idx1: index of the -log(r1) table from the first step. // Outputs of the extra range reduction steps: // sum: adding -log(r1) - log(r2) - log(r3) - log(r4) to the resulted sum. // return value: the reduced argument v satisfying: // -0x1.0002143p-29 <= v < 0x1p-29, and ulp(v) >= 2^(-125). pub(crate) fn log_range_reduction( m_x: f64, log_table: &[&[DyadicFloat128]; 4], sum: DyadicFloat128, ) -> (DyadicFloat128, DyadicFloat128) { let v = (m_x * f64::from_bits(0x43b0000000000000)) as i64; // ulp = 2^-60 // Range reduction - Step 2 // Output range: vv2 in [-0x1.3ffcp-15, 0x1.3e3dp-15]. // idx2 = trunc(2^14 * (v + 2^-8 + 2^-15)) let idx2 = ((v.wrapping_add(0x10_2000_0000_0000)) >> 46) as usize; let z0 = log_table[1][idx2]; let mut sum = sum + z0; let s2: i64 = S2[idx2] as i64; // |s| <= 2^-7, ulp = 2^-16 let sv2 = s2 * v; // |s*v| < 2^-14, ulp = 2^(-60-16) = 2^-76 let spv2 = s2.wrapping_shl(44).wrapping_add(v); // |s + v| < 2^-14, ulp = 2^-60 let vv2 = spv2.wrapping_shl(16).wrapping_add(sv2); // |vv2| < 2^-14, ulp = 2^-76 // Range reduction - Step 3 // Output range: vv3 in [-0x1.01928p-22 , 0x1p-22] // idx3 = trunc(2^21 * (v + 80*2^-21 + 2^-22)) let idx3 = vv2.wrapping_add(0x2840_0000_0000_0000).wrapping_shr(55) as usize; sum = sum + log_table[2][idx3]; let s3 = S3[idx3] as i64; // |s| < 2^-13, ulp = 2^-21 let spv3: i64 = s3.wrapping_shl(55).wrapping_add(vv2); // |s + v| < 2^-21, ulp = 2^-76 // |s*v| < 2^-27, ulp = 2^(-76-21) = 2^-97 let sv3: i128 = s3 as i128 * vv2 as i128; // |vv3| < 2^-21, ulp = 2^-97 let vv3 = (spv3 as i128).wrapping_shl(21).wrapping_add(sv3); // Range reduction - Step 4 // Output range: vv4 in [-0x1.0002143p-29 , 0x1p-29] // idx4 = trunc(2^21 * (v + 65*2^-28 + 2^-29)) let idx4 = ((((vv3 >> 68) as i32).wrapping_add(131)) >> 1) as usize; let z4 = log_table[3][idx4]; sum = sum + z4; let s4: i128 = S4[idx4] as i128; // |s| < 2^-21, ulp = 2^-28 // |s + v| < 2^-28, ulp = 2^-97 let spv4 = s4.wrapping_shl(69).wrapping_add(vv3); // |s*v| < 2^-42, ulp = 2^(-97-28) = 2^-125 let sv4 = s4 * vv3; // |vv4| < 2^-28, ulp = 2^-125 let vv4 = spv4.wrapping_shl(28).wrapping_add(sv4); let mut z0 = if vv4 < 0 { DyadicFloat128 { sign: DyadicSign::Neg, exponent: -125, mantissa: (-vv4) as u128, } } else { DyadicFloat128 { sign: DyadicSign::Pos, exponent: -125, mantissa: vv4 as u128, } }; z0.normalize(); (z0, sum) } pxfm-0.1.23/src/logs/log_td.rs000064400000000000000000000122141046102023000142320ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; use crate::logs::log_td_table::LOG_NEG_TD; use crate::pow_tables::POW_INVERSE; use crate::triple_double::TripleDouble; #[inline(always)] fn log_td_poly(z: f64) -> TripleDouble { /* See ./notes/td_log.sollya */ const P: [(u64, u64, u64); 10] = [ (0x38fc6038ddcc5680, 0x3c755555556795ff, 0x3fd5555555555555), (0x372720effda9e638, 0xba86f68986749d55, 0xbfd0000000000000), (0x38deb738e67c5280, 0xbc699b2852652c20, 0x3fc999999999999a), (0x3900b719d69f9950, 0xbc65526cf5c3f935, 0xbfc5555555555555), (0xb8ad0f51dccb7c02, 0xbc34fc5a6b8b9f2d, 0x3fc24924924924aa), (0xb8faeee1e6f2b960, 0xbc52e65780d7da8f, 0xbfc0000000000023), (0xb8f306e8001c6280, 0x3c5d0f68afb70c37, 0x3fbc71c71c2042d4), (0x38d6940b092bf340, 0xbc3280fbebf81ea0, 0xbfb999999934f78b), (0xb8daa1cce08da780, 0x3c48da171d2f9c73, 0x3fb74612a55c4784), (0x38e9232517db1c80, 0x3c553b70480fc993, 0xbfb5559a592ab15c), ]; let x2 = DoubleDouble::from_exact_mult(z, z); let mut t = TripleDouble::f64_mul_add( z, TripleDouble::from_bit_pair(P[9]), TripleDouble::from_bit_pair(P[8]), ); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[7])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[6])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[5])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[4])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[3])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[2])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[1])); t = TripleDouble::f64_mul_add(z, t, TripleDouble::from_bit_pair(P[0])); t = TripleDouble::quick_mult_dd(t, x2); t = TripleDouble::quick_mult_f64(t, z); TripleDouble::f64_mul_dd_add(-0.5, x2, t) } #[inline] pub(crate) fn log_td(x: f64) -> TripleDouble { let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; t *= CY[c]; let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let log_r = TripleDouble::from_bit_pair(LOG_NEG_TD[(i - 181) as usize]); let z = f64::mul_add(r, t, -1.0); const LOG2_DD: TripleDouble = TripleDouble::from_bit_pair((0x3907b57a079a1934, 0x3c7abc9e3b39803f, 0x3fe62e42fefa39ef)); let tt = TripleDouble::f64_mul_add(be as f64, LOG2_DD, log_r); let v = TripleDouble::add_f64(z, tt); let p = log_td_poly(z); TripleDouble::add_f64(v.hi, TripleDouble::new(v.lo + p.lo, v.mid + p.mid, p.hi)) } #[cfg(test)] mod tests { use super::*; #[test] fn test_log_td() { assert_eq!(log_td(184467440737095500000.).to_f64(), 46.66400464883055); } } pxfm-0.1.23/src/logs/log_td_table.rs000064400000000000000000000333471046102023000154130ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by Sage: from POW_INV ```python R = RealField(150) def hex_to_float(h): return struct.unpack('>d', struct.pack('>Q', h))[0] # Convert each hex value to RealField real_array = [R(hex_to_float(h)) for h in values] # Show results for r in real_array: print_triple_double("", -RealField(180)(r).log()) ``` **/ pub(crate) static LOG_NEG_TD: [(u64, u64, u64); 182] = [ (0x38f1406554719540, 0x3c6bc60efafc6f6e, 0xbfd5ff3070a793d4), (0xb916f95d595cbf2e, 0x3c78ebcb7dee9a3d, 0xbfd5a42ab0f4cfe2), (0x3908294131dd7142, 0x3c6819cf7e308ddb, 0xbfd548a2c3add263), (0x391fcf3e64c8cd74, 0x3c742a87d977dc5e, 0xbfd4ec973260026a), (0xb8e16c8675ad963d, 0x3c69ffc341f177dc, 0xbfd49006804009d1), (0x3913f95697c9bfc2, 0x3c729931715ac903, 0xbfd432ef2a04e814), (0x3919ea6f9f60989c, 0x3c70bcfb6082ce6d, 0xbfd404308686a7e4), (0xb90beb7a3cee7e03, 0x3c6c68651945f97c, 0xbfd3a64c556945ea), (0xb90ee510a580b3b3, 0x3c64dd4c580919f8, 0xbfd347dd9a987d55), (0x390864244294826f, 0x3c78f4cdb95ebdf9, 0xbfd2e8e2bae11d31), (0xb9162d6a3aacbe58, 0xbc77ad24c13f040e, 0xbfd2895a13de86a3), (0x390a168b2a9642c4, 0x3c776f5eb09628af, 0xbfd22941fbcf7966), (0xb918cf23e43622b1, 0x3c7c9fdf9a0c4b07, 0xbfd1f8ff9e48a2f3), (0x3918eb33aa901486, 0xbc79d3d1b0e4d147, 0xbfd1980d2dd4236f), (0x38e4a5b394627b29, 0xbc77b66298edd24a, 0xbfd136870293a8b0), (0x38beb31a74640ec7, 0xbc589fa0ab4cb31d, 0xbfd1058bf9ae4ad5), (0xb8ec51bc06b5f7c1, 0xbc77dcfde8061c03, 0xbfd0a324e27390e3), (0x3900dddc4cf9a1f9, 0x3c628ec217a5022d, 0xbfd0402594b4d041), (0x39035f6dfd3ddd52, 0x3c6caaae64f21acb, 0xbfcfb9186d5e3e2b), (0xb8798a014b61d510, 0xbc2c5f6dfd018c37, 0xbfcf550a564b7b37), (0xb8edee364d35208a, 0x3c46e03a39bfc89b, 0xbfce8c0252aa5a60), (0xb8c55db94ebc4018, 0x3c461578001e0162, 0xbfce27076e2af2e6), (0xb8ec3c6ce7a257f4, 0xbc66e443597e4d40, 0xbfcd5c216b4fbb91), (0xb90a24ae3b2f53a1, 0x3c64f689f8434012, 0xbfcc8ff7c79a9a22), (0xb89f00f527d33467, 0x3c673dee38a3fb6b, 0xbfcc2968558c18c1), (0xb903dcf06e27bef1, 0xbc6ba27fdc19e1a0, 0xbfcb5b519e8fb5a4), (0x38da262591d1968b, 0x3c5398cff3641985, 0xbfcaf3c94e80bff3), (0xb8d3f1f8db36c599, 0xbc493711b07a998c, 0xbfca23bc1fe2b563), (0xb8f28792ae1aabc8, 0xbc6575e31f003e0c, 0xbfc9bb362e7dfb83), (0xb8dc0d0e377c6294, 0x3c6569d851a56770, 0xbfc8e928de886d41), (0x38f0a5aa8fb49481, 0x3c6bf7fdbfa08d9a, 0xbfc87fa06520c911), (0xb8a91ff852536204, 0xbc4be36b2d6a0608, 0xbfc7ab890210d909), (0x38f0be957f10f5fb, 0x3c5b264062a84cdb, 0xbfc740f8f54037a5), (0x38dc825cda7da31d, 0x3c6caae268ecd179, 0xbfc6d60fe719d21d), (0x38e1406554719540, 0x3c5bc60efafc6f6e, 0xbfc5ff3070a793d4), (0xb8f60e1f10db27cb, 0x3c565d22aa8ad7cf, 0xbfc59338d9982086), (0x38b04bfef68b5ce2, 0xbc668981bcc36756, 0xbfc4ba36f39a55e5), (0x390f3be9a8337458, 0xbc69f4f6543e1f88, 0xbfc44d2b6ccb7d1e), (0x38fb40efe811e153, 0x3c5ab3a8e7d81017, 0xbfc3dfc2b0ecc62a), (0x38a5e72f6cc4e614, 0x3c06b9c7d96091fa, 0xbfc303d718e47fd3), (0x390977b021b7c784, 0xbc6301771c407dbf, 0xbfc29552f81ff523), (0xb90eea44ec5389a5, 0xbc6f547bf1809e88, 0xbfc2266f190a5acb), (0xb8fbd933781e73cd, 0xbc6a28813e3a7f07, 0xbfc14785846742ac), (0x39071dbd9a581398, 0xbc69a5dc5e9030ac, 0xbfc0d77e7cd08e59), (0x38ee98f4812aa997, 0xbc550c647eb86499, 0xbfc0671512ca596e), (0x38f0ece597165991, 0xbc585f325c5bbacd, 0xbfbf0a30c01162a6), (0xb8b55db94ebc4018, 0x3c361578001e0162, 0xbfbe27076e2af2e6), (0xb8e20959368928d5, 0xbc5790dd951d90fa, 0xbfbd4313d66cb35d), (0xb8dda7659abe370e, 0xbc35d617ef8161b1, 0xbfbc5e548f5bc743), (0xb8e8f353ecfc45da, 0xbc5942f48aa70ea9, 0xbfba926d3a4ad563), (0x38cbb52cb975cbeb, 0x3c42099e1c184e8e, 0xbfb9ab42462033ad), (0x38ce547ecfe0df94, 0x3c24a697ab3424a9, 0xbfb8c345d6319b21), (0xb8fa115d17a663c2, 0x3c5eeedfcdd94131, 0xbfb7da766d7b12cd), (0xb8fc66d48ed8883f, 0x3c5388458ec21b6a, 0xbfb60658a93750c4), (0xb8f584bc9c7e09bc, 0xbc5a49e39a1a8be4, 0xbfb51b073f06183f), (0xb8d7465d8f6866cf, 0xbc4ddd4f935996c9, 0xbfb42edcbea646f0), (0x38e15fbcbe26b491, 0x3c5b599f227becbb, 0xbfb341d7961bd1d1), (0x38bd2c3f5a497e44, 0x3c1c125963fc4cfd, 0xbfb253f62f0a1417), (0x38bb925bd6fa5998, 0x3c379da3e8c22cda, 0xbfb16536eea37ae1), (0x38e0ece597165991, 0xbc485f325c5bbacd, 0xbfaf0a30c01162a6), (0xb8acecc7db99d86a, 0xbc21e3c53257fd47, 0xbfad276b8adb0b52), (0x38b6b5431d9cbf04, 0x3c3eb9759c130499, 0xbfab42dd711971bf), (0x38e9e0ef8448a202, 0xbc4f5a0e80520bf2, 0xbfa95c830ec8e3eb), (0xb8b63c9bf701b2a9, 0xbc418d3ca87b9296, 0xbfa77458f632dcfc), (0x38d33fb67ae4f6ce, 0x3c4ce55c2b4e2b72, 0xbfa58a5bafc8e4d5), (0xb8dc8d57ae1e11bd, 0x3c45bfa937f551bb, 0xbfa39e87b9febd60), (0x38df6acb8073198b, 0x3c3e9ae889bac481, 0xbfa1b0d98923d980), (0x38d814544147acc9, 0xbc333e3f04f1ef23, 0xbf9f829b0e783300), (0xb899ffdb5331f453, 0x3bf0ae69229dc868, 0xbf9b9fc027af9198), (0xb89dcd4f102a521d, 0x3c35b602ace3a510, 0xbf97b91b07d5b11b), (0xb8a98d0797189a4d, 0x3c10cb5a902b3a1c, 0xbf93cea44346a575), (0x38b52414fc416fc2, 0x3c183092c59642a1, 0xbf8fc0a8b0fc03e4), (0xb8aa850a4a1800ea, 0x3c116d7687d3df21, 0xbf87dc475f810a77), (0xb86a567b6587df34, 0x3bce44b7e3711ebf, 0xbf7fe02a6b106789), (0x0000000000000000, 0x0000000000000000, 0x8000000000000000), (0x0000000000000000, 0x0000000000000000, 0x8000000000000000), (0x387b59b52a5681bd, 0x3bec14b9f9377a1d, 0x3f78121214586b54), (0x38c6b69dd1ac0a31, 0xbc2c5517f64bc223, 0x3f841929f96832f0), (0xb8bf713b529d3d76, 0x3c2806208c04c220, 0x3f8c317384c75f06), (0xb8b3e8da8eba2824, 0xbc2cd7b66e01c26d, 0x3f9228fb1fea2e28), (0xb86484372b0fc178, 0xbbf8ed4d357c9c97, 0x3f963d6178690bd6), (0xb8aee63a49c74224, 0x3c1ec1a5f86d41f9, 0x3f9a55f548c5c43f), (0x38ce166b9e0c701b, 0x3c375b44595cab18, 0x3f9e72bf2813ce51), (0x38d3bc1c184cef0a, 0x3c4c05cf1d753622, 0x3fa0415d89e74444), (0x38c1de8382dc46eb, 0xbc4947f792615916, 0x3fa252f32f8d183f), (0x38eb92d06f3fe3af, 0xbc4cdd6f7f4a137e, 0x3fa466aed42de3ea), (0x38e85f24bc417540, 0x3c40413e6505e603, 0x3fa67c94f2d4bb58), (0xb8cd5f973f27591e, 0x3c3a8be97660a23d, 0x3fa894aa149fb343), (0xb8cd0957659a8681, 0x3c2a353bb42e0add, 0x3faaaef2d0fb10fc), (0x38cb1c2ce23545f5, 0x3c3e5cf3a0f56f72, 0x3fabbcebfc68f420), (0xb8dc4ea8dab3d31c, 0x3c44e6c986f44c55, 0x3fadda8adc67ee4e), (0x38e915fc13249a8b, 0xbc4cd9f1f95c2eed, 0x3faffa6911ab9301), (0x38db4cbd380a58f0, 0xbc5a4a128d192686, 0x3fb10e45b3cae831), (0xb8f531cc3e70565e, 0xbc5cc0fbce104eaa, 0x3fb2207b5c78549e), (0xb8dd345728d4891b, 0xbc5d15d38d2fa3f7, 0x3fb2aa04a44717a5), (0x38eb282b433139ab, 0x3c47a976d3b5b45f, 0x3fb3bdf5a7d1ee64), (0xb8e3165ac490d812, 0x3c5769f42c7842cc, 0x3fb4d3115d207eac), (0xb8fdf1f1f9a97a34, 0xbc545f9d61c68c1b, 0x3fb55e10050e0384), (0x38edb15b559f2b8c, 0xbc59acd8b33f8fdc, 0x3fb674f089365a7a), (0xb8eb73942ba54569, 0x3c5abca5b4fdb880, 0x3fb78d02263d82d3), (0xb8dc199e47fc4f1b, 0x3c3b9f2dffbeed43, 0x3fb8197e2f40e3f0), (0x38f089735832ff2f, 0xbc5478a85704ccb7, 0x3fb9335e5d594989), (0xb8f9be73856e63dd, 0xbc55b5ca203e4259, 0x3fba4e7640b1bc38), (0xb8fd1dc4ae609d89, 0x3c537d8f39bee659, 0x3fbadc77ee5aea8c), (0x38ec5646e7873ff4, 0xbc4cdc9f6f5f38c7, 0x3fbbf968769fca11), (0xb8ca4a0195f6076f, 0x3c49daf7df76ad2a, 0x3fbd179788219364), (0xb8f0554118a2fe2d, 0x3c5401fa71733019, 0x3fbda727638446a2), (0xb8b1980fad2b8c8f, 0xbc4a2bf991780d3f, 0x3fbec739830a1120), (0xb8eba1da9ea4e2ac, 0xbc59361574fb24e2, 0x3fbf57bc7d9005db), (0x38d491637376842d, 0x3c639e2d3f8b7d10, 0x3fc03cdc0a51ec0d), (0xb8fa7da07274e01d, 0xbc6dd7009902bf32, 0x3fc08598b59e3a07), (0x38f03c776a3fb0f1, 0xbc50e63a5f01c691, 0x3fc1178e8227e47c), (0x390a1136855b465f, 0xbc62d56ff61c2bfb, 0x3fc160c8024b27b1), (0xb8dc641c1655b965, 0x3c462c9ef939ac5d, 0x3fc1f3b925f25d41), (0xb9030309bfb61ce3, 0xbc66e38161051d69, 0x3fc23d712a49c202), (0xb8fdedef6e5214fa, 0xbc5499a3f25af95f, 0x3fc2d1610c86813a), (0xb8ab9d980d8c440b, 0xbc5c4716bdfc0cc9, 0x3fc31b994d3a4f85), (0xb8c44d5c95f5d241, 0x3c370d6cdf05266c, 0x3fc3b08b6757f2a9), (0xb9055cfc4715d0cf, 0xbc6d87e6a354d056, 0x3fc3fb45a59928cc), (0x38f046ddd0c4995f, 0xbc50d5604930f135, 0x3fc4913d8333b561), (0xb90e5aae7083b870, 0xbc6927d47803c5f4, 0x3fc4dc7b897bc1c8), (0xb8fcb60e1eb82c6c, 0x3c64f4d710fec38e, 0x3fc5737cc9018cdd), (0xb8c25a7abe3c6675, 0xbc21f5b44c0df7e7, 0x3fc5bf406b543db2), (0xb8d0587f8805bff2, 0xbc3d34f0f4621bed, 0x3fc6574ebe8c133a), (0x38ef4165ace952df, 0x3c696332bd4b341f, 0x3fc6a399dabbd383), (0xb905e04327207755, 0xbc68de59c21e166c, 0x3fc6f0128b756abc), (0x38fa90e246a61446, 0x3c5ef8f6ebcfb201, 0x3fc7898d85444c73), (0x38ee9d5bdc04215b, 0xbc4ac5f0c075b847, 0x3fc7d6903caf5ad0), (0xb8ea55c7d1bf59b5, 0x3c6d685f35eea2a0, 0x3fc871213750e994), (0x38e5f9812ac08ffd, 0x3c555aa8b6997a40, 0x3fc8beafeb38fe8c), (0x39025a9fa0ff7316, 0x3c6054473941ad99, 0x3fc90c6db9fcbcd9), (0xb90b9f17794734cf, 0x3c6f47dfd871f87f, 0x3fc9a8778debaa38), (0x38dc16be326ac41a, 0x3c435a19605e67ef, 0x3fc9f6c407089664), (0x38f185cfa0a62d77, 0x3c5df207dc5c34c6, 0x3fca454082e6ab05), (0xb8f307466a8570bb, 0x3c6ab5ca9eaa088a, 0x3fcae2ca6f672bd4), (0xb8f0459563c86e85, 0xbc66353ab386a94d, 0x3fcb31d8575bce3d), (0x38dac5281fdd139f, 0x3c3a0ee735d9f0ec, 0x3fcb811730b823d2), (0x38d0aaa7d9462021, 0x3c3dd355f6a516d7, 0x3fcbd087383bd8ad), (0x3900f039c9a8a2e5, 0xbc68e58b2c57a4a5, 0x3fcc6ffbc6f00f71), (0xb8e7196d3db630d3, 0x3c653d154280394f, 0x3fccc000c9db3c52), (0x38ef01fe115ec7f7, 0x3c660629242471a2, 0x3fcd1037f2655e7b), (0xb8ff3a153d8d4fe0, 0x3c5aa11d49f96cb9, 0x3fcdb13db0d48940), (0xb8de287e4407f374, 0x3c5fea48dd7b81d1, 0x3fce020cc6235ab5), (0xb8eb5b6e7d96592d, 0x3c42276041f43042, 0x3fce530effe71012), (0xb8b755b33ca06006, 0xbc6d33919ab94074, 0x3fcea4449f04aaf5), (0xb8f96415b209f7c5, 0xbc527c77ded76aad, 0x3fcf474b134df229), (0xb90c93e26ec48e0e, 0x3c6f665066f980a2, 0x3fcf991c6cb3b379), (0xb878c9ae634d3c77, 0x3c28de00938b4c40, 0x3fcfeb2233ea07cd), (0x38ed5f4501b8b4a6, 0xbc418290bd2932e2, 0x3fd01eae5626c691), (0x3902e2a91d8de3c6, 0xbc70779634061cbc, 0x3fd047e60cde83b8), (0xb90f2a6f815b079c, 0x3c643c2e68684d53, 0x3fd09aa572e6c6d4), (0x38f078ecd47fd065, 0x3c5162c79d5d11ee, 0x3fd0c42d676162e3), (0x390349ab8071c6f5, 0xbc692b49ef282b09, 0x3fd0edd060b78081), (0x39003c776a3fb0f1, 0xbc60e63a5f01c691, 0x3fd1178e8227e47c), (0x38b86b8fcae82457, 0x3c1e0936abd4fa6e, 0x3fd14167ef367783), (0x39062e66c6742717, 0x3c766fbd28b40935, 0x3fd16b5ccbacfb73), (0xb904298ef6ad5800, 0xbc612aeb84249223, 0x3fd1bf99635a6b95), (0x391fb7583fdc5cd1, 0x3c7512c3749a1e4e, 0x3fd1e9e1678899f4), (0xb8fbbc46cf6d5b05, 0x3c6f7ae91aeba60a, 0x3fd214456d0eb8d4), (0xb8d69da0a6f43fa8, 0x3c3bb75d1addf870, 0x3fd23ec5991eba49), (0xb9163d5cf0b6f233, 0x3c7e0efadd9db02b, 0x3fd269621134db92), (0xb8ba9b5dfcb5442c, 0xbc6856e61c515740, 0x3fd2941afb186b7c), (0x3908cc4b2b27c162, 0xbc782dad7fd86088, 0x3fd2bef07cdc9354), (0xb91f0f8d6f3c6a8e, 0xbc73d69909e5c3dc, 0x3fd314f1e1d35ce4), (0xb8f954216e4fd4b3, 0xbc5cd55b8a4746c0, 0x3fd3401e12aecba1), (0x38f5f12812782422, 0xbc5324f0e883858e, 0x3fd36b6776be1117), (0x38e44a223cab7ad9, 0xbc5ce2b31b31e8b0, 0x3fd396ce359bbf54), (0xb905ea8429f9f46d, 0xbc72ad27e50a8ec6, 0x3fd3c25277333184), (0x390cccb5749e39eb, 0x3c783d680d3c1084, 0x3fd3edf463c1683e), (0xb90c920829097668, 0x3c60dbb243827392, 0x3fd419b423d5e8c7), (0x3913cee6bc2e326b, 0xbc72b125247b0fa5, 0x3fd44591e0539f49), (0xb8d019b2f322342b, 0x3c38fb4c14c56eef, 0x3fd4718dc271c41b), (0x38fc6086c0bb1e94, 0xbc69964a168ccaca, 0x3fd49da7f3bcc41f), (0xb8f1ef0823bae5d2, 0xbc5123615b147a5d, 0x3fd4c9e09e172c3c), (0xb8e658171677adeb, 0xbc758cb3124b9245, 0x3fd4f637ebba9810), (0xb90777dce76e5542, 0xbc68f7e9b38a6979, 0x3fd522ae0738a3d8), (0xb9125eeb277e3f77, 0xbc7aacfdbbdab914, 0x3fd54f431b7be1a9), (0xb8e942cd558167e2, 0xbc60908d15f88b63, 0x3fd57bf753c8d1fb), (0xb8f6a2ed327a4daa, 0xbc5e6c2bdfb3e037, 0x3fd5a8cadbbedfa1), (0xb91d89fab3e76435, 0xbc76541148cbb8a2, 0x3fd5d5bddf595f30), (0xb8e72adc1a985ccf, 0xbc56e8920c09b73f, 0x3fd602d08af091ec), (0x3901e7352eee5ee9, 0x3c6dc18ce51fff99, 0x3fd630030b3aac49), ]; pxfm-0.1.23/src/logs/logf.rs000064400000000000000000000356161046102023000137240ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::min_normal_f32; use crate::common::*; use crate::polyeval::f_polyeval3; use std::hint::black_box; #[repr(C, align(8))] pub(crate) struct LogReductionF32Aligned(pub(crate) [u32; 128]); pub(crate) static LOG_REDUCTION_F32: LogReductionF32Aligned = LogReductionF32Aligned([ 0x3f800000, 0x3f7e0000, 0x3f7c0000, 0x3f7a0000, 0x3f780000, 0x3f760000, 0x3f740000, 0x3f720000, 0x3f700000, 0x3f6f0000, 0x3f6d0000, 0x3f6b0000, 0x3f6a0000, 0x3f680000, 0x3f660000, 0x3f650000, 0x3f630000, 0x3f620000, 0x3f600000, 0x3f5f0000, 0x3f5d0000, 0x3f5c0000, 0x3f5a0000, 0x3f590000, 0x3f570000, 0x3f560000, 0x3f540000, 0x3f530000, 0x3f520000, 0x3f500000, 0x3f4f0000, 0x3f4e0000, 0x3f4c0000, 0x3f4b0000, 0x3f4a0000, 0x3f490000, 0x3f480000, 0x3f460000, 0x3f450000, 0x3f440000, 0x3f430000, 0x3f420000, 0x3f400000, 0x3f3f0000, 0x3f3e0000, 0x3f3d0000, 0x3f3c0000, 0x3f3b0000, 0x3f3a0000, 0x3f390000, 0x3f380000, 0x3f370000, 0x3f360000, 0x3f350000, 0x3f340000, 0x3f330000, 0x3f320000, 0x3f310000, 0x3f300000, 0x3f2f0000, 0x3f2e0000, 0x3f2d0000, 0x3f2c0000, 0x3f2b0000, 0x3f2a0000, 0x3f2a0000, 0x3f290000, 0x3f280000, 0x3f270000, 0x3f260000, 0x3f250000, 0x3f250000, 0x3f240000, 0x3f230000, 0x3f220000, 0x3f210000, 0x3f200000, 0x3f200000, 0x3f1f0000, 0x3f1e0000, 0x3f1d0000, 0x3f1d0000, 0x3f1c0000, 0x3f1b0000, 0x3f1a0000, 0x3f1a0000, 0x3f190000, 0x3f180000, 0x3f180000, 0x3f170000, 0x3f160000, 0x3f160000, 0x3f150000, 0x3f140000, 0x3f140000, 0x3f130000, 0x3f120000, 0x3f120000, 0x3f110000, 0x3f100000, 0x3f100000, 0x3f0f0000, 0x3f0e0000, 0x3f0e0000, 0x3f0d0000, 0x3f0d0000, 0x3f0c0000, 0x3f0b0000, 0x3f0b0000, 0x3f0a0000, 0x3f0a0000, 0x3f090000, 0x3f080000, 0x3f080000, 0x3f070000, 0x3f070000, 0x3f060000, 0x3f060000, 0x3f050000, 0x3f050000, 0x3f040000, 0x3f040000, 0x3f030000, 0x3f030000, 0x3f020000, 0x3f020000, 0x3f010000, 0x3f000000, ]); static LOG_R: [u64; 128] = [ 0x0000000000000000, 0x3f8010157588de71, 0x3f90205658935847, 0x3f98492528c8cabf, 0x3fa0415d89e74444, 0x3fa466aed42de3ea, 0x3fa894aa149fb343, 0x3faccb73cdddb2cc, 0x3fb08598b59e3a07, 0x3fb1973bd1465567, 0x3fb3bdf5a7d1ee64, 0x3fb5e95a4d9791cb, 0x3fb700d30aeac0e1, 0x3fb9335e5d594989, 0x3fbb6ac88dad5b1c, 0x3fbc885801bc4b23, 0x3fbec739830a1120, 0x3fbfe89139dbd566, 0x3fc1178e8227e47c, 0x3fc1aa2b7e23f72a, 0x3fc2d1610c86813a, 0x3fc365fcb0159016, 0x3fc4913d8333b561, 0x3fc527e5e4a1b58d, 0x3fc6574ebe8c133a, 0x3fc6f0128b756abc, 0x3fc823c16551a3c2, 0x3fc8beafeb38fe8c, 0x3fc95a5adcf7017f, 0x3fca93ed3c8ad9e3, 0x3fcb31d8575bce3d, 0x3fcbd087383bd8ad, 0x3fcd1037f2655e7b, 0x3fcdb13db0d48940, 0x3fce530effe71012, 0x3fcef5ade4dcffe6, 0x3fcf991c6cb3b379, 0x3fd07138604d5862, 0x3fd0c42d676162e3, 0x3fd1178e8227e47c, 0x3fd16b5ccbacfb73, 0x3fd1bf99635a6b95, 0x3fd269621134db92, 0x3fd2bef07cdc9354, 0x3fd314f1e1d35ce4, 0x3fd36b6776be1117, 0x3fd3c25277333184, 0x3fd419b423d5e8c7, 0x3fd4718dc271c41b, 0x3fd4c9e09e172c3c, 0x3fd522ae0738a3d8, 0x3fd57bf753c8d1fb, 0x3fd5d5bddf595f30, 0x3fd630030b3aac49, 0x3fd68ac83e9c6a14, 0x3fd6e60ee6af1972, 0x3fd741d876c67bb1, 0x3fd79e26687cfb3e, 0x3fd7fafa3bd8151c, 0x3fd85855776dcbfb, 0x3fd8b639a88b2df5, 0x3fd914a8635bf68a, 0x3fd973a3431356ae, 0x3fd9d32bea15ed3b, 0x3fda33440224fa79, 0x3fda33440224fa79, 0x3fda93ed3c8ad9e3, 0x3fdaf5295248cdd0, 0x3fdb56fa04462909, 0x3fdbb9611b80e2fb, 0x3fdc1c60693fa39e, 0x3fdc1c60693fa39e, 0x3fdc7ff9c74554c9, 0x3fdce42f18064743, 0x3fdd490246defa6b, 0x3fddae75484c9616, 0x3fde148a1a2726ce, 0x3fde148a1a2726ce, 0x3fde7b42c3ddad73, 0x3fdee2a156b413e5, 0x3fdf4aa7ee03192d, 0x3fdf4aa7ee03192d, 0x3fdfb358af7a4884, 0x3fe00e5ae5b207ab, 0x3fe04360be7603ad, 0x3fe04360be7603ad, 0x3fe078bf0533c568, 0x3fe0ae76e2d054fa, 0x3fe0ae76e2d054fa, 0x3fe0e4898611cce1, 0x3fe11af823c75aa8, 0x3fe11af823c75aa8, 0x3fe151c3f6f29612, 0x3fe188ee40f23ca6, 0x3fe188ee40f23ca6, 0x3fe1c07849ae6007, 0x3fe1f8635fc61659, 0x3fe1f8635fc61659, 0x3fe230b0d8bebc98, 0x3fe269621134db92, 0x3fe269621134db92, 0x3fe2a2786d0ec107, 0x3fe2dbf557b0df43, 0x3fe2dbf557b0df43, 0x3fe315da4434068b, 0x3fe315da4434068b, 0x3fe35028ad9d8c86, 0x3fe38ae2171976e7, 0x3fe38ae2171976e7, 0x3fe3c6080c36bfb5, 0x3fe3c6080c36bfb5, 0x3fe4019c2125ca93, 0x3fe43d9ff2f923c5, 0x3fe43d9ff2f923c5, 0x3fe47a1527e8a2d3, 0x3fe47a1527e8a2d3, 0x3fe4b6fd6f970c1f, 0x3fe4b6fd6f970c1f, 0x3fe4f45a835a4e19, 0x3fe4f45a835a4e19, 0x3fe5322e26867857, 0x3fe5322e26867857, 0x3fe5707a26bb8c66, 0x3fe5707a26bb8c66, 0x3fe5af405c3649e0, 0x3fe5af405c3649e0, 0x3fe5ee82aa241920, 0x0000000000000000, ]; /// Natural logarithm /// /// Max found ULP 0.4999988 #[inline] pub fn f_logf(x: f32) -> f32 { let mut x_u = x.to_bits(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; let mut m = -(E_BIAS as i32); if x_u < 0x4c5d65a5u32 { if x_u == 0x3f7f4d6fu32 { return black_box(f64::from_bits(0xbf6659ec80000000) as f32) + min_normal_f32(true); } else if x_u == 0x41178febu32 { return black_box(f64::from_bits(0x4001fcbce0000000) as f32) + min_normal_f32(true); } else if x_u == 0x3f800000u32 { return 0.; } else if x_u == 0x1e88452du32 { return black_box(f64::from_bits(0xc046d7b180000000) as f32) + min_normal_f32(true); } if x_u < f32::MIN_POSITIVE.to_bits() { if x == 0.0 { return f32::NEG_INFINITY; } // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4160000000000000) as f32).to_bits(); m -= 23; } } else { if x_u == 0x4c5d65a5u32 { return black_box(f32::from_bits(0x418f034b)) + min_normal_f32(true); } else if x_u == 0x65d890d3u32 { return black_box(f32::from_bits(0x4254d1f9)) + min_normal_f32(true); } else if x_u == 0x6f31a8ecu32 { return black_box(f32::from_bits(0x42845a89)) + min_normal_f32(true); } else if x_u == 0x7a17f30au32 { return black_box(f32::from_bits(0x42a28a1b)) + min_normal_f32(true); } else if x_u == 0x500ffb03u32 { return black_box(f32::from_bits(0x41b7ee9a)) + min_normal_f32(true); } else if x_u == 0x5cd69e88u32 { return black_box(f32::from_bits(0x4222e0a3)) + min_normal_f32(true); } else if x_u == 0x5ee8984eu32 { return black_box(f32::from_bits(0x422e4a21)) + min_normal_f32(true); } if x_u > f32::MAX.to_bits() { if x_u == 0x80000000u32 { return f32::NEG_INFINITY; } if x.is_sign_negative() && !x.is_nan() { return f32::NAN + x; } // x is +inf or nan if x.is_nan() { return f32::NAN; } return x; } } let mant = x_u & 0x007F_FFFF; // Extract 7 leading fractional bits of the mantissa let index = mant.wrapping_shr(16); // Add unbiased exponent. Add an extra 1 if the 7 leading fractional bits are // all 1's. m = m.wrapping_add(x_u.wrapping_add(1 << 16).wrapping_shr(23) as i32); x_u = set_exponent_f32(x_u, 0x7F); let v; let u = f32::from_bits(x_u); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v = f_fmlaf(u, f32::from_bits(LOG_REDUCTION_F32.0[index as usize]), -1.0) as f64; // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log2::LOG_RANGE_REDUCTION; v = f_fmla( u as f64, f64::from_bits(LOG_RANGE_REDUCTION[index as usize]), -1.0, ); // Exact } // Degree-5 polynomial approximation of log generated by Sollya with: // > P = fpminimax(log(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); const COEFFS: [u64; 4] = [ 0xbfe000000000fe63, 0x3fd555556e963c16, 0xbfd000028dedf986, 0x3fc966681bfda7f7, ]; let v2 = v * v; // Exact let p2 = f_fmla(v, f64::from_bits(COEFFS[3]), f64::from_bits(COEFFS[2])); let p1 = f_fmla(v, f64::from_bits(COEFFS[1]), f64::from_bits(COEFFS[0])); let p0 = f64::from_bits(LOG_R[index as usize]) + v; const LOG_2: f64 = f64::from_bits(0x3fe62e42fefa39ef); let r = f_fmla(m as f64, LOG_2, f_polyeval3(v2, p0, p1, p2)); r as f32 } #[inline] pub(crate) fn fast_logf(x: f32) -> f64 { let mut x_u = x.to_bits(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; let mut m = -(E_BIAS as i32); if x_u < f32::MIN_POSITIVE.to_bits() { // Normalize denormal inputs. x_u = (x * f64::from_bits(0x4160000000000000) as f32).to_bits(); m -= 23; } let mant = x_u & 0x007F_FFFF; // Extract 7 leading fractional bits of the mantissa let index = mant.wrapping_shr(16); // Add unbiased exponent. Add an extra 1 if the 7 leading fractional bits are // all 1's. m = m.wrapping_add(x_u.wrapping_add(1 << 16).wrapping_shr(23) as i32); x_u = set_exponent_f32(x_u, 0x7F); let v; let u = f32::from_bits(x_u); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v = f_fmlaf(u, f32::from_bits(LOG_REDUCTION_F32.0[index as usize]), -1.0) as f64; // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::log2::LOG_RANGE_REDUCTION; v = f_fmla( u as f64, f64::from_bits(LOG_RANGE_REDUCTION[index as usize]), -1.0, ); // Exact } // Degree-5 polynomial approximation of log generated by Sollya with: // > P = fpminimax(log(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); const COEFFS: [u64; 4] = [ 0xbfe000000000fe63, 0x3fd555556e963c16, 0xbfd000028dedf986, 0x3fc966681bfda7f7, ]; let v2 = v * v; // Exact let p2 = f_fmla(v, f64::from_bits(COEFFS[3]), f64::from_bits(COEFFS[2])); let p1 = f_fmla(v, f64::from_bits(COEFFS[1]), f64::from_bits(COEFFS[0])); let p0 = f64::from_bits(LOG_R[index as usize]) + v; const LOG_2: f64 = f64::from_bits(0x3fe62e42fefa39ef); f_fmla(m as f64, LOG_2, f_polyeval3(v2, p0, p1, p2)) } /// Log for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn logf(d: f32) -> f32 { let ux = d.to_bits(); #[allow(clippy::collapsible_if)] if ux < (1 << 23) || ux >= 0x7f800000u32 { if ux == 0 || ux >= 0x7f800000u32 { if ux == 0x7f800000u32 { return d; } let ax = ux.wrapping_shl(1); if ax == 0u32 { // -0.0 return f32::NEG_INFINITY; } if ax > 0xff000000u32 { return d + d; } // nan return f32::NAN; } } let mut ix = d.to_bits(); /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; let n = (ix >> 23) as i32 - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; let a = f32::from_bits(ix) as f64; let x = (a - 1.) / (a + 1.); let x2 = x * x; let mut u = 0.2222220222147750310e+0; u = fmla(u, x2, 0.2857142871244668543e+0); u = fmla(u, x2, 0.3999999999950960318e+0); u = fmla(u, x2, 0.6666666666666734090e+0); u = fmla(u, x2, 2.); fmla(x, u, std::f64::consts::LN_2 * (n as f64)) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_logf() { assert!( (logf(1f32) - 0f32).abs() < 1e-6, "Invalid result {}", logf(1f32) ); assert!( (logf(5f32) - 1.60943791243410037460f32).abs() < 1e-6, "Invalid result {}", logf(5f32) ); assert_eq!(logf(0.), f32::NEG_INFINITY); assert!(logf(-1.).is_nan()); assert!(logf(f32::NAN).is_nan()); assert!(logf(f32::NEG_INFINITY).is_nan()); assert_eq!(logf(f32::INFINITY), f32::INFINITY); } #[test] fn test_flogf() { assert!( (f_logf(1f32) - 0f32).abs() < 1e-6, "Invalid result {}", f_logf(1f32) ); assert!( (f_logf(5f32) - 1.60943791243410037460f32).abs() < 1e-6, "Invalid result {}", f_logf(5f32) ); assert_eq!(f_logf(0.), f32::NEG_INFINITY); assert!(f_logf(-1.).is_nan()); assert!(f_logf(f32::NAN).is_nan()); assert!(f_logf(f32::NEG_INFINITY).is_nan()); assert_eq!(f_logf(f32::INFINITY), f32::INFINITY); } } pxfm-0.1.23/src/logs/mod.rs000064400000000000000000000063531046102023000135500ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ #![deny(unreachable_pub)] mod fast_log; mod fast_log_dd; mod log; mod log10; mod log10dd; mod log10dd_coeffs; mod log10f; mod log10p1; mod log10p1_tables; mod log10p1f; mod log10td; mod log10td_coeffs; mod log1p; mod log1p_dd; mod log1p_dyadic; mod log1p_dyadic_tables; mod log1pf; mod log1pmx; mod log1pmxf; mod log2; mod log2dd; mod log2dd_coeffs; mod log2f; mod log2p1; mod log2p1_dyadic_tables; mod log2p1_tables; mod log2p1f; mod log2td; mod log2td_coeffs; mod log_dd; mod log_dd_coeffs; mod log_dyadic; mod log_range_reduction; mod log_td; mod log_td_table; mod logf; pub(crate) use fast_log::simple_fast_log; pub(crate) use fast_log_dd::{fast_log_d_to_dd, fast_log_dd}; pub(crate) use log::log_dyadic; pub use log::{f_log, log}; pub(crate) use log_dd::{log_dd, log_dd_fast}; pub use log1p::f_log1p; pub(crate) use log1p::log1p_f64_dyadic; pub(crate) use log1p_dd::{log1p_dd, log1p_fast_dd}; pub use log1pf::f_log1pf; pub use log1pmx::f_log1pmx; pub use log1pmxf::f_log1pmxf; #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] pub(crate) use log2::LOG_CD; pub use log2::f_log2; pub(crate) use log2::{LOG_COEFFS, LOG_RANGE_REDUCTION}; pub use log2f::f_log2f; pub(crate) use log2f::{LOG2_R, dirty_log2f}; pub use log2p1::f_log2p1; pub use log2p1f::f_log2p1f; pub(crate) use log10::LOG_R_DD; pub use log10::f_log10; pub use log10f::f_log10f; pub use log10p1::f_log10p1; pub use log10p1f::f_log10p1f; #[allow(unused)] pub(crate) use logf::LOG_REDUCTION_F32; pub(crate) use logf::fast_logf; pub use logf::{f_logf, logf}; pxfm-0.1.23/src/polyeval.rs000064400000000000000000002120271046102023000136550ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf}; use crate::double_double::DoubleDouble; use crate::dyadic_float::DyadicFloat128; use std::ops::Mul; pub(crate) trait PolyevalMla { fn polyeval_mla(a: Self, b: Self, c: Self) -> Self; } impl PolyevalMla for f64 { #[inline(always)] fn polyeval_mla(a: Self, b: Self, c: Self) -> Self { f_fmla(a, b, c) } } impl PolyevalMla for f32 { #[inline(always)] fn polyeval_mla(a: Self, b: Self, c: Self) -> Self { f_fmlaf(a, b, c) } } impl PolyevalMla for DoubleDouble { #[inline(always)] fn polyeval_mla(a: Self, b: Self, c: Self) -> Self { DoubleDouble::mul_add(a, b, c) } } impl PolyevalMla for DyadicFloat128 { #[inline(always)] fn polyeval_mla(a: Self, b: Self, c: Self) -> Self { c.quick_add(&a.quick_mul(&b)) } } // impl PolyevalMla for DyadicFloat256 { // #[inline(always)] // fn polyeval_mla(a: Self, b: Self, c: Self) -> Self { // c.quick_add(&a.quick_mul(&b)) // } // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval6>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, ) -> T { let x2 = x * x; let u0 = T::polyeval_mla(x, a5, a4); let u1 = T::polyeval_mla(x, a3, a2); let u2 = T::polyeval_mla(x, a1, a0); let v0 = T::polyeval_mla(x2, u0, u1); T::polyeval_mla(x2, v0, u2) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval5>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // ) -> T { // let t2 = T::polyeval_mla(x, a4, a3); // let t3 = T::polyeval_mla(x, t2, a2); // let t4 = T::polyeval_mla(x, t3, a1); // T::polyeval_mla(x, t4, a0) // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval9>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, ) -> T { let mut acc = a8; acc = T::polyeval_mla(x, acc, a7); acc = T::polyeval_mla(x, acc, a6); acc = T::polyeval_mla(x, acc, a5); acc = T::polyeval_mla(x, acc, a4); acc = T::polyeval_mla(x, acc, a3); acc = T::polyeval_mla(x, acc, a2); acc = T::polyeval_mla(x, acc, a1); T::polyeval_mla(x, acc, a0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_estrin_polyeval9>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let p0 = T::polyeval_mla(x, a1, a0); let p1 = T::polyeval_mla(x, a3, a2); let p2 = T::polyeval_mla(x, a5, a4); let p3 = T::polyeval_mla(x, a7, a6); let q0 = T::polyeval_mla(x2, p1, p0); let q1 = T::polyeval_mla(x2, p3, p2); let r0 = T::polyeval_mla(x4, q1, q0); T::polyeval_mla(x8, a8, r0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval10>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let p0 = T::polyeval_mla(x, a1, a0); let p1 = T::polyeval_mla(x, a3, a2); let p2 = T::polyeval_mla(x, a5, a4); let p3 = T::polyeval_mla(x, a7, a6); let p4 = T::polyeval_mla(x, a9, a8); let q0 = T::polyeval_mla(x2, p1, p0); let q1 = T::polyeval_mla(x2, p3, p2); let r0 = T::polyeval_mla(x4, q1, q0); T::polyeval_mla(x8, p4, r0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval11>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let q0 = T::polyeval_mla(x, a1, a0); let q1 = T::polyeval_mla(x, a3, a2); let q2 = T::polyeval_mla(x, a5, a4); let q3 = T::polyeval_mla(x, a7, a6); let q4 = T::polyeval_mla(x, a9, a8); let r0 = T::polyeval_mla(x2, q1, q0); let r1 = T::polyeval_mla(x2, q3, q2); let s0 = T::polyeval_mla(x4, r1, r0); let s1 = T::polyeval_mla(x2, a10, q4); T::polyeval_mla(x8, s1, s0) } #[inline(always)] pub(crate) fn f_polyeval3(x: T, a0: T, a1: T, a2: T) -> T { T::polyeval_mla(x, T::polyeval_mla(x, a2, a1), a0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval4(x: T, a0: T, a1: T, a2: T, a3: T) -> T { let t2 = T::polyeval_mla(x, a3, a2); let t5 = T::polyeval_mla(x, t2, a1); T::polyeval_mla(x, t5, a0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval13>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let t0 = T::polyeval_mla(x, a3, a2); let t1 = T::polyeval_mla(x, a1, a0); let t2 = T::polyeval_mla(x, a7, a6); let t3 = T::polyeval_mla(x, a5, a4); let t4 = T::polyeval_mla(x, a11, a10); let t5 = T::polyeval_mla(x, a9, a8); let q0 = T::polyeval_mla(x2, t0, t1); let q1 = T::polyeval_mla(x2, t2, t3); let q2 = T::polyeval_mla(x2, t4, t5); let q3 = a12; let r0 = T::polyeval_mla(x4, q1, q0); let r1 = T::polyeval_mla(x4, q3, q2); T::polyeval_mla(x8, r1, r0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval12>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let e0 = T::polyeval_mla(x, a1, a0); let e1 = T::polyeval_mla(x, a3, a2); let e2 = T::polyeval_mla(x, a5, a4); let e3 = T::polyeval_mla(x, a7, a6); let e4 = T::polyeval_mla(x, a9, a8); let e5 = T::polyeval_mla(x, a11, a10); let f0 = T::polyeval_mla(x2, e1, e0); let f1 = T::polyeval_mla(x2, e3, e2); let f2 = T::polyeval_mla(x2, e5, e4); let g0 = T::polyeval_mla(x4, f1, f0); T::polyeval_mla(x8, f2, g0) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_horner_polyeval13>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // ) -> T { // let mut acc = a12; // acc = T::polyeval_mla(x, acc, a11); // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_horner_polyeval14>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // ) -> T { // let mut acc = a13; // acc = T::polyeval_mla(x, acc, a12); // acc = T::polyeval_mla(x, acc, a11); // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_horner_polyeval12>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // ) -> T { // let mut acc = a11; // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval11( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // ) -> T { // let k0 = T::polyeval_mla(x, a10, a9); // let k1 = T::polyeval_mla(x, k0, a8); // let z0 = T::polyeval_mla(x, k1, a7); // let t0a = T::polyeval_mla(x, z0, a6); // let t1 = T::polyeval_mla(x, t0a, a5); // let t2 = T::polyeval_mla(x, t1, a4); // let t3 = T::polyeval_mla(x, t2, a3); // let t4 = T::polyeval_mla(x, t3, a2); // let t5 = T::polyeval_mla(x, t4, a1); // T::polyeval_mla(x, t5, a0) // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval14>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let g0 = T::polyeval_mla(x, a1, a0); let g1 = T::polyeval_mla(x, a3, a2); let g2 = T::polyeval_mla(x, a5, a4); let g3 = T::polyeval_mla(x, a7, a6); let g4 = T::polyeval_mla(x, a9, a8); let g5 = T::polyeval_mla(x, a11, a10); let g6 = T::polyeval_mla(x, a13, a12); let h0 = T::polyeval_mla(x2, g1, g0); let h1 = T::polyeval_mla(x2, g3, g2); let h2 = T::polyeval_mla(x2, g5, g4); let q0 = T::polyeval_mla(x4, h1, h0); let q1 = T::polyeval_mla(x4, g6, h2); T::polyeval_mla(x8, q1, q0) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval12( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // ) -> T { // let t0 = T::polyeval_mla(x, a11, a10); // let k0 = T::polyeval_mla(x, t0, a9); // let k1 = T::polyeval_mla(x, k0, a8); // let z0 = T::polyeval_mla(x, k1, a7); // let t0a = T::polyeval_mla(x, z0, a6); // let t1 = T::polyeval_mla(x, t0a, a5); // let t2 = T::polyeval_mla(x, t1, a4); // let t3 = T::polyeval_mla(x, t2, a3); // let t4 = T::polyeval_mla(x, t3, a2); // let t5 = T::polyeval_mla(x, t4, a1); // T::polyeval_mla(x, t5, a0) // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval7( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, ) -> T { let t1 = T::polyeval_mla(x, a6, a5); let t2 = T::polyeval_mla(x, t1, a4); let t3 = T::polyeval_mla(x, t2, a3); let t4 = T::polyeval_mla(x, t3, a2); let t5 = T::polyeval_mla(x, t4, a1); T::polyeval_mla(x, t5, a0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_estrin_polyeval7>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let b0 = T::polyeval_mla(x, a1, a0); let b1 = T::polyeval_mla(x, a3, a2); let b2 = T::polyeval_mla(x, a5, a4); let c0 = T::polyeval_mla(x2, b1, b0); let c1 = T::polyeval_mla(x2, a6, b2); T::polyeval_mla(x4, c1, c0) } #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval5(x: T, a0: T, a1: T, a2: T, a3: T, a4: T) -> T { let mut acc = a4; acc = T::polyeval_mla(x, acc, a3); acc = T::polyeval_mla(x, acc, a2); acc = T::polyeval_mla(x, acc, a1); T::polyeval_mla(x, acc, a0) } #[allow(clippy::too_many_arguments)] pub(crate) fn f_estrin_polyeval5>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, ) -> T { let x2 = x * x; let p01 = T::polyeval_mla(x, a1, a0); let p23 = T::polyeval_mla(x, a3, a2); let t = T::polyeval_mla(x2, a4, p23); T::polyeval_mla(x2, t, p01) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval8( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, ) -> T { let z0 = T::polyeval_mla(x, a7, a6); let t1 = T::polyeval_mla(x, z0, a5); let t2 = T::polyeval_mla(x, t1, a4); let t3 = T::polyeval_mla(x, t2, a3); let t4 = T::polyeval_mla(x, t3, a2); let t5 = T::polyeval_mla(x, t4, a1); T::polyeval_mla(x, t5, a0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_estrin_polyeval8>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let p0 = T::polyeval_mla(x, a1, a0); let p1 = T::polyeval_mla(x, a3, a2); let p2 = T::polyeval_mla(x, a5, a4); let p3 = T::polyeval_mla(x, a7, a6); let q0 = T::polyeval_mla(x2, p1, p0); let q1 = T::polyeval_mla(x2, p3, p2); T::polyeval_mla(x4, q1, q0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval16>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, a14: T, a15: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let q0 = T::polyeval_mla(x, a1, a0); let q1 = T::polyeval_mla(x, a3, a2); let q2 = T::polyeval_mla(x, a5, a4); let q3 = T::polyeval_mla(x, a7, a6); let q4 = T::polyeval_mla(x, a9, a8); let q5 = T::polyeval_mla(x, a11, a10); let q6 = T::polyeval_mla(x, a13, a12); let q7 = T::polyeval_mla(x, a15, a14); let r0 = T::polyeval_mla(x2, q1, q0); let r1 = T::polyeval_mla(x2, q3, q2); let r2 = T::polyeval_mla(x2, q5, q4); let r3 = T::polyeval_mla(x2, q7, q6); let s0 = T::polyeval_mla(x4, r1, r0); let s1 = T::polyeval_mla(x4, r3, r2); T::polyeval_mla(x8, s1, s0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval15>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, a14: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let e0 = T::polyeval_mla(x, a1, a0); let e1 = T::polyeval_mla(x, a3, a2); let e2 = T::polyeval_mla(x, a5, a4); let e3 = T::polyeval_mla(x, a7, a6); let e4 = T::polyeval_mla(x, a9, a8); let e5 = T::polyeval_mla(x, a11, a10); let e6 = T::polyeval_mla(x, a13, a12); // Level 2 let f0 = T::polyeval_mla(x2, e1, e0); let f1 = T::polyeval_mla(x2, e3, e2); let f2 = T::polyeval_mla(x2, e5, e4); let f3 = T::polyeval_mla(x2, a14, e6); // Level 3 let g0 = T::polyeval_mla(x4, f1, f0); let g1 = T::polyeval_mla(x4, f3, f2); // Final T::polyeval_mla(x8, g1, g0) } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval18>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, a14: T, a15: T, a16: T, a17: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let x16 = x8 * x8; let q0 = T::polyeval_mla(x, a1, a0); let q1 = T::polyeval_mla(x, a3, a2); let q2 = T::polyeval_mla(x, a5, a4); let q3 = T::polyeval_mla(x, a7, a6); let q4 = T::polyeval_mla(x, a9, a8); let q5 = T::polyeval_mla(x, a11, a10); let q6 = T::polyeval_mla(x, a13, a12); let q7 = T::polyeval_mla(x, a15, a14); let q8 = T::polyeval_mla(x, a17, a16); let r0 = T::polyeval_mla(x2, q1, q0); let r1 = T::polyeval_mla(x2, q3, q2); let r2 = T::polyeval_mla(x2, q5, q4); let r3 = T::polyeval_mla(x2, q7, q6); let s0 = T::polyeval_mla(x4, r1, r0); let s1 = T::polyeval_mla(x4, r3, r2); let t0 = T::polyeval_mla(x8, s1, s0); T::polyeval_mla(x16, q8, t0) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval17>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // ) -> T { // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // let x16 = x8 * x8; // // let p0 = T::polyeval_mla(x, a1, a0); // let p1 = T::polyeval_mla(x, a3, a2); // let p2 = T::polyeval_mla(x, a5, a4); // let p3 = T::polyeval_mla(x, a7, a6); // let p4 = T::polyeval_mla(x, a9, a8); // let p5 = T::polyeval_mla(x, a11, a10); // let p6 = T::polyeval_mla(x, a13, a12); // let p7 = T::polyeval_mla(x, a15, a14); // // let q0 = T::polyeval_mla(x2, p1, p0); // let q1 = T::polyeval_mla(x2, p3, p2); // let q2 = T::polyeval_mla(x2, p5, p4); // let q3 = T::polyeval_mla(x2, p7, p6); // // let r0 = T::polyeval_mla(x4, q1, q0); // let r1 = T::polyeval_mla(x4, q3, q2); // // let s0 = T::polyeval_mla(x8, r1, r0); // // T::polyeval_mla(x16, a16, s0) // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval19>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, a14: T, a15: T, a16: T, a17: T, a18: T, ) -> T { // let z000 = T::polyeval_mla(x, a18, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let x16 = x8 * x8; // Level 0: pairs let e0 = T::polyeval_mla(x, a1, a0); // a0 + a1·x let e1 = T::polyeval_mla(x, a3, a2); // a2 + a3·x let e2 = T::polyeval_mla(x, a5, a4); let e3 = T::polyeval_mla(x, a7, a6); let e4 = T::polyeval_mla(x, a9, a8); let e5 = T::polyeval_mla(x, a11, a10); let e6 = T::polyeval_mla(x, a13, a12); let e7 = T::polyeval_mla(x, a15, a14); let e8 = T::polyeval_mla(x, a17, a16); // Level 1: combine with x² let f0 = T::polyeval_mla(x2, e1, e0); let f1 = T::polyeval_mla(x2, e3, e2); let f2 = T::polyeval_mla(x2, e5, e4); let f3 = T::polyeval_mla(x2, e7, e6); // Level 2: combine with x⁴ let g0 = T::polyeval_mla(x4, f1, f0); let g1 = T::polyeval_mla(x4, f3, f2); // Level 3: combine with x⁸ let h0 = T::polyeval_mla(x8, g1, g0); // Final: combine with x¹⁶ let final_poly = T::polyeval_mla(x16, e8, h0); // Degree 18: Add a18·x¹⁸ // This assumes `x18 = x16 * x2`, since x² already computed let x18 = x16 * x2; T::polyeval_mla(x18, a18, final_poly) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval20>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // ) -> T { // // let z000 = T::polyeval_mla(x, a19, a18); // // let z000 = T::polyeval_mla(x, z000, a17); // // let z00 = T::polyeval_mla(x, z000, a16); // // let z01 = T::polyeval_mla(x, z00, a15); // // let t1 = T::polyeval_mla(x, z01, a14); // // let t2 = T::polyeval_mla(x, t1, a13); // // let t3 = T::polyeval_mla(x, t2, a12); // // let t4 = T::polyeval_mla(x, t3, a11); // // let t5 = T::polyeval_mla(x, t4, a10); // // let t6 = T::polyeval_mla(x, t5, a9); // // let t7 = T::polyeval_mla(x, t6, a8); // // let t8 = T::polyeval_mla(x, t7, a7); // // let t9 = T::polyeval_mla(x, t8, a6); // // let t10 = T::polyeval_mla(x, t9, a5); // // let t11 = T::polyeval_mla(x, t10, a4); // // let t12 = T::polyeval_mla(x, t11, a3); // // let t13 = T::polyeval_mla(x, t12, a2); // // let t14 = T::polyeval_mla(x, t13, a1); // // T::polyeval_mla(x, t14, a0) // // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // let x16 = x8 * x8; // // // Evaluate groups of 2 terms at a time // let e0 = T::polyeval_mla(x, a1, a0); // let e1 = T::polyeval_mla(x, a3, a2); // let e2 = T::polyeval_mla(x, a5, a4); // let e3 = T::polyeval_mla(x, a7, a6); // let e4 = T::polyeval_mla(x, a9, a8); // let e5 = T::polyeval_mla(x, a11, a10); // let e6 = T::polyeval_mla(x, a13, a12); // let e7 = T::polyeval_mla(x, a15, a14); // let e8 = T::polyeval_mla(x, a17, a16); // let e9 = T::polyeval_mla(x, a19, a18); // // // Now build up using higher powers // let f0 = T::polyeval_mla(x2, e1, e0); // (e1 * x² + e0) // let f1 = T::polyeval_mla(x2, e3, e2); // let f2 = T::polyeval_mla(x2, e5, e4); // let f3 = T::polyeval_mla(x2, e7, e6); // let f4 = T::polyeval_mla(x2, e9, e8); // // // Next level // let g0 = T::polyeval_mla(x4, f1, f0); // let g1 = T::polyeval_mla(x4, f3, f2); // // // Final levels // let h0 = T::polyeval_mla(x8, g1, g0); // T::polyeval_mla(x16, f4, h0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_horner_polyeval21( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // ) -> T { // let z000 = T::polyeval_mla(x, a20, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval21>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // ) -> T { // // let z000 = T::polyeval_mla(x, a20, a19); // // let z000 = T::polyeval_mla(x, z000, a18); // // let z000 = T::polyeval_mla(x, z000, a17); // // let z00 = T::polyeval_mla(x, z000, a16); // // let z01 = T::polyeval_mla(x, z00, a15); // // let t1 = T::polyeval_mla(x, z01, a14); // // let t2 = T::polyeval_mla(x, t1, a13); // // let t3 = T::polyeval_mla(x, t2, a12); // // let t4 = T::polyeval_mla(x, t3, a11); // // let t5 = T::polyeval_mla(x, t4, a10); // // let t6 = T::polyeval_mla(x, t5, a9); // // let t7 = T::polyeval_mla(x, t6, a8); // // let t8 = T::polyeval_mla(x, t7, a7); // // let t9 = T::polyeval_mla(x, t8, a6); // // let t10 = T::polyeval_mla(x, t9, a5); // // let t11 = T::polyeval_mla(x, t10, a4); // // let t12 = T::polyeval_mla(x, t11, a3); // // let t13 = T::polyeval_mla(x, t12, a2); // // let t14 = T::polyeval_mla(x, t13, a1); // // T::polyeval_mla(x, t14, a0) // // // Powers // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // let x16 = x8 * x8; // // // Level 0: smallest groups // let e0 = T::polyeval_mla(x, a1, a0); // a0 + a1*x // let e1 = T::polyeval_mla(x, a3, a2); // a2 + a3*x // let e2 = T::polyeval_mla(x, a5, a4); // let e3 = T::polyeval_mla(x, a7, a6); // let e4 = T::polyeval_mla(x, a9, a8); // let e5 = T::polyeval_mla(x, a11, a10); // let e6 = T::polyeval_mla(x, a13, a12); // let e7 = T::polyeval_mla(x, a15, a14); // let e8 = T::polyeval_mla(x, a17, a16); // let e9 = T::polyeval_mla(x, a19, a18); // a18 + a19*x // // // a20 is alone for now // // // Level 1: group by x² // let f0 = T::polyeval_mla(x2, e1, e0); // (e1)*x² + e0 // let f1 = T::polyeval_mla(x2, e3, e2); // let f2 = T::polyeval_mla(x2, e5, e4); // let f3 = T::polyeval_mla(x2, e7, e6); // let f4 = T::polyeval_mla(x2, e9, e8); // // // Level 2: group by x⁴ // let g0 = T::polyeval_mla(x4, f1, f0); // let g1 = T::polyeval_mla(x4, f3, f2); // // // Level 3: group by x⁸ // let h0 = T::polyeval_mla(x8, g1, g0); // // // Level 4: final // let i0 = T::polyeval_mla(x16, f4, a20); // (e9 x + a20) * x² → then into x¹⁶ // T::polyeval_mla(x8, i0, h0) // // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval22>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, a14: T, a15: T, a16: T, a17: T, a18: T, a19: T, a20: T, a21: T, ) -> T { let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let x16 = x8 * x8; let p0 = T::polyeval_mla(x, a1, a0); // a1·x + a0 let p1 = T::polyeval_mla(x, a3, a2); // a3·x + a2 let p2 = T::polyeval_mla(x, a5, a4); let p3 = T::polyeval_mla(x, a7, a6); let p4 = T::polyeval_mla(x, a9, a8); let p5 = T::polyeval_mla(x, a11, a10); let p6 = T::polyeval_mla(x, a13, a12); let p7 = T::polyeval_mla(x, a15, a14); let p8 = T::polyeval_mla(x, a17, a16); let p9 = T::polyeval_mla(x, a19, a18); let p10 = T::polyeval_mla(x, a21, a20); let q0 = T::polyeval_mla(x2, p1, p0); // (a3·x + a2)·x² + (a1·x + a0) let q1 = T::polyeval_mla(x2, p3, p2); let q2 = T::polyeval_mla(x2, p5, p4); let q3 = T::polyeval_mla(x2, p7, p6); let q4 = T::polyeval_mla(x2, p9, p8); let r0 = T::polyeval_mla(x4, q1, q0); // q1·x⁴ + q0 let r1 = T::polyeval_mla(x4, q3, q2); let s0 = T::polyeval_mla(x8, r1, r0); // r1·x⁸ + r0 let r2 = T::polyeval_mla(x4, p10, q4); // p10·x⁴ + q4 T::polyeval_mla(x16, r2, s0) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval28>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // ) -> T { // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // // // Degree 0–3 // let e0 = T::polyeval_mla(x, a1, a0); // let e1 = T::polyeval_mla(x, a3, a2); // let p0 = T::polyeval_mla(x2, e1, e0); // // // Degree 4–7 // let e2 = T::polyeval_mla(x, a5, a4); // let e3 = T::polyeval_mla(x, a7, a6); // let p1 = T::polyeval_mla(x2, e3, e2); // // // Degree 8–11 // let e4 = T::polyeval_mla(x, a9, a8); // let e5 = T::polyeval_mla(x, a11, a10); // let p2 = T::polyeval_mla(x2, e5, e4); // // // Degree 12–15 // let e6 = T::polyeval_mla(x, a13, a12); // let e7 = T::polyeval_mla(x, a15, a14); // let p3 = T::polyeval_mla(x2, e7, e6); // // // Degree 16–19 // let e8 = T::polyeval_mla(x, a17, a16); // let e9 = T::polyeval_mla(x, a19, a18); // let p4 = T::polyeval_mla(x2, e9, e8); // // // Degree 20–23 // let e10 = T::polyeval_mla(x, a21, a20); // let e11 = T::polyeval_mla(x, a23, a22); // let p5 = T::polyeval_mla(x2, e11, e10); // // // Degree 24–27 // let e12 = T::polyeval_mla(x, a25, a24); // let e13 = T::polyeval_mla(x, a27, a26); // let p6 = T::polyeval_mla(x2, e13, e12); // // // Group into x⁴ // let q0 = T::polyeval_mla(x4, p1, p0); // let q1 = T::polyeval_mla(x4, p3, p2); // let q2 = T::polyeval_mla(x4, p5, p4); // // // Final x⁸ group // let r0 = T::polyeval_mla(x8, q1, q0); // let r1 = T::polyeval_mla(x8, p6, q2); // // // Final result // T::polyeval_mla(x8 * x8, r1, r0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval23>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // ) -> T { // let mut acc = a22; // acc = T::polyeval_mla(x, acc, a21); // acc = T::polyeval_mla(x, acc, a20); // acc = T::polyeval_mla(x, acc, a19); // acc = T::polyeval_mla(x, acc, a18); // acc = T::polyeval_mla(x, acc, a17); // acc = T::polyeval_mla(x, acc, a16); // acc = T::polyeval_mla(x, acc, a15); // acc = T::polyeval_mla(x, acc, a14); // acc = T::polyeval_mla(x, acc, a13); // acc = T::polyeval_mla(x, acc, a12); // acc = T::polyeval_mla(x, acc, a11); // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } #[inline(always)] #[allow(clippy::too_many_arguments)] pub(crate) fn f_polyeval24>( x: T, a0: T, a1: T, a2: T, a3: T, a4: T, a5: T, a6: T, a7: T, a8: T, a9: T, a10: T, a11: T, a12: T, a13: T, a14: T, a15: T, a16: T, a17: T, a18: T, a19: T, a20: T, a21: T, a22: T, a23: T, ) -> T { // let z000 = T::polyeval_mla(x, a23, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) let x2 = x * x; let x4 = x2 * x2; let x8 = x4 * x4; let x16 = x8 * x8; // Group degree 0–1 let e0 = T::polyeval_mla(x, a1, a0); // Group degree 2–3 let e1 = T::polyeval_mla(x, a3, a2); // Group degree 4–5 let e2 = T::polyeval_mla(x, a5, a4); // Group degree 6–7 let e3 = T::polyeval_mla(x, a7, a6); // Group degree 8–9 let e4 = T::polyeval_mla(x, a9, a8); // Group degree 10–11 let e5 = T::polyeval_mla(x, a11, a10); // Group degree 12–13 let e6 = T::polyeval_mla(x, a13, a12); // Group degree 14–15 let e7 = T::polyeval_mla(x, a15, a14); // Group degree 16–17 let e8 = T::polyeval_mla(x, a17, a16); // Group degree 18–19 let e9 = T::polyeval_mla(x, a19, a18); // Group degree 20–21 let e10 = T::polyeval_mla(x, a21, a20); // Group degree 22–23 let e11 = T::polyeval_mla(x, a23, a22); // Now group into x2 terms let f0 = T::polyeval_mla(x2, e1, e0); let f1 = T::polyeval_mla(x2, e3, e2); let f2 = T::polyeval_mla(x2, e5, e4); let f3 = T::polyeval_mla(x2, e7, e6); let f4 = T::polyeval_mla(x2, e9, e8); let f5 = T::polyeval_mla(x2, e11, e10); // Now group into x4 terms let g0 = T::polyeval_mla(x4, f1, f0); let g1 = T::polyeval_mla(x4, f3, f2); let g2 = T::polyeval_mla(x4, f5, f4); // Now group into x8 terms let h0 = T::polyeval_mla(x8, g1, g0); let h1 = g2; // Final step (x16 term) T::polyeval_mla(x16, h1, h0) } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval25>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // ) -> T { // let z000 = T::polyeval_mla(x, a24, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval26>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // ) -> T { // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // let x16 = x8 * x8; // // let y0 = T::polyeval_mla(x, a1, a0); // let y1 = T::polyeval_mla(x, a3, a2); // let y2 = T::polyeval_mla(x, a5, a4); // let y3 = T::polyeval_mla(x, a7, a6); // let y4 = T::polyeval_mla(x, a9, a8); // let y5 = T::polyeval_mla(x, a11, a10); // let y6 = T::polyeval_mla(x, a13, a12); // let y7 = T::polyeval_mla(x, a15, a14); // let y8 = T::polyeval_mla(x, a17, a16); // let y9 = T::polyeval_mla(x, a19, a18); // let y10 = T::polyeval_mla(x, a21, a20); // let y11 = T::polyeval_mla(x, a23, a22); // let y12 = T::polyeval_mla(x, a25, a24); // // let z0 = T::polyeval_mla(x2, y1, y0); // let z1 = T::polyeval_mla(x2, y3, y2); // let z2 = T::polyeval_mla(x2, y5, y4); // let z3 = T::polyeval_mla(x2, y7, y6); // let z4 = T::polyeval_mla(x2, y9, y8); // let z5 = T::polyeval_mla(x2, y11, y10); // // let w0 = T::polyeval_mla(x4, z1, z0); // let w1 = T::polyeval_mla(x4, z3, z2); // let w2 = T::polyeval_mla(x4, z5, z4); // // let v0 = T::polyeval_mla(x8, w1, w0); // let v1 = T::polyeval_mla(x8, y12, w2); // // T::polyeval_mla(x16, v1, v0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval27>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // ) -> T { // let z000 = T::polyeval_mla(x, a26, a25); // let z000 = T::polyeval_mla(x, z000, a24); // let z000 = T::polyeval_mla(x, z000, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval30>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // ) -> T { // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // let x16 = x8 * x8; // // // Degree 0–1 // let e0 = T::polyeval_mla(x, a1, a0); // // Degree 2–3 // let e1 = T::polyeval_mla(x, a3, a2); // // Degree 4–5 // let e2 = T::polyeval_mla(x, a5, a4); // // Degree 6–7 // let e3 = T::polyeval_mla(x, a7, a6); // // Degree 8–9 // let e4 = T::polyeval_mla(x, a9, a8); // // Degree 10–11 // let e5 = T::polyeval_mla(x, a11, a10); // // Degree 12–13 // let e6 = T::polyeval_mla(x, a13, a12); // // Degree 14–15 // let e7 = T::polyeval_mla(x, a15, a14); // // // Combine with x² // let f0 = T::polyeval_mla(x2, e1, e0); // deg 0–3 // let f1 = T::polyeval_mla(x2, e3, e2); // deg 4–7 // let f2 = T::polyeval_mla(x2, e5, e4); // deg 8–11 // let f3 = T::polyeval_mla(x2, e7, e6); // deg 12–15 // // // Combine with x⁴ // let g0 = T::polyeval_mla(x4, f1, f0); // deg 0–7 // let g1 = T::polyeval_mla(x4, f3, f2); // deg 8–15 // // // Degree 16–17 // let e8 = T::polyeval_mla(x, a17, a16); // // Degree 18–19 // let e9 = T::polyeval_mla(x, a19, a18); // // Degree 20–21 // let e10 = T::polyeval_mla(x, a21, a20); // // Degree 22–23 // let e11 = T::polyeval_mla(x, a23, a22); // // Degree 24–25 // let e12 = T::polyeval_mla(x, a25, a24); // // Degree 26–27 // let e13 = T::polyeval_mla(x, a27, a26); // // Degree 28–29 // let e14 = T::polyeval_mla(x, a29, a28); // // // Combine with x² // let f4 = T::polyeval_mla(x2, e9, e8); // deg 16–19 // let f5 = T::polyeval_mla(x2, e11, e10); // deg 20–23 // let f6 = T::polyeval_mla(x2, e13, e12); // deg 24–27 // // // Combine remaining term (28–29) // let f7 = e14; // // // Combine with x⁴ // let g2 = T::polyeval_mla(x4, f5, f4); // deg 16–23 // let g3 = T::polyeval_mla(x4, f7, f6); // deg 24–29 // // // Combine with x⁸ // let h0 = T::polyeval_mla(x8, g1, g0); // deg 0–15 // let h1 = T::polyeval_mla(x8, g3, g2); // deg 16–29 // // // Final combination with x¹⁶ // T::polyeval_mla(x16, h1, h0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_horner_polyeval30>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // ) -> T { // let mut acc = a29; // acc = T::polyeval_mla(x, acc, a28); // acc = T::polyeval_mla(x, acc, a27); // acc = T::polyeval_mla(x, acc, a26); // acc = T::polyeval_mla(x, acc, a25); // acc = T::polyeval_mla(x, acc, a24); // acc = T::polyeval_mla(x, acc, a23); // acc = T::polyeval_mla(x, acc, a22); // acc = T::polyeval_mla(x, acc, a21); // acc = T::polyeval_mla(x, acc, a20); // acc = T::polyeval_mla(x, acc, a19); // acc = T::polyeval_mla(x, acc, a18); // acc = T::polyeval_mla(x, acc, a17); // acc = T::polyeval_mla(x, acc, a16); // acc = T::polyeval_mla(x, acc, a15); // acc = T::polyeval_mla(x, acc, a14); // acc = T::polyeval_mla(x, acc, a13); // acc = T::polyeval_mla(x, acc, a12); // acc = T::polyeval_mla(x, acc, a11); // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval31>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // ) -> T { // let z000 = T::polyeval_mla(x, a30, a29); // let z000 = T::polyeval_mla(x, z000, a28); // let z000 = T::polyeval_mla(x, z000, a27); // let z000 = T::polyeval_mla(x, z000, a26); // let z000 = T::polyeval_mla(x, z000, a25); // let z000 = T::polyeval_mla(x, z000, a24); // let z000 = T::polyeval_mla(x, z000, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval33>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // ) -> T { // let z000 = T::polyeval_mla(x, a32, a31); // let z000 = T::polyeval_mla(x, z000, a30); // let z000 = T::polyeval_mla(x, z000, a29); // let z000 = T::polyeval_mla(x, z000, a28); // let z000 = T::polyeval_mla(x, z000, a27); // let z000 = T::polyeval_mla(x, z000, a26); // let z000 = T::polyeval_mla(x, z000, a25); // let z000 = T::polyeval_mla(x, z000, a24); // let z000 = T::polyeval_mla(x, z000, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval29>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // ) -> T { // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // // // Level 0 // let e0 = T::polyeval_mla(x, a1, a0); // let e1 = T::polyeval_mla(x, a3, a2); // let e2 = T::polyeval_mla(x, a5, a4); // let e3 = T::polyeval_mla(x, a7, a6); // let e4 = T::polyeval_mla(x, a9, a8); // let e5 = T::polyeval_mla(x, a11, a10); // let e6 = T::polyeval_mla(x, a13, a12); // let e7 = T::polyeval_mla(x, a15, a14); // let e8 = T::polyeval_mla(x, a17, a16); // let e9 = T::polyeval_mla(x, a19, a18); // let e10 = T::polyeval_mla(x, a21, a20); // let e11 = T::polyeval_mla(x, a23, a22); // let e12 = T::polyeval_mla(x, a25, a24); // let e13 = T::polyeval_mla(x, a27, a26); // let e14 = a28; // single term left // // // Level 1 // let f0 = T::polyeval_mla(x2, e1, e0); // e1*x² + e0 // let f1 = T::polyeval_mla(x2, e3, e2); // let f2 = T::polyeval_mla(x2, e5, e4); // let f3 = T::polyeval_mla(x2, e7, e6); // let f4 = T::polyeval_mla(x2, e9, e8); // let f5 = T::polyeval_mla(x2, e11, e10); // let f6 = T::polyeval_mla(x2, e13, e12); // let f7 = e14; // promote // // // Level 2 // let g0 = T::polyeval_mla(x4, f1, f0); // let g1 = T::polyeval_mla(x4, f3, f2); // let g2 = T::polyeval_mla(x4, f5, f4); // let g3 = T::polyeval_mla(x4, f7, f6); // // // Level 3 // let h0 = T::polyeval_mla(x8, g1, g0); // let h1 = T::polyeval_mla(x8, g3, g2); // // // Final level // let x16 = x8 * x8; // T::polyeval_mla(x16, h1, h0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval37>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // a33: T, // a34: T, // a35: T, // a36: T, // ) -> T { // let z000 = T::polyeval_mla(x, a36, a35); // let z000 = T::polyeval_mla(x, z000, a34); // let z000 = T::polyeval_mla(x, z000, a33); // let z000 = T::polyeval_mla(x, z000, a32); // let z000 = T::polyeval_mla(x, z000, a31); // let z000 = T::polyeval_mla(x, z000, a30); // let z000 = T::polyeval_mla(x, z000, a29); // let z000 = T::polyeval_mla(x, z000, a28); // let z000 = T::polyeval_mla(x, z000, a27); // let z000 = T::polyeval_mla(x, z000, a26); // let z000 = T::polyeval_mla(x, z000, a25); // let z000 = T::polyeval_mla(x, z000, a24); // let z000 = T::polyeval_mla(x, z000, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval36>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // a33: T, // a34: T, // a35: T, // ) -> T { // let z000 = T::polyeval_mla(x, a35, a34); // let z000 = T::polyeval_mla(x, z000, a33); // let z000 = T::polyeval_mla(x, z000, a32); // let z000 = T::polyeval_mla(x, z000, a31); // let z000 = T::polyeval_mla(x, z000, a30); // let z000 = T::polyeval_mla(x, z000, a29); // let z000 = T::polyeval_mla(x, z000, a28); // let z000 = T::polyeval_mla(x, z000, a27); // let z000 = T::polyeval_mla(x, z000, a26); // let z000 = T::polyeval_mla(x, z000, a25); // let z000 = T::polyeval_mla(x, z000, a24); // let z000 = T::polyeval_mla(x, z000, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval41>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // a33: T, // a34: T, // a35: T, // a36: T, // a37: T, // a38: T, // a39: T, // a40: T, // ) -> T { // let mut acc = a40; // acc = T::polyeval_mla(x, acc, a39); // acc = T::polyeval_mla(x, acc, a38); // acc = T::polyeval_mla(x, acc, a37); // acc = T::polyeval_mla(x, acc, a36); // acc = T::polyeval_mla(x, acc, a35); // acc = T::polyeval_mla(x, acc, a34); // acc = T::polyeval_mla(x, acc, a33); // acc = T::polyeval_mla(x, acc, a32); // acc = T::polyeval_mla(x, acc, a31); // acc = T::polyeval_mla(x, acc, a30); // acc = T::polyeval_mla(x, acc, a29); // acc = T::polyeval_mla(x, acc, a28); // acc = T::polyeval_mla(x, acc, a27); // acc = T::polyeval_mla(x, acc, a26); // acc = T::polyeval_mla(x, acc, a25); // acc = T::polyeval_mla(x, acc, a24); // acc = T::polyeval_mla(x, acc, a23); // acc = T::polyeval_mla(x, acc, a22); // acc = T::polyeval_mla(x, acc, a21); // acc = T::polyeval_mla(x, acc, a20); // acc = T::polyeval_mla(x, acc, a19); // acc = T::polyeval_mla(x, acc, a18); // acc = T::polyeval_mla(x, acc, a17); // acc = T::polyeval_mla(x, acc, a16); // acc = T::polyeval_mla(x, acc, a15); // acc = T::polyeval_mla(x, acc, a14); // acc = T::polyeval_mla(x, acc, a13); // acc = T::polyeval_mla(x, acc, a12); // acc = T::polyeval_mla(x, acc, a11); // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval44>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // a33: T, // a34: T, // a35: T, // a36: T, // a37: T, // a38: T, // a39: T, // a40: T, // a41: T, // a42: T, // a43: T, // ) -> T { // let mut acc = a43; // acc = T::polyeval_mla(x, acc, a42); // acc = T::polyeval_mla(x, acc, a41); // acc = T::polyeval_mla(x, acc, a40); // acc = T::polyeval_mla(x, acc, a39); // acc = T::polyeval_mla(x, acc, a38); // acc = T::polyeval_mla(x, acc, a37); // acc = T::polyeval_mla(x, acc, a36); // acc = T::polyeval_mla(x, acc, a35); // acc = T::polyeval_mla(x, acc, a34); // acc = T::polyeval_mla(x, acc, a33); // acc = T::polyeval_mla(x, acc, a32); // acc = T::polyeval_mla(x, acc, a31); // acc = T::polyeval_mla(x, acc, a30); // acc = T::polyeval_mla(x, acc, a29); // acc = T::polyeval_mla(x, acc, a28); // acc = T::polyeval_mla(x, acc, a27); // acc = T::polyeval_mla(x, acc, a26); // acc = T::polyeval_mla(x, acc, a25); // acc = T::polyeval_mla(x, acc, a24); // acc = T::polyeval_mla(x, acc, a23); // acc = T::polyeval_mla(x, acc, a22); // acc = T::polyeval_mla(x, acc, a21); // acc = T::polyeval_mla(x, acc, a20); // acc = T::polyeval_mla(x, acc, a19); // acc = T::polyeval_mla(x, acc, a18); // acc = T::polyeval_mla(x, acc, a17); // acc = T::polyeval_mla(x, acc, a16); // acc = T::polyeval_mla(x, acc, a15); // acc = T::polyeval_mla(x, acc, a14); // acc = T::polyeval_mla(x, acc, a13); // acc = T::polyeval_mla(x, acc, a12); // acc = T::polyeval_mla(x, acc, a11); // acc = T::polyeval_mla(x, acc, a10); // acc = T::polyeval_mla(x, acc, a9); // acc = T::polyeval_mla(x, acc, a8); // acc = T::polyeval_mla(x, acc, a7); // acc = T::polyeval_mla(x, acc, a6); // acc = T::polyeval_mla(x, acc, a5); // acc = T::polyeval_mla(x, acc, a4); // acc = T::polyeval_mla(x, acc, a3); // acc = T::polyeval_mla(x, acc, a2); // acc = T::polyeval_mla(x, acc, a1); // T::polyeval_mla(x, acc, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval43>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // a33: T, // a34: T, // a35: T, // a36: T, // a37: T, // a38: T, // a39: T, // a40: T, // a41: T, // a42: T, // ) -> T { // let z000 = T::polyeval_mla(x, a42, a41); // let z000 = T::polyeval_mla(x, z000, a40); // let z000 = T::polyeval_mla(x, z000, a39); // let z000 = T::polyeval_mla(x, z000, a38); // let z000 = T::polyeval_mla(x, z000, a37); // let z000 = T::polyeval_mla(x, z000, a36); // let z000 = T::polyeval_mla(x, z000, a35); // let z000 = T::polyeval_mla(x, z000, a34); // let z000 = T::polyeval_mla(x, z000, a33); // let z000 = T::polyeval_mla(x, z000, a32); // let z000 = T::polyeval_mla(x, z000, a31); // let z000 = T::polyeval_mla(x, z000, a30); // let z000 = T::polyeval_mla(x, z000, a29); // let z000 = T::polyeval_mla(x, z000, a28); // let z000 = T::polyeval_mla(x, z000, a27); // let z000 = T::polyeval_mla(x, z000, a26); // let z000 = T::polyeval_mla(x, z000, a25); // let z000 = T::polyeval_mla(x, z000, a24); // let z000 = T::polyeval_mla(x, z000, a23); // let z000 = T::polyeval_mla(x, z000, a22); // let z000 = T::polyeval_mla(x, z000, a21); // let z000 = T::polyeval_mla(x, z000, a20); // let z000 = T::polyeval_mla(x, z000, a19); // let z000 = T::polyeval_mla(x, z000, a18); // let z000 = T::polyeval_mla(x, z000, a17); // let z00 = T::polyeval_mla(x, z000, a16); // let z01 = T::polyeval_mla(x, z00, a15); // let t1 = T::polyeval_mla(x, z01, a14); // let t2 = T::polyeval_mla(x, t1, a13); // let t3 = T::polyeval_mla(x, t2, a12); // let t4 = T::polyeval_mla(x, t3, a11); // let t5 = T::polyeval_mla(x, t4, a10); // let t6 = T::polyeval_mla(x, t5, a9); // let t7 = T::polyeval_mla(x, t6, a8); // let t8 = T::polyeval_mla(x, t7, a7); // let t9 = T::polyeval_mla(x, t8, a6); // let t10 = T::polyeval_mla(x, t9, a5); // let t11 = T::polyeval_mla(x, t10, a4); // let t12 = T::polyeval_mla(x, t11, a3); // let t13 = T::polyeval_mla(x, t12, a2); // let t14 = T::polyeval_mla(x, t13, a1); // T::polyeval_mla(x, t14, a0) // } // #[inline(always)] // #[allow(clippy::too_many_arguments)] // pub(crate) fn f_polyeval35>( // x: T, // a0: T, // a1: T, // a2: T, // a3: T, // a4: T, // a5: T, // a6: T, // a7: T, // a8: T, // a9: T, // a10: T, // a11: T, // a12: T, // a13: T, // a14: T, // a15: T, // a16: T, // a17: T, // a18: T, // a19: T, // a20: T, // a21: T, // a22: T, // a23: T, // a24: T, // a25: T, // a26: T, // a27: T, // a28: T, // a29: T, // a30: T, // a31: T, // a32: T, // a33: T, // a34: T, // ) -> T { // // let z000 = T::polyeval_mla(x, a34, a33); // // let z000 = T::polyeval_mla(x, z000, a32); // // let z000 = T::polyeval_mla(x, z000, a31); // // let z000 = T::polyeval_mla(x, z000, a30); // // let z000 = T::polyeval_mla(x, z000, a29); // // let z000 = T::polyeval_mla(x, z000, a28); // // let z000 = T::polyeval_mla(x, z000, a27); // // let z000 = T::polyeval_mla(x, z000, a26); // // let z000 = T::polyeval_mla(x, z000, a25); // // let z000 = T::polyeval_mla(x, z000, a24); // // let z000 = T::polyeval_mla(x, z000, a23); // // let z000 = T::polyeval_mla(x, z000, a22); // // let z000 = T::polyeval_mla(x, z000, a21); // // let z000 = T::polyeval_mla(x, z000, a20); // // let z000 = T::polyeval_mla(x, z000, a19); // // let z000 = T::polyeval_mla(x, z000, a18); // // let z000 = T::polyeval_mla(x, z000, a17); // // let z00 = T::polyeval_mla(x, z000, a16); // // let z01 = T::polyeval_mla(x, z00, a15); // // let t1 = T::polyeval_mla(x, z01, a14); // // let t2 = T::polyeval_mla(x, t1, a13); // // let t3 = T::polyeval_mla(x, t2, a12); // // let t4 = T::polyeval_mla(x, t3, a11); // // let t5 = T::polyeval_mla(x, t4, a10); // // let t6 = T::polyeval_mla(x, t5, a9); // // let t7 = T::polyeval_mla(x, t6, a8); // // let t8 = T::polyeval_mla(x, t7, a7); // // let t9 = T::polyeval_mla(x, t8, a6); // // let t10 = T::polyeval_mla(x, t9, a5); // // let t11 = T::polyeval_mla(x, t10, a4); // // let t12 = T::polyeval_mla(x, t11, a3); // // let t13 = T::polyeval_mla(x, t12, a2); // // let t14 = T::polyeval_mla(x, t13, a1); // // T::polyeval_mla(x, t14, a0) // // let x2 = x * x; // let x4 = x2 * x2; // let x8 = x4 * x4; // let x16 = x8 * x8; // let x32 = x16 * x16; // // // Level 0 // let z0 = T::polyeval_mla(x, a1, a0); // let z1 = T::polyeval_mla(x, a3, a2); // let z2 = T::polyeval_mla(x, a5, a4); // let z3 = T::polyeval_mla(x, a7, a6); // let z4 = T::polyeval_mla(x, a9, a8); // let z5 = T::polyeval_mla(x, a11, a10); // let z6 = T::polyeval_mla(x, a13, a12); // let z7 = T::polyeval_mla(x, a15, a14); // let z8 = T::polyeval_mla(x, a17, a16); // let z9 = T::polyeval_mla(x, a19, a18); // let z10 = T::polyeval_mla(x, a21, a20); // let z11 = T::polyeval_mla(x, a23, a22); // let z12 = T::polyeval_mla(x, a25, a24); // let z13 = T::polyeval_mla(x, a27, a26); // let z14 = T::polyeval_mla(x, a29, a28); // let z15 = T::polyeval_mla(x, a31, a30); // let z16 = T::polyeval_mla(x, a33, a32); // let z17 = a34; // // // Level 1 // let y0 = T::polyeval_mla(x2, z1, z0); // let y1 = T::polyeval_mla(x2, z3, z2); // let y2 = T::polyeval_mla(x2, z5, z4); // let y3 = T::polyeval_mla(x2, z7, z6); // let y4 = T::polyeval_mla(x2, z9, z8); // let y5 = T::polyeval_mla(x2, z11, z10); // let y6 = T::polyeval_mla(x2, z13, z12); // let y7 = T::polyeval_mla(x2, z15, z14); // let y8 = T::polyeval_mla(x2, z17, z16); // // // Level 2 // let w0 = T::polyeval_mla(x4, y1, y0); // let w1 = T::polyeval_mla(x4, y3, y2); // let w2 = T::polyeval_mla(x4, y5, y4); // let w3 = T::polyeval_mla(x4, y7, y6); // let w4 = y8; // // // Level 3 // let v0 = T::polyeval_mla(x8, w1, w0); // let v1 = T::polyeval_mla(x8, w3, w2); // let v2 = w4; // // // Level 4 // let u0 = T::polyeval_mla(x16, v1, v0); // let u1 = v2; // // // Level 5 (final) // T::polyeval_mla(x32, u1, u0) // } pxfm-0.1.23/src/pow.rs000064400000000000000000000474521046102023000126370ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{EXP_MASK, get_exponent_f64}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::exp; use crate::logs::log_dyadic; use crate::pow_exec::{exp_dyadic, pow_exp_1, pow_log_1}; use crate::triple_double::TripleDouble; use crate::{f_exp2, f_exp10, log}; #[inline] pub(crate) fn is_integer(n: f64) -> bool { n == n.round_ties_even() } #[inline] pub(crate) fn is_odd_integer(x: f64) -> bool { let x_u = x.to_bits(); let x_e = (x_u & EXP_MASK) >> 52; let lsb = (x_u | EXP_MASK).trailing_zeros(); const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; const UNIT_EXPONENT: u64 = E_BIAS + 52; x_e + lsb as u64 == UNIT_EXPONENT } #[cold] fn pow_exp10_fallback(x: f64) -> f64 { f_exp10(x) } #[cold] fn pow_exp2_fallback(x: f64) -> f64 { f_exp2(x) } #[cold] #[inline(never)] fn f_powi(x: f64, y: f64) -> f64 { let mut iter_count = y.abs() as usize; let mut s = DoubleDouble::new(0., x); // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { DoubleDouble::new(0., 1.) }; while { iter_count >>= 1; iter_count } != 0 { s = DoubleDouble::mult(s, s); if iter_count % 2 != 0 { acc = DoubleDouble::mult(acc, s); } } let dz = if y.is_sign_negative() { acc.recip() } else { acc }; let ub = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), -dz.hi, dz.lo); // 2^-59 let lb = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), dz.hi, dz.lo); // 2^-59 if ub == lb { return dz.to_f64(); } f_powi_hard(x, y) } #[cold] #[inline(never)] fn f_powi_hard(x: f64, y: f64) -> f64 { let mut iter_count = y.abs() as usize; let mut s = TripleDouble::new(0., 0., x); // exponentiation by squaring: O(log(y)) complexity let mut acc = if iter_count % 2 != 0 { s } else { TripleDouble::new(0., 0., 1.) }; while { iter_count >>= 1; iter_count } != 0 { s = TripleDouble::quick_mult(s, s); if iter_count % 2 != 0 { acc = TripleDouble::quick_mult(acc, s); } } let dz = if y.is_sign_negative() { acc.recip() } else { acc }; dz.to_f64() } /// Power function /// /// max found ULP 0.5 pub fn f_pow(x: f64, y: f64) -> f64 { let mut y = y; let x_sign = x.is_sign_negative(); let y_sign = y.is_sign_negative(); let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff; let y_abs = y.to_bits() & 0x7fff_ffff_ffff_ffff; const MANTISSA_MASK: u64 = (1u64 << 52) - 1; let y_mant = y.to_bits() & MANTISSA_MASK; let x_u = x.to_bits(); let x_a = x_abs; let y_a = y_abs; let mut x = x; // If x or y is signaling NaN if x.is_nan() || y.is_nan() { return f64::NAN; } let mut s = 1.0; // The double precision number that is closest to 1 is (1 - 2^-53), which has // log2(1 - 2^-53) ~ -1.715...p-53. // So if |y| > |1075 / log2(1 - 2^-53)|, and x is finite: // |y * log2(x)| = 0 or > 1075. // Hence, x^y will either overflow or underflow if x is not zero. if y_mant == 0 || y_a > 0x43d7_4910_d52d_3052 || x_u == 1f64.to_bits() || x_u >= f64::INFINITY.to_bits() || x_u < f64::MIN.to_bits() { // Exceptional exponents. if y == 0.0 { return 1.0; } match y_a { 0x3fe0_0000_0000_0000 => { if x == 0.0 || x_u == f64::NEG_INFINITY.to_bits() { // pow(-0, 1/2) = +0 // pow(-inf, 1/2) = +inf return if y_sign { 1.0 / (x * x) } else { x * x }; } return if y_sign { if x.is_infinite() { return if x.is_sign_positive() { 0. } else { f64::NAN }; } #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let r = x.sqrt() / x; let rx = r * x; let drx = f_fmla(r, x, -rx); let h = f_fmla(r, rx, -1.0) + r * drx; let dr = (r * 0.5) * h; r - dr } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let r = x.sqrt() / x; let d2x = DoubleDouble::from_exact_mult(r, x); let DoubleDouble { hi: h, lo: pr } = DoubleDouble::quick_mult_f64(d2x, r); let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_full_exact_add(-1.0, h); let h = DoubleDouble::from_exact_add(p, pr + q); let dr = DoubleDouble::quick_mult_f64(h, r * 0.5); r - dr.hi - dr.lo } } else { x.sqrt() }; } 0x3ff0_0000_0000_0000 => { return if y_sign { 1.0 / x } else { x }; } 0x4000_0000_0000_0000 => { let x_e = get_exponent_f64(x); if x_e > 511 { return if y_sign { 0. } else { f64::INFINITY }; } // not enough precision to make 0.5 ULP for subnormals if x_e.abs() < 70 { let x_sqr = DoubleDouble::from_exact_mult(x, x); return if y_sign { let recip = x_sqr.recip(); recip.to_f64() } else { x_sqr.to_f64() }; } } _ => {} } // |y| > |1075 / log2(1 - 2^-53)|. if y_a > 0x43d7_4910_d52d_3052 { if y_a >= 0x7ff0_0000_0000_0000 { // y is inf or nan if y_mant != 0 { // y is NaN // pow(1, NaN) = 1 // pow(x, NaN) = NaN return if x_u == 1f64.to_bits() { 1.0 } else { y }; } // Now y is +-Inf if f64::from_bits(x_abs).is_nan() { // pow(NaN, +-Inf) = NaN return x; } if x_a == 0x3ff0_0000_0000_0000 { // pow(+-1, +-Inf) = 1.0 return 1.0; } if x == 0.0 && y_sign { // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO return f64::INFINITY; } // pow (|x| < 1, -inf) = +inf // pow (|x| < 1, +inf) = 0.0 // pow (|x| > 1, -inf) = 0.0 // pow (|x| > 1, +inf) = +inf return if (x_a < 1f64.to_bits()) == y_sign { f64::INFINITY } else { 0.0 }; } // x^y will overflow / underflow in double precision. Set y to a // large enough exponent but not too large, so that the computations // won't overflow in double precision. y = if y_sign { f64::from_bits(0xc630000000000000) } else { f64::from_bits(0x4630000000000000) }; } // y is finite and non-zero. if x_u == 1f64.to_bits() { // pow(1, y) = 1 return 1.0; } if x == 0.0 { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { // pow(0, negative number) = inf return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } // pow(0, positive number) = 0 return if out_is_neg { -0.0 } else { 0.0 }; } else if x == 2.0 { return pow_exp2_fallback(y); } else if x == 10.0 { return pow_exp10_fallback(y); } if x_a == f64::INFINITY.to_bits() { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { return if out_is_neg { -0.0 } else { 0.0 }; } return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_a > f64::INFINITY.to_bits() { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } // x is finite and negative, and y is a finite integer. let is_y_integer = is_integer(y); // y is integer and in [-102;102] and |x|<2^10 // this is correct only for positive exponent number without FMA, // otherwise reciprocal may overflow. #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] if is_y_integer && y_a <= 0x4059800000000000u64 && x_a <= 0x4090000000000000u64 && x_a > 0x3cc0_0000_0000_0000 { return f_powi(x, y); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] if is_y_integer && y_a <= 0x4059800000000000u64 && x_a <= 0x4090000000000000u64 && x_a > 0x3cc0_0000_0000_0000 && y.is_sign_positive() { return f_powi(x, y); } if x_sign { if is_y_integer { x = -x; if is_odd_integer(y) { // sign = -1.0; static CS: [f64; 2] = [1.0, -1.0]; // set sign to 1 for y even, to -1 for y odd let y_parity = if (y.abs()) >= f64::from_bits(0x4340000000000000) { 0usize } else { (y as i64 & 0x1) as usize }; s = CS[y_parity]; } } else { // pow( negative, non-integer ) = NaN return f64::NAN; } } // y is finite and non-zero. if x_u == 1f64.to_bits() { // pow(1, y) = 1 return 1.0; } if x == 0.0 { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { // pow(0, negative number) = inf return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } // pow(0, positive number) = 0 return if out_is_neg { -0.0 } else { 0.0 }; } if x_a == f64::INFINITY.to_bits() { let out_is_neg = x_sign && is_odd_integer(y); if y_sign { return if out_is_neg { -0.0 } else { 0.0 }; } return if out_is_neg { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_a > f64::INFINITY.to_bits() { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } } // approximate log(x) let (mut l, cancel) = pow_log_1(x); /* We should avoid a spurious underflow/overflow in y*log(x). Underflow: for x<>1, the smallest absolute value of log(x) is obtained for x=1-2^-53, with |log(x)| ~ 2^-53. Thus to avoid a spurious underflow we require |y| >= 2^-969. Overflow: the largest absolute value of log(x) is obtained for x=2^-1074, with |log(x)| < 745. Thus to avoid a spurious overflow we require |y| < 2^1014. */ let ey = ((y.to_bits() >> 52) & 0x7ff) as i32; if ey < 0x36 || ey >= 0x7f5 { l.lo = f64::NAN; l.hi = f64::NAN; } let r = DoubleDouble::quick_mult_f64(l, y); let res = pow_exp_1(r, s); static ERR: [u64; 2] = [0x3bf2700000000000, 0x3c55700000000000]; let res_min = res.hi + f_fmla(f64::from_bits(ERR[cancel as usize]), -res.hi, res.lo); let res_max = res.hi + f_fmla(f64::from_bits(ERR[cancel as usize]), res.hi, res.lo); if res_min == res_max { return res_max; } pow_rational128(x, y, s) } #[cold] fn pow_rational128(x: f64, y: f64, s: f64) -> f64 { /* the idea of returning res_max instead of res_min is due to Laurent Théry: it is better in case of underflow since res_max = +0 always. */ let f_y = DyadicFloat128::new_from_f64(y); let r = log_dyadic(x) * f_y; let mut result = exp_dyadic(r); // 2^R.ex <= R < 2^(R.ex+1) // /* case R < 2^-1075: underflow case */ // if result.exponent < -1075 { // return 0.5 * (s * f64::from_bits(0x0000000000000001)); // } result.sign = if s == -1.0 { DyadicSign::Neg } else { DyadicSign::Pos }; result.fast_as_f64() } /// Pow for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn pow(d: f64, n: f64) -> f64 { let value = d.abs(); let r = n * log(value); let c = exp(r); if n == 0. { return 1.; } if d < 0.0 { let y = n as i32; if y % 2 == 0 { c } else { -c } } else { c } } #[cfg(test)] mod tests { use super::*; #[test] fn powf_test() { assert!( (pow(2f64, 3f64) - 8f64).abs() < 1e-9, "Invalid result {}", pow(2f64, 3f64) ); assert!( (pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9, "Invalid result {}", pow(0.5f64, 2f64) ); } #[test] fn f_pow_test() { assert_eq!(f_pow( 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371, -0.5, ), 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!(f_pow( 0.000000000000000000000000000000000000000000000000000021798599361155193, -2., ),2104470396771397700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!( f_pow(-25192281723900620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000., -2.), 0. ); assert_eq!( f_pow(0.000000000000000000000000000000000000000000000000000021799650661798696, -2.), 2104267423084451500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000. ); assert_eq!( f_pow(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014916691520383755, -2.), 44942267764413600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000. ); assert_eq!( f_pow( 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371, -0.5, ), 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000. ); assert_eq!(f_pow(1., f64::INFINITY), 1.); assert_eq!(f_pow(2., f64::INFINITY), f64::INFINITY); assert_eq!(f_pow(f64::INFINITY, -0.5), 0.); assert!( (f_pow(2f64, 3f64) - 8f64).abs() < 1e-9, "Invalid result {}", f_pow(2f64, 3f64) ); assert!( (f_pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9, "Invalid result {}", f_pow(0.5f64, 2f64) ); assert_eq!(f_pow(2.1f64, 2.7f64), 7.412967494768546); assert_eq!(f_pow(27., 1. / 3.), 3.); } #[test] fn powi_test() { assert_eq!(f_pow(f64::from_bits(0x3cc0_0000_0000_0000), 102.), 0.0); assert_eq!(f_pow(3., 3.), 27.); assert_eq!(f_pow(3., -3.), 1. / 27.); assert_eq!(f_pow(3., 102.), 4.638397686588102e48); assert_eq!(f_pow(0.000000000000011074474670636028, -22.), 10589880229528372000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); } } pxfm-0.1.23/src/pow_exec.rs000064400000000000000000000732331046102023000136370ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::dd_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1, ldexp}; use crate::exponents::{EXPM1_T0, EXPM1_T1}; use crate::polyeval::{f_polyeval6, f_polyeval8}; use crate::pow_tables::{EXP_T1_2_DYADIC, EXP_T2_2_DYADIC, POW_INVERSE, POW_LOG_INV}; #[inline(always)] pub(crate) fn log_poly_1(z: f64) -> DoubleDouble { /* The following is a degree-8 polynomial generated by Sollya for log(1+x)-x+x^2/2 over [-0.0040283203125,0.0040283203125] with absolute error < 2^-81.63 and relative error < 2^-72.423 (see sollya/P_1.sollya). The relative error is for x - x^2/2 + P(x) with respect to log(1+x). */ const P_1: [u64; 6] = [ 0x3fd5555555555558, 0xbfd0000000000003, 0x3fc999999981f535, 0xbfc55555553d1eb4, 0x3fc2494526fd4a06, 0xbfc0001f0c80e8ce, ]; let w = DoubleDouble::from_exact_mult(z, z); let t = dd_fmla(f64::from_bits(P_1[5]), z, f64::from_bits(P_1[4])); let mut u = dd_fmla(f64::from_bits(P_1[3]), z, f64::from_bits(P_1[2])); let mut v = dd_fmla(f64::from_bits(P_1[1]), z, f64::from_bits(P_1[0])); u = dd_fmla(t, w.hi, u); v = dd_fmla(u, w.hi, v); u = v * w.hi; DoubleDouble::new(dd_fmla(u, z, -0.5 * w.lo), -0.5 * w.hi) } /* Given 2^-1074 <= x <= 0x1.fffffffffffffp+1023, this routine puts in h+l an approximation of log(x) such that |l| < 2^-23.89*|h| and | h + l - log(x) | <= elog * |log x| with elog = 2^-73.527 if x < 1/sqrt(2) or sqrt(2) < x, and elog = 2^-67.0544 if 1/sqrt(2) < x < sqrt(2) (note that x cannot equal 1/sqrt(2) nor sqrt(2)). */ #[inline] pub(crate) fn pow_log_1(x: f64) -> (DoubleDouble, bool) { /* for 181 <= i <= 362, r[i] = _INVERSE[i-181] is a 9-bit approximation of 1/x[i], where i*2^-8 <= x[i] < (i+1)*2^-8. More precisely r[i] is a 9-bit value such that r[i]*y-1 is representable exactly on 53 bits for for any y, i*2^-8 <= y < (i+1)*2^-8. Moreover |r[i]*y-1| < 0.0040283203125. Table generated with the accompanying pow.sage file, with l=inverse_centered(k=8,prec=9,maxbits=53,verbose=false) */ let x_u = x.to_bits(); let mut m = x_u & 0xfffffffffffff; let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64; let t; if e != 0 { t = m | (0x3ffu64 << 52); m = m.wrapping_add(1u64 << 52); e -= 0x3ff; } else { /* x is a subnormal double */ let k = m.leading_zeros() - 11; e = -0x3fei64 - k as i64; m = m.wrapping_shl(k); t = m | (0x3ffu64 << 52); } /* now |x| = 2^_e*_t = 2^(_e-52)*m with 1 <= _t < 2, and 2^52 <= _m < 2^53 */ // log(x) = log(t) + E · log(2) let mut t = f64::from_bits(t); // If m > sqrt(2) we divide it by 2 so ensure 1/sqrt(2) < t < sqrt(2) let c: usize = (m >= 0x16a09e667f3bcd) as usize; static CY: [f64; 2] = [1.0, 0.5]; static CM: [u64; 2] = [44, 45]; e = e.wrapping_add(c as i64); let be = e; let i = m >> CM[c]; /* i/2^8 <= t < (i+1)/2^8 */ /* when c=1, we have 0x16a09e667f3bcd <= m < 2^53, thus 90 <= i <= 127; when c=0, we have 2^52 <= m < 0x16a09e667f3bcd, thus 128 <= i <= 181 */ t *= CY[c]; /* now 0x1.6a09e667f3bcdp-1 <= t < 0x1.6a09e667f3bcdp+0, and log(x) = E * log(2) + log(t) */ let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]); let l1 = f64::from_bits(POW_LOG_INV[(i - 181) as usize].1); let l2 = f64::from_bits(POW_LOG_INV[(i - 181) as usize].0); let z = dd_fmla(r, t, -1.0); const LOG2_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3d2ef35793c76730), f64::from_bits(0x3fe62e42fefa3800), ); let th = dd_fmla(be as f64, LOG2_DD.hi, l1); let tl = dd_fmla(be as f64, LOG2_DD.lo, l2); let mut v = DoubleDouble::f64_add(th, DoubleDouble::new(tl, z)); let p = log_poly_1(z); v = DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi)); if e == 0 && v.lo.abs() > (v.hi.abs()) * f64::from_bits(0x3e70000000000000) { v = DoubleDouble::from_exact_add(v.hi, v.lo); return (v, true); } (v, false) } /* Given z such that |z| < 2^-12.905, this routine puts in qh+ql an approximation of exp(z) such that | (qh+ql) / exp(z) - 1 | < 2^-64.902632 and |ql| <= 2^-51.999. */ #[inline(always)] fn exp_poly_1(z: f64) -> DoubleDouble { /* The following is a degree-4 polynomial generated by Sollya for exp(x) over [-2^-12.905,2^-12.905] with absolute error < 2^-74.34 (see sollya/Q_1.sollya). */ const Q_1: [u64; 5] = [ 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fc5555555997996, 0x3fa5555555849d8d, ]; let mut q = dd_fmla(f64::from_bits(Q_1[4]), z, f64::from_bits(Q_1[3])); q = dd_fmla(q, z, f64::from_bits(Q_1[2])); let h0 = dd_fmla(q, z, f64::from_bits(Q_1[1])); let v1 = DoubleDouble::from_exact_mult(z, h0); DoubleDouble::f64_add(f64::from_bits(Q_1[0]), v1) } /* Given z such that |z| < 2^-12.905, this routine puts in qh+ql an approximation of exp(z) such that | (qh+ql) / exp(z) - 1 | < 2^-64.902632 and |ql| <= 2^-51.999. */ #[inline(always)] fn exp_poly_dd(z: DoubleDouble) -> DoubleDouble { /* The following is a degree-4 polynomial generated by Sollya for exp(x) over [-2^-12.905,2^-12.905] */ const Q_1: [(u64, u64); 7] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3a20e40000000000, 0x3ff0000000000000), (0x3a04820000000000, 0x3fe0000000000000), (0xbc756423c5338a66, 0x3fc5555555555556), (0xbc5560f74db5556c, 0x3fa5555555555556), (0x3c3648eca89bc6ac, 0x3f8111111144fbee), (0xbbd53d924ae90c8c, 0x3f56c16c16ffeecc), ]; let mut p = DoubleDouble::mult(z, DoubleDouble::from_bit_pair(Q_1[6])); p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[5])); p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[4])); p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[3])); p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[2])); p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[1])); p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[0])); p } #[inline] pub(crate) fn pow_exp_1(r: DoubleDouble, s: f64) -> DoubleDouble { const RHO0: f64 = f64::from_bits(0xc0874910ee4e8a27); // #define RHO1 -0x1.577453f1799a6p+9 /* We increase the initial value of RHO1 to avoid spurious underflow in the result value el. However, it is not possible to obtain a lower bound on |el| from the input value rh, thus this modified value of RHO1 is obtained experimentally. */ const RHO1: f64 = f64::from_bits(0xc08483b8cca421af); const RHO2: f64 = f64::from_bits(0x40862e42e709a95b); const RHO3: f64 = f64::from_bits(0x40862e4316ea5df9); // use !(rh <= RHO2) instead of rh < RHO2 to catch rh = NaN too #[allow(clippy::neg_cmp_op_on_partial_ord)] if !(r.hi <= RHO2) { return if r.hi > RHO3 { /* If rh > RHO3, we are sure there is overflow, For s=1 we return eh = el = DBL_MAX, which yields res_min = res_max = +Inf for rounding up or to nearest, and res_min = res_max = DBL_MAX for rounding down or toward zero, which will yield the correct rounding. For s=-1 we return eh = el = -DBL_MAX, which similarly gives res_min = res_max = -Inf or res_min = res_max = -DBL_MAX, which is the correct rounding. */ DoubleDouble::new( f64::from_bits(0x7fefffffffffffff) * s, f64::from_bits(0x7fefffffffffffff) * s, ) } else { /* If RHO2 < rh <= RHO3, we are in the intermediate region where there might be overflow or not, thus we set eh = el = NaN, which will set res_min = res_max = NaN, the comparison res_min == res_max will fail: we defer to the 2nd phase. */ DoubleDouble::new(f64::NAN, f64::NAN) }; } if r.hi < RHO1 { return if r.hi < RHO0 { /* For s=1, we have eh=el=+0 except for rounding up, thus res_min=+0 or -0, res_max=+0 in the main code, the rounding test succeeds, and we return res_max which is the expected result in the underflow case. For s=1 and rounding up, we have eh=+0, el=2^-1074, thus res_min = res_max = 2^-1074, which is the expected result too. For s=-1, we have eh=el=-0 except for rounding down, thus res_min=-0 or +0, res_max=-0 in the main code, the rounding test succeeds, and we return res_max which is the expected result in the underflow case. For s=-1 and rounding down, we have eh=-0, el=-2^-1074, thus res_min = res_max = -2^-1074, which is the expected result too. */ DoubleDouble::new(f64::from_bits(0x0000000000000001) * (0.5 * s), 0.0 * s) } else { /* RHO0 <= rh < RHO1 or s < 0: we defer to the 2nd phase */ DoubleDouble::new(f64::NAN, f64::NAN) }; } const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); let k = (r.hi * INVLOG2).round(); const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); let zh = dd_fmla(LOG2H, -k, r.hi); let zl = dd_fmla(LOG2L, -k, r.lo); let bk = k as i64; /* Note: k is an integer, this is just a conversion. */ let mk = (bk >> 12) + 0x3ff; let i2 = (bk >> 6) & 0x3f; let i1 = bk & 0x3f; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i2 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let mut de = DoubleDouble::quick_mult(t1, t0); let q = exp_poly_1(zh + zl); de = DoubleDouble::quick_mult(de, q); /* we should have 1 < M < 2047 here, since we filtered out potential underflow/overflow cases at the beginning of this function */ let mut du = (mk as u64).wrapping_shl(52); du = (f64::from_bits(du) * s).to_bits(); de.hi *= f64::from_bits(du); de.lo *= f64::from_bits(du); de } #[inline] pub(crate) fn exp_dd_fast(r: DoubleDouble) -> DoubleDouble { const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); let k = (r.hi * INVLOG2).round(); const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); let mut z = DoubleDouble::mul_f64_add(DoubleDouble::new(LOG2L, LOG2H), -k, r); z = DoubleDouble::from_exact_add(z.hi, z.lo); let bk = k as i64; /* Note: k is an integer, this is just a conversion. */ let mk = (bk >> 12) + 0x3ff; let i2 = (bk >> 6) & 0x3f; let i1 = bk & 0x3f; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i2 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let mut de = DoubleDouble::quick_mult(t1, t0); // exp(hi + lo) = exp(hi) * exp(lo) let q_hi = exp_poly_1(z.hi); // Taylor series exp(x) ~ 1 + x since z.lo < ulp(z.h) let q_lo = DoubleDouble::from_exact_add(1., z.lo); let q = DoubleDouble::quick_mult(q_hi, q_lo); de = DoubleDouble::quick_mult(de, q); /* we should have 1 < M < 2047 here, since we filtered out potential underflow/overflow cases at the beginning of this function */ let du = (mk as u64).wrapping_shl(52); de.hi *= f64::from_bits(du); de.lo *= f64::from_bits(du); de } #[inline] pub(crate) fn pow_exp_dd(r: DoubleDouble, s: f64) -> DoubleDouble { const RHO0: f64 = f64::from_bits(0xc0874910ee4e8a27); // #define RHO1 -0x1.577453f1799a6p+9 /* We increase the initial value of RHO1 to avoid spurious underflow in the result value el. However, it is not possible to obtain a lower bound on |el| from the input value rh, thus this modified value of RHO1 is obtained experimentally. */ const RHO1: f64 = f64::from_bits(0xc08483b8cca421af); const RHO2: f64 = f64::from_bits(0x40862e42e709a95b); const RHO3: f64 = f64::from_bits(0x40862e4316ea5df9); // use !(rh <= RHO2) instead of rh < RHO2 to catch rh = NaN too #[allow(clippy::neg_cmp_op_on_partial_ord)] if !(r.hi <= RHO2) { return if r.hi > RHO3 { /* If rh > RHO3, we are sure there is overflow, For s=1 we return eh = el = DBL_MAX, which yields res_min = res_max = +Inf for rounding up or to nearest, and res_min = res_max = DBL_MAX for rounding down or toward zero, which will yield the correct rounding. For s=-1 we return eh = el = -DBL_MAX, which similarly gives res_min = res_max = -Inf or res_min = res_max = -DBL_MAX, which is the correct rounding. */ DoubleDouble::new( f64::from_bits(0x7fefffffffffffff) * s, f64::from_bits(0x7fefffffffffffff) * s, ) } else { /* If RHO2 < rh <= RHO3, we are in the intermediate region where there might be overflow or not, thus we set eh = el = NaN, which will set res_min = res_max = NaN, the comparison res_min == res_max will fail: we defer to the 2nd phase. */ DoubleDouble::new(f64::NAN, f64::NAN) }; } if r.hi < RHO1 { return if r.hi < RHO0 { /* For s=1, we have eh=el=+0 except for rounding up, thus res_min=+0 or -0, res_max=+0 in the main code, the rounding test succeeds, and we return res_max which is the expected result in the underflow case. For s=1 and rounding up, we have eh=+0, el=2^-1074, thus res_min = res_max = 2^-1074, which is the expected result too. For s=-1, we have eh=el=-0 except for rounding down, thus res_min=-0 or +0, res_max=-0 in the main code, the rounding test succeeds, and we return res_max which is the expected result in the underflow case. For s=-1 and rounding down, we have eh=-0, el=-2^-1074, thus res_min = res_max = -2^-1074, which is the expected result too. */ DoubleDouble::new(f64::from_bits(0x0000000000000001) * (0.5 * s), 0.0 * s) } else { /* RHO0 <= rh < RHO1 or s < 0: we defer to the 2nd phase */ DoubleDouble::new(f64::NAN, f64::NAN) }; } const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); /* Note: if the rounding mode is to nearest, we can save about 2 cycles (on an i7-8700) by replacing the computation of k by the following classical trick: const double magic = 0x1.8p+52; double k = __builtin_fma (rh, INVLOG2, magic) - magic; */ let k = (r.hi * INVLOG2).round(); const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); let z = DoubleDouble::mul_f64_add(DoubleDouble::new(LOG2L, LOG2H), -k, r); let bk = k as i64; /* Note: k is an integer, this is just a conversion. */ let mk = (bk >> 12) + 0x3ff; let i2 = (bk >> 6) & 0x3f; let i1 = bk & 0x3f; let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i2 as usize]); let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]); let mut de = DoubleDouble::quick_mult(t1, t0); let q = exp_poly_dd(z); de = DoubleDouble::quick_mult(de, q); /* we should have 1 < M < 2047 here, since we filtered out potential underflow/overflow cases at the beginning of this function */ let mut du = (mk as u64).wrapping_shl(52); du = (f64::from_bits(du) * s).to_bits(); de.hi *= f64::from_bits(du); de.lo *= f64::from_bits(du); de } /* #[inline(always)] pub(crate) fn expm1_poly_dd(z: DoubleDouble) -> DoubleDouble { /* Sollya: pretty = proc(u) { return ~(floor(u*1000)/1000); }; d = [-2^-12.905,2^-12.905]; f = expm1(x); w = 1; pf = fpminimax(f, [|1,2,3,4,5,6,7|], [|1, 1, 107...|], d, absolute, floating); err_p = -log2(dirtyinfnorm(pf*w-f, d)); display = decimal; for i from 1 to degree(pf) do print(coeff(pf, i)); print (pf); display = decimal; print ("absolute error:",pretty(err_p)); f = 1; w = 1/expm1(x); err_p = -log2(dirtyinfnorm(pf*w-f, d)); print ("relative error:",pretty(err_p)); */ const Q: [(u64, u64); 7] = [ (0x0000000000000000, 0x3ff0000000000000), (0x0000000000000000, 0x3fe0000000000000), (0xbc75555554d7c48c, 0x3fc5555555555556), (0xbc555a40ffb472d9, 0x3fa5555555555556), (0x3c24866314c38093, 0x3f8111111111110e), (0x3be34665978dddb8, 0x3f56c16c16efac90), (0x3baeab43b813ef24, 0x3f2a01a1e12d253c), ]; let z2 = z * z; let z4 = z2 * z2; let b0 = DoubleDouble::quick_mul_add( z, DoubleDouble::from_bit_pair(Q[1]), DoubleDouble::from_bit_pair(Q[0]), ); let b1 = DoubleDouble::quick_mul_add( z, DoubleDouble::from_bit_pair(Q[3]), DoubleDouble::from_bit_pair(Q[2]), ); let b2 = DoubleDouble::quick_mul_add( z, DoubleDouble::from_bit_pair(Q[5]), DoubleDouble::from_bit_pair(Q[4]), ); let c0 = DoubleDouble::quick_mul_add(z2, b1, b0); let c1 = DoubleDouble::quick_mul_add(z2, DoubleDouble::from_bit_pair(Q[6]), b2); let p = DoubleDouble::quick_mul_add(z4, c1, c0); DoubleDouble::quick_mult(p, z) } */ #[inline(always)] pub(crate) fn expm1_poly_fast(z: DoubleDouble) -> DoubleDouble { // Polynomial generated by Sollya: // d = [-2^-12.905,2^-12.905]; // f = expm1(x); // w = 1; // pf = fpminimax(f, [|1,2,3,4,5,6,7|], [|1, 1, D...|], d, absolute, floating); // See ./notes/compound_m1_expm1_fast.sollya let p = f_polyeval6( z.hi, f64::from_bits(0x3fe0000000000000), f64::from_bits(0x3fc5555555555555), f64::from_bits(0x3fa55555555553de), f64::from_bits(0x3f81111144995a9a), f64::from_bits(0x3f56c241f9a791c5), f64::from_bits(0xbfad9209c6d8b9e1), ); let px = DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_mult(z.hi, p), z.hi); // expm1(hi + lo) = expm1(hi) + expm1(lo)(1 + expm1(hi)) = expm1(hi) + expm1(lo)expm1(hi) + expm1(lo) // expm1(lo) ~ lo let expm1_hi = DoubleDouble::f64_add(z.hi, px); let mut lowest_part = DoubleDouble::quick_mult_f64(expm1_hi, z.lo); lowest_part = DoubleDouble::full_add_f64(lowest_part, z.lo); DoubleDouble::quick_dd_add(expm1_hi, lowest_part) } /// |z.hi| < 2^-7 #[inline(always)] pub(crate) fn expm1_poly_dd_tiny(z: DoubleDouble) -> DoubleDouble { // Polynomial generated in Sollya // d = [-2^-7,2^-7]; // f = expm1(x); // w = 1; // pf = fpminimax(f, [|1,2,3,4,5,6,7,8,9|], [|1, 1, 107...|], d, absolute, floating); // See ./notes/compound_expm1_tiny.sollya const Q: [(u64, u64); 9] = [ (0x0000000000000000, 0x3ff0000000000000), (0x0000000000000000, 0x3fe0000000000000), (0x3c6555564150ff16, 0x3fc5555555555555), (0x3c4586275c26f8a5, 0x3fa5555555555555), (0xbc19e6193ac658a6, 0x3f81111111111111), (0xbbf025e72dc21051, 0x3f56c16c16c1500a), (0x3bc2d641a7b7b9b8, 0x3f2a01a01a07dc46), (0xbb42cc8aaeeb3d00, 0x3efa01a29fef3e6f), (0x3b52b1589125ce82, 0x3ec71db6af553255), ]; let z = DoubleDouble::from_exact_add(z.hi, z.lo); let mut d = DoubleDouble::quick_mul_add( z, DoubleDouble::from_bit_pair(Q[8]), DoubleDouble::from_bit_pair(Q[7]), ); d = DoubleDouble::quick_mul_add(z, d, DoubleDouble::from_bit_pair(Q[6])); d = DoubleDouble::quick_mul_add(z, d, DoubleDouble::from_bit_pair(Q[5])); d = DoubleDouble::quick_mul_add(z, d, DoubleDouble::from_bit_pair(Q[4])); d = DoubleDouble::quick_mul_add(z, d, DoubleDouble::from_bit_pair(Q[3])); d = DoubleDouble::quick_mul_add(z, d, DoubleDouble::from_bit_pair(Q[2])); d = DoubleDouble::quick_mul_add_f64(z, d, f64::from_bits(0x3fe0000000000000)); d = DoubleDouble::quick_mul_add_f64(z, d, f64::from_bits(0x3ff0000000000000)); DoubleDouble::quick_mult(d, z) } #[inline] pub(crate) fn pow_expm1_1(r: DoubleDouble, s: f64) -> DoubleDouble { const RHO0: f64 = f64::from_bits(0xc0874910ee4e8a27); // #define RHO1 -0x1.577453f1799a6p+9 /* We increase the initial value of RHO1 to avoid spurious underflow in the result value el. However, it is not possible to obtain a lower bound on |el| from the input value rh, thus this modified value of RHO1 is obtained experimentally. */ const RHO1: f64 = f64::from_bits(0xc08483b8cca421af); const RHO2: f64 = f64::from_bits(0x40862e42e709a95b); const RHO3: f64 = f64::from_bits(0x40862e4316ea5df9); // use !(rh <= RHO2) instead of rh < RHO2 to catch rh = NaN too #[allow(clippy::neg_cmp_op_on_partial_ord)] if !(r.hi <= RHO2) { return if r.hi > RHO3 { /* If rh > RHO3, we are sure there is overflow, For s=1 we return eh = el = DBL_MAX, which yields res_min = res_max = +Inf for rounding up or to nearest, and res_min = res_max = DBL_MAX for rounding down or toward zero, which will yield the correct rounding. For s=-1 we return eh = el = -DBL_MAX, which similarly gives res_min = res_max = -Inf or res_min = res_max = -DBL_MAX, which is the correct rounding. */ DoubleDouble::new( f64::from_bits(0x7fefffffffffffff) * s, f64::from_bits(0x7fefffffffffffff) * s, ) } else { /* If RHO2 < rh <= RHO3, we are in the intermediate region where there might be overflow or not, thus we set eh = el = NaN, which will set res_min = res_max = NaN, the comparison res_min == res_max will fail: we defer to the 2nd phase. */ DoubleDouble::new(f64::NAN, f64::NAN) }; } if r.hi < RHO1 { if r.hi < RHO0 { /* For s=1, we have eh=el=+0 except for rounding up, thus res_min=+0 or -0, res_max=+0 in the main code, the rounding test succeeds, and we return res_max which is the expected result in the underflow case. For s=1 and rounding up, we have eh=+0, el=2^-1074, thus res_min = res_max = 2^-1074, which is the expected result too. For s=-1, we have eh=el=-0 except for rounding down, thus res_min=-0 or +0, res_max=-0 in the main code, the rounding test succeeds, and we return res_max which is the expected result in the underflow case. For s=-1 and rounding down, we have eh=-0, el=-2^-1074, thus res_min = res_max = -2^-1074, which is the expected result too. */ return DoubleDouble::full_add_f64( DoubleDouble::new(f64::from_bits(0x0000000000000001) * (0.5 * s), 0.0 * s), -1.0, ); } else { /* RHO0 <= rh < RHO1 or s < 0: we return -1 */ return DoubleDouble::new(0., -1.); }; } let ax = r.hi.to_bits() & 0x7fffffffffffffffu64; const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef); const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f); if ax <= 0x3f80000000000000 { // |x| < 2^-7 if ax < 0x3970000000000000 { // |x| < 2^-104 return r; } let d = expm1_poly_dd_tiny(r); return d; } const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe); let k = (r.hi * INVLOG2).round_ties_even(); let z = DoubleDouble::mul_f64_add(DoubleDouble::new(LOG2L, LOG2H), -k, r); let bk = k as i64; /* Note: k is an integer, this is just a conversion. */ let mk = (bk >> 12) + 0x3ff; let i2 = (bk >> 6) & 0x3f; let i1 = bk & 0x3f; let t0 = DoubleDouble::from_bit_pair(EXPM1_T0[i2 as usize]); let t1 = DoubleDouble::from_bit_pair(EXPM1_T1[i1 as usize]); let tbh = DoubleDouble::quick_mult(t1, t0); let mut de = tbh; // exp(k)=2^k*exp(r) + (2^k - 1) let q = expm1_poly_fast(z); de = DoubleDouble::quick_mult(de, q); de = DoubleDouble::add(tbh, de); let ie = mk - 0x3ff; let off: f64 = f64::from_bits((2048i64 + 1023i64).wrapping_sub(ie).wrapping_shl(52) as u64); let e: f64; if ie < 53 { let fhz = DoubleDouble::from_exact_add(off, de.hi); de.hi = fhz.hi; e = fhz.lo; } else if ie < 104 { let fhz = DoubleDouble::from_exact_add(de.hi, off); de.hi = fhz.hi; e = fhz.lo; } else { e = 0.; } de.lo += e; de.hi = ldexp(de.to_f64(), ie as i32); de.lo = 0.; de } fn exp_dyadic_poly(x: DyadicFloat128) -> DyadicFloat128 { const Q_2: [DyadicFloat128; 8] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffd0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0088_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8000_0000_0000_0000_0000_000c_06f3_cd29_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xaaaa_aaaa_aaaa_aaaa_aaaa_aa6a_1e07_76ae_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xaaaa_aaaa_aaaa_aaa3_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x8888_8888_8888_8897_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xb60b_60b9_3214_6a54_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -140, mantissa: 0xd00d_00cd_9841_6862_0000_0000_0000_0000_u128, }, ]; f_polyeval8( x, Q_2[0], Q_2[1], Q_2[2], Q_2[3], Q_2[4], Q_2[5], Q_2[6], Q_2[7], ) } /* put in r an approximation of exp(x), for |x| < 744.45, with relative error < 2^-121.70 */ #[inline] pub(crate) fn exp_dyadic(x: DyadicFloat128) -> DyadicFloat128 { let ex = x.exponent + 127; if ex >= 10 // underflow or overflow { return DyadicFloat128 { sign: DyadicSign::Pos, exponent: if x.sign == DyadicSign::Neg { -1076 } else { 1025 }, mantissa: x.mantissa, }; } const LOG2_INV: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -115, mantissa: 0xb8aa_3b29_5c17_f0bc_0000_0000_0000_0000_u128, }; const LOG2: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb172_17f7_d1cf_79ab_c9e3_b398_03f2_f6af_u128, }; let mut bk = x * LOG2_INV; let k = bk.trunc_to_i64(); /* k = trunc(K) [rounded towards zero, exact] */ /* The rounding error of mul_dint_int64() is bounded by 6 ulps, thus since |K| <= 4399162*log(2) < 3049267, the error on K is bounded by 2^-103.41. This error is divided by 2^12 below, thus yields < 2^-115.41. */ bk = LOG2.mul_int64(k); bk.exponent -= 12; bk.sign = bk.sign.negate(); let y = x + bk; let bm = k >> 12; let i2 = (k >> 6) & 0x3f; let i1 = k & 0x3f; let mut r = exp_dyadic_poly(y); r = EXP_T1_2_DYADIC[i2 as usize] * r; r = EXP_T2_2_DYADIC[i1 as usize] * r; r.exponent += bm as i16; /* exact */ r } #[cfg(test)] mod tests { use super::*; use crate::f_expm1; #[test] fn test_log() { let k = DyadicFloat128::new_from_f64(2.5); assert_eq!(exp_dyadic(k).fast_as_f64(), 12.182493960703473); } #[test] fn test_exp() { let k = pow_expm1_1(DoubleDouble::new(0., 2.543543543543), 1.); println!("{}", k.to_f64()); println!("{}", f_expm1(2.543543543543)); } } pxfm-0.1.23/src/pow_tables.rs000064400000000000000000001103201046102023000141520ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; pub(crate) static POW_INVERSE: [u64; 182] = [ 0x3ff6900000000000, 0x3ff6700000000000, 0x3ff6500000000000, 0x3ff6300000000000, 0x3ff6100000000000, 0x3ff5f00000000000, 0x3ff5e00000000000, 0x3ff5c00000000000, 0x3ff5a00000000000, 0x3ff5800000000000, 0x3ff5600000000000, 0x3ff5400000000000, 0x3ff5300000000000, 0x3ff5100000000000, 0x3ff4f00000000000, 0x3ff4e00000000000, 0x3ff4c00000000000, 0x3ff4a00000000000, 0x3ff4800000000000, 0x3ff4700000000000, 0x3ff4500000000000, 0x3ff4400000000000, 0x3ff4200000000000, 0x3ff4000000000000, 0x3ff3f00000000000, 0x3ff3d00000000000, 0x3ff3c00000000000, 0x3ff3a00000000000, 0x3ff3900000000000, 0x3ff3700000000000, 0x3ff3600000000000, 0x3ff3400000000000, 0x3ff3300000000000, 0x3ff3200000000000, 0x3ff3000000000000, 0x3ff2f00000000000, 0x3ff2d00000000000, 0x3ff2c00000000000, 0x3ff2b00000000000, 0x3ff2900000000000, 0x3ff2800000000000, 0x3ff2700000000000, 0x3ff2500000000000, 0x3ff2400000000000, 0x3ff2300000000000, 0x3ff2100000000000, 0x3ff2000000000000, 0x3ff1f00000000000, 0x3ff1e00000000000, 0x3ff1c00000000000, 0x3ff1b00000000000, 0x3ff1a00000000000, 0x3ff1900000000000, 0x3ff1700000000000, 0x3ff1600000000000, 0x3ff1500000000000, 0x3ff1400000000000, 0x3ff1300000000000, 0x3ff1200000000000, 0x3ff1000000000000, 0x3ff0f00000000000, 0x3ff0e00000000000, 0x3ff0d00000000000, 0x3ff0c00000000000, 0x3ff0b00000000000, 0x3ff0a00000000000, 0x3ff0900000000000, 0x3ff0800000000000, 0x3ff0700000000000, 0x3ff0600000000000, 0x3ff0500000000000, 0x3ff0400000000000, 0x3ff0300000000000, 0x3ff0200000000000, 0x3ff0000000000000, 0x3ff0000000000000, 0x3fefd00000000000, 0x3fefb00000000000, 0x3fef900000000000, 0x3fef700000000000, 0x3fef500000000000, 0x3fef300000000000, 0x3fef100000000000, 0x3fef000000000000, 0x3feee00000000000, 0x3feec00000000000, 0x3feea00000000000, 0x3fee800000000000, 0x3fee600000000000, 0x3fee500000000000, 0x3fee300000000000, 0x3fee100000000000, 0x3fedf00000000000, 0x3fedd00000000000, 0x3fedc00000000000, 0x3feda00000000000, 0x3fed800000000000, 0x3fed700000000000, 0x3fed500000000000, 0x3fed300000000000, 0x3fed200000000000, 0x3fed000000000000, 0x3fece00000000000, 0x3fecd00000000000, 0x3fecb00000000000, 0x3fec900000000000, 0x3fec800000000000, 0x3fec600000000000, 0x3fec500000000000, 0x3fec300000000000, 0x3fec200000000000, 0x3fec000000000000, 0x3febf00000000000, 0x3febd00000000000, 0x3febc00000000000, 0x3feba00000000000, 0x3feb900000000000, 0x3feb700000000000, 0x3feb600000000000, 0x3feb400000000000, 0x3feb300000000000, 0x3feb100000000000, 0x3feb000000000000, 0x3feae00000000000, 0x3fead00000000000, 0x3feac00000000000, 0x3feaa00000000000, 0x3fea900000000000, 0x3fea700000000000, 0x3fea600000000000, 0x3fea500000000000, 0x3fea300000000000, 0x3fea200000000000, 0x3fea100000000000, 0x3fe9f00000000000, 0x3fe9e00000000000, 0x3fe9d00000000000, 0x3fe9c00000000000, 0x3fe9a00000000000, 0x3fe9900000000000, 0x3fe9800000000000, 0x3fe9600000000000, 0x3fe9500000000000, 0x3fe9400000000000, 0x3fe9300000000000, 0x3fe9100000000000, 0x3fe9000000000000, 0x3fe8f00000000000, 0x3fe8e00000000000, 0x3fe8d00000000000, 0x3fe8b00000000000, 0x3fe8a00000000000, 0x3fe8900000000000, 0x3fe8800000000000, 0x3fe8700000000000, 0x3fe8600000000000, 0x3fe8400000000000, 0x3fe8300000000000, 0x3fe8200000000000, 0x3fe8100000000000, 0x3fe8000000000000, 0x3fe7f00000000000, 0x3fe7e00000000000, 0x3fe7c00000000000, 0x3fe7b00000000000, 0x3fe7a00000000000, 0x3fe7900000000000, 0x3fe7800000000000, 0x3fe7700000000000, 0x3fe7600000000000, 0x3fe7500000000000, 0x3fe7400000000000, 0x3fe7300000000000, 0x3fe7200000000000, 0x3fe7100000000000, 0x3fe7000000000000, 0x3fe6f00000000000, 0x3fe6e00000000000, 0x3fe6d00000000000, 0x3fe6c00000000000, 0x3fe6b00000000000, 0x3fe6a00000000000, ]; pub(crate) static POW_LOG_INV: [(u64, u64); 182] = [ (0xbd2e9e439f105039, 0xbfd5ff3070a79000), (0x3cde63af2df7ba69, 0xbfd5a42ab0f4d000), (0xbd23167e63081cf7, 0xbfd548a2c3add000), (0xbd234d7aaf04d104, 0xbfd4ec9732600000), (0x3d38bccffe1a0f8c, 0xbfd4900680401000), (0x3d3fb129931715ad, 0xbfd432ef2a04f000), (0xbd3f8ef43049f7d3, 0xbfd404308686a000), (0xbd37a71cbcd735d0, 0xbfd3a64c55694000), (0x3d25594dd4c58092, 0xbfd347dd9a988000), (0x3d267b1e99b72bd8, 0xbfd2e8e2bae12000), (0xbd3a8d7ad24c13f0, 0xbfd2895a13de8000), (0x3d3a6976f5eb0963, 0xbfd22941fbcf8000), (0xbd27946c040cbe77, 0xbfd1f8ff9e48a000), (0xbd2b7b3a7a361c9a, 0xbfd1980d2dd42000), (0x3d3d3e8499d67123, 0xbfd136870293b000), (0x3d34ab9d817d52cd, 0xbfd1058bf9ae5000), (0xbd0c6bee7ef4030e, 0xbfd0a324e2739000), (0xbcf036b89ef42d7f, 0xbfd0402594b4d000), (0x3d0d572aab993c87, 0xbfcfb9186d5e4000), (0x3d2323e3a09202fe, 0xbfcf550a564b8000), (0x3d26805b80e8e6ff, 0xbfce8c0252aa6000), (0x3d3a342c2af0003c, 0xbfce27076e2b0000), (0x3d21ba91bbca681b, 0xbfcd5c216b4fc000), (0x3d27794f689f8434, 0xbfcc8ff7c79aa000), (0x3d2cfd73dee38a40, 0xbfcc2968558c2000), (0x3d34b722ec011f31, 0xbfcb5b519e8fc000), (0x3cba4e633fcd9066, 0xbfcaf3c94e80c000), (0x3d3539cd91dc9f0b, 0xbfca23bc1fe2c000), (0x3d21f2a8a1ce0ffc, 0xbfc9bb362e7e0000), (0xbd3a8154b13d72d5, 0xbfc8e928de886000), (0xbd322120401202fc, 0xbfc87fa06520c000), (0x3d2bdb9072534a58, 0xbfc7ab890210e000), (0x3d30b66c99018aa1, 0xbfc740f8f5404000), (0x3d3bc6e557134767, 0xbfc6d60fe719e000), (0x3d38586f183bebf2, 0xbfc5ff3070a7a000), (0xbcf0ba68b7555d4a, 0xbfc59338d9982000), (0x3d34354bb3f219e5, 0xbfc4ba36f39a6000), (0x3d170cc16135783c, 0xbfc44d2b6ccb8000), (0xbd28a72a62b8c13f, 0xbfc3dfc2b0ecc000), (0x3cd680b5ce3ecb05, 0xbfc303d718e48000), (0x3d35b967f4471dfc, 0xbfc29552f8200000), (0x3d24d20ab840e7f6, 0xbfc2266f190a6000), (0xbd1563451027c750, 0xbfc1478584674000), (0xbd3cb2cd2ee2f482, 0xbfc0d77e7cd08000), (0x3d2a47579cdc0a3d, 0xbfc0671512ca6000), (0x3d3d599e83368e91, 0xbfbf0a30c0118000), (0x3d2a342c2af0003c, 0xbfbe27076e2b0000), (0x3d29454379135713, 0xbfbd4313d66cc000), (0xbd1d0c57585fbe06, 0xbfbc5e548f5bc000), (0xbd3563650bd22a9c, 0xbfba926d3a4ac000), (0x3d28a64826787061, 0xbfb9ab4246204000), (0xbd3b20f5acb42a66, 0xbfb8c345d6318000), (0xbd32cc844480c89b, 0xbfb7da766d7b0000), (0xbd30c3b1dee9c4f8, 0xbfb60658a9374000), (0xbd383f69278e686a, 0xbfb51b073f060000), (0xbd1bc0eeea7c9acd, 0xbfb42edcbea64000), (0xbd31d09299837610, 0xbfb341d7961bc000), (0xbd3416f8fb69a701, 0xbfb253f62f0a0000), (0x3d147c5e768fa309, 0xbfb16536eea38000), (0x3d2d599e83368e91, 0xbfaf0a30c0118000), (0xbd16a423c78a64b0, 0xbfad276b8adb0000), (0x3d1c827ae5d6704c, 0xbfab42dd71198000), (0x3d2c148297c5feb8, 0xbfa95c830ec90000), (0x3d3181dce586af09, 0xbfa77458f6330000), (0x3d2b2b739570ad39, 0xbfa58a5bafc90000), (0xbd3eafd480ad9015, 0xbfa39e87b9fe8000), (0x3d33401e9ae889bb, 0xbfa1b0d989240000), (0xbd2980267c7e09e4, 0xbf9f829b0e780000), (0x3d3b9a010ae6922a, 0xbf9b9fc027b00000), (0x3d33b955b602ace4, 0xbf97b91b07d60000), (0x3d36a2c432d6a40b, 0xbf93cea443470000), (0xbcdf1e7cf6d3a69c, 0xbf8fc0a8b0fc0000), (0x3d3eb1245b5da1f5, 0xbf87dc475f820000), (0xbd19e23f0dda40e4, 0xbf7fe02a6b100000), (0x0000000000000000, 0x0000000000000000), (0x0000000000000000, 0x0000000000000000), (0x3d1ad50382973f27, 0x3f78121214580000), (0x3d1977c755d01368, 0x3f841929f9680000), (0xbd341f33fcefb9fe, 0x3f8c317384c80000), (0x3d2713e3284991fe, 0x3f9228fb1fea0000), (0x3d07abf389596542, 0x3f963d6178690000), (0xbd2de0709f2d03c9, 0x3f9a55f548c60000), (0xbd28d75149774d47, 0x3f9e72bf28140000), (0xbd3dddc7f461c516, 0x3fa0415d89e78000), (0x3d283e9ae021b67b, 0x3fa252f32f8d0000), (0xbd2c167375bdfd28, 0x3fa466aed42e0000), (0x3d3dac20827cca0c, 0x3fa67c94f2d48000), (0x3d39a19a8be97661, 0x3fa894aa149f8000), (0x3d20fc1a353bb42e, 0x3faaaef2d0fb0000), (0xbd17bf868c317c2a, 0x3fabbcebfc690000), (0xbd21b1ac64d9e42f, 0x3fadda8adc680000), (0x3d23008c98381a8f, 0x3faffa6911ab8000), (0xbd37cf69284a3465, 0x3fb10e45b3cb0000), (0x3d349d8cfc10c7bf, 0x3fb2207b5c784000), (0x3d37a48ba8b1cb41, 0x3fb2aa04a4470000), (0xbd319bd0ad125895, 0x3fb3bdf5a7d20000), (0xbcf53a2582f4e1ef, 0x3fb4d3115d208000), (0x3d0c1d740c53c72e, 0x3fb55e10050e0000), (0x3d3a79994c9d3302, 0x3fb674f089364000), (0x3d069b5794b69fb7, 0x3fb78d02263d8000), (0xbd3c0fe460d20041, 0x3fb8197e2f410000), (0x3d23115c3abd47da, 0x3fb9335e5d594000), (0xbd0e42b6b94407c8, 0x3fba4e7640b1c000), (0xbd3573b209c31904, 0x3fbadc77ee5b0000), (0x3d24218c8d824283, 0x3fbbf968769fc000), (0x3d336433b5efbeed, 0x3fbd179788218000), (0x3d1a89401fa71733, 0x3fbda72763844000), (0x3d311fcba80cdd10, 0x3fbec739830a0000), (0x3d176a6c9ea8b04e, 0x3fbf57bc7d900000), (0x3d381a9cf169fc5c, 0x3fc03cdc0a51e000), (0xbd27e5dd7009902c, 0x3fc08598b59e4000), (0x3d21ef78ce2d07f2, 0x3fc1178e8227e000), (0x3d2ec2d2a9009e3d, 0x3fc160c8024b2000), (0xbd15f74e9b083633, 0x3fc1f3b925f26000), (0x3d100d238fd3df5c, 0x3fc23d712a49c000), (0x3d039d6ccb81b4a1, 0x3fc2d1610c868000), (0x3d3f098ee3a50810, 0x3fc31b994d3a4000), (0xbd3aade8f29320fb, 0x3fc3b08b67580000), (0x3d319713c0cae559, 0x3fc3fb45a5992000), (0xbd353e43558124c4, 0x3fc4913d8333c000), (0x3d0c79b60ae1ff0f, 0x3fc4dc7b897bc000), (0x3d39baa7a6b887f6, 0x3fc5737cc9018000), (0xbd127023eb68981c, 0x3fc5bf406b544000), (0xbd398c1d34f0f462, 0x3fc6574ebe8c2000), (0xbd38f934e66a15a6, 0x3fc6a399dabbe000), (0x3d3577390d31ef0f, 0x3fc6f0128b756000), (0x3d38e67be3dbaf3f, 0x3fc7898d85444000), (0xbd24c06b17c301d7, 0x3fc7d6903caf6000), (0x3d3328eb42f9af75, 0x3fc871213750e000), (0xbd073d54aae92cd1, 0x3fc8beafeb390000), (0xbd1935f57718d7ca, 0x3fc90c6db9fcc000), (0x3d3470fa3efec390, 0x3fc9a8778deba000), (0xbd3337d94bcd3f43, 0x3fc9f6c40708a000), (0x3d360a77c81f7171, 0x3fca454082e6a000), (0x3d37a8d5ae54f550, 0x3fcae2ca6f672000), (0x3d3c794e562a63cb, 0x3fcb31d8575bc000), (0x3d1e90683b9cd768, 0x3fcb811730b82000), (0xbd2d4bc4595412b6, 0x3fcbd087383be000), (0x3d3ee138d3a69d43, 0x3fcc6ffbc6f00000), (0xbd1d6d585d57aff9, 0x3fccc000c9db4000), (0xbd084a7e75b6f6e4, 0x3fcd1037f2656000), (0x3d32806a847527e6, 0x3fcdb13db0d48000), (0xbd252b00adb91424, 0x3fce020cc6236000), (0xbd3fdbdbb13f7c18, 0x3fce530effe72000), (0x3d35e91663732a36, 0x3fcea4449f04a000), (0xbd3bae49f1df7b5e, 0x3fcf474b134e0000), (0xbd390d04cd7cc834, 0x3fcf991c6cb3c000), (0x3d2f3418de00938b, 0x3fcfeb2233ea0000), (0x3d3a43dcfade85ae, 0x3fd01eae5626c000), (0x3d2dbdf10d397f3c, 0x3fd047e60cde8000), (0x3d3b50a1e1734342, 0x3fd09aa572e6c000), (0x3d27188b163ceae9, 0x3fd0c42d67616000), (0x3d0019b52d8435f5, 0x3fd0edd060b78000), (0x3d31ef78ce2d07f2, 0x3fd1178e8227e000), (0x3d3e0c07824daaf5, 0x3fd14167ef367000), (0xbd323299042d74bf, 0x3fd16b5ccbad0000), (0xbd31ac89575c2125, 0x3fd1bf99635a7000), (0xbd382eaed3c8b65e, 0x3fd1e9e16788a000), (0xbd3caf0428b728a3, 0x3fd214456d0ec000), (0xbd36dbe448a2e522, 0x3fd23ec5991ec000), (0xbd31b61f10522625, 0x3fd269621134e000), (0xbd3210c2b730e28b, 0x3fd2941afb187000), (0x3d2a9cfa4a5004f4, 0x3fd2bef07cdc9000), (0xbd28e27ad3213cb8, 0x3fd314f1e1d36000), (0xbd317c73556e291d, 0x3fd3401e12aed000), (0x3d116ecdb0f177c8, 0x3fd36b6776be1000), (0xbd05839c5663663d, 0x3fd396ce359bc000), (0x3d183b54b606bd5c, 0x3fd3c25277333000), (0xbd3f067c297f2c3f, 0x3fd3edf463c17000), (0xbd3ce379226de3ec, 0x3fd419b423d5f000), (0xbd06e95892923d88, 0x3fd44591e053a000), (0x3d306c18fb4c14c5, 0x3fd4718dc271c000), (0x3d307b334daf4b9a, 0x3fd49da7f3bcc000), (0xbd2e20891b0ad8a4, 0x3fd4c9e09e173000), (0xbd3fc158cb3124b9, 0x3fd4f637ebbaa000), (0x3d2ebe708164c759, 0x3fd522ae0738a000), (0x3d1a8954c0910952, 0x3fd54f431b7be000), (0x3d1fadedee5d40ef, 0x3fd57bf753c8d000), (0xbcf7c79b0af7ecf8, 0x3fd5a8cadbbee000), (0xbd0a0b2a08a465dc, 0x3fd5d5bddf596000), (0x3d1ebe9176df3f65, 0x3fd602d08af09000), (0xbd2db623e731ae00, 0x3fd630030b3ab000), ]; pub(crate) static EXP2_MID1: [(u64, u64); 64] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc719083535b085d, 0x3ff02c9a3e778061), (0x3c8d73e2a475b465, 0x3ff059b0d3158574), (0x3c6186be4bb284ff, 0x3ff0874518759bc8), (0x3c98a62e4adc610b, 0x3ff0b5586cf9890f), (0x3c403a1727c57b53, 0x3ff0e3ec32d3d1a2), (0xbc96c51039449b3a, 0x3ff11301d0125b51), (0xbc932fbf9af1369e, 0x3ff1429aaea92de0), (0xbc819041b9d78a76, 0x3ff172b83c7d517b), (0x3c8e5b4c7b4968e4, 0x3ff1a35beb6fcb75), (0x3c9e016e00a2643c, 0x3ff1d4873168b9aa), (0x3c8dc775814a8495, 0x3ff2063b88628cd6), (0x3c99b07eb6c70573, 0x3ff2387a6e756238), (0x3c82bd339940e9d9, 0x3ff26b4565e27cdd), (0x3c8612e8afad1255, 0x3ff29e9df51fdee1), (0x3c90024754db41d5, 0x3ff2d285a6e4030b), (0x3c86f46ad23182e4, 0x3ff306fe0a31b715), (0x3c932721843659a6, 0x3ff33c08b26416ff), (0xbc963aeabf42eae2, 0x3ff371a7373aa9cb), (0xbc75e436d661f5e3, 0x3ff3a7db34e59ff7), (0x3c8ada0911f09ebc, 0x3ff3dea64c123422), (0xbc5ef3691c309278, 0x3ff4160a21f72e2a), (0x3c489b7a04ef80d0, 0x3ff44e086061892d), (0x3c73c1a3b69062f0, 0x3ff486a2b5c13cd0), (0x3c7d4397afec42e2, 0x3ff4bfdad5362a27), (0xbc94b309d25957e3, 0x3ff4f9b2769d2ca7), (0xbc807abe1db13cad, 0x3ff5342b569d4f82), (0x3c99bb2c011d93ad, 0x3ff56f4736b527da), (0x3c96324c054647ad, 0x3ff5ab07dd485429), (0x3c9ba6f93080e65e, 0x3ff5e76f15ad2148), (0xbc9383c17e40b497, 0x3ff6247eb03a5585), (0xbc9bb60987591c34, 0x3ff6623882552225), (0xbc9bdd3413b26456, 0x3ff6a09e667f3bcd), (0xbc6bbe3a683c88ab, 0x3ff6dfb23c651a2f), (0xbc816e4786887a99, 0x3ff71f75e8ec5f74), (0xbc90245957316dd3, 0x3ff75feb564267c9), (0xbc841577ee04992f, 0x3ff7a11473eb0187), (0x3c705d02ba15797e, 0x3ff7e2f336cf4e62), (0xbc9d4c1dd41532d8, 0x3ff82589994cce13), (0xbc9fc6f89bd4f6ba, 0x3ff868d99b4492ed), (0x3c96e9f156864b27, 0x3ff8ace5422aa0db), (0x3c85cc13a2e3976c, 0x3ff8f1ae99157736), (0xbc675fc781b57ebc, 0x3ff93737b0cdc5e5), (0xbc9d185b7c1b85d1, 0x3ff97d829fde4e50), (0x3c7c7c46b071f2be, 0x3ff9c49182a3f090), (0xbc9359495d1cd533, 0x3ffa0c667b5de565), (0xbc9d2f6edb8d41e1, 0x3ffa5503b23e255d), (0x3c90fac90ef7fd31, 0x3ffa9e6b5579fdbf), (0x3c97a1cd345dcc81, 0x3ffae89f995ad3ad), (0xbc62805e3084d708, 0x3ffb33a2b84f15fb), (0xbc75584f7e54ac3b, 0x3ffb7f76f2fb5e47), (0x3c823dd07a2d9e84, 0x3ffbcc1e904bc1d2), (0x3c811065895048dd, 0x3ffc199bdd85529c), (0x3c92884dff483cad, 0x3ffc67f12e57d14b), (0x3c7503cbd1e949db, 0x3ffcb720dcef9069), (0xbc9cbc3743797a9c, 0x3ffd072d4a07897c), (0x3c82ed02d75b3707, 0x3ffd5818dcfba487), (0x3c9c2300696db532, 0x3ffda9e603db3285), (0xbc91a5cd4f184b5c, 0x3ffdfc97337b9b5f), (0x3c839e8980a9cc8f, 0x3ffe502ee78b3ff6), (0xbc9e9c23179c2893, 0x3ffea4afa2a490da), (0x3c9dc7f486a4b6b0, 0x3ffefa1bee615a27), (0x3c99d3e12dd8a18b, 0x3fff50765b6e4540), (0x3c874853f3a5931e, 0x3fffa7c1819e90d8), ]; /* for 0 <= i < 64, T1_2[i] is a 128-bit nearest approximation of 2^(i/64), with error bounded by 2^-128 (both absolutely and relatively). */ #[rustfmt::skip] pub(crate) static EXP_T1_2_DYADIC: [DyadicFloat128; 64] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8164_d1f3_bc03_0773_7be5_6527_bd14_def5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x82cd_8698_ac2b_a1d7_3e2a_475b_4652_0bff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x843a_28c3_acde_4046_1af9_2eca_13fd_1582_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x85aa_c367_cc48_7b14_c5c9_5b8c_2154_c1b2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x871f_6196_9e8d_1010_3a17_27c5_7b52_a956_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8898_0e80_92da_8527_5df8_d76c_98c6_7563_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8a14_d575_496e_fd9a_080c_a1d9_2c36_80c2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8b95_c1e3_ea8b_d6e6_fbe4_6287_58a5_3c90_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8d1a_df5b_7e5b_a9e5_b4c7_b496_8e41_ad36_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8ea4_398b_45cd_53c0_2dc0_144c_8783_d4c6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9031_dc43_1466_b1dc_7758_14a8_494e_87e2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x91c3_d373_ab11_c336_0fd6_d8e0_ae5a_c9d8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x935a_2b2f_13e6_e92b_d339_940e_9d92_4ee7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x94f4_efa8_fef7_0961_2e8a_fad1_2551_de54_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9694_2d37_2018_5a00_48ea_9b68_3a9c_22c5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9837_f051_8db8_a96f_46ad_2318_2e42_f6f6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x99e0_4593_20b7_fa64_e430_86cb_34b5_fcaf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9b8d_39b9_d54e_5538_a2a8_17a2_a3cc_3f1f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9d3e_d9a7_2cff_b750_de49_4cf0_50e9_9b0b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x9ef5_3260_91a1_11ad_a091_1f09_ebb9_fdd1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa0b0_510f_b971_4fc2_192d_c79e_db0f_d9a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa270_4303_0c49_6818_9b7a_04ef_80cf_dea8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa435_15ae_09e6_809e_0d1d_b483_1781_e1ef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa5fe_d6a9_b151_38ea_1cbd_7f62_1710_701b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa7cd_93b4_e965_3569_9ec5_b4d5_039f_72af_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xa9a1_5ab4_ea7c_0ef8_541e_24ec_3531_fa73_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xab7a_39b5_a93e_d337_6580_23b2_759e_0079_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xad58_3eea_42a1_4ac6_4980_a8c8_f59a_2ec4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xaf3b_78ad_690a_4374_df26_101c_cbb3_5033_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb123_f581_d2ac_258f_87d0_37e9_6d21_5d8e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb311_c412_a911_2489_3ecf_14dc_798a_519c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb504_f333_f9de_6484_597d_89b3_754a_be9f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb6fd_91e3_28d1_7791_0716_5f0d_dd54_1a5a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xb8fb_af47_62fb_9ee9_1b87_9778_566b_65a2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbaff_5ab2_133e_45fb_74d5_19d2_4593_838c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbd08_a39f_580c_36be_a881_1fb6_6d0f_af7a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xbf17_99b6_7a73_1082_e815_d0ab_cbf0_b851_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc12c_4cca_6670_9456_7c45_7d59_a500_87b5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc346_ccda_2497_6407_20ec_8561_28b8_3a42_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc567_2a11_5506_dadd_3e2a_d0c9_64dd_9f37_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc78d_74c8_abb9_b15c_c13a_2e39_76c0_277e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc9b9_bd86_6e2f_27a2_80e1_f92a_0511_697e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xcbec_14fe_f272_7c5c_f490_7c8f_45eb_f6dd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xce24_8c15_1f84_80e3_e235_838f_95f2_c6ed_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd063_33da_ef2b_2594_d6d4_5c65_59a4_d502_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd2a8_1d91_f12a_e45a_1224_8e57_c3de_4028_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd4f3_5aab_cfed_fa1f_5921_deff_a626_2c5b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd744_fcca_d69d_6af4_39a6_8bb9_902d_3fde_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xd99d_15c2_78af_d7b5_fe87_3dec_a3e1_2bac_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xdbfb_b797_daf2_3755_3d84_0d5a_9e29_aa64_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xde60_f482_5e0e_9123_dd07_a2d9_e846_6859_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe0cc_deec_2a94_e111_0658_9504_8dd3_33ca_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe33f_8972_be8a_5a51_09bf_e907_9598_0eed_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe5b9_06e7_7c83_48a8_1e5e_8f4a_4edb_b0ed_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xe839_6a50_3c4b_dc68_7917_90d0_ac70_c7de_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xeac0_c6e7_dd24_392e_d02d_75b3_706e_54fb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xed4f_301e_d994_2b84_600d_2db6_a64b_fb12_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xefe4_b99b_dcda_f5cb_4656_1cf6_948d_b913_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf281_773c_59ff_b139_e898_0a9c_c8f4_7a4b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf525_7d15_2486_cc2c_7b9d_0c7a_ed98_0fc3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xf7d0_df73_0ad1_3bb8_fe90_d496_d60f_b6eb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xfa83_b2db_722a_033a_7c25_bb14_315d_7fcd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xfd3e_0c0c_f486_c174_853f_3a59_31e0_ee03_u128, }, ]; /* for 0 <= i < 64, T2_2[i] is a 128-bit nearest approximation of 2^(i/2^12), with error bounded by 2^-128 (both absolutely and relatively). */ #[rustfmt::skip] pub(crate) static EXP_T2_2_DYADIC: [DyadicFloat128; 64] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8005_8baf_7fee_3b5d_1c71_8b38_e549_cb93_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x800b_179c_8202_8fd0_945e_54e2_ae18_f2f0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8010_a3c7_08e7_3282_2b96_d62d_51c1_5a07_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8016_302f_1746_7628_3690_dfe4_4d11_d008_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x801b_bcd4_afca_cb08_e23a_986b_d3e6_26f0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8021_49b7_d51e_befb_7bdb_adbc_888a_eb29_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8026_d6d8_89ec_fd69_b904_bbfb_40d3_a2b7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x802c_6436_d0e0_4f50_ff8c_e94a_6797_b3ce_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8031_f1d2_aca3_9b43_ad9d_b772_901d_96b6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8037_7fac_1fe1_e56a_61cd_0bff_d7cf_c683_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x803d_0dc3_2d46_4f85_4345_6f71_b96a_ffd4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8042_9c17_d77c_18ed_49fc_841a_fba9_c3c6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8048_2aaa_212e_9e95_86f7_b54f_6c45_c85e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x804d_b97a_0d09_5b0c_6c9f_1f7d_1efc_fe68_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8053_4887_9db7_e67d_171e_b1ce_ef1d_1f28_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8058_d7d2_d5e5_f6b0_94d5_89f6_08ee_4aa2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x805e_675b_b83f_5f0f_2ed3_8ab8_472b_2144_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8063_f722_4770_10a1_b165_2de1_378a_f1a1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8069_8726_8624_1a12_b4ad_9233_a039_0cad_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x806f_1768_7707_a7af_e54e_c5f9_66eb_1872_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8074_a7e8_1cc7_036b_4d20_4ecf_c11f_4aab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x807a_38a5_7a0e_94dc_9bf3_ef4d_9be2_d1e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x807f_c9a0_918a_e142_7068_ab22_3058_5d13_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8085_5ad9_65e8_8b83_a0cc_0a49_c10e_a66b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x808a_ec4f_f9d4_5430_8409_9bf6_830f_2768_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8090_7e04_4ffb_1984_3aa8_b9cb_bc65_a8ab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8096_0ff6_6b09_d765_f7d8_8c09_28ba_3947_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x809b_a226_4dad_a76a_4a8a_4f44_bb70_3db6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80a1_3493_fa93_c0d4_6699_dc50_dd96_b774_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80a6_c73f_7469_7897_6e04_72ed_4ccf_a2e0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80ac_5a28_bddc_4157_ba2d_c7e0_c72e_51ba_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80b1_ed4f_d999_ab6c_2533_5719_b6e6_fd20_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80b7_80b4_ca4f_64df_534d_fa74_1784_6aa4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80bd_1457_92ab_3970_fc41_c5c2_d533_6ccc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80c2_a838_355b_1297_34dc_28ba_ed8f_3fde_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80c8_3c56_b50c_f77f_b880_575e_a035_48c1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80cd_d0b3_146f_0d11_32c1_f987_0442_8c71_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80d3_654d_562f_95ec_890e_222a_5eb9_5372_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80d8_fa25_7cfc_f26e_2462_8efd_9ca9_d59b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80de_8f3b_8b85_a0af_3b13_310f_5ad5_7fb1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80e4_248f_8478_3c87_1a9d_fefa_eb61_6564_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80e9_ba21_6a83_7f8c_718d_1151_d109_bf98_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80ef_4ff1_4056_4116_9967_09da_2e25_f04c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80f4_e5ff_089f_763e_e0ad_c640_acaa_6b0b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80fa_7c4a_c60e_31e1_d4eb_5edc_6b34_1283_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8100_12d4_7b51_a4a0_8ccd_7223_8207_19e3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8105_a99c_2b19_1ce1_f24e_bd6e_b9ca_4292_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x810b_40a1_d814_06d4_0cef_03ab_14a6_6550_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8110_d7e5_84f1_ec6d_4bf9_4297_d151_9822_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8116_6f67_3462_756d_d0d8_372f_966c_f15e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x811c_0726_e915_6760_b979_31db_7b7b_e2ec_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8121_9f24_a5ba_a59d_6abd_3b0e_ab9c_7048_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8127_3760_6d02_3148_daf8_88e9_6508_151a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x812c_cfda_419c_2956_dc80_4682_1f46_122e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8132_6892_2638_ca8b_6846_ad73_a8d9_027f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8138_0188_1d88_6f7b_e885_724f_1413_1287_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x813d_9abc_2a3b_9090_8376_8490_519d_f895_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8143_342e_4f02_c405_661b_22b4_5e25_de18_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8148_cdde_8e8e_bdec_0f11_430f_ef78_c6ee_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x814e_67cc_eb90_502c_9977_5205_944e_adc4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8154_01f9_68b8_6a87_07de_463a_40d1_8261_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8159_9c64_08b8_1a94_8f4a_0b67_48df_7960_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x815f_370c_ce40_8bc8_e240_4468_cfe5_ab9f_u128, }, ]; pxfm-0.1.23/src/powf.rs000064400000000000000000000560441046102023000130020ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::biased_exponent_f64; use crate::common::*; use crate::double_double::DoubleDouble; use crate::exponents::expf; use crate::logf; use crate::logs::LOG2_R; use crate::polyeval::{f_polyeval3, f_polyeval6, f_polyeval10}; use crate::pow_tables::EXP2_MID1; use crate::powf_tables::{LOG2_R_TD, LOG2_R2_DD, POWF_R2}; /// Power function for given value for const context. /// This is simplified version just to make a good approximation on const context. #[inline] pub const fn powf(d: f32, n: f32) -> f32 { let value = d.abs(); let c = expf(n * logf(value)); if n == 1. { return d; } if d < 0.0 { let y = n as i32; if y % 2 == 0 { c } else { -c } } else { c } } #[inline] pub(crate) const fn is_integer(x: f32) -> bool { let x_u = x.to_bits(); let x_e = (x_u & EXP_MASK_F32) >> 23; let lsb = (x_u | EXP_MASK_F32).trailing_zeros(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; const UNIT_EXPONENT: u32 = E_BIAS + 23; x_e + lsb >= UNIT_EXPONENT } #[inline] pub(crate) fn is_odd_integer(x: f32) -> bool { let x_u = x.to_bits(); let x_e = (x_u & EXP_MASK_F32) >> 23; let lsb = (x_u | EXP_MASK_F32).trailing_zeros(); const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; const UNIT_EXPONENT: u32 = E_BIAS + 23; x_e + lsb == UNIT_EXPONENT } #[inline] const fn larger_exponent(a: f64, b: f64) -> bool { biased_exponent_f64(a) >= biased_exponent_f64(b) } // Calculate 2^(y * log2(x)) in double-double precision. // At this point we can reuse the following values: // idx_x: index for extra precision of log2 for the middle part of log2(x). // dx: the reduced argument for log2(x) // y6: 2^6 * y. // lo6_hi: the high part of 2^6 * (y - (hi + mid)) // exp2_hi_mid: high part of 2^(hi + mid) #[cold] #[inline(never)] fn powf_dd(idx_x: i32, dx: f64, y6: f64, lo6_hi: f64, exp2_hi_mid: DoubleDouble) -> f64 { // Perform a second range reduction step: // idx2 = round(2^14 * (dx + 2^-8)) = round ( dx * 2^14 + 2^6) // dx2 = (1 + dx) * r2 - 1 // Output range: // -0x1.3ffcp-15 <= dx2 <= 0x1.3e3dp-15 let idx2 = f_fmla( dx, f64::from_bits(0x40d0000000000000), f64::from_bits(0x4050000000000000), ) .round() as usize; let dx2 = f_fmla(1.0 + dx, f64::from_bits(POWF_R2[idx2]), -1.0); // Exact const COEFFS: [(u64, u64); 6] = [ (0x3c7777d0ffda25e0, 0x3ff71547652b82fe), (0xbc6777d101cf0a84, 0xbfe71547652b82fe), (0x3c7ce04b5140d867, 0x3fdec709dc3a03fd), (0x3c7137b47e635be5, 0xbfd71547652b82fb), (0xbc5b5a30b3bdb318, 0x3fd2776c516a92a2), (0x3c62d2fbd081e657, 0xbfcec70af1929ca6), ]; let dx_dd = DoubleDouble::new(0.0, dx2); let p = f_polyeval6( dx_dd, DoubleDouble::from_bit_pair(COEFFS[0]), DoubleDouble::from_bit_pair(COEFFS[1]), DoubleDouble::from_bit_pair(COEFFS[2]), DoubleDouble::from_bit_pair(COEFFS[3]), DoubleDouble::from_bit_pair(COEFFS[4]), DoubleDouble::from_bit_pair(COEFFS[5]), ); // log2(1 + dx2) ~ dx2 * P(dx2) let log2_x_lo = DoubleDouble::quick_mult_f64(p, dx2); // Lower parts of (e_x - log2(r1)) of the first range reduction constant let log2_r_td = LOG2_R_TD[idx_x as usize]; let log2_x_mid = DoubleDouble::new(f64::from_bits(log2_r_td.0), f64::from_bits(log2_r_td.1)); // -log2(r2) + lower part of (e_x - log2(r1)) let log2_x_m = DoubleDouble::add(DoubleDouble::from_bit_pair(LOG2_R2_DD[idx2]), log2_x_mid); // log2(1 + dx2) - log2(r2) + lower part of (e_x - log2(r1)) // Since we don't know which one has larger exponent to apply Fast2Sum // algorithm, we need to check them before calling double-double addition. let log2_x = if larger_exponent(log2_x_m.hi, log2_x_lo.hi) { DoubleDouble::add(log2_x_m, log2_x_lo) } else { DoubleDouble::add(log2_x_lo, log2_x_m) }; let lo6_hi_dd = DoubleDouble::new(0.0, lo6_hi); // 2^6 * y * (log2(1 + dx2) - log2(r2) + lower part of (e_x - log2(r1))) let prod = DoubleDouble::quick_mult_f64(log2_x, y6); // 2^6 * (y * log2(x) - (hi + mid)) = 2^6 * lo let lo6 = if larger_exponent(prod.hi, lo6_hi) { DoubleDouble::add(prod, lo6_hi_dd) } else { DoubleDouble::add(lo6_hi_dd, prod) }; const EXP2_COEFFS: [(u64, u64); 10] = [ (0x0000000000000000, 0x3ff0000000000000), (0x3c1abc9e3b398024, 0x3f862e42fefa39ef), (0xbba5e43a5429bddb, 0x3f0ebfbdff82c58f), (0xbb2d33162491268f, 0x3e8c6b08d704a0c0), (0x3a94fb32d240a14e, 0x3e03b2ab6fba4e77), (0x39ee84e916be83e0, 0x3d75d87fe78a6731), (0xb989a447bfddc5e6, 0x3ce430912f86bfb8), (0xb8e31a55719de47f, 0x3c4ffcbfc588ded9), (0xb850ba57164eb36b, 0x3bb62c034beb8339), (0xb7b8483eabd9642d, 0x3b1b5251ff97bee1), ]; let pp = f_polyeval10( lo6, DoubleDouble::from_bit_pair(EXP2_COEFFS[0]), DoubleDouble::from_bit_pair(EXP2_COEFFS[1]), DoubleDouble::from_bit_pair(EXP2_COEFFS[2]), DoubleDouble::from_bit_pair(EXP2_COEFFS[3]), DoubleDouble::from_bit_pair(EXP2_COEFFS[4]), DoubleDouble::from_bit_pair(EXP2_COEFFS[5]), DoubleDouble::from_bit_pair(EXP2_COEFFS[6]), DoubleDouble::from_bit_pair(EXP2_COEFFS[7]), DoubleDouble::from_bit_pair(EXP2_COEFFS[8]), DoubleDouble::from_bit_pair(EXP2_COEFFS[9]), ); let rr = DoubleDouble::quick_mult(exp2_hi_mid, pp); // Make sure the sum is normalized: let r = DoubleDouble::from_exact_add(rr.hi, rr.lo); const FRACTION_MASK: u64 = (1u64 << 52) - 1; let mut r_bits = r.hi.to_bits(); if ((r_bits & 0xfff_ffff) == 0) && (r.lo != 0.0) { let hi_sign = r.hi.to_bits() >> 63; let lo_sign = r.lo.to_bits() >> 63; if hi_sign == lo_sign { r_bits = r_bits.wrapping_add(1); } else if (r_bits & FRACTION_MASK) > 0 { r_bits = r_bits.wrapping_sub(1); } } f64::from_bits(r_bits) } /// Power function /// /// Max found ULP 0.5 #[inline] pub fn f_powf(x: f32, y: f32) -> f32 { let mut x_u = x.to_bits(); let x_abs = x_u & 0x7fff_ffff; let mut y = y; let y_u = y.to_bits(); let y_abs = y_u & 0x7fff_ffff; let mut x = x; if ((y_abs & 0x0007_ffff) == 0) || (y_abs > 0x4f170000) { // y is signaling NaN if x.is_nan() || y.is_nan() { if y.abs() == 0. { return 1.; } if x == 1. { return 1.; } return f32::NAN; } // Exceptional exponents. if y == 0.0 { return 1.0; } match y_abs { 0x7f80_0000 => { if x_abs > 0x7f80_0000 { // pow(NaN, +-Inf) = NaN return x; } if x_abs == 0x3f80_0000 { // pow(+-1, +-Inf) = 1.0f return 1.0; } if x == 0.0 && y_u == 0xff80_0000 { // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO return f32::INFINITY; } // pow (|x| < 1, -inf) = +inf // pow (|x| < 1, +inf) = 0.0f // pow (|x| > 1, -inf) = 0.0f // pow (|x| > 1, +inf) = +inf return if (x_abs < 0x3f80_0000) == (y_u == 0xff80_0000) { f32::INFINITY } else { 0. }; } _ => { match y_u { 0x3f00_0000 => { // pow(x, 1/2) = sqrt(x) if x == 0.0 || x_u == 0xff80_0000 { // pow(-0, 1/2) = +0 // pow(-inf, 1/2) = +inf // Make sure it is correct for FTZ/DAZ. return x * x; } let r = x.sqrt(); return if r.to_bits() != 0x8000_0000 { r } else { 0.0 }; } 0x3f80_0000 => { return x; } // y = 1.0f 0x4000_0000 => return x * x, // y = 2.0f _ => { let is_int = is_integer(y); if is_int && (y_u > 0x4000_0000) && (y_u <= 0x41c0_0000) { // Check for exact cases when 2 < y < 25 and y is an integer. let mut msb: i32 = if x_abs == 0 { 32 - 2 } else { x_abs.leading_zeros() as i32 }; msb = if msb > 8 { msb } else { 8 }; let mut lsb: i32 = if x_abs == 0 { 0 } else { x_abs.trailing_zeros() as i32 }; lsb = if lsb > 23 { 23 } else { lsb }; let extra_bits: i32 = 32 - 2 - lsb - msb; let iter = y as i32; if extra_bits * iter <= 23 + 2 { // The result is either exact or exactly half-way. // But it is exactly representable in double precision. let x_d = x as f64; let mut result = x_d; for _ in 1..iter { result *= x_d; } return result as f32; } } if y_abs > 0x4f17_0000 { // if y is NaN if y_abs > 0x7f80_0000 { if x_u == 0x3f80_0000 { // x = 1.0f // pow(1, NaN) = 1 return 1.0; } // pow(x, NaN) = NaN return y; } // x^y will be overflow / underflow in single precision. Set y to a // large enough exponent but not too large, so that the computations // won't be overflow in double precision. y = f32::from_bits((y_u & 0x8000_0000).wrapping_add(0x4f800000u32)); } } } } } } const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32; let mut ex = -(E_BIAS as i32); let mut sign: u64 = 0; if ((x_u & 0x801f_ffffu32) == 0) || x_u >= 0x7f80_0000u32 || x_u < 0x0080_0000u32 { if x.is_nan() { return f32::NAN; } if x_u == 0x3f80_0000 { return 1.; } let x_is_neg = x.to_bits() > 0x8000_0000; if x == 0.0 { let out_is_neg = x_is_neg && is_odd_integer(f32::from_bits(y_u)); if y_u > 0x8000_0000u32 { // pow(0, negative number) = inf return if x_is_neg { f32::NEG_INFINITY } else { f32::INFINITY }; } // pow(0, positive number) = 0 return if out_is_neg { -0.0 } else { 0.0 }; } if x_abs == 0x7f80_0000u32 { // x = +-Inf let out_is_neg = x_is_neg && is_odd_integer(f32::from_bits(y_u)); if y_u >= 0x7fff_ffff { return if out_is_neg { -0.0 } else { 0.0 }; } return if out_is_neg { f32::NEG_INFINITY } else { f32::INFINITY }; } if x_abs > 0x7f80_0000 { // x is NaN. // pow (aNaN, 0) is already taken care above. return x; } // Normalize denormal inputs. if x_abs < 0x0080_0000u32 { ex = ex.wrapping_sub(64); x *= f32::from_bits(0x5f800000); } // x is finite and negative, and y is a finite integer. if x.is_sign_negative() { if is_integer(y) { x = -x; if is_odd_integer(y) { sign = 0x8000_0000_0000_0000u64; } } else { // pow( negative, non-integer ) = NaN return f32::NAN; } } } // x^y = 2^( y * log2(x) ) // = 2^( y * ( e_x + log2(m_x) ) ) // First we compute log2(x) = e_x + log2(m_x) x_u = x.to_bits(); // Extract exponent field of x. ex = ex.wrapping_add((x_u >> 23) as i32); let e_x = ex as f64; // Use the highest 7 fractional bits of m_x as the index for look up tables. let x_mant = x_u & ((1u32 << 23) - 1); let idx_x = (x_mant >> (23 - 7)) as i32; // Add the hidden bit to the mantissa. // 1 <= m_x < 2 let m_x = f32::from_bits(x_mant | 0x3f800000); // Reduced argument for log2(m_x): // dx = r * m_x - 1. // The computation is exact, and -2^-8 <= dx < 2^-7. // Then m_x = (1 + dx) / r, and // log2(m_x) = log2( (1 + dx) / r ) // = log2(1 + dx) - log2(r). let dx; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::logs::LOG_REDUCTION_F32; dx = f_fmlaf( m_x, f32::from_bits(LOG_REDUCTION_F32.0[idx_x as usize]), -1.0, ) as f64; // Exact. } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::logs::LOG_RANGE_REDUCTION; dx = f_fmla( m_x as f64, f64::from_bits(LOG_RANGE_REDUCTION[idx_x as usize]), -1.0, ); // Exact } // Degree-5 polynomial approximation: // dx * P(dx) ~ log2(1 + dx) // Generated by Sollya with: // > P = fpminimax(log2(1 + x)/x, 5, [|D...|], [-2^-8, 2^-7]); // > dirtyinfnorm(log2(1 + x)/x - P, [-2^-8, 2^-7]); // 0x1.653...p-52 const COEFFS: [u64; 6] = [ 0x3ff71547652b82fe, 0xbfe71547652b7a07, 0x3fdec709dc458db1, 0xbfd715479c2266c9, 0x3fd2776ae1ddf8f0, 0xbfce7b2178870157, ]; let dx2 = dx * dx; // Exact let c0 = f_fmla(dx, f64::from_bits(COEFFS[1]), f64::from_bits(COEFFS[0])); let c1 = f_fmla(dx, f64::from_bits(COEFFS[3]), f64::from_bits(COEFFS[2])); let c2 = f_fmla(dx, f64::from_bits(COEFFS[5]), f64::from_bits(COEFFS[4])); let p = f_polyeval3(dx2, c0, c1, c2); // s = e_x - log2(r) + dx * P(dx) // Approximation errors: // |log2(x) - s| < ulp(e_x) + (bounds on dx) * (error bounds of P(dx)) // = ulp(e_x) + 2^-7 * 2^-51 // < 2^8 * 2^-52 + 2^-7 * 2^-43 // ~ 2^-44 + 2^-50 let s = f_fmla(dx, p, f64::from_bits(LOG2_R[idx_x as usize]) + e_x); // To compute 2^(y * log2(x)), we break the exponent into 3 parts: // y * log(2) = hi + mid + lo, where // hi is an integer // mid * 2^6 is an integer // |lo| <= 2^-7 // Then: // x^y = 2^(y * log2(x)) = 2^hi * 2^mid * 2^lo, // In which 2^mid is obtained from a look-up table of size 2^6 = 64 elements, // and 2^lo ~ 1 + lo * P(lo). // Thus, we have: // hi + mid = 2^-6 * round( 2^6 * y * log2(x) ) // If we restrict the output such that |hi| < 150, (hi + mid) uses (8 + 6) // bits, hence, if we use double precision to perform // round( 2^6 * y * log2(x)) // the lo part is bounded by 2^-7 + 2^(-(52 - 14)) = 2^-7 + 2^-38 // In the following computations: // y6 = 2^6 * y // hm = 2^6 * (hi + mid) = round(2^6 * y * log2(x)) ~ round(y6 * s) // lo6 = 2^6 * lo = 2^6 * (y - (hi + mid)) = y6 * log2(x) - hm. let y6 = (y * f32::from_bits(0x42800000)) as f64; // Exact. let hm = (s * y6).round(); // let log2_rr = LOG2_R2_DD[idx_x as usize]; // // lo6 = 2^6 * lo. // let lo6_hi = f_fmla(y6, e_x + f64::from_bits(log2_rr.1), -hm); // Exact // // Error bounds: // // | (y*log2(x) - hm * 2^-6 - lo) / y| < err(dx * p) + err(LOG2_R_DD.lo) // // < 2^-51 + 2^-75 // let lo6 = f_fmla(y6, f_fmla(dx, p, f64::from_bits(log2_rr.0)), lo6_hi); // lo6 = 2^6 * lo. let lo6_hi = f_fmla(y6, e_x + f64::from_bits(LOG2_R_TD[idx_x as usize].2), -hm); // Exact // Error bounds: // | (y*log2(x) - hm * 2^-6 - lo) / y| < err(dx * p) + err(LOG2_R_DD.lo) // < 2^-51 + 2^-75 let lo6 = f_fmla( y6, f_fmla(dx, p, f64::from_bits(LOG2_R_TD[idx_x as usize].1)), lo6_hi, ); // |2^(hi + mid) - exp2_hi_mid| <= ulp(exp2_hi_mid) / 2 // Clamp the exponent part into smaller range that fits double precision. // For those exponents that are out of range, the final conversion will round // them correctly to inf/max float or 0/min float accordingly. let mut hm_i = hm as i64; hm_i = if hm_i > (1i64 << 15) { 1 << 15 } else if hm_i < (-(1i64 << 15)) { -(1 << 15) } else { hm_i }; let idx_y = hm_i & 0x3f; // 2^hi let exp_hi_i = (hm_i >> 6).wrapping_shl(52); // 2^mid let exp_mid_i = EXP2_MID1[idx_y as usize].1; // (-1)^sign * 2^hi * 2^mid // Error <= 2^hi * 2^-53 let exp2_hi_mid_i = (exp_hi_i.wrapping_add(exp_mid_i as i64) as u64).wrapping_add(sign); let exp2_hi_mid = f64::from_bits(exp2_hi_mid_i); // Degree-5 polynomial approximation P(lo6) ~ 2^(lo6 / 2^6) = 2^(lo). // Generated by Sollya with: // > P = fpminimax(2^(x/64), 5, [|1, D...|], [-2^-1, 2^-1]); // > dirtyinfnorm(2^(x/64) - P, [-0.5, 0.5]); // 0x1.a2b77e618f5c4c176fd11b7659016cde5de83cb72p-60 const EXP2_COEFFS: [u64; 6] = [ 0x3ff0000000000000, 0x3f862e42fefa39ef, 0x3f0ebfbdff82a23a, 0x3e8c6b08d7076268, 0x3e03b2ad33f8b48b, 0x3d75d870c4d84445, ]; let lo6_sqr = lo6 * lo6; let d0 = f_fmla( lo6, f64::from_bits(EXP2_COEFFS[1]), f64::from_bits(EXP2_COEFFS[0]), ); let d1 = f_fmla( lo6, f64::from_bits(EXP2_COEFFS[3]), f64::from_bits(EXP2_COEFFS[2]), ); let d2 = f_fmla( lo6, f64::from_bits(EXP2_COEFFS[5]), f64::from_bits(EXP2_COEFFS[4]), ); let pp = f_polyeval3(lo6_sqr, d0, d1, d2); let r = pp * exp2_hi_mid; let r_u = r.to_bits(); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] const ERR: u64 = 64; #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] const ERR: u64 = 128; let r_upper = f64::from_bits(r_u + ERR) as f32; let r_lower = f64::from_bits(r_u - ERR) as f32; if r_upper == r_lower { return r_upper; } // Scale lower part of 2^(hi + mid) let exp2_hi_mid_dd = DoubleDouble { lo: if idx_y != 0 { f64::from_bits((exp_hi_i as u64).wrapping_add(EXP2_MID1[idx_y as usize].0)) } else { 0. }, hi: exp2_hi_mid, }; let r_dd = powf_dd(idx_x, dx, y6, lo6_hi, exp2_hi_mid_dd); r_dd as f32 } /// Dirty fast pow #[inline] pub fn dirty_powf(d: f32, n: f32) -> f32 { use crate::exponents::dirty_exp2f; use crate::logs::dirty_log2f; let value = d.abs(); let lg = dirty_log2f(value); let c = dirty_exp2f(n * lg); if d < 0.0 { let y = n as i32; if y % 2 == 0 { c } else { -c } } else { c } } #[cfg(test)] mod tests { use super::*; #[test] fn powf_test() { assert!( (powf(2f32, 3f32) - 8f32).abs() < 1e-6, "Invalid result {}", powf(2f32, 3f32) ); assert!( (powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6, "Invalid result {}", powf(0.5f32, 2f32) ); } #[test] fn f_powf_test() { assert!( (f_powf(2f32, 3f32) - 8f32).abs() < 1e-6, "Invalid result {}", f_powf(2f32, 3f32) ); assert!( (f_powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6, "Invalid result {}", f_powf(0.5f32, 2f32) ); assert_eq!(f_powf(0.5f32, 1.5432f32), 0.34312353); assert_eq!( f_powf(f32::INFINITY, 0.00000000000000000000000000000000038518824), f32::INFINITY ); assert_eq!(f_powf(f32::NAN, 0.0), 1.); assert_eq!(f_powf(1., f32::NAN), 1.); } #[test] fn dirty_powf_test() { assert!( (dirty_powf(2f32, 3f32) - 8f32).abs() < 1e-6, "Invalid result {}", dirty_powf(2f32, 3f32) ); assert!( (dirty_powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6, "Invalid result {}", dirty_powf(0.5f32, 2f32) ); } } pxfm-0.1.23/src/powf_tables.rs000064400000000000000000000570061046102023000143330ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ pub(crate) static POWF_R2: [u64; 193] = [ 0x3ff0101000000000, 0x3ff00fd000000000, 0x3ff00f9000000000, 0x3ff00f5000000000, 0x3ff00f1000000000, 0x3ff00ed000000000, 0x3ff00e9000000000, 0x3ff00e5000000000, 0x3ff00e1000000000, 0x3ff00dd000000000, 0x3ff00d9000000000, 0x3ff00d5000000000, 0x3ff00d1000000000, 0x3ff00cd000000000, 0x3ff00c9000000000, 0x3ff00c5000000000, 0x3ff00c1000000000, 0x3ff00bd000000000, 0x3ff00b9000000000, 0x3ff00b4000000000, 0x3ff00b0000000000, 0x3ff00ac000000000, 0x3ff00a8000000000, 0x3ff00a4000000000, 0x3ff00a0000000000, 0x3ff009c000000000, 0x3ff0098000000000, 0x3ff0094000000000, 0x3ff0090000000000, 0x3ff008c000000000, 0x3ff0088000000000, 0x3ff0084000000000, 0x3ff0080000000000, 0x3ff007c000000000, 0x3ff0078000000000, 0x3ff0074000000000, 0x3ff0070000000000, 0x3ff006c000000000, 0x3ff0068000000000, 0x3ff0064000000000, 0x3ff0060000000000, 0x3ff005c000000000, 0x3ff0058000000000, 0x3ff0054000000000, 0x3ff0050000000000, 0x3ff004c000000000, 0x3ff0048000000000, 0x3ff0044000000000, 0x3ff0040000000000, 0x3ff003c000000000, 0x3ff0038000000000, 0x3ff0034000000000, 0x3ff0030000000000, 0x3ff002c000000000, 0x3ff0028000000000, 0x3ff0024000000000, 0x3ff0020000000000, 0x3ff001c000000000, 0x3ff0018000000000, 0x3ff0014000000000, 0x3ff0010000000000, 0x3ff000c000000000, 0x3ff0008000000000, 0x3ff0004000000000, 0x3ff0000000000000, 0x3fefff8000000000, 0x3fefff0000000000, 0x3feffe8000000000, 0x3feffe0000000000, 0x3feffd8000000000, 0x3feffd0000000000, 0x3feffc8000000000, 0x3feffc0000000000, 0x3feffb8000000000, 0x3feffb0000000000, 0x3feffa8000000000, 0x3feffa0000000000, 0x3feff98000000000, 0x3feff90000000000, 0x3feff88000000000, 0x3feff80000000000, 0x3feff78000000000, 0x3feff70000000000, 0x3feff68000000000, 0x3feff60000000000, 0x3feff58000000000, 0x3feff50000000000, 0x3feff48000000000, 0x3feff40000000000, 0x3feff38000000000, 0x3feff30000000000, 0x3feff28000000000, 0x3feff20000000000, 0x3feff18000000000, 0x3feff10000000000, 0x3feff08000000000, 0x3feff00000000000, 0x3fefef8000000000, 0x3fefef0000000000, 0x3fefee8000000000, 0x3fefee0000000000, 0x3fefed8000000000, 0x3fefed0000000000, 0x3fefec8000000000, 0x3fefec0000000000, 0x3fefeb8000000000, 0x3fefeb0000000000, 0x3fefea8000000000, 0x3fefea0000000000, 0x3fefe98000000000, 0x3fefe92000000000, 0x3fefe8a000000000, 0x3fefe82000000000, 0x3fefe7a000000000, 0x3fefe72000000000, 0x3fefe6a000000000, 0x3fefe62000000000, 0x3fefe5a000000000, 0x3fefe52000000000, 0x3fefe4a000000000, 0x3fefe42000000000, 0x3fefe3a000000000, 0x3fefe32000000000, 0x3fefe2a000000000, 0x3fefe22000000000, 0x3fefe1a000000000, 0x3fefe12000000000, 0x3fefe0a000000000, 0x3fefe02000000000, 0x3fefdfa000000000, 0x3fefdf2000000000, 0x3fefdea000000000, 0x3fefde2000000000, 0x3fefdda000000000, 0x3fefdd2000000000, 0x3fefdca000000000, 0x3fefdc2000000000, 0x3fefdba000000000, 0x3fefdb2000000000, 0x3fefdaa000000000, 0x3fefda2000000000, 0x3fefd9a000000000, 0x3fefd92000000000, 0x3fefd8c000000000, 0x3fefd84000000000, 0x3fefd7c000000000, 0x3fefd74000000000, 0x3fefd6c000000000, 0x3fefd64000000000, 0x3fefd5c000000000, 0x3fefd54000000000, 0x3fefd4c000000000, 0x3fefd44000000000, 0x3fefd3c000000000, 0x3fefd34000000000, 0x3fefd2c000000000, 0x3fefd24000000000, 0x3fefd1c000000000, 0x3fefd14000000000, 0x3fefd0c000000000, 0x3fefd04000000000, 0x3fefcfc000000000, 0x3fefcf4000000000, 0x3fefcec000000000, 0x3fefce4000000000, 0x3fefcdc000000000, 0x3fefcd6000000000, 0x3fefcce000000000, 0x3fefcc6000000000, 0x3fefcbe000000000, 0x3fefcb6000000000, 0x3fefcae000000000, 0x3fefca6000000000, 0x3fefc9e000000000, 0x3fefc96000000000, 0x3fefc8e000000000, 0x3fefc86000000000, 0x3fefc7e000000000, 0x3fefc76000000000, 0x3fefc6e000000000, 0x3fefc66000000000, 0x3fefc5e000000000, 0x3fefc56000000000, 0x3fefc4e000000000, 0x3fefc46000000000, 0x3fefc40000000000, 0x3fefc38000000000, 0x3fefc30000000000, 0x3fefc28000000000, 0x3fefc20000000000, 0x3fefc18000000000, 0x3fefc10000000000, 0x3fefc08000000000, ]; pub(crate) static LOG2_R_TD: [(u64, u64, u64); 128] = [ (0x0000000000000000, 0x0000000000000000, 0x0000000000000000), (0x3b084a2c615b70ad, 0xbe6177c23362928c, 0x3f872c8000000000), (0xbb3f27b820fd03ea, 0xbe9179e0caa9c9ab, 0x3f97440000000000), (0xbb2f27ef487c8f34, 0xbe8c6cea541f5b70, 0x3fa184c000000000), (0xbb3e3f80fbc71454, 0xbe966c4d4e554434, 0x3fa773a000000000), (0xbb09f8ef14d5f6ee, 0xbe770700a00fdd55, 0x3fad6ec000000000), (0x3b2452bbce7398c1, 0x3e853002a4e86631, 0x3fb1bb3000000000), (0xbae990555535afd0, 0x3e6fcd15f101c142, 0x3fb4c56000000000), (0x3b1447e30ad393ee, 0x3e925b3eed319ced, 0x3fb7d60000000000), (0x3b3b7759da88a2da, 0xbe94195120d8486f, 0x3fb960d000000000), (0x3b1cee7766ece702, 0x3e845b878e27d0d9, 0x3fbc7b5000000000), (0xbb2a55c745ecdc2f, 0x3e9770744593a4cb, 0x3fbf9c9000000000), (0x3b2f7ec992caa67f, 0x3e9c673032495d24, 0x3fc097e000000000), (0xbb2433638c6ece3e, 0xbe91eaa65b49696e, 0x3fc22db000000000), (0x3b358f27b6518824, 0x3e9b2866f2850b22, 0x3fc3c6f800000000), (0xbb086bdcfdfd4a4c, 0x3e68ee37cd2ea9d3, 0x3fc494f800000000), (0xbafff7044a68a7fa, 0x3e77e86f9c2154fb, 0x3fc633a800000000), (0xbaeaa21694561327, 0x3e58e3cfc25f0ce6, 0x3fc7046000000000), (0xba8d209f2d4239c6, 0x3e357f7a64ccd537, 0x3fc8a89800000000), (0xbb3a55e97e60e632, 0xbe9a761c09fbd2ae, 0x3fc97c2000000000), (0x3b3261179225541e, 0x3e924bea9a2c66f3, 0x3fcb260000000000), (0xbad08fa30510fca9, 0xbe660002ccfe43f5, 0x3fcbfc6800000000), (0xbb363ec8d56242f9, 0x3e969f220e97f22c, 0x3fcdac2000000000), (0x3b38bcdaf0534365, 0xbe96164f64c210e0, 0x3fce858000000000), (0x3b11003282896056, 0xbe70c1678ae89767, 0x3fd01d9c00000000), (0x3b101bcc7025fa92, 0xbe9f26a05c813d57, 0x3fd08bd000000000), (0xbaffe8a8648e9ebc, 0x3e74d8fc561c8d44, 0x3fd169c000000000), (0x3b008dfb23650c75, 0xbe9362ad8f7ca2d0, 0x3fd1d98400000000), (0xbb0f8d5a89861a5e, 0x3e92b13cd6c4d042, 0x3fd249cc00000000), (0xbb3a1c872983511e, 0xbe91c8f11979a5db, 0x3fd32c0000000000), (0x3b2e8e21bff3336b, 0x3e8c2ab3edefe569, 0x3fd39de800000000), (0x3affd1994fb2c4a1, 0x3e57c3eca28e69ca, 0x3fd4106000000000), (0x3af6b94b51cf76b1, 0xbe734c4e99e1c6c6, 0x3fd4f6fc00000000), (0xbb331d55da1d0f66, 0xbe9194a871b63619, 0x3fd56b2400000000), (0xbb2378b22691e28b, 0x3e8e3dd5c1c885ae, 0x3fd5dfdc00000000), (0x3ac99e302970e411, 0xbe86ccf3b1129b7c, 0x3fd6552c00000000), (0x3ad20164a049664d, 0xbe82f346e2bf924b, 0x3fd6cb1000000000), (0xbb2d14aac4d864c3, 0xbe8fa61aaa59c1d8, 0x3fd7b8a000000000), (0x3b0496ab4e4b293f, 0x3e990c11fd32a3ab, 0x3fd8304c00000000), (0xba9d209f2d4239c6, 0x3e457f7a64ccd537, 0x3fd8a89800000000), (0x3aeeae3326327bab, 0x3e4249ba76fee235, 0x3fd9218000000000), (0x3b2fa05bddfded8c, 0xbe8aad2729b21ae5, 0x3fd99b0800000000), (0xbb2624140d175ba2, 0x3e971810a5e18180, 0x3fda8ff800000000), (0x3aef1c5160c515c1, 0xbe46172fe015e13c, 0x3fdb0b6800000000), (0xbb086a6204eec8c0, 0x3e75ec6c1bfbf89a, 0x3fdb877c00000000), (0x3b1718f761dd3915, 0x3e7678bf6cdedf51, 0x3fdc043800000000), (0xbb3d4ee66c3700e4, 0x3e9c2d45fe43895e, 0x3fdc819c00000000), (0xbb27d14533586306, 0xbe99ee52ed49d71d, 0x3fdcffb000000000), (0x3ae5ce9fb5a7bb5b, 0x3e45786af187a96b, 0x3fdd7e6c00000000), (0xbb2ae6face57ad3b, 0x3e83ab0dc56138c9, 0x3fddfdd800000000), (0x3b15ac93b443d55f, 0x3e9fe538ab34efb5, 0x3fde7df400000000), (0x3b3f1753e0ae1e8f, 0xbe9e4fee07aa4b68, 0x3fdefec800000000), (0x3b3cdfd4c297069b, 0xbe9172f32fe67287, 0x3fdf804c00000000), (0x3b097a0e8f3ba742, 0xbe99a83ff9ab9cc8, 0x3fe0014400000000), (0xbb1800450f5b2357, 0xbe968cb06cece193, 0x3fe042be00000000), (0xbb1a839041241fe7, 0x3e98cd71ddf82e20, 0x3fe0849400000000), (0x3b1ed0b8eeccca86, 0x3e95e18ab2df3ae6, 0x3fe0c6ca00000000), (0x3b03dd41df9689b3, 0x3e65dee4d9d8a273, 0x3fe1096000000000), (0xbad990555535afd0, 0x3e5fcd15f101c142, 0x3fe14c5600000000), (0xbb21773d02c9055c, 0xbe82474b0f992ba1, 0x3fe18fae00000000), (0xbb14aeef330c53c1, 0x3e74b5a92a606047, 0x3fe1d36800000000), (0x3b28e6ff749ebacb, 0x3e916186fcf54bbd, 0x3fe2178600000000), (0x3abc09d761c548eb, 0x3e418efabeb7d722, 0x3fe25c0a00000000), (0x3b1aaa73a428e1e4, 0xbe7e5fc7d238691d, 0x3fe2a0f400000000), (0xbb0af2f3d8b63fba, 0x3e9f5809faf6283c, 0x3fe2e64400000000), (0xbb0af2f3d8b63fba, 0x3e9f5809faf6283c, 0x3fe2e64400000000), (0x3b278de359f2bb88, 0x3e9c6e1dcd0cb449, 0x3fe32bfe00000000), (0xbb3415ae1a715618, 0x3e976e0e8f74b4d5, 0x3fe3722200000000), (0xbb04991b5375621f, 0xbe7cb82c89692d99, 0x3fe3b8b200000000), (0xbb3827d37deb2236, 0xbe963161c5432aeb, 0x3fe3ffae00000000), (0x3b29576edac01c78, 0x3e9458104c41b901, 0x3fe4471600000000), (0x3b29576edac01c78, 0x3e9458104c41b901, 0x3fe4471600000000), (0xbb205a27b81e2219, 0xbe9cd9d0cde578d5, 0x3fe48ef000000000), (0x3ad237616778b4ba, 0x3e5b9884591add87, 0x3fe4d73800000000), (0x3b33b7d7e5d148bb, 0x3e9c6042978605ff, 0x3fe51ff200000000), (0xbb0cc3f936a5977c, 0xbe9fc4c96b37dcf6, 0x3fe5692200000000), (0x3ac20164a049664d, 0xbe72f346e2bf924b, 0x3fe5b2c400000000), (0x3ac20164a049664d, 0xbe72f346e2bf924b, 0x3fe5b2c400000000), (0xbb2a212919a92f7a, 0x3e9c4e4fbb68a4d1, 0x3fe5fcdc00000000), (0xbb2b64b03f7230dd, 0xbe89d499bd9b3226, 0x3fe6476e00000000), (0xbb21ec6379e6e3b9, 0xbe8f89b355ede26f, 0x3fe6927800000000), (0xbb21ec6379e6e3b9, 0xbe8f89b355ede26f, 0x3fe6927800000000), (0xbb14ba44c03bfbbd, 0x3e753c7e319f6e92, 0x3fe6ddfc00000000), (0xbb2c36fc650d030f, 0xbe9b291f070528c7, 0x3fe729fe00000000), (0xbaf69e5693a7f067, 0x3e62967a451a7b48, 0x3fe7767c00000000), (0xbaf69e5693a7f067, 0x3e62967a451a7b48, 0x3fe7767c00000000), (0x3b36598aae91499a, 0x3e9244fcff690fce, 0x3fe7c37a00000000), (0x3b299d61ec432837, 0x3e846fd97f5dc572, 0x3fe810fa00000000), (0x3b299d61ec432837, 0x3e846fd97f5dc572, 0x3fe810fa00000000), (0x3b3855c42078f81b, 0xbe9f3a7352663e50, 0x3fe85efe00000000), (0xbb259408e8151070, 0x3e8b3cda690370b5, 0x3fe8ad8400000000), (0xbb259408e8151070, 0x3e8b3cda690370b5, 0x3fe8ad8400000000), (0x3b133b318085e50a, 0x3e83226b211bf1d9, 0x3fe8fc9200000000), (0x3b0343fe7c9cb4ae, 0x3e8d24b136c101ee, 0x3fe94c2800000000), (0x3b0343fe7c9cb4ae, 0x3e8d24b136c101ee, 0x3fe94c2800000000), (0xbb3d19522e56fe60, 0x3e97c40c7907e82a, 0x3fe99c4800000000), (0xbb223b9d8ea55c3e, 0xbe9e81781d97ee91, 0x3fe9ecf600000000), (0xbb223b9d8ea55c3e, 0xbe9e81781d97ee91, 0x3fe9ecf600000000), (0x3b1829440c24aeb6, 0xbe96a77813f94e01, 0x3fea3e3000000000), (0xbb3624140d175ba2, 0xbe91cfdeb43cfd00, 0x3fea8ffa00000000), (0xbb3624140d175ba2, 0xbe91cfdeb43cfd00, 0x3fea8ffa00000000), (0x3b2afa6f024fb045, 0xbe8f983f74d3138f, 0x3feae25600000000), (0xbb1603ad3a5d326d, 0xbe8e278ae1a1f51f, 0x3feb354600000000), (0xbb1603ad3a5d326d, 0xbe8e278ae1a1f51f, 0x3feb354600000000), (0xbb20c1e0e5855d6a, 0xbe897552b7b5ea45, 0x3feb88cc00000000), (0xbb20c1e0e5855d6a, 0xbe897552b7b5ea45, 0x3feb88cc00000000), (0x3b1c817ad56baa16, 0xbe719b4f3c72c4f8, 0x3febdcea00000000), (0x3b244c47ac1bf62b, 0x3e8f7402d26f1a12, 0x3fec31a200000000), (0x3b244c47ac1bf62b, 0x3e8f7402d26f1a12, 0x3fec31a200000000), (0xbb169b9465eae1e6, 0xbe82056d5dd31d96, 0x3fec86f800000000), (0xbb169b9465eae1e6, 0xbe82056d5dd31d96, 0x3fec86f800000000), (0xbb024a6d9d1d1904, 0xbe76e46335aae723, 0x3fecdcec00000000), (0xbb33826144575ac4, 0xbe9beb244c59f331, 0x3fed338200000000), (0xbb33826144575ac4, 0xbe9beb244c59f331, 0x3fed338200000000), (0x3aedbc96b3b12b25, 0x3e416c071e93fd97, 0x3fed8aba00000000), (0x3aedbc96b3b12b25, 0x3e416c071e93fd97, 0x3fed8aba00000000), (0x3b268a8ccdbd1f33, 0x3e9d8175819530c2, 0x3fede29800000000), (0x3b268a8ccdbd1f33, 0x3e9d8175819530c2, 0x3fede29800000000), (0x3b0e586711df5ea1, 0x3e851bd552842c1c, 0x3fee3b2000000000), (0x3b0e586711df5ea1, 0x3e851bd552842c1c, 0x3fee3b2000000000), (0xbb0bc25adf042483, 0x3e9914e204f19d94, 0x3fee945200000000), (0xbb0bc25adf042483, 0x3e9914e204f19d94, 0x3fee945200000000), (0x3b3d7d82b65c5686, 0x3e9c55d997da24fd, 0x3feeee3200000000), (0x3b3d7d82b65c5686, 0x3e9c55d997da24fd, 0x3feeee3200000000), (0xbb23f108c0857ca3, 0xbe9685c2d2298a6e, 0x3fef48c400000000), (0xbb23f108c0857ca3, 0xbe9685c2d2298a6e, 0x3fef48c400000000), (0xbb1bd800bca7a221, 0x3e97a4887bd74039, 0x3fefa40600000000), (0x0000000000000000, 0x0000000000000000, 0x3ff0000000000000), ]; // Look up table for the second range reduction step: // Generated by Sollya with: // > for i from -64 to 128 do { // r = 2^-16 * nearestint(2^16 / (1 + i * 2^-14) ); // a = -log2(r); // b = round(a, D, RN); // c = round(a - b, D, RN); // print("{", c, ", ", b, "},"); // }; pub(crate) static LOG2_R2_DD: [(u64, u64); 193] = [ (0x3c1ff25180953e64, 0xbf7720c2ab2312a9), (0xbc115ffd79560d8f, 0xbf76c4c92b1478ff), (0x3c1b8d6d6f2e3579, 0xbf7668ce3c873549), (0xbc15bfc3f0d5ef71, 0xbf760cd1df6fde91), (0xbbfd1f7a8777984a, 0xbf75b0d413c30b5e), (0x3bd8e858515b8343, 0xbf7554d4d97551ab), (0x3c1e165c4014c1f2, 0xbf74f8d4307b46ec), (0x3c00f84b2cc14c7e, 0xbf749cd218c9800b), (0x3c1de618ed0db9a6, 0xbf7440ce9254916c), (0xbc1f6b8587e64f22, 0xbf73e4c99d110ee7), (0xbbf7f793c84cfa63, 0xbf7388c338f38bd0), (0xbbe7d7ecf6258c9a, 0xbf732cbb65f09aee), (0xbc1810bc5ac188f5, 0xbf72d0b223fcce81), (0xbc1950035fc5b67c, 0xbf7274a7730cb841), (0x3c14f47f3048cdad, 0xbf72189b5314e95d), (0x3bb269519861e298, 0xbf71bc8dc409f279), (0xbc15c2b0a46a7e2f, 0xbf71607ec5e063b3), (0x3c05001ac8f0bda8, 0xbf71046e588ccca0), (0x3c1106f246af5d41, 0xbf70a85c7c03bc4a), (0x3bd82a00583b34ba, 0xbf70354423e3c666), (0x3beb6f37deb31370, 0xbf6fb25e19f11aec), (0xbc044a2140444811, 0xbf6efa310d6550ec), (0x3c0f5e68a763133f, 0xbf6e4201220d4858), (0x3c0692083115f0b9, 0xbf6d89ce57d219a6), (0x3c0144bb17b9ac9c, 0xbf6cd198ae9cdc3d), (0x3c0ee7f086d32c05, 0xbf6c19602656a671), (0xbc0d4f1167538dbe, 0xbf6b6124bee88d82), (0x3c07df8d226c67e0, 0xbf6aa8e6783ba5a2), (0x3c060545d61b9512, 0xbf69f0a5523901eb), (0x3c054c99c2917020, 0xbf6938614cc9b468), (0xbbfa7e678d7280de, 0xbf68801a67d6ce10), (0xbbf6d419bbeb223a, 0xbf67c7d0a3495ec9), (0x3bfce2b9892e27e9, 0xbf670f83ff0a7565), (0xbc0a4db4eff7bd61, 0xbf6657347b031fa2), (0x3c05bb04682fab82, 0xbf659ee2171c6a2f), (0xbbf78b8bfe6a3ade, 0xbf64e68cd33f60a3), (0x3c0574c3ce9b89b1, 0xbf642e34af550d87), (0x3c008fb216647b7b, 0xbf6375d9ab467a4d), (0x3bded5a50e7b919c, 0xbf62bd7bc6fcaf56), (0x3c091ad7a23f86fe, 0xbf62051b0260b3f0), (0x3bf3ab2c932b8b0a, 0xbf614cb75d5b8e54), (0xbc0c63bcdf120f7a, 0xbf609450d7d643a9), (0x3bf8af8c4ab4e82d, 0xbf5fb7cee373b008), (0x3bea52c2ca9d8b9b, 0xbf5e46f655de9cc6), (0xbbf460b177a58742, 0xbf5cd61806bf5166), (0x3bd611089de8d12a, 0xbf5b6533f5e7cf9b), (0xbba4209853cee70c, 0xbf59f44a232a16ee), (0x3bf964e032541a28, 0xbf58835a8e5824c3), (0xbbdfa9f94392637b, 0xbf5712653743f454), (0xbbf3293693721a53, 0xbf55a16a1dbf7eb6), (0xbbb6e2af03c83c6e, 0xbf543069419cbad5), (0xbbeb5f05b9d5bd29, 0xbf52bf62a2ad9d74), (0x3bf3db883c072f72, 0xbf514e5640c41930), (0xbbba675a1c045304, 0xbf4fba8837643cf6), (0x3bd3b9c2aeb00068, 0xbf4cd85866933743), (0xbbd2911a381901eb, 0xbf49f61d0eb8f98b), (0xbbb5ea75a74def03, 0xbf4713d62f7957c3), (0xbbc305b92f93ffe0, 0xbf443183c878218d), (0x3bbb7c8c8dd40d35, 0xbf414f25d959223a), (0x3bddc915d58a62f6, 0xbf3cd978c3804191), (0x3bdc7bc3fe53cd94, 0xbf37148ec2a1bfc9), (0xbbc427ce595cc53c, 0xbf314f8daf5e3bcf), (0xbbcd523885ac824c, 0xbf2714eb11fa5363), (0xbba945957f63330a, 0xbf1715193b17d35d), (0x0000000000000000, 0x0000000000000000), (0xbb988fb2ea8bf9ea, 0x3f17157590356aee), (0xbbb5aeaee345d04e, 0x3f2715a3bc3593d5), (0xbbd7fce430230132, 0x3f31505d6ee104c5), (0xbb99a480f204ff09, 0x3f3716001718cb2b), (0xbbb00e7233f2d8bd, 0x3f3cdbb9d77ae5a8), (0x3bc09d379fa18c5d, 0x3f4150c5586012b8), (0x3beb6b9d90a104d3, 0x3f4433b951d0b231), (0x3be4d9a3ea651885, 0x3f4716b8d86bc285), (0xbbc7590b3a76f0f9, 0x3f49f9c3ec8db94f), (0x3bef183ca5b21bfe, 0x3f4cdcda8e93107f), (0xbbda7e3465ba1270, 0x3f4fbffcbed8465f), (0xbbf7821f738d1221, 0x3f5151953edceec6), (0x3be3bb4c0fb95359, 0x3f52c331e5ca2e7d), (0x3bf236028e962f80, 0x3f5434d4546227fc), (0x3bdaaaa64d30f184, 0x3f55a67c8ad32315), (0xbbfa821b7cc57a7a, 0x3f57182a894b69c6), (0xbbf13d9d78aace21, 0x3f5889de4ff94838), (0xbbf2f249a6b923a0, 0x3f59fb97df0b0cc2), (0xbbbd47dc3664be7a, 0x3f5b6d5736af07e6), (0x3bfbd1522c6418fb, 0x3f5cdf1c57138c53), (0xbbfbacdbb22d2163, 0x3f5e50e74066eee6), (0xbbfca7604812d77b, 0x3f5fc2b7f2d786a5), (0xbc02b6832f8830bf, 0x3f609a473749d663), (0x3be4e712033d0457, 0x3f61533559e4de55), (0xbbd473dd044017b5, 0x3f620c26615409f1), (0xbc0e033bcac726d3, 0x3f62c51a4dae8915), (0xbc04a47a2b18a0fa, 0x3f637e111f0b8cb5), (0x3bd6f3615771c17b, 0x3f64370ad58246dd), (0x3bec0ee6c32d6236, 0x3f64f0077129eab0), (0x3bffa94c99761b8f, 0x3f65a906f219ac67), (0xbbf979e6b473fbf8, 0x3f6662095868c153), (0x3bf30edde8d24c7b, 0x3f671b0ea42e5fda), (0xbbfd01594fe1421c, 0x3f67d416d581bf7c), (0x3c050bf7b995b49a, 0x3f688d21ec7a18cd), (0xbc028ea2bcec5018, 0x3f69462fe92ea57c), (0x3beed6add489c30b, 0x3f69ff40cbb6a04b), (0x3bf201d5c3bbeb69, 0x3f6ab85494294517), (0xbbfa05d0d4461ea9, 0x3f6b716b429dd0d3), (0xbc07c974c8a392fd, 0x3f6c2a84d72b8189), (0xbbff068238451bde, 0x3f6ce3a151e9965b), (0xbbd5e4d95c6259c3, 0x3f6d9cc0b2ef4f83), (0xbc01fc262efaad6c, 0x3f6e55e2fa53ee53), (0x3c049eee7abc7716, 0x3f6f0f08282eb533), (0xbbe903de284d2782, 0x3f6fc8303c96e7a6), (0xbc0ec564845134cb, 0x3f7040ad9bd1e522), (0xbbd7692b7791cf1f, 0x3f70861eadabc3dc), (0xbc137829afb11c10, 0x3f70e2b6b51e4f7e), (0x3c16706b91c3b0ba, 0x3f713f5030033459), (0xbc17558ccd710756, 0x3f719beb1e6616c9), (0x3c179f72a5bbe9de, 0x3f71f88780529bb1), (0xbc1e1297c110b250, 0x3f72552555d46886), (0x3c129930d567ca26, 0x3f72b1c49ef72343), (0x3bea08cbd7592a17, 0x3f730e655bc67275), (0x3c1e4f9d4ac5db83, 0x3f736b078c4dfd31), (0xbc1ed1b0aafd30c2, 0x3f73c7ab30996b1c), (0x3c1e78f0aa014b32, 0x3f74245048b46462), (0x3ba8594548038a0f, 0x3f7480f6d4aa91c2), (0x3c03df498168a333, 0x3f74dd9ed4879c82), (0x3c1b1c502544f82a, 0x3f753a4848572e77), (0xbc0dc50552fe0da9, 0x3f7596f33024f203), (0xbc1671d85c357d5e, 0x3f75f39f8bfc9212), (0x3bf1c670cabccefa, 0x3f76504d5be9ba1e), (0xbc19983a9e98f318, 0x3f76acfc9ff8162f), (0x3c1ae1a26af3eebe, 0x3f7709ad583352d6), (0x3c1655eb510bfda3, 0x3f77665f84a71d35), (0xbbfe287bc0192e15, 0x3f77c313255f22f8), (0x3c0cc4944139ccbf, 0x3f781fc83a671257), (0x3c14e09b4cb8645b, 0x3f787c7ec3ca9a19), (0xbbf5becc991e3a5f, 0x3f78d936c1956991), (0xbc1ddfa3f1e15ba8, 0x3f7935f033d3309e), (0xbc1b7b06ea3fb362, 0x3f7992ab1a8f9fac), (0x3c132d614904e46c, 0x3f79ef6775d667b4), (0xbbf7186892b5bfae, 0x3f7a4c2545b33a3e), (0xbc1d4de10b28dfd8, 0x3f7aa8e48a31c95c), (0x3c14bb4b3bdc8175, 0x3f7b05a5435dc7ad), (0x3c19cedbd1d7fba5, 0x3f7b62677142e860), (0xbbd0ed3379beaffd, 0x3f7bbf2b13ecdf2f), (0x3c16e86a125567a6, 0x3f7c1bf02b676060), (0xbc135038e0c0a52c, 0x3f7c6184f1b326d9), (0x3bc05ef8bf5adf5e, 0x3f7cbe4c95b6c5ab), (0xbbeb7338b99a6b26, 0x3f7d1b15aeab217c), (0x3c09e901c30c427e, 0x3f7d77e03c9bf0a4), (0xbc11f28a9c0b3d47, 0x3f7dd4ac3f94ea0a), (0xbc1140ef760d3b63, 0x3f7e3179b7a1c520), (0xbc0ab65b1037f517, 0x3f7e8e48a4ce39e7), (0xbc076940c457ce6d, 0x3f7eeb19072600ed), (0x3bfda3ae65a605cf, 0x3f7f47eadeb4d34d), (0x3c1b15d0bce2ede6, 0x3f7fa4be2b866ab0), (0x3c2e02aa1fa9dc57, 0x3f8000c976d340a6), (0x3c16be971a5565b9, 0x3f802f34929068f3), (0xbbf8a9319a6ed164, 0x3f805da069008be7), (0x3c1825079f1e0ec5, 0x3f808c0cfa298771), (0x3c060d5749321466, 0x3f80ba7a461139c8), (0xbc25b8f4c479e2e0, 0x3f80e8e84cbd8169), (0xbc1e3e1248004e29, 0x3f8117570e343d17), (0x3c09ac06487c3750, 0x3f8145c68a7b4bdd), (0x3c1f657ea5c03ea4, 0x3f817436c1988d0d), (0xbc25a965659a05e2, 0x3f81a2a7b391e040), (0xbc221ce9b9bfc512, 0x3f81d119606d2554), (0xbc230fda247ad0e1, 0x3f81ff8bc8303c70), (0xbc1382c78a45cdea, 0x3f822dfeeae10601), (0x3c246ae4a64073d4, 0x3f8250d5bf952374), (0xbc1dcad2cec3b84b, 0x3f827f4a29740a2f), (0xbc2413fbeb0b0635, 0x3f82adbf4e50cdf9), (0x3c2f28e6a48bcb90, 0x3f82dc352e315049), (0xbc296f286e1eb086, 0x3f830aabc91b72e0), (0xbc2f88c04206dfa1, 0x3f8339231f1517c1), (0xbc211ea20e195841, 0x3f83679b30242139), (0xbc0d6e71452b674a, 0x3f839613fc4e71dc), (0xbc257c578233b1b3, 0x3f83c48d8399ec85), (0xbc0ec430f03b76e0, 0x3f83f307c60c7455), (0x3c2e00dd1902ffb9, 0x3f842182c3abecb5), (0xbc2f22bcd96afe38, 0x3f844ffe7c7e3957), (0x3c208fd90f841d30, 0x3f847e7af0893e2f), (0x3c109594c5552bcc, 0x3f84acf81fd2df7e), (0xbc201a8a652e5602, 0x3f84db760a6101c9), (0xbbf826168febb3d0, 0x3f8509f4b03989dc), (0xbc17eb21a35021e3, 0x3f85387411625ccc), (0xbc266cbc818e1750, 0x3f8566f42de15ff4), (0x3bf9b784dd6cebda, 0x3f85957505bc78f6), (0x3c22b121ab482456, 0x3f85b8562298c65b), (0xbc15d29869dd8233, 0x3f85e6d842633702), (0xbc2572a1b6cd63cf, 0x3f86155b1d99f672), (0xbc1a1f355360e877, 0x3f8643deb442eb59), (0xbc2b6f1cd2e1c03f, 0x3f8672630663fcad), (0xbc22aaa11ccddcae, 0x3f86a0e8140311aa), (0x3c23d979ddf4746c, 0x3f86cf6ddd2611d4), (0xbc0dc930484501f8, 0x3f86fdf461d2e4f8), ]; pxfm-0.1.23/src/round.rs000064400000000000000000000126131046102023000131500ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{get_exponent_f32, get_exponent_f64, mantissa_f32, mantissa_f64}; #[inline] pub const fn roundf(x: f32) -> f32 { // If x is infinity NaN or zero, return it. if !x.is_normal() { return x; } let exponent = get_exponent_f32(x); const FRACTION_LENGTH: u32 = 23; // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. if exponent >= FRACTION_LENGTH as i32 { return x; } if exponent == -1 { // Absolute value of x is greater than equal to 0.5 but less than 1. return if x.is_sign_negative() { -1.0 } else { 1.0 }; } if exponent <= -2 { // Absolute value of x is less than 0.5. return if x.is_sign_negative() { -0.0 } else { 0.0 }; } let trim_size = (FRACTION_LENGTH as i32).wrapping_sub(exponent); let half_bit_set = mantissa_f32(x) & (1u32 << (trim_size - 1)) != 0; let x_u = x.to_bits(); let trunc_u: u32 = (x_u >> trim_size).wrapping_shl(trim_size as u32); // If x is already an integer, return it. if trunc_u == x_u { return x; } let trunc_value = f32::from_bits(trunc_u); if !half_bit_set { // Franctional part is less than 0.5 so round value is the // same as the trunc value. trunc_value } else if x.is_sign_negative() { trunc_value - 1.0 } else { trunc_value + 1.0 } } #[inline] pub const fn round(x: f64) -> f64 { // If x is infinity NaN or zero, return it. if !x.is_normal() { return x; } let exponent = get_exponent_f64(x); const FRACTION_LENGTH: u64 = 52; // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. if exponent >= FRACTION_LENGTH as i64 { return x; } if exponent == -1 { // Absolute value of x is greater than equal to 0.5 but less than 1. return if x.is_sign_negative() { -1.0 } else { 1.0 }; } if exponent <= -2 { // Absolute value of x is less than 0.5. return if x.is_sign_negative() { -0.0 } else { 0.0 }; } let trim_size = (FRACTION_LENGTH as i64).wrapping_sub(exponent); let half_bit_set = mantissa_f64(x) & (1u64 << (trim_size.wrapping_sub(1))) != 0; let x_u = x.to_bits(); let trunc_u: u64 = (x_u >> trim_size).wrapping_shl(trim_size as u32); // If x is already an integer, return it. if trunc_u == x_u { return x; } let trunc_value = f64::from_bits(trunc_u); if !half_bit_set { // Franctional part is less than 0.5 so round value is the // same as the trunc value. trunc_value } else if x.is_sign_negative() { trunc_value - 1.0 } else { trunc_value + 1.0 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_roundf() { assert_eq!(roundf(0f32), 0.0f32.round()); assert_eq!(roundf(1f32), 1.0f32.round()); assert_eq!(roundf(1.2f32), 1.2f32.round()); assert_eq!(roundf(-1.2f32), (-1.2f32).round()); assert_eq!(roundf(-1.6f32), (-1.6f32).round()); assert_eq!(roundf(-1.5f32), (-1.5f32).round()); assert_eq!(roundf(1.6f32), 1.6f32.round()); assert_eq!(roundf(1.5f32), 1.5f32.round()); assert_eq!(roundf(2.5f32), 2.5f32.round()); } #[test] fn test_round() { assert_eq!(round(0.), 0.0f64.round()); assert_eq!(round(1.), 1.0f64.round()); assert_eq!(round(1.2), 1.2f64.round()); assert_eq!(round(-1.2), (-1.2f64).round()); assert_eq!(round(-1.6), (-1.6f64).round()); assert_eq!(round(-1.5), (-1.5f64).round()); assert_eq!(round(1.6), 1.6f64.round()); assert_eq!(round(1.5), 1.5f64.round()); assert_eq!(round(2.5), 2.5f64.round()); } } pxfm-0.1.23/src/round_ties_even.rs000064400000000000000000000164571046102023000152230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{get_exponent_f32, get_exponent_f64, mantissa_f32, mantissa_f64}; #[inline] pub const fn roundf_ties_even(x: f32) -> f32 { // If x is infinity NaN or zero, return it. if !x.is_normal() { return x; } let exponent = get_exponent_f32(x); const FRACTION_LENGTH: u32 = 23; // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. if exponent >= FRACTION_LENGTH as i32 { return x; } if exponent == -1 { // Absolute value of x is greater than equal to 0.5 but less than 1. return if x.is_sign_negative() { -0.0 } else { 0.0 }; } if exponent <= -2 { // Absolute value of x is less than 0.5. return if x.is_sign_negative() { -0.0 } else { 0.0 }; } let trim_size = (FRACTION_LENGTH as i32).wrapping_sub(exponent); let trim_value = mantissa_f32(x) & (1u32 << trim_size).wrapping_sub(1); let half_value = 1u32 << (trim_size.wrapping_sub(1)); let x_u = x.to_bits(); let trunc_u: u32 = (x_u >> trim_size).wrapping_shl(trim_size as u32); // If x is already an integer, return it. if trunc_u == x_u { return x; } let trunc_value = f32::from_bits(trunc_u); // If exponent is 0, trimSize will be equal to the mantissa width, and // truncIsOdd` will not be correct. So, we handle it as a special case // below. let trunc_is_odd = mantissa_f32(trunc_value) & (1u32 << trim_size) != 0; if trim_value > half_value { if x.is_sign_negative() { trunc_value - 1.0 } else { trunc_value + 1.0 } } else if trim_value == half_value { if exponent == 0 { return if x.is_sign_negative() { -2.0 } else { 2.0 }; } if trunc_is_odd { if x.is_sign_negative() { trunc_value - 1.0 } else { trunc_value + 1.0 } } else { trunc_value } } else { trunc_value } } #[inline] pub const fn round_ties_even(x: f64) -> f64 { // If x is infinity NaN or zero, return it. if !x.is_normal() { return x; } let exponent = get_exponent_f64(x); const FRACTION_LENGTH: u64 = 52; // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. if exponent >= FRACTION_LENGTH as i64 { return x; } if exponent == -1 { // Absolute value of x is greater than equal to 0.5 but less than 1. return if x.is_sign_negative() { -0.0 } else { 0.0 }; } if exponent <= -2 { // Absolute value of x is less than 0.5. return if x.is_sign_negative() { -0.0 } else { 0.0 }; } let trim_size = (FRACTION_LENGTH as i64).wrapping_sub(exponent); let trim_value = mantissa_f64(x) & (1u64 << trim_size).wrapping_sub(1); let half_value = 1u64 << (trim_size.wrapping_sub(1)); let x_u = x.to_bits(); let trunc_u: u64 = (x_u >> trim_size).wrapping_shl(trim_size as u32); // If x is already an integer, return it. if trunc_u == x_u { return x; } let trunc_value = f64::from_bits(trunc_u); // If exponent is 0, trimSize will be equal to the mantissa width, and // truncIsOdd` will not be correct. So, we handle it as a special case // below. let trunc_is_odd = mantissa_f64(trunc_value) & (1u64 << trim_size) != 0; if trim_value > half_value { if x.is_sign_negative() { trunc_value - 1.0 } else { trunc_value + 1.0 } } else if trim_value == half_value { if exponent == 0 { return if x.is_sign_negative() { -2.0 } else { 2.0 }; } if trunc_is_odd { if x.is_sign_negative() { trunc_value - 1.0 } else { trunc_value + 1.0 } } else { trunc_value } } else { trunc_value } } #[cfg(test)] mod tests { use super::*; #[test] fn test_roundf_ties_even() { assert_eq!(roundf_ties_even(0f32), 0.0f32.round_ties_even()); assert_eq!(roundf_ties_even(0.5f32), 0.5f32.round_ties_even()); assert_eq!(roundf_ties_even(-0.5), (-0.5f32).round_ties_even()); assert_eq!(roundf_ties_even(1f32), 1.0f32.round_ties_even()); assert_eq!(roundf_ties_even(1.2f32), 1.2f32.round_ties_even()); assert_eq!(roundf_ties_even(-1.2f32), (-1.2f32).round_ties_even()); assert_eq!(roundf_ties_even(-1.6f32), (-1.6f32).round_ties_even()); assert_eq!(roundf_ties_even(-1.5f32), (-1.5f32).round_ties_even()); assert_eq!(roundf_ties_even(1.6f32), 1.6f32.round_ties_even()); assert_eq!(roundf_ties_even(1.5f32), 1.5f32.round_ties_even()); assert_eq!(roundf_ties_even(2.5f32), 2.5f32.round_ties_even()); } #[test] fn test_round_ties_even() { assert_eq!(round_ties_even(0.), 0.0f64.round_ties_even()); assert_eq!(round_ties_even(0.5), 0.5f64.round_ties_even()); assert_eq!(round_ties_even(-0.5), (-0.5f64).round_ties_even()); assert_eq!(round_ties_even(1.), 1.0f64.round_ties_even()); assert_eq!(round_ties_even(1.2), 1.2f64.round_ties_even()); assert_eq!(round_ties_even(-1.2), (-1.2f64).round_ties_even()); assert_eq!(round_ties_even(-1.6), (-1.6f64).round_ties_even()); assert_eq!(round_ties_even(-1.5), (-1.5f64).round_ties_even()); assert_eq!(round_ties_even(1.6), 1.6f64.round_ties_even()); assert_eq!(round_ties_even(1.5), 1.5f64.round_ties_even()); assert_eq!(round_ties_even(2.5), 2.5f64.round_ties_even()); assert_eq!(round_ties_even(-2.5), (-2.5f64).round_ties_even()); } } pxfm-0.1.23/src/sec.rs000064400000000000000000000126641046102023000126010ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::min_normal_f64; use crate::double_double::DoubleDouble; use crate::sin::{get_sin_k_rational, range_reduction_small, sincos_eval}; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::{range_reduction_small_f128, sincos_eval_dyadic}; use crate::sincos_reduce::LargeArgumentReduction; #[cold] fn sec_accurate(x: f64, argument_reduction: &mut LargeArgumentReduction, x_e: u64, k: u64) -> f64 { const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let u_f128 = if x_e < EXP_BIAS + 16 { range_reduction_small_f128(x) } else { argument_reduction.accurate() }; let sin_cos = sincos_eval_dyadic(&u_f128); // -sin(k * pi/128) = sin((k + 128) * pi/128) // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let msin_k_f128 = get_sin_k_rational(k.wrapping_add(128)); let cos_k_f128 = get_sin_k_rational(k.wrapping_add(64)); // cos(x) = cos((k * pi/128 + u) // = cos(u) * cos(k*pi/128) - sin(u) * sin(k*pi/128) let r = (cos_k_f128 * sin_cos.v_cos) + (msin_k_f128 * sin_cos.v_sin); r.reciprocal().fast_as_f64() } /// Secant for double precision /// /// ULP 0.5 pub fn f_sec(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-26 if x_e < E_BIAS - 7 { // |x| < 2^-26 if x_e < E_BIAS - 27 { // Signed zeros. if x == 0.0 { return 1.0; } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. return 1.0 - min_normal_f64(); } k = 0; y = DoubleDouble::new(0.0, x); } else { // Small range reduction. (y, k) = range_reduction_small(x); } } else { // Inf or NaN if x_e > 2 * E_BIAS { // sec(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. // k = argument_reduction.high_part(x); (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, cos_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, msin_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = rr.recip_raphson(); let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return rr.to_f64(); } sec_accurate(x, &mut argument_reduction, x_e, k) } #[cfg(test)] mod tests { use super::*; #[test] fn test_sec() { assert_eq!(f_sec(-175432.), 1.461049620895326); assert_eq!(f_sec(175432.), 1.461049620895326); assert_eq!(f_sec(-10.), -1.1917935066878957); assert_eq!(f_sec(10.), -1.1917935066878957); assert_eq!(f_sec(5.), 3.5253200858160882); assert_eq!(f_sec(-5.), 3.5253200858160882); assert_eq!(f_sec(0.), 1.0); assert!(f_sec(f64::NAN).is_nan()); assert!(f_sec(f64::INFINITY).is_nan()); assert!(f_sec(f64::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/shared_eval.rs000064400000000000000000000056461046102023000143060ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; #[inline] pub(crate) fn poly_dd_3(x: DoubleDouble, poly: [(u64, u64); 3], l: f64) -> DoubleDouble { let zch = poly[2]; let ach = f64::from_bits(zch.0) + l; let acl = (f64::from_bits(zch.0) - ach) + l + f64::from_bits(zch.1); let mut ch = DoubleDouble::new(acl, ach); let zch = poly[1]; ch = DoubleDouble::quick_mult(ch, x); let th = ch.hi + f64::from_bits(zch.0); let tl = (f64::from_bits(zch.0) - th) + ch.hi; ch.hi = th; ch.lo += tl + f64::from_bits(zch.1); let zch = poly[0]; ch = DoubleDouble::quick_mult(ch, x); let th = ch.hi + f64::from_bits(zch.0); let tl = (f64::from_bits(zch.0) - th) + ch.hi; ch.hi = th; ch.lo += tl + f64::from_bits(zch.1); ch } #[inline] pub(crate) fn poly_dekker_generic( x: DoubleDouble, poly: [(u64, u64); N], ) -> DoubleDouble { let zch = poly.last().unwrap(); let ach = f64::from_bits(zch.0); let acl = f64::from_bits(zch.1); let mut ch = DoubleDouble::new(acl, ach); for zch in poly.iter().rev().skip(1) { ch = DoubleDouble::quick_mult(ch, x); let th = ch.hi + f64::from_bits(zch.0); let tl = (f64::from_bits(zch.0) - th) + ch.hi; ch.hi = th; ch.lo += tl + f64::from_bits(zch.1); } ch } pxfm-0.1.23/src/sin.rs000064400000000000000000000340021046102023000126060ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dyad_fmla, f_fmla, min_normal_f64}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::sin_helper::sincos_eval_dd; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::SIN_K_PI_OVER_128_F128; use crate::sincos_reduce::LargeArgumentReduction; // For 2^-7 < |x| < 2^16, return k and u such that: // k = round(x * 128/pi) // x mod pi/128 = x - k * pi/128 ~ u.hi + u.lo // Error bound: // |(x - k * pi/128) - (u_hi + u_lo)| <= max(ulp(ulp(u_hi)), 2^-119) // <= 2^-111. #[inline] pub(crate) fn range_reduction_small(x: f64) -> (DoubleDouble, u64) { const MPI_OVER_128: [u64; 3] = [0xbf9921fb54400000, 0xbd70b4611a600000, 0xbb43198a2e037073]; const ONE_TWENTY_EIGHT_OVER_PI_D: f64 = f64::from_bits(0x40445f306dc9c883); let prod_hi = x * ONE_TWENTY_EIGHT_OVER_PI_D; let kd = prod_hi.round(); // Let y = x - k * (pi/128) // Then |y| < pi / 256 // With extra rounding errors, we can bound |y| < 1.6 * 2^-7. let y_hi = f_fmla(kd, f64::from_bits(MPI_OVER_128[0]), x); // Exact // |u.hi| < 1.6*2^-7 let u_hi = f_fmla(kd, f64::from_bits(MPI_OVER_128[1]), y_hi); let u0 = y_hi - u_hi; // Exact // |u.lo| <= max(ulp(u.hi), |kd * MPI_OVER_128[2]|) let u1 = f_fmla(kd, f64::from_bits(MPI_OVER_128[1]), u0); // Exact let u_lo = f_fmla(kd, f64::from_bits(MPI_OVER_128[2]), u1); // Error bound: // |x - k * pi/128| - (u.hi + u.lo) <= ulp(u.lo) // <= ulp(max(ulp(u.hi), kd*MPI_OVER_128[2])) // <= 2^(-7 - 104) = 2^-111. (DoubleDouble::new(u_lo, u_hi), (kd as i64) as u64) } #[inline] pub(crate) fn get_sin_k_rational(kk: u64) -> DyadicFloat128 { let idx = if (kk & 64) != 0 { 64 - (kk & 63) } else { kk & 63 }; let mut ans = SIN_K_PI_OVER_128_F128[idx as usize]; if (kk & 128) != 0 { ans.sign = DyadicSign::Neg; } ans } pub(crate) struct SinCos { pub(crate) v_sin: DoubleDouble, pub(crate) v_cos: DoubleDouble, pub(crate) err: f64, } #[inline] pub(crate) fn sincos_eval(u: DoubleDouble) -> SinCos { // Evaluate sin(y) = sin(x - k * (pi/128)) // We use the degree-7 Taylor approximation: // sin(y) ~ y - y^3/3! + y^5/5! - y^7/7! // Then the error is bounded by: // |sin(y) - (y - y^3/3! + y^5/5! - y^7/7!)| < |y|^9/9! < 2^-54/9! < 2^-72. // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms // < ulp(u_hi^3) gives us: // y - y^3/3! + y^5/5! - y^7/7! = ... // ~ u_hi + u_hi^3 * (-1/6 + u_hi^2 * (1/120 - u_hi^2 * 1/5040)) + // + u_lo (1 + u_hi^2 * (-1/2 + u_hi^2 / 24)) let u_hi_sq = u.hi * u.hi; // Error < ulp(u_hi^2) < 2^(-6 - 52) = 2^-58. // p1 ~ 1/120 + u_hi^2 / 5040. let p1 = f_fmla( u_hi_sq, f64::from_bits(0xbf2a01a01a01a01a), f64::from_bits(0x3f81111111111111), ); // q1 ~ -1/2 + u_hi^2 / 24. let q1 = f_fmla( u_hi_sq, f64::from_bits(0x3fa5555555555555), f64::from_bits(0xbfe0000000000000), ); let u_hi_3 = u_hi_sq * u.hi; // p2 ~ -1/6 + u_hi^2 (1/120 - u_hi^2 * 1/5040) let p2 = f_fmla(u_hi_sq, p1, f64::from_bits(0xbfc5555555555555)); // q2 ~ 1 + u_hi^2 (-1/2 + u_hi^2 / 24) let q2 = f_fmla(u_hi_sq, q1, 1.0); let sin_lo = f_fmla(u_hi_3, p2, u.lo * q2); // Overall, |sin(y) - (u_hi + sin_lo)| < 2*ulp(u_hi^3) < 2^-69. // Evaluate cos(y) = cos(x - k * (pi/128)) // We use the degree-8 Taylor approximation: // cos(y) ~ 1 - y^2/2 + y^4/4! - y^6/6! + y^8/8! // Then the error is bounded by: // |cos(y) - (...)| < |y|^10/10! < 2^-81 // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms // < ulp(u_hi^3) gives us: // 1 - y^2/2 + y^4/4! - y^6/6! + y^8/8! = ... // ~ 1 - u_hi^2/2 + u_hi^4(1/24 + u_hi^2 (-1/720 + u_hi^2/40320)) + // + u_hi u_lo (-1 + u_hi^2/6) // We compute 1 - u_hi^2 accurately: // v_hi + v_lo ~ 1 - u_hi^2/2 // with error <= 2^-105. let u_hi_neg_half = (-0.5) * u.hi; let (mut v_lo, v_hi); #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { v_hi = f_fmla(u.hi, u_hi_neg_half, 1.0); v_lo = 1.0 - v_hi; // Exact v_lo = f_fmla(u.hi, u_hi_neg_half, v_lo); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let u_hi_sq_neg_half = DoubleDouble::from_exact_mult(u.hi, u_hi_neg_half); let v = DoubleDouble::from_exact_add(1.0, u_hi_sq_neg_half.hi); v_lo = v.lo; v_lo += u_hi_sq_neg_half.lo; v_hi = v.hi; } // r1 ~ -1/720 + u_hi^2 / 40320 let r1 = f_fmla( u_hi_sq, f64::from_bits(0x3efa01a01a01a01a), f64::from_bits(0xbf56c16c16c16c17), ); // s1 ~ -1 + u_hi^2 / 6 let s1 = f_fmla(u_hi_sq, f64::from_bits(0x3fc5555555555555), -1.0); let u_hi_4 = u_hi_sq * u_hi_sq; let u_hi_u_lo = u.hi * u.lo; // r2 ~ 1/24 + u_hi^2 (-1/720 + u_hi^2 / 40320) let r2 = f_fmla(u_hi_sq, r1, f64::from_bits(0x3fa5555555555555)); // s2 ~ v_lo + u_hi * u_lo * (-1 + u_hi^2 / 6) let s2 = f_fmla(u_hi_u_lo, s1, v_lo); let cos_lo = f_fmla(u_hi_4, r2, s2); // Overall, |cos(y) - (v_hi + cos_lo)| < 2*ulp(u_hi^4) < 2^-75. let sin_u = DoubleDouble::from_exact_add(u.hi, sin_lo); let cos_u = DoubleDouble::from_exact_add(v_hi, cos_lo); let err = f_fmla( u_hi_3, f64::from_bits(0x3cc0000000000000), f64::from_bits(0x3960000000000000), ); SinCos { v_sin: sin_u, v_cos: cos_u, err, } } #[cold] #[inline(never)] fn sin_accurate(y: DoubleDouble, sin_k: DoubleDouble, cos_k: DoubleDouble) -> f64 { let r_sincos = sincos_eval_dd(y); // k is an integer and -pi / 256 <= y <= pi / 256. // Then sin(x) = sin((k * pi/128 + y) // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr.to_f64() } /// Sine for double precision /// /// ULP 0.5 pub fn f_sin(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-26 if x_e < E_BIAS - 26 { // Signed zeros. if x == 0.0 { return x; } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. return dyad_fmla(x, f64::from_bits(0xbc90000000000000), x); } // // Small range reduction. (y, k) = range_reduction_small(x); } else { // Inf or NaN if x_e > 2 * E_BIAS { // sin(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return rr.to_f64(); } sin_accurate(y, sin_k, cos_k) } #[cold] #[inline(never)] fn cos_accurate(y: DoubleDouble, msin_k: DoubleDouble, cos_k: DoubleDouble) -> f64 { // const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; // let u_f128 = if x_e < EXP_BIAS + 16 { // range_reduction_small_f128(x) // } else { // argument_reduction.accurate() // }; // // let sin_cos = sincos_eval_dyadic(&u_f128); // // // -sin(k * pi/128) = sin((k + 128) * pi/128) // // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). // let msin_k_f128 = get_sin_k_rational(k.wrapping_add(128)); // let cos_k_f128 = get_sin_k_rational(k.wrapping_add(64)); // // // cos(x) = cos((k * pi/128 + u) // // = cos(u) * cos(k*pi/128) - sin(u) * sin(k*pi/128) // let r = (cos_k_f128 * sin_cos.v_cos) + (msin_k_f128 * sin_cos.v_sin); // r.fast_as_f64() let r_sincos = sincos_eval_dd(y); // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). // So k is an integer and -pi / 256 <= y <= pi / 256. // Then sin(x) = sin((k * pi/128 + y) // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, cos_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, msin_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr.to_f64() } /// Cosine for double precision /// /// ULP 0.5 pub fn f_cos(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-26 if x_e < E_BIAS - 7 { // |x| < 2^-26 if x_e < E_BIAS - 27 { // Signed zeros. if x == 0.0 { return 1.0; } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. return 1.0 - min_normal_f64(); } k = 0; y = DoubleDouble::new(0.0, x); } else { // // Small range reduction. (y, k) = range_reduction_small(x); } } else { // Inf or NaN if x_e > 2 * E_BIAS { // cos(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. // k = argument_reduction.high_part(x); (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). // So k is an integer and -pi / 256 <= y <= pi / 256. // Then cos(x) = cos((k * pi/128 + y) // = cos(y) * cos(k*pi/128) - sin(y) * sin(k*pi/128) let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, cos_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, msin_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return rr.to_f64(); } cos_accurate(y, msin_k, cos_k) } #[cfg(test)] mod tests { use super::*; #[test] fn cos_test() { assert_eq!(f_cos(0.0), 1.0); assert_eq!(f_cos(1.0), 0.5403023058681398); assert_eq!(f_cos(-0.5), 0.8775825618903728); } #[test] fn sin_test() { assert_eq!(f_sin(2.8477476437362989E-306), 2.8477476437362989E-306); assert_eq!(f_sin(0.0), 0.0); assert_eq!(f_sin(1.0), 0.8414709848078965); assert_eq!(f_sin(-0.5), -0.479425538604203); } } pxfm-0.1.23/src/sin_cosf/argument_reduction.rs000064400000000000000000000311461046102023000175240ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::get_exponent_f32; use crate::common::f_fmla; #[derive(Debug, Copy, Clone)] pub(crate) struct ArgumentReducer { pub(crate) x: f64, pub(crate) x_abs: u32, } impl ArgumentReducer { // Return k and y, where // k = round(x * 32 / pi) and y = (x * 32 / pi) - k. #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] #[inline] pub(crate) fn reduce_small(self) -> (f64, i64) { /* Generated in SageMath: z = RealField(300)(32) / RealField(300).pi() n = 53 x_hi = RealField(n)(z) # convert to f64 x_mid = RealField(n)(z - RealField(300)(x_hi)) x_lo = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid)) print(double_to_hex(x_hi), ",") print(double_to_hex(x_mid), ",") print(double_to_hex(x_lo), ",") */ const THIRTYTWO_OVER_PI: [u64; 3] = [0x40245f306dc9c883, 0xbcc6b01ec5417056, 0xb966447e493ad4ce]; let kd = (self.x * f64::from_bits(THIRTYTWO_OVER_PI[0])).round(); let mut y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[0]), -kd); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[1]), y); (y, kd as i64) } // Return k and y, where // k = round(x * 32 / pi) and y = (x * 32 / pi) - k. #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] #[inline] pub(crate) fn reduce_small(self) -> (f64, i64) { /* Generated in SageMath: z = RealField(300)(32) / RealField(300).pi() n = 28 x_hi = RealField(n)(z) # convert to f64 x_mid = RealField(n)(z - RealField(300)(x_hi)) x_lo = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid)) print(double_to_hex(x_hi), ",") print(double_to_hex(x_mid), ",") print(double_to_hex(x_lo), ",") */ const THIRTYTWO_OVER_PI: [u64; 3] = [0x40245f306e000000, 0xbe3b1bbeae000000, 0x3c63f84eb0000000]; let prod = self.x * f64::from_bits(THIRTYTWO_OVER_PI[0]); let kd = prod.round(); let mut y = prod - kd; y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[1]), y); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[2]), y); (y, kd as i64) } // Return k and y, where // k = round(x * 32 / pi) and y = (x * 32 / pi) - k. #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] #[inline] pub(crate) fn reduce_large(self, exponent: i32) -> (f64, i64) { /* Generated in SageMath: z = RealField(300)(32) / RealField(300).pi() n = 53 x_hi = RealField(n)(z) # convert to f64 x_mid = RealField(n)(z - RealField(300)(x_hi)) x_lo = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid)) x_lo_2 = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo)) x_lo_3 = z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo) - RealField(300)(x_lo_2) print(double_to_hex(x_hi), ",") print(double_to_hex(x_mid), ",") print(double_to_hex(x_lo), ",") print(double_to_hex(x_lo_2), ",") print(double_to_hex(x_lo_3), ",") */ const THIRTYTWO_OVER_PI: [u64; 5] = [ 0x40245f306dc9c883, 0xbcc6b01ec5417056, 0xb966447e493ad4ce, 0x360e21c820ff28b2, 0xb29508510ea79237, ]; // 2^45 <= |x| < 2^99 if exponent < 99 { // - When x < 2^99, the full exact product of x * THIRTYTWO_OVER_PI[0] // contains at least one integral bit <= 2^5. // - When 2^45 <= |x| < 2^55, the lowest 6 unit bits are contained // in the last 12 bits of double(x * THIRTYTWO_OVER_PI[0]). // - When |x| >= 2^55, the LSB of double(x * THIRTYTWO_OVER_PI[0]) is at // least 2^6. let mut prod_hi = self.x * f64::from_bits(THIRTYTWO_OVER_PI[0]); prod_hi = f64::from_bits( prod_hi.to_bits() & (if exponent < 55 { 0xfffffffffffff000 } else { 0xffffffffffffffff }), ); // |x| < 2^55 let k_hi = prod_hi.round(); let truncated_prod = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[0]), -k_hi); let prod_lo = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[1]), truncated_prod); let k_lo = prod_lo.round(); let mut y = f_fmla( self.x, f64::from_bits(THIRTYTWO_OVER_PI[1]), truncated_prod - k_lo, ); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[2]), y); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[3]), y); return (y, k_lo as i64); } // - When x >= 2^110, the full exact product of x * THIRTYTWO_OVER_PI[0] does // not contain any of the lowest 6 unit bits, so we can ignore it completely. // - When 2^99 <= |x| < 2^110, the lowest 6 unit bits are contained // in the last 12 bits of double(x * THIRTYTWO_OVER_PI[1]). // - When |x| >= 2^110, the LSB of double(x * THIRTYTWO_OVER_PI[1]) is at // least 64. let mut prod_hi = self.x * f64::from_bits(THIRTYTWO_OVER_PI[1]); prod_hi = f64::from_bits( prod_hi.to_bits() & (if exponent < 110 { 0xfffffffffffff000 } else { 0xffffffffffffffff }), ); // |x| < 2^110 let k_hi = prod_hi.round(); let truncated_prod = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[1]), -k_hi); let prod_lo = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[2]), truncated_prod); let k_lo = prod_lo.round(); let mut y = f_fmla( self.x, f64::from_bits(THIRTYTWO_OVER_PI[2]), truncated_prod - k_lo, ); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[3]), y); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[4]), y); (y, k_lo as i64) } // Return k and y, where // k = round(x * 32 / pi) and y = (x * 32 / pi) - k. #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] #[inline] pub(crate) fn reduce_large(self, exponent: i32) -> (f64, i64) { // For large range, there are at most 2 parts of THIRTYTWO_OVER_PI_28 // contributing to the lowest 6 binary digits (k & 63). If the least // significant bit of x * the least significant bit of THIRTYTWO_OVER_PI_28[i] // >= 64, we can completely ignore THIRTYTWO_OVER_PI_28[i]. // Generated by SageMath: // z = RealField(300)(32) / RealField(300).pi() // n = 28 // x_hi = RealField(n)(z) # convert to f64 // x_mid = RealField(n)(z - RealField(300)(x_hi)) // x_lo = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid)) // x_lo_2 = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo)) // x_lo_3 = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo) - RealField(300)(x_lo_2)) // x_lo_4 = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo) - RealField(300)(x_lo_2) - RealField(300)(x_lo_3)) // x_lo_5 = RealField(n)(z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo) - RealField(300)(x_lo_2) - RealField(300)(x_lo_3) - RealField(300)(x_lo_4)) // x_lo_6 = (z - RealField(300)(x_hi) - RealField(300)(x_mid) - RealField(300)(x_lo) - RealField(300)(x_lo_2) - RealField(300)(x_lo_3) - RealField(300)(x_lo_4) - RealField(300)(x_lo_5)) // // // print(double_to_hex(x_hi), ",") // print(double_to_hex(x_mid), ",") // print(double_to_hex(x_lo), ",") // print(double_to_hex(x_lo_2), ",") // print(double_to_hex(x_lo_3), ",") // print(double_to_hex(x_lo_4), ",") // print(double_to_hex(x_lo_5), ",") // print(double_to_hex(x_lo_6), ",") static THIRTYTWO_OVER_PI: [u64; 8] = [ 0x40245f306e000000, 0xbe3b1bbeae000000, 0x3c63f84eb0000000, 0xba87056592000000, 0x38bc0db62a000000, 0xb6e4cd8778000000, 0xb51bef806c000000, 0x33363abdebbc561b, ]; let mut idx = 0; const FRACTION_LEN: i32 = 23; let x_lsb_exp_m4 = exponent - FRACTION_LEN; // Exponents of the least significant bits of the corresponding entries in // THIRTYTWO_OVER_PI_28. static THIRTYTWO_OVER_PI_28_LSB_EXP: [i32; 8] = [-24, -55, -81, -114, -143, -170, -200, -230]; // Skipping the first parts of 32/pi such that: // LSB of x * LSB of THIRTYTWO_OVER_PI_28[i] >= 32. while x_lsb_exp_m4 + THIRTYTWO_OVER_PI_28_LSB_EXP[idx] > 5 { idx += 1; } let prod_hi = self.x * f64::from_bits(THIRTYTWO_OVER_PI[idx]); // Get the integral part of x * THIRTYTWO_OVER_PI_28[idx] let k_hi = prod_hi.round(); // Get the fractional part of x * THIRTYTWO_OVER_PI_28[idx] let frac = prod_hi - k_hi; let prod_lo = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[idx + 1]), frac); let k_lo = prod_lo.round(); // Now y is the fractional parts. let mut y = prod_lo - k_lo; y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[idx + 2]), y); y = f_fmla(self.x, f64::from_bits(THIRTYTWO_OVER_PI[idx + 3]), y); (y, (k_hi as i64).wrapping_add(k_lo as i64)) } #[inline] pub(crate) fn reduce(self) -> (f64, i64) { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] const SMALL_PASS_BOUND: u32 = 0x5600_0000u32; #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] const SMALL_PASS_BOUND: u32 = 0x4a80_0000u32; if self.x_abs < SMALL_PASS_BOUND { // 2^45 self.reduce_small() } else { self.reduce_large(get_exponent_f32(f32::from_bits(self.x_abs))) } } } pxfm-0.1.23/src/sin_cosf/argument_reduction_pi.rs000064400000000000000000000050741046102023000202150ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; #[derive(Debug, Copy, Clone)] pub(crate) struct ArgumentReducerPi { pub(crate) x: f64, } impl ArgumentReducerPi { // Return k and y, where // k = round(x * 32 / pi) and y = (x * 32 / pi) - k. #[inline] pub(crate) fn reduce(self) -> (f64, i64) { let kd = (self.x * 32.).round(); let y = f_fmla(self.x, 32.0, -kd); (y, kd as i64) } // Return k and y, where // k = round(x * 2 / pi) and y = (x * 2 / pi) - k. #[inline] pub(crate) fn reduce_0p25(self) -> (f64, i64) { let kd = (self.x + self.x).round(); let y = f_fmla(kd, -0.5, self.x); (y, kd as i64) } // // // Return k and y, where // // k = round(x * 2 / pi) and y = (x * 2 / pi) - k. // #[inline] // pub(crate) fn reduce_0p10(self) -> (f64, i64) { // let kd = (self.x * 4.).round(); // let y = f_fmla(kd, -0.25, self.x); // (y, kd as i64) // } } pxfm-0.1.23/src/sin_cosf/cosf.rs000064400000000000000000000113271046102023000145570ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Computes cosine function /// /// ULP 0.5 /// #[inline] pub fn f_cosf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let x = f32::from_bits(x_abs); let xd = x as f64; // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000244141 if x_abs < 0x3980_0000u32 { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; return f_fmlaf(x, f32::from_bits(0xb3000000), 1.); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { return f_fmla(xd, f64::from_bits(0xbe60000000000000), 1.) as f32; } } // Cosine // Generated poly by Sollya: // f_cos_16 = cos(x); // // Q = fpminimax(f_cos_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); // See ./notes/cosf.sollya let x2 = xd * xd; let p = f_polyeval5( x2, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfdffffffffffcea), f64::from_bits(0x3fa55555553d611a), f64::from_bits(0xbf56c16b2e26561a), f64::from_bits(0x3ef9faa67b9da80b), ); return p as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // Formula: // cos(x) = cos((k + y)*pi/32) // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..63 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. // Combine the results with the sine of sum formula: // cos(x) = cos((k + y)*pi/32) // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) // = cosm1_y * cos_k + sin_y * sin_k // = (cosm1_y * cos_k + cos_k) + sin_y * sin_k let rs = sincosf_eval(xd, x_abs); f_fmla(rs.sin_y, -rs.sin_k, f_fmla(rs.cosm1_y, rs.cos_k, rs.cos_k)) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_cosf_test() { assert_eq!(f_cosf(0.0), 1.0); assert_eq!(f_cosf(std::f32::consts::PI), -1f32); assert_eq!(f_cosf(0.5), 0.87758255); assert_eq!(f_cosf(0.7), 0.7648422); assert_eq!(f_cosf(1.7), -0.12884454); assert!(f_cosf(f32::INFINITY).is_nan()); assert!(f_cosf(f32::NEG_INFINITY).is_nan()); assert!(f_cosf(f32::NAN).is_nan()); assert_eq!(f_cosf(0.0002480338), 0.9999999692396206); } } pxfm-0.1.23/src/sin_cosf/cosm1f.rs000064400000000000000000000102571046102023000150160ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval4; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Computes cos(x) - 1 /// /// ULP 0.5 pub fn f_cosm1f(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let x = f32::from_bits(x_abs); // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { let xd = x as f64; // |x| < 0.000244141 if x_abs < 0x3980_0000u32 { // Taylor expansion for small cos(x) - 1 ~ -x^2/2 + x^4/24 + O(x^6) let x_sqr = xd * xd; const R: f64 = 1. / 2.; return (-x_sqr * R) as f32; } // Cosine // Generated poly by Sollya: // Polynomial cos(x) - 1 = x^2 * P(x^2) // // d = [0.0000000000001, pi/16]; // f_cosm1 = cos(x) - 1; // Q = fpminimax(f_cosm1, [|2,4,6,8|], [|0, D...|], d); let x2 = xd * xd; let p = f_polyeval4( x2, f64::from_bits(0xbfe0000000000000), f64::from_bits(0x3fa55555554ed21a), f64::from_bits(0xbf56c16b981a61d0), f64::from_bits(0x3ef9fc205e761f45), ); return (p * x2) as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // cos(x) - 1 = -2*sin^2(x/2) // Hence we're computing sin using formula: // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. let x_abs = (x * 0.5).to_bits(); let xd = f32::from_bits(x_abs) as f64; let rs = sincosf_eval(xd, x_abs); let sin_x_over_2 = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)); let sin_sqr = sin_x_over_2 * sin_x_over_2; let cosm1x = -2. * sin_sqr; cosm1x as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_cosm1f_test() { assert_eq!(f_cosm1f(0.00015928394), -1.2685687e-8); assert_eq!(f_cosm1f(0.0), 0.0); assert_eq!(f_cosm1f(std::f32::consts::PI), -2.); assert_eq!(f_cosm1f(0.5), -0.122417435); assert_eq!(f_cosm1f(0.7), -0.2351578); assert_eq!(f_cosm1f(1.7), -1.1288445); assert!(f_cosm1f(f32::INFINITY).is_nan()); assert!(f_cosm1f(f32::NEG_INFINITY).is_nan()); assert!(f_cosm1f(f32::NAN).is_nan()); assert_eq!(f_cosm1f(0.0002480338), -3.076038e-8); } } pxfm-0.1.23/src/sin_cosf/cospif.rs000064400000000000000000000106431046102023000151100ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::polyeval::f_polyeval5; use crate::sin_cosf::argument_reduction_pi::ArgumentReducerPi; use crate::sin_cosf::sincosf_eval::{cospif_eval, sinpif_eval}; /// Computes cos(PI*x) /// /// Max ULP 0.5 #[inline] pub fn f_cospif(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let x = f32::from_bits(x_abs); let xd = x as f64; // |x| <= 1/16 if x_abs <= 0x3d80_0000u32 { // |x| < 0.00000009546391 if x_abs < 0x38a2_f984u32 { #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; return f_fmlaf(x, f32::from_bits(0xb3000000), 1.); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::common::f_fmla; return f_fmla(xd, f64::from_bits(0xbe60000000000000), 1.) as f32; } } // Cos(x*PI) // Generated poly by Sollya: // d = [0, 1/16]; // f_cos = cos(y*pi); // Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); // // See ./notes/cospif.sollya let x2 = xd * xd; let p = f_polyeval5( x2, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xc013bd3cc9be43f7), f64::from_bits(0x40103c1f08091fe0), f64::from_bits(0xbff55d3ba3d94835), f64::from_bits(0x3fce173c2a00e74e), ); return p as f32; } // Numbers greater or equal to 2^23 are always integers or NaN if x_abs >= 0x4b00_0000u32 { if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } if x_abs < 0x4b80_0000u32 { static CF: [f32; 2] = [1., -1.]; return CF[((x_abs & 0x1) != 0) as usize]; } return 1.; } // We're computing cos(y) after argument reduction then return valid value // based on quadrant let reducer = ArgumentReducerPi { x: x as f64 }; let (y, k) = reducer.reduce_0p25(); // Decide based on quadrant what kernel function to use (match k & 3 { 0 => cospif_eval(y), 1 => sinpif_eval(-y), 2 => -cospif_eval(y), _ => sinpif_eval(y), }) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_cospif() { assert_eq!(f_cospif(115.30706), -0.5696978); assert!(f_cospif(f32::INFINITY).is_nan()); } } pxfm-0.1.23/src/sin_cosf/cscf.rs000064400000000000000000000105731046102023000145450ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::{f_polyeval3, f_polyeval5}; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Cosecant ( 1 / sin(x) ) /// /// ULP 0.5 #[inline] pub fn f_cscf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000443633 if x_abs < 0x39e8_9769u32 { if x_abs == 0u32 { // For signed zeros. return if x.is_sign_negative() { f32::NEG_INFINITY } else { f32::INFINITY }; } let dx = x as f64; let c_term = 1. / dx; let x2 = dx * dx; // Maclaurin series // 1/x + x/6 + (7 x^3)/360 + (31 x^5)/15120 + O(x^7) let p = f_polyeval3( x2, f64::from_bits(0x3fc5555555555555), f64::from_bits(0x3f93e93e93e93e94), f64::from_bits(0x3f60b2463814bc5f), ); return f_fmla(dx, p, c_term) as f32; } let xsqr = xd * xd; /* Generated by Sollya: f = 1 / sin(x) - 1/x; d = [0.000443633; pi/16]; pf = fpminimax(f, [|1, 3, 5, 7, 9|], [|D...|], d, relative, floating); See ./notes/cscf.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x3fc5555555555562), f64::from_bits(0x3f93e93e93e730a3), f64::from_bits(0x3f60cbb77382ae6f), f64::from_bits(0x3f2b85bfd4188934), f64::from_bits(0x3ef697a32ebe822d), ); return f_fmla(xd, p, 1. / xd) as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // Formula: // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. let rs = sincosf_eval(xd, x_abs); (1. / f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k))) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_cscf_test() { assert_eq!(f_cscf(0.04915107), 20.353632); assert_eq!(f_cscf(0.5), 2.0858297); assert_eq!(f_cscf(0.07), 14.297387); assert_eq!(f_cscf(3.6171106e-5), 27646.375); assert_eq!(f_cscf(-5.535772e-10), -1806432800.0); assert_eq!(f_cscf(0.0), f32::INFINITY); assert_eq!(f_cscf(-0.0), f32::NEG_INFINITY); assert_eq!(f_cscf(-1.0854926e-19), -9.2124077e18); } } pxfm-0.1.23/src/sin_cosf/mod.rs000064400000000000000000000044121046102023000144010ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod argument_reduction; mod argument_reduction_pi; mod cosf; mod cosm1f; mod cospif; mod cscf; mod secf; mod sincf; mod sincosf; mod sincosf_eval; mod sincospif; mod sincpif; mod sinf; mod sinmxf; mod sinpif; pub(crate) use argument_reduction_pi::ArgumentReducerPi; pub use cosf::f_cosf; pub use cosm1f::f_cosm1f; pub use cospif::f_cospif; pub use cscf::f_cscf; pub use secf::f_secf; pub use sincf::f_sincf; pub use sincosf::f_sincosf; pub(crate) use sincosf_eval::{tanf_eval, tanpif_eval}; pub use sincospif::f_sincospif; pub use sincpif::f_sincpif; pub use sinf::f_sinf; pub use sinmxf::f_sinmxf; pub use sinpif::f_sinpif; pub(crate) use sinpif::fast_sinpif; pxfm-0.1.23/src/sin_cosf/secf.rs000064400000000000000000000120161046102023000145410ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval6; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Computes secant ( 1 / cos(x) ) /// /// Max found ULP 0.5 #[inline] pub fn f_secf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let x = f32::from_bits(x_abs); let xd = x as f64; // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000244141 if x_abs < 0x3980_0000u32 { // for such small interval just doing 2 first coefficients from taylor series // FMA availability is mandatory to perform it in f32 without upcasting to f64. #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; let x2 = x * x; return f_fmlaf(x2, f32::from_bits(0x3f000000), 1.); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let x2 = xd * xd; return f_fmla(x2, f64::from_bits(0x3fe0000000000000), 1.) as f32; } } // Secant // Generated poly by Sollya: // f = 1 / cos(x); // d = [0.000244141; pi/16]; // pf = fpminimax(f, [|0, 2, 4, 6, 8, 10|], [|1, D...|], d, relative, floating); // // See ./notes/secf.sollya let x2 = xd * xd; let p = f_polyeval6( x2, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x3fe000000001c0fb), f64::from_bits(0x3fcaaaaaa0b8a71b), f64::from_bits(0x3fb5b06437bc5a13), f64::from_bits(0x3fa192a33a9fca4f), f64::from_bits(0x3f8dde280c29af37), ); return p as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // Formula: // cos(x) = cos((k + y)*pi/32) // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..63 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. // Combine the results with the sine of sum formula: // cos(x) = cos((k + y)*pi/32) // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) // = cosm1_y * cos_k + sin_y * sin_k // = (cosm1_y * cos_k + cos_k) + sin_y * sin_k // then sec(x) = 1/cos(x) let rs = sincosf_eval(xd, x_abs); (1. / f_fmla(rs.sin_y, -rs.sin_k, f_fmla(rs.cosm1_y, rs.cos_k, rs.cos_k))) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_secf() { assert_eq!(f_secf(0.0), 1.0); assert_eq!(f_secf(0.5), 1.139494); assert_eq!(f_secf(-0.5), 1.139494); assert_eq!(f_secf(1.5), 14.136833); assert_eq!(f_secf(-1.5), 14.136833); assert!(f_secf(f32::INFINITY).is_nan()); assert!(f_secf(f32::NEG_INFINITY).is_nan()); assert!(f_secf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/sin_cosf/sincf.rs000064400000000000000000000102071046102023000147230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Computes sinc(x) /// /// Max found ULP 0.5 #[inline] pub fn f_sincf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000443633 if x_abs < 0x39e8_9769u32 { if x_abs == 0u32 { // For signed zeros. return 1.; } /* Generated by Sollya: f = sin(x) / x; d = [0.0; 0.000443633]; pf = fpminimax(f, [|0, 2|], [|1, D...|], d, relative, floating); See ./notes/sincf.sollya */ return f_fmla( xd * xd, f64::from_bits(0xbfc555555265f618), f64::from_bits(0x3ff0000000000000), ) as f32; } let xsqr = xd * xd; /* Generated by Sollya: f_sinpi_16 = sin(x)/x; Q = fpminimax(f_sinpi_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); See ./notes/sincosf.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfc55555555554c6), f64::from_bits(0x3f81111111085e65), f64::from_bits(0xbf2a019f70fb4d4f), f64::from_bits(0x3ec718d179815e74), ); return p as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // Formula: // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. let rs = sincosf_eval(xd, x_abs); let v_sin = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)); (v_sin / xd) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_sincf() { assert_eq!(f_sincf(-7.991783e37), -1.1754942946874968e-38); assert_eq!(f_sincf(-8.04695e37), 1.1754942974913884e-38); assert_eq!(f_sincf(-0.00044236073), 0.9999999673861641); assert_eq!(f_sincf(0.0), 1.0); assert_eq!(f_sincf(0.2), 0.99334663); assert!(f_sincf(f32::INFINITY).is_nan()); assert!(f_sincf(f32::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/sin_cosf/sincosf.rs000064400000000000000000000136401046102023000152710ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Sine and cosine /// /// Max found ULP on working range 0.49999967 #[inline] pub fn f_sincosf(x: f32) -> (f32, f32) { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000443633 if x_abs < 0x3980_0000u32 { if x_abs == 0u32 { // For signed zeros. return (x, 1.0); } #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; let sf = f_fmlaf(x, f32::from_bits(0xb3000000), x); let cf = f_fmlaf(f32::from_bits(x_abs), f32::from_bits(0xb3000000), 1.); return (sf, cf); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let sf = f_fmla(xd, f64::from_bits(0xbe60000000000000), xd) as f32; let cf = f_fmla(xd, f64::from_bits(0xbe60000000000000), 1.) as f32; return (sf, cf); } } let xsqr = xd * xd; /* Generated by Sollya: f_sinpi_16 = sin(x)/x; Q = fpminimax(f_sinpi_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); See ./notes/sincosf.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfc55555555554c6), f64::from_bits(0x3f81111111085e65), f64::from_bits(0xbf2a019f70fb4d4f), f64::from_bits(0x3ec718d179815e74), ); let sf = (xd * p) as f32; // Cosine // Generated poly by Sollya: // f_cos_16 = cos(x); // // Q = fpminimax(f_cos_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); let cf = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfdffffffffffcea), f64::from_bits(0x3fa55555553d611a), f64::from_bits(0xbf56c16b2e26561a), f64::from_bits(0x3ef9faa67b9da80b), ); return (sf, cf as f32); } if x_abs >= 0x7f80_0000u32 { return (x + f32::NAN, x + f32::NAN); } // Formula: // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. let rs = sincosf_eval(xd, x_abs); let sf = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)) as f32; let cf = f_fmla(rs.sin_y, -rs.sin_k, f_fmla(rs.cosm1_y, rs.cos_k, rs.cos_k)) as f32; (sf, cf) } #[cfg(test)] mod tests { use super::*; #[test] fn f_sincosf_test() { let sincos0 = f_sincosf(0.0); assert!(sincos0.0 < 1e-8); assert_eq!(sincos0.1, 1.0); let sincos_pi = f_sincosf(std::f32::consts::PI); assert!(sincos_pi.0 < 1e-8); let sincos_pi_0_5 = f_sincosf(0.5); assert_eq!(sincos_pi_0_5.0, 0.47942555); assert_eq!(sincos_pi_0_5.1, 0.87758255); let sincos_pi_n0_5 = f_sincosf(-0.5); assert_eq!(sincos_pi_n0_5.0, -0.47942555); assert_eq!(sincos_pi_n0_5.1, 0.87758255); let v_z = f_sincosf(0.0002480338); assert_eq!(v_z.1, 0.9999999692396206); } #[test] fn f_sincosf_edge_test() { let s0 = f_sincosf(f32::INFINITY); assert!(s0.0.is_nan()); assert!(s0.1.is_nan()); let s1 = f_sincosf(f32::NEG_INFINITY); assert!(s1.0.is_nan()); assert!(s1.1.is_nan()); let s2 = f_sincosf(f32::NAN); assert!(s2.0.is_nan()); assert!(s2.1.is_nan()); } } pxfm-0.1.23/src/sin_cosf/sincosf_eval.rs000064400000000000000000000256571046102023000163130ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::polyeval::{f_estrin_polyeval7, f_polyeval3, f_polyeval4, f_polyeval6}; use crate::sin_cosf::argument_reduction::ArgumentReducer; use crate::sin_cosf::argument_reduction_pi::ArgumentReducerPi; /** Generated in SageMath: ```text print("[") for k in range(64): k = RealField(150)(k) * RealField(150).pi() / RealField(150)(32) print(double_to_hex(k.sin()) + ",") print("];") ``` **/ static SIN_K_PI_OVER32: [u64; 64] = [ 0x0000000000000000, 0x3fb917a6bc29b42c, 0x3fc8f8b83c69a60b, 0x3fd294062ed59f06, 0x3fd87de2a6aea963, 0x3fde2b5d3806f63b, 0x3fe1c73b39ae68c8, 0x3fe44cf325091dd6, 0x3fe6a09e667f3bcd, 0x3fe8bc806b151741, 0x3fea9b66290ea1a3, 0x3fec38b2f180bdb1, 0x3fed906bcf328d46, 0x3fee9f4156c62dda, 0x3fef6297cff75cb0, 0x3fefd88da3d12526, 0x3ff0000000000000, 0x3fefd88da3d12526, 0x3fef6297cff75cb0, 0x3fee9f4156c62dda, 0x3fed906bcf328d46, 0x3fec38b2f180bdb1, 0x3fea9b66290ea1a3, 0x3fe8bc806b151741, 0x3fe6a09e667f3bcd, 0x3fe44cf325091dd6, 0x3fe1c73b39ae68c8, 0x3fde2b5d3806f63b, 0x3fd87de2a6aea963, 0x3fd294062ed59f06, 0x3fc8f8b83c69a60b, 0x3fb917a6bc29b42c, 0xb69f77598338bfdf, 0xbfb917a6bc29b42c, 0xbfc8f8b83c69a60b, 0xbfd294062ed59f06, 0xbfd87de2a6aea963, 0xbfde2b5d3806f63b, 0xbfe1c73b39ae68c8, 0xbfe44cf325091dd6, 0xbfe6a09e667f3bcd, 0xbfe8bc806b151741, 0xbfea9b66290ea1a3, 0xbfec38b2f180bdb1, 0xbfed906bcf328d46, 0xbfee9f4156c62dda, 0xbfef6297cff75cb0, 0xbfefd88da3d12526, 0xbff0000000000000, 0xbfefd88da3d12526, 0xbfef6297cff75cb0, 0xbfee9f4156c62dda, 0xbfed906bcf328d46, 0xbfec38b2f180bdb1, 0xbfea9b66290ea1a3, 0xbfe8bc806b151741, 0xbfe6a09e667f3bcd, 0xbfe44cf325091dd6, 0xbfe1c73b39ae68c8, 0xbfde2b5d3806f63b, 0xbfd87de2a6aea963, 0xbfd294062ed59f06, 0xbfc8f8b83c69a60b, 0xbfb917a6bc29b42c, ]; pub(crate) struct SinCosf { pub(crate) sin_k: f64, pub(crate) cos_k: f64, pub(crate) sin_y: f64, pub(crate) cosm1_y: f64, } pub(crate) struct TanfEval { pub(crate) msin_k: f64, pub(crate) cos_k: f64, pub(crate) tan_y: f64, } #[inline] pub(crate) fn sincosf_eval(x: f64, x_abs: u32) -> SinCosf { let argument_reduction = ArgumentReducer { x, x_abs }; let (y, k) = argument_reduction.reduce(); let y_sqr = y * y; // After range reduction, k = round(x * 32 / pi) and y = (x * 32 / pi) - k. // So k is an integer and -0.5 <= y <= 0.5. // Then sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) let sin_k = f64::from_bits(SIN_K_PI_OVER32[((k as u64) & 63) as usize]); // cos(k * pi/32) = sin(k * pi/32 + pi/2) = sin((k + 16) * pi/32). // cos_k = cos(k * pi/32) let cos_k = f64::from_bits(SIN_K_PI_OVER32[((k.wrapping_add(16) as u64) & 63) as usize]); // Degree-6 minimax even polynomial for sin(y*pi/32)/y generated by Sollya // with: // > Q = fpminimax(sin(y*pi/32)/y, [|0, 2, 4, 6|], [|D...|], [0, 0.5]); // // See ./notes/sincosf.sollya let sin_y = y * f_polyeval4( y_sqr, f64::from_bits(0x3fb921fb54442d18), f64::from_bits(0xbf24abbce625abb1), f64::from_bits(0x3e7466bc624f2776), f64::from_bits(0xbdb32c3a619d4a7e), ); // Degree-6 minimax even polynomial for cos(y*pi/32) generated by Sollya with: // > P = fpminimax(cos(x*pi/32), [|0, 2, 4, 6|], [|1, D...|], [0, 0.5]); // Note that cosm1_y = cos(y*pi/32) - 1. // // See ./notes/sincosf.sollya let cosm1_y = y_sqr * f_polyeval3( y_sqr, f64::from_bits(0xbf73bd3cc9be430b), f64::from_bits(0x3ed03c1f070c2e27), f64::from_bits(0xbe155cc84bd94200), ); SinCosf { sin_k, cos_k, sin_y, cosm1_y, } } #[inline] pub(crate) fn sincospif_eval(x: f64) -> SinCosf { let argument_reduction = ArgumentReducerPi { x }; let (y, k) = argument_reduction.reduce(); let y_sqr = y * y; // After range reduction, k = round(x * 32 / pi) and y = (x * 32 / pi) - k. // So k is an integer and -0.5 <= y <= 0.5. // Then sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) let sin_k = f64::from_bits(SIN_K_PI_OVER32[((k as u64) & 63) as usize]); // cos(k * pi/32) = sin(k * pi/32 + pi/2) = sin((k + 16) * pi/32). // cos_k = cos(k * pi/32) let cos_k = f64::from_bits(SIN_K_PI_OVER32[((k.wrapping_add(16) as u64) & 63) as usize]); // Degree-6 minimax even polynomial for sin(y*pi/32)/y generated by Sollya // with: // > Q = fpminimax(sin(y*pi/32)/y, [|0, 2, 4, 6|], [|D...|], [0, 0.5]); // // See ./notes/sincosf.sollya let sin_y = y * f_polyeval4( y_sqr, f64::from_bits(0x3fb921fb54442d18), f64::from_bits(0xbf24abbce625abb1), f64::from_bits(0x3e7466bc624f2776), f64::from_bits(0xbdb32c3a619d4a7e), ); // Degree-6 minimax even polynomial for cos(y*pi/32) generated by Sollya with: // > P = fpminimax(cos(x*pi/32), [|0, 2, 4, 6|], [|1, D...|], [0, 0.5]); // Note that cosm1_y = cos(y*pi/32) - 1. // // See ./notes/sincosf.sollya let cosm1_y = y_sqr * f_polyeval3( y_sqr, f64::from_bits(0xbf73bd3cc9be430b), f64::from_bits(0x3ed03c1f070c2e27), f64::from_bits(0xbe155cc84bd94200), ); SinCosf { sin_k, cos_k, sin_y, cosm1_y, } } #[inline] pub(crate) fn tanpif_eval(y: f64, k: i64) -> TanfEval { let y_sqr = y * y; // After range reduction, k = round(x * 32 / pi) and y = (x * 32 / pi) - k. // So k is an integer and -0.5 <= y <= 0.5. // picking minus sin and cos according to quadrant let msin_k = f64::from_bits(SIN_K_PI_OVER32[((k as u64).wrapping_add(32) & 63) as usize]); let cos_k = f64::from_bits(SIN_K_PI_OVER32[((k.wrapping_add(16) as u64) & 63) as usize]); // tan(x*pi/32) generated by Sollya: // d = [0, 0.5]; // f_tan = tan(y*pi/32)/y; // Q = fpminimax(f_tan, [|0, 2, 4, 6|], [|D...|], d, relative, floating); // See ./notes/tanpif.sollya let tan_y = f_polyeval4( y_sqr, f64::from_bits(0x3fb921fb54442cef), f64::from_bits(0x3f34abbce63a363e), f64::from_bits(0x3eb466baced705e8), f64::from_bits(0x3e346a33cde88184), ) * y; TanfEval { tan_y, msin_k, cos_k, } } #[inline] pub(crate) fn tanf_eval(x: f64, x_abs: u32) -> TanfEval { let (y, k) = ArgumentReducer { x, x_abs }.reduce(); let y_sqr = y * y; // After range reduction, k = round(x * 32 / pi) and y = (x * 32 / pi) - k. // So k is an integer and -0.5 <= y <= 0.5. // picking minus sin and cos according to quadrant let msin_k = f64::from_bits(SIN_K_PI_OVER32[((k as u64).wrapping_add(32) & 63) as usize]); let cos_k = f64::from_bits(SIN_K_PI_OVER32[((k.wrapping_add(16) as u64) & 63) as usize]); // tan(x*pi/32) generated by Sollya: // d = [0, 0.5]; // f_tan = tan(x*pi/32)/x; // Q = fpminimax(f_tan, [|0, 2, 4, 6|], [|D...|], d); // See ./notes/tanf.sollya let tan_y = f_polyeval4( y_sqr, f64::from_bits(0x3fb921fb54442cef), f64::from_bits(0x3f34abbce63a363e), f64::from_bits(0x3eb466baced705e8), f64::from_bits(0x3e346a33cde88184), ) * y; TanfEval { tan_y, msin_k, cos_k, } } /** Poly for sin(pi*y) on [-0.25; 0.25]. Generated by Sollya: ```text d = [0,0.25]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|D...|], d, relative, floating); ``` See ./notes/sinpif_0p25.sollya **/ #[inline] pub(crate) fn sinpif_eval(y: f64) -> f64 { let y2 = y * y; f_polyeval6( y2, f64::from_bits(0x400921fb54442cf8), f64::from_bits(0xc014abbce6257778), f64::from_bits(0x400466bc670fa464), f64::from_bits(0xbfe32d2c627f47da), f64::from_bits(0x3fb5071be0a2d3da), f64::from_bits(0xbf7dd4e0ae5b9fcd), ) * y } /** Poly for sin(pi*y) on [-0.25; 0.25]. Generated by Sollya: ```text d = [0,0.25]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10, 12|], [|D...|], d, relative, floating); ``` See ./notes/sinpif_0p25_2.sollya **/ #[inline] pub(crate) fn sinpif_eval2(y: f64) -> f64 { let y2 = y * y; f_estrin_polyeval7( y2, f64::from_bits(0x400921fb54442d18), f64::from_bits(0xc014abbce625be09), f64::from_bits(0x400466bc67754fff), f64::from_bits(0xbfe32d2ccdfe9424), f64::from_bits(0x3fb50782d5f14825), f64::from_bits(0xbf7e2fe76fdffd2b), f64::from_bits(0x3f3e357ef99eb0bb), ) * y } /** Poly for cos(pi*y) on [-0.25; 0.25]. Generated by Sollya: ```text d = [0, 0.25]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8, 10|], [|1, D...|], d, relative, floating); ``` See ./notes/cospif_0p25.sollya **/ #[inline] pub(crate) fn cospif_eval(y: f64) -> f64 { let y2 = y * y; f_estrin_polyeval7( y2, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xc013bd3cc9be459b), f64::from_bits(0x40103c1f081b0c98), f64::from_bits(0xbff55d3c7dc25308), f64::from_bits(0x3fce1f4fb6e12563), f64::from_bits(0xbf9a6c9c101c1182), f64::from_bits(0x3f5f3d9faffda250), ) } pxfm-0.1.23/src/sin_cosf/sincospif.rs000064400000000000000000000144141046102023000156220ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincospif_eval; /// Computes sin(x) and cos(x) at the same time /// /// Max ULP 0.5 #[inline] pub fn f_sincospif(x: f32) -> (f32, f32) { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= 1/16 if x_abs <= 0x3d80_0000u32 { // |x| < 0.00000009546391 if x_abs < 0x38a2_f984u32 { const PI: f64 = f64::from_bits(0x400921fb54442d18); const MPI_E3_OVER_6: f64 = f64::from_bits(0xc014abbce625be53); // Small values approximated with Taylor poly for sine // x = pi * x - pi^3*x^3/6 let x2 = xd * xd; let p = f_fmla(x2, MPI_E3_OVER_6, PI); let sf = (xd * p) as f32; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; let cs = f_fmlaf(x, f32::from_bits(0xb3000000), 1.); return (sf, cs); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let cs = f_fmla(xd, f64::from_bits(0xbe60000000000000), 1.) as f32; return (sf, cs); } } // Cos(x*PI) // Generated poly by Sollya: // d = [0, 1/16]; // f_cos = cos(y*pi); // Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); // // See ./notes/cospif.sollya let x2 = xd * xd; let cs = f_polyeval5( x2, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xc013bd3cc9be43f7), f64::from_bits(0x40103c1f08091fe0), f64::from_bits(0xbff55d3ba3d94835), f64::from_bits(0x3fce173c2a00e74e), ) as f32; /* Sin(x*PI) Generated by Sollya: d = [0, 1/16]; f_sin = sin(y*pi)/y; Q = fpminimax(sin(y*pi)/y, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); See ./notes/sinpif.sollya */ let p = f_polyeval5( x2, f64::from_bits(0x400921fb54442d18), f64::from_bits(0xc014abbce625bbf2), f64::from_bits(0x400466bc675e116a), f64::from_bits(0xbfe32d2c0b62d41c), f64::from_bits(0x3fb501ec4497cb7d), ); let sf = (xd * p) as f32; return (sf, cs); } // Numbers greater or equal to 2^23 are always integers or NaN if x_abs >= 0x4b00_0000u32 { if x_abs >= 0x7f80_0000u32 { return (x + f32::NAN, x + f32::NAN); } static SF: [f32; 2] = [0., -0.]; let sf = SF[x.is_sign_negative() as usize]; if x_abs < 0x4b80_0000u32 { static CF: [f32; 2] = [1., -1.]; let cs = CF[((x_abs & 0x1) != 0) as usize]; return (sf, cs); } return (sf, 1.); } // Formula: // cos(x) = cos((k + y)*pi/32) // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..63 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. // Combine the results with the sine of sum formula: // cos(x) = cos((k + y)*pi/32) // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) // = cosm1_y * cos_k + sin_y * sin_k // = (cosm1_y * cos_k + cos_k) + sin_y * sin_k // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) let rs = sincospif_eval(xd); let cs = f_fmla(rs.sin_y, -rs.sin_k, f_fmla(rs.cosm1_y, rs.cos_k, rs.cos_k)) as f32; let sf = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)) as f32; (sf, cs) } #[cfg(test)] mod tests { use super::*; use crate::{f_cospif, f_sinpif}; #[test] fn test_sincospif() { let v0 = f_sincospif(-8489897.0); assert_eq!(v0.0, f_sinpif(-8489897.0)); assert_eq!(v0.1, f_cospif(-8489897.0)); let v1 = f_sincospif(3.23); assert_eq!(v1.0, f_sinpif(3.23)); assert_eq!(v1.1, f_cospif(3.23)); } } pxfm-0.1.23/src/sin_cosf/sincpif.rs000064400000000000000000000077371046102023000152720ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincospif_eval; /// Computes sin(PI*x)/(PI*x) /// /// Produces normalized sinc. /// /// ulp 0.5 pub fn f_sincpif(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= 1/16 if x_abs <= 0x3d80_0000u32 { // |x| < 0.0000009546391 if x_abs < 0x3580_2126u32 { if x_abs == 0u32 { return 1.; } const M_SQR_PI_OVER_6: f64 = f64::from_bits(0xbffa51a6625307d3); // Small values approximated with Taylor poly // sincpi(x) ~ 1 - x^2*Pi^2/6 + O(x^4) let x2 = xd * xd; let p = f_fmla(x2, M_SQR_PI_OVER_6, 1.); return p as f32; } let xsqr = xd * xd; // Generated by Sollya: // d = [0, 1/16]; // f_sincpif = sin(y*pi)/(y*pi); // Q = fpminimax(f_sincpif, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); // See ./notes/sincpif.sollya let p = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbffa51a662530723), f64::from_bits(0x3fe9f9cb401e8e85), f64::from_bits(0xbfc86a8da89c9234), f64::from_bits(0x3f9ac0a16798157e), ); return p as f32; } // Numbers greater or equal to 2^23 are always integers or NaN // integers are always 0 if x_abs >= 0x4b00_0000u32 || x.floor() == x { if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } return if x.is_sign_negative() { -0. } else { 0. }; } const PI: f64 = f64::from_bits(0x400921fb54442d18); let rs = sincospif_eval(xd); let sf = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)); (sf / (PI * xd)) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_sincpif_eval() { assert_eq!(f_sincpif(1.0), 0.); assert_eq!(f_sincpif(2.0), 0.); assert_eq!(f_sincpif(3.0), 0.); assert_eq!(f_sincpif(0.0543242), 0.99515265); assert_eq!(f_sincpif(0.002134242), 0.9999925); assert_eq!(f_sincpif(0.00000005421321), 1.0); assert!(f_sincpif(f32::INFINITY).is_nan()); assert!(f_sincpif(f32::NEG_INFINITY).is_nan()); assert!(f_sincpif(f32::NAN).is_nan()); } } pxfm-0.1.23/src/sin_cosf/sinf.rs000064400000000000000000000111411046102023000145560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Sine function /// /// Max found ULP 0.5 #[inline] pub fn f_sinf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000443633 if x_abs < 0x39e8_9769u32 { if x_abs == 0u32 { // For signed zeros. return x; } #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; return f_fmlaf(x, f32::from_bits(0xb3000000), x); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { return f_fmla(xd, f64::from_bits(0xbe60000000000000), xd) as f32; } } let xsqr = xd * xd; /* Generated by Sollya: f_sinpi_16 = sin(x)/x; Q = fpminimax(f_sinpi_16, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); See ./notes/sinf.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfc55555555554c6), f64::from_bits(0x3f81111111085e65), f64::from_bits(0xbf2a019f70fb4d4f), f64::from_bits(0x3ec718d179815e74), ); return (xd * p) as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // Formula: // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. let rs = sincosf_eval(xd, x_abs); f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_sinf_test() { assert_eq!(f_sinf(0.0), 0.0); assert_eq!(f_sinf(1.0), 0.84147096); assert_eq!(f_sinf(0.3), 0.29552022); assert_eq!(f_sinf(-1.0), -0.84147096); assert_eq!(f_sinf(-0.3), -0.29552022); assert_eq!(f_sinf(std::f32::consts::PI / 2.), 1.); assert!(f_sinf(f32::INFINITY).is_nan()); assert!(f_sinf(f32::NEG_INFINITY).is_nan()); assert!((f_sinf(std::f32::consts::PI) - 0f32).abs() < 1e-6); assert!((f_sinf(std::f32::consts::FRAC_PI_2) - 1f32).abs() < 1e-6); } } pxfm-0.1.23/src/sin_cosf/sinmxf.rs000064400000000000000000000103021046102023000151210ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::sincosf_eval::sincosf_eval; /// Computes sin(x) - x pub fn f_sinmxf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; let ax: u32 = x.to_bits().wrapping_shl(1); if ax == 0 || ax >= 0xffu32 << 24 { if x_abs == 0u32 { // For signed zeros. return x; } if x.is_infinite() || x.is_nan() { return f32::NAN; } } // |x| <= pi/16 if x_abs <= 0x3e49_0fdbu32 { // |x| < 0.000443633 if x_abs < 0x39e8_9769u32 { // sin(x) - x ~ -x^3/6 + x^5/120 + O(x^7) let dx = x as f64; let x2 = dx * dx; let c = f_fmla( x2, f64::from_bits(0x3f81111111111111), f64::from_bits(0xbfc5555555555555), ) * x2; return (c * dx) as f32; } let xsqr = xd * xd; // Generated by Sollya: // d = [2^-10, pi/16]; // f_sinmx = (sin(x) - x)/x; // Q = fpminimax(f_sinmx, [|0, 2, 4, 6, 8|], [|D...|], d); // See ./notes/sinmxf.sollya let p = f_polyeval5( xsqr, f64::from_bits(0xbb8f6a339382f07f), f64::from_bits(0xbfc5555555555545), f64::from_bits(0x3f811111110ddf5c), f64::from_bits(0xbf2a019fb330c620), f64::from_bits(0x3ec719bc2a614884), ); return (xd * p) as f32; } // Formula: // sin(x) = sin((k + y)*pi/32) // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are // computed using degree-7 and degree-6 minimax polynomials generated by // Sollya respectively. let rs = sincosf_eval(xd, x_abs); let sinx = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k)); (sinx - xd) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_sinf_test() { assert_eq!(f_sinmxf(0.00016344387), -0.00000000000072770376); assert_eq!(f_sinmxf(0.0), 0.0); assert_eq!(f_sinmxf(1.0), -0.15852901); assert_eq!(f_sinmxf(0.3), -0.004479794); assert_eq!(f_sinmxf(-1.0), 0.15852901); assert_eq!(f_sinmxf(-0.3), 0.004479794); assert_eq!(f_sinmxf(std::f32::consts::PI / 2.), -0.5707964); assert!(f_sinmxf(f32::INFINITY).is_nan()); assert!(f_sinmxf(f32::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/sin_cosf/sinpif.rs000064400000000000000000000134151046102023000151150ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::argument_reduction_pi::ArgumentReducerPi; use crate::sin_cosf::sincosf_eval::{cospif_eval, sinpif_eval, sinpif_eval2}; /// Computes sin(PI*x) /// /// Max ULP 0.5 #[inline] pub fn f_sinpif(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= 1/16 if x_abs <= 0x3d80_0000u32 { // |x| < 0.0000009546391 if x_abs < 0x3580_2126u32 { if x_abs == 0u32 { // For signed zeros. return x; } const PI: f64 = f64::from_bits(0x400921fb54442d18); const MPI_E3_OVER_6: f64 = f64::from_bits(0xc014abbce625be53); // Small values approximated with Taylor poly // x = pi * x - pi^3*x^3/6 let x2 = xd * xd; let p = f_fmla(x2, MPI_E3_OVER_6, PI); return (xd * p) as f32; } let xsqr = xd * xd; /* Generated by Sollya: d = [0, 1/16]; f_sin = sin(y*pi)/y; Q = fpminimax(sin(y*pi)/y, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); See ./notes/sinpif.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x400921fb54442d18), f64::from_bits(0xc014abbce625bbf2), f64::from_bits(0x400466bc675e116a), f64::from_bits(0xbfe32d2c0b62d41c), f64::from_bits(0x3fb501ec4497cb7d), ); return (xd * p) as f32; } // Numbers greater or equal to 2^23 are always integers or NaN if x_abs >= 0x4b00_0000u32 { if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } return if x.is_sign_negative() { -0. } else { 0. }; } // We're computing sin(y) after argument reduction then return valid value // based on quadrant let reducer = ArgumentReducerPi { x: x as f64 }; let (y, k) = reducer.reduce_0p25(); // Decide based on quadrant what kernel function to use (match k & 3 { 0 => sinpif_eval(y), 1 => cospif_eval(y), 2 => sinpif_eval(-y), _ => -cospif_eval(y), }) as f32 } pub(crate) fn fast_sinpif(x: f32) -> f64 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| <= 1/16 if x_abs <= 0x3d80_0000u32 { // |x| < 0.0000009546391 if x_abs < 0x3580_2126u32 { if x_abs == 0u32 { // For signed zeros. return x as f64; } const PI: f64 = f64::from_bits(0x400921fb54442d18); const MPI_E3_OVER_6: f64 = f64::from_bits(0xc014abbce625be53); // Small values approximated with Taylor poly // x = pi * x - pi^3*x^3/6 let x2 = xd * xd; let p = f_fmla(x2, MPI_E3_OVER_6, PI); return xd * p; } let xsqr = xd * xd; /* Generated by Sollya: d = [0, 1/16]; f_sin = sin(y*pi)/y; Q = fpminimax(sin(y*pi)/y, [|0, 2, 4, 6, 8|], [|D...|], d, relative, floating); See ./notes/sinpif.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x400921fb54442d18), f64::from_bits(0xc014abbce625bbf2), f64::from_bits(0x400466bc675e116a), f64::from_bits(0xbfe32d2c0b62d41c), f64::from_bits(0x3fb501ec4497cb7d), ); return xd * p; } let reducer = ArgumentReducerPi { x: x as f64 }; let (y, k) = reducer.reduce_0p25(); // Decide based on quadrant what kernel function to use match k & 3 { 0 => sinpif_eval2(y), 1 => cospif_eval(y), 2 => sinpif_eval2(-y), _ => -cospif_eval(y), } } #[cfg(test)] mod tests { use super::*; #[test] fn test_f_sinpif() { assert_eq!(f_sinpif(1.12199515e-7), 3.524852e-7); assert_eq!(f_sinpif(-0.31706), -0.83934295); assert_eq!(f_sinpif(0.30706), 0.8218538); assert_eq!(f_sinpif(115.30706), -0.82185423); assert!(f_sinpif(f32::INFINITY).is_nan()); assert!(f_sinpif(f32::NEG_INFINITY).is_nan()); assert!(f_sinpif(f32::NAN).is_nan()); } } pxfm-0.1.23/src/sin_helper.rs000064400000000000000000000315271046102023000141560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dyad_fmla, min_normal_f64}; use crate::double_double::DoubleDouble; use crate::dyadic_float::DyadicFloat128; use crate::sin::{SinCos, get_sin_k_rational, range_reduction_small, sincos_eval}; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::{range_reduction_small_f128_f128, sincos_eval_dyadic}; #[inline] fn sin_eval_dd(z: DoubleDouble) -> DoubleDouble { const SIN_C: [(u64, u64); 5] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc65555555555555, 0xbfc5555555555555), (0x3c01111111111111, 0x3f81111111111111), (0xbb6a01a01a01a01a, 0xbf2a01a01a01a01a), (0xbb6c154f8ddc6c00, 0x3ec71de3a556c734), ]; let x2 = DoubleDouble::quick_mult(z, z); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(SIN_C[4]), DoubleDouble::from_bit_pair(SIN_C[3]), ); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(SIN_C[2])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(SIN_C[1])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(SIN_C[0])); DoubleDouble::quick_mult(p, z) } pub(crate) fn sin_dd_small(z: DoubleDouble) -> DoubleDouble { let x_e = (z.hi.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 8 { return sin_eval_dd(z); } let (u_f128, k) = range_reduction_small_dd(z); let sin_cos = sincos_eval_dd(u_f128); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(sin_cos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos.v_sin, cos_k); let mut rr = DoubleDouble::from_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr } pub(crate) fn sin_dd_small_fast(z: DoubleDouble) -> DoubleDouble { let x_e = (z.hi.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 8 { return sin_eval_dd(z); } let (u_f128, k) = range_reduction_small_dd(z); let sin_cos = sincos_eval(u_f128); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(sin_cos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos.v_sin, cos_k); let mut rr = DoubleDouble::from_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr } #[inline] fn cos_eval_dd(z: DoubleDouble) -> DoubleDouble { let x2 = DoubleDouble::quick_mult(z, z); const COS_C: [(u64, u64); 5] = [ (0x0000000000000000, 0x3ff0000000000000), (0x0000000000000000, 0xbfe0000000000000), (0x3c45555555555555, 0x3fa5555555555555), (0x3bef49f49f49f49f, 0xbf56c16c16c16c17), (0x3b3a01a01a01a01a, 0x3efa01a01a01a01a), ]; let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(COS_C[4]), DoubleDouble::from_bit_pair(COS_C[3]), ); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(COS_C[2])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(COS_C[1])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(COS_C[0])); p } pub(crate) fn cos_dd_small(z: DoubleDouble) -> DoubleDouble { let x_e = (z.hi.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 8 { return cos_eval_dd(z); } let (u_f128, k) = range_reduction_small_dd(z); let sin_cos = sincos_eval_dd(u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(sin_cos.v_cos, cos_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos.v_sin, msin_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr } pub(crate) fn cos_dd_small_fast(z: DoubleDouble) -> DoubleDouble { let x_e = (z.hi.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 8 { return cos_eval_dd(z); } let (u_f128, k) = range_reduction_small_dd(z); let sin_cos = sincos_eval(u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(sin_cos.v_cos, cos_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos.v_sin, msin_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr } pub(crate) fn sin_f128_small(z: DyadicFloat128) -> DyadicFloat128 { let (u_f128, k) = range_reduction_small_f128_f128(z); let sin_cos = sincos_eval_dyadic(&u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sin_k_f128 = get_sin_k_rational(k as u64); let cos_k_f128 = get_sin_k_rational((k as u64).wrapping_add(64)); // sin(x) = sin(k * pi/128 + u) // = sin(u) * cos(k*pi/128) + cos(u) * sin(k*pi/128) (sin_k_f128 * sin_cos.v_cos) + (cos_k_f128 * sin_cos.v_sin) } pub(crate) fn cos_f128_small(z: DyadicFloat128) -> DyadicFloat128 { let (u_f128, k) = range_reduction_small_f128_f128(z); let sin_cos = sincos_eval_dyadic(&u_f128); // -sin(k * pi/128) = sin((k + 128) * pi/128) // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let msin_k_f128 = get_sin_k_rational((k as u64).wrapping_add(128)); let cos_k_f128 = get_sin_k_rational((k as u64).wrapping_add(64)); // cos(x) = cos((k * pi/128 + u) // = cos(u) * cos(k*pi/128) - sin(u) * sin(k*pi/128) (cos_k_f128 * sin_cos.v_cos) + (msin_k_f128 * sin_cos.v_sin) } #[inline] pub(crate) fn sin_small(z: f64) -> f64 { let x_e = (z.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 26 { return dyad_fmla(z, f64::from_bits(0xbc90000000000000), z); } let (angle_dd, k) = range_reduction_small(z); let sin_cos = sincos_eval(angle_dd); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(sin_cos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr.to_f64() } #[inline] pub(crate) fn cos_small(z: f64) -> f64 { let x_e = (z.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; if x_e < E_BIAS - 27 { // Signed zeros. if z == 0.0 { return 1.0; } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. return 1.0 - min_normal_f64(); } let (u_f128, k) = range_reduction_small(z); let sin_cos = sincos_eval(u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(sin_cos.v_cos, cos_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos.v_sin, msin_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr.to_f64() } #[inline] pub(crate) fn sincos_eval_dd(u: DoubleDouble) -> SinCos { const SIN_C: [(u64, u64); 5] = [ (0x0000000000000000, 0x3ff0000000000000), (0xbc65555555555555, 0xbfc5555555555555), (0x3c01111111111111, 0x3f81111111111111), (0xbb6a01a01a01a01a, 0xbf2a01a01a01a01a), (0xbb6c154f8ddc6c00, 0x3ec71de3a556c734), ]; let x2 = DoubleDouble::quick_mult(u, u); let mut p = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(SIN_C[4]), DoubleDouble::from_bit_pair(SIN_C[3]), ); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(SIN_C[2])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(SIN_C[1])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(SIN_C[0])); let sin_u = DoubleDouble::quick_mult(p, u); const COS_C: [(u64, u64); 5] = [ (0x0000000000000000, 0x3ff0000000000000), (0x0000000000000000, 0xbfe0000000000000), (0x3c45555555555555, 0x3fa5555555555555), (0x3bef49f49f49f49f, 0xbf56c16c16c16c17), (0x3b3a01a01a01a01a, 0x3efa01a01a01a01a), ]; let mut p = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(COS_C[4]), DoubleDouble::from_bit_pair(COS_C[3]), ); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(COS_C[2])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(COS_C[1])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(COS_C[0])); let cos_u = p; SinCos { v_sin: sin_u, v_cos: cos_u, err: 0., } } #[inline] pub(crate) fn range_reduction_small_dd(x: DoubleDouble) -> (DoubleDouble, i64) { const MPI_OVER_128: [u64; 5] = [ 0xbf9921fb54400000, 0xbd70b4611a600000, 0xbb43198a2e000000, 0xb91b839a25200000, 0xb6b2704453400000, ]; const ONE_TWENTY_EIGHT_OVER_PI_D: f64 = f64::from_bits(0x40445f306dc9c883); let prod_hi = DoubleDouble::quick_mult_f64(x, ONE_TWENTY_EIGHT_OVER_PI_D); let kd = prod_hi.to_f64().round(); let p_hi = f64::from_bits(MPI_OVER_128[0]); // hi let p_mid = f64::from_bits(MPI_OVER_128[1]); // mid let p_lo = f64::from_bits(MPI_OVER_128[2]); // lo let p_lo_lo = f64::from_bits(MPI_OVER_128[3]); // lo_lo let mut q = DoubleDouble::f64_mul_f64_add(kd, p_hi, x); q = DoubleDouble::f64_mul_f64_add(kd, p_mid, q); q = DoubleDouble::f64_mul_f64_add(kd, p_lo, q); q = DoubleDouble::f64_mul_f64_add(kd, p_lo_lo, q); (q, kd as i64) } pxfm-0.1.23/src/sin_table.rs000064400000000000000000000322631046102023000137640ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ pub(crate) static SIN_K_PI_OVER_128: [(u64, u64); 256] = [ (0x0000000000000000, 0x0000000000000000), (0xbbfb1d63091a0130, 0x3f992155f7a3667e), (0xbc2912bd0d569a90, 0x3fa91f65f10dd814), (0xbc49a088a8bf6b2c, 0x3fb2d52092ce19f6), (0xbc3e2718d26ed688, 0x3fb917a6bc29b42c), (0x3c4a2704729ae56d, 0x3fbf564e56a9730e), (0x3c513000a89a11e0, 0x3fc2c8106e8e613a), (0x3c6531ff779ddac6, 0x3fc5e214448b3fc6), (0xbc626d19b9ff8d82, 0x3fc8f8b83c69a60b), (0xbc1af1439e521935, 0x3fcc0b826a7e4f63), (0xbc642deef11da2c4, 0x3fcf19f97b215f1b), (0x3c7824c20ab7aa9a, 0x3fd111d262b1f677), (0xbc75d28da2c4612d, 0x3fd294062ed59f06), (0x3c70c97c4afa2518, 0x3fd4135c94176601), (0xbc1efdc0d58cf620, 0x3fd58f9a75ab1fdd), (0xbc744b19e0864c5d, 0x3fd7088530fa459f), (0xbc672cedd3d5a610, 0x3fd87de2a6aea963), (0x3c66da81290bdbab, 0x3fd9ef7943a8ed8a), (0x3c65b362cb974183, 0x3fdb5d1009e15cc0), (0x3c56850e59c37f8f, 0x3fdcc66e9931c45e), (0x3c5e0d891d3c6841, 0x3fde2b5d3806f63b), (0xbc32ec1fc1b776b8, 0x3fdf8ba4dbf89aba), (0xbc8a5a014347406c, 0x3fe073879922ffee), (0xbc8ef23b69abe4f1, 0x3fe11eb3541b4b23), (0x3c8b25dd267f6600, 0x3fe1c73b39ae68c8), (0xbc85da743ef3770c, 0x3fe26d054cdd12df), (0xbc6efcc626f74a6f, 0x3fe30ff7fce17035), (0x3c7e3e25e3954964, 0x3fe3affa292050b9), (0x3c68076a2cfdc6b3, 0x3fe44cf325091dd6), (0x3c63c293edceb327, 0x3fe4e6cabbe3e5e9), (0xbc875720992bfbb2, 0x3fe57d69348ceca0), (0xbc7251b352ff2a37, 0x3fe610b7551d2cdf), (0xbc8bdd3413b26456, 0x3fe6a09e667f3bcd), (0x3c80d4ef0f1d915c, 0x3fe72d0837efff96), (0xbc70f537acdf0ad7, 0x3fe7b5df226aafaf), (0xbc76f420f8ea3475, 0x3fe83b0e0bff976e), (0xbc82c5e12ed1336d, 0x3fe8bc806b151741), (0x3c83d419a920df0b, 0x3fe93a22499263fb), (0xbc830ee286712474, 0x3fe9b3e047f38741), (0xbc7128bb015df175, 0x3fea29a7a0462782), (0x3c39f630e8b6dac8, 0x3fea9b66290ea1a3), (0xbc8926da300ffcce, 0x3feb090a58150200), (0xbc8bc69f324e6d61, 0x3feb728345196e3e), (0xbc8825a732ac700a, 0x3febd7c0ac6f952a), (0xbc76e0b1757c8d07, 0x3fec38b2f180bdb1), (0xbc52fb761e946603, 0x3fec954b213411f5), (0xbc5e7b6bb5ab58ae, 0x3feced7af43cc773), (0xbc84ef5295d25af2, 0x3fed4134d14dc93a), (0x3c7457e610231ac2, 0x3fed906bcf328d46), (0x3c883c37c6107db3, 0x3feddb13b6ccc23c), (0xbc8014c76c126527, 0x3fee212104f686e5), (0xbc616b56f2847754, 0x3fee6288ec48e112), (0x3c8760b1e2e3f81e, 0x3fee9f4156c62dda), (0x3c7e82c791f59cc2, 0x3feed740e7684963), (0x3c752c7adc6b4989, 0x3fef0a7efb9230d7), (0xbc7d7bafb51f72e6, 0x3fef38f3ac64e589), (0x3c7562172a361fd3, 0x3fef6297cff75cb0), (0x3c7ab256778ffcb6, 0x3fef8764fa714ba9), (0xbc87a0a8ca13571f, 0x3fefa7557f08a517), (0x3c81ec8668ecacee, 0x3fefc26470e19fd3), (0xbc887df6378811c7, 0x3fefd88da3d12526), (0x3c6521ecd0c67e35, 0x3fefe9cdad01883a), (0xbc6c57bc2e24aa15, 0x3feff621e3796d7e), (0xbc81354d4556e4cb, 0x3feffd886084cd0d), (0x0000000000000000, 0x3ff0000000000000), (0xbc81354d4556e4cb, 0x3feffd886084cd0d), (0xbc6c57bc2e24aa15, 0x3feff621e3796d7e), (0x3c6521ecd0c67e35, 0x3fefe9cdad01883a), (0xbc887df6378811c7, 0x3fefd88da3d12526), (0x3c81ec8668ecacee, 0x3fefc26470e19fd3), (0xbc87a0a8ca13571f, 0x3fefa7557f08a517), (0x3c7ab256778ffcb6, 0x3fef8764fa714ba9), (0x3c7562172a361fd3, 0x3fef6297cff75cb0), (0xbc7d7bafb51f72e6, 0x3fef38f3ac64e589), (0x3c752c7adc6b4989, 0x3fef0a7efb9230d7), (0x3c7e82c791f59cc2, 0x3feed740e7684963), (0x3c8760b1e2e3f81e, 0x3fee9f4156c62dda), (0xbc616b56f2847754, 0x3fee6288ec48e112), (0xbc8014c76c126527, 0x3fee212104f686e5), (0x3c883c37c6107db3, 0x3feddb13b6ccc23c), (0x3c7457e610231ac2, 0x3fed906bcf328d46), (0xbc84ef5295d25af2, 0x3fed4134d14dc93a), (0xbc5e7b6bb5ab58ae, 0x3feced7af43cc773), (0xbc52fb761e946603, 0x3fec954b213411f5), (0xbc76e0b1757c8d07, 0x3fec38b2f180bdb1), (0xbc8825a732ac700a, 0x3febd7c0ac6f952a), (0xbc8bc69f324e6d61, 0x3feb728345196e3e), (0xbc8926da300ffcce, 0x3feb090a58150200), (0x3c39f630e8b6dac8, 0x3fea9b66290ea1a3), (0xbc7128bb015df175, 0x3fea29a7a0462782), (0xbc830ee286712474, 0x3fe9b3e047f38741), (0x3c83d419a920df0b, 0x3fe93a22499263fb), (0xbc82c5e12ed1336d, 0x3fe8bc806b151741), (0xbc76f420f8ea3475, 0x3fe83b0e0bff976e), (0xbc70f537acdf0ad7, 0x3fe7b5df226aafaf), (0x3c80d4ef0f1d915c, 0x3fe72d0837efff96), (0xbc8bdd3413b26456, 0x3fe6a09e667f3bcd), (0xbc7251b352ff2a37, 0x3fe610b7551d2cdf), (0xbc875720992bfbb2, 0x3fe57d69348ceca0), (0x3c63c293edceb327, 0x3fe4e6cabbe3e5e9), (0x3c68076a2cfdc6b3, 0x3fe44cf325091dd6), (0x3c7e3e25e3954964, 0x3fe3affa292050b9), (0xbc6efcc626f74a6f, 0x3fe30ff7fce17035), (0xbc85da743ef3770c, 0x3fe26d054cdd12df), (0x3c8b25dd267f6600, 0x3fe1c73b39ae68c8), (0xbc8ef23b69abe4f1, 0x3fe11eb3541b4b23), (0xbc8a5a014347406c, 0x3fe073879922ffee), (0xbc32ec1fc1b776b8, 0x3fdf8ba4dbf89aba), (0x3c5e0d891d3c6841, 0x3fde2b5d3806f63b), (0x3c56850e59c37f8f, 0x3fdcc66e9931c45e), (0x3c65b362cb974183, 0x3fdb5d1009e15cc0), (0x3c66da81290bdbab, 0x3fd9ef7943a8ed8a), (0xbc672cedd3d5a610, 0x3fd87de2a6aea963), (0xbc744b19e0864c5d, 0x3fd7088530fa459f), (0xbc1efdc0d58cf620, 0x3fd58f9a75ab1fdd), (0x3c70c97c4afa2518, 0x3fd4135c94176601), (0xbc75d28da2c4612d, 0x3fd294062ed59f06), (0x3c7824c20ab7aa9a, 0x3fd111d262b1f677), (0xbc642deef11da2c4, 0x3fcf19f97b215f1b), (0xbc1af1439e521935, 0x3fcc0b826a7e4f63), (0xbc626d19b9ff8d82, 0x3fc8f8b83c69a60b), (0x3c6531ff779ddac6, 0x3fc5e214448b3fc6), (0x3c513000a89a11e0, 0x3fc2c8106e8e613a), (0x3c4a2704729ae56d, 0x3fbf564e56a9730e), (0xbc3e2718d26ed688, 0x3fb917a6bc29b42c), (0xbc49a088a8bf6b2c, 0x3fb2d52092ce19f6), (0xbc2912bd0d569a90, 0x3fa91f65f10dd814), (0xbbfb1d63091a0130, 0x3f992155f7a3667e), (0x0000000000000000, 0x0000000000000000), (0x3bfb1d63091a0130, 0xbf992155f7a3667e), (0x3c2912bd0d569a90, 0xbfa91f65f10dd814), (0x3c49a088a8bf6b2c, 0xbfb2d52092ce19f6), (0x3c3e2718d26ed688, 0xbfb917a6bc29b42c), (0xbc4a2704729ae56d, 0xbfbf564e56a9730e), (0xbc513000a89a11e0, 0xbfc2c8106e8e613a), (0xbc6531ff779ddac6, 0xbfc5e214448b3fc6), (0x3c626d19b9ff8d82, 0xbfc8f8b83c69a60b), (0x3c1af1439e521935, 0xbfcc0b826a7e4f63), (0x3c642deef11da2c4, 0xbfcf19f97b215f1b), (0xbc7824c20ab7aa9a, 0xbfd111d262b1f677), (0x3c75d28da2c4612d, 0xbfd294062ed59f06), (0xbc70c97c4afa2518, 0xbfd4135c94176601), (0x3c1efdc0d58cf620, 0xbfd58f9a75ab1fdd), (0x3c744b19e0864c5d, 0xbfd7088530fa459f), (0x3c672cedd3d5a610, 0xbfd87de2a6aea963), (0xbc66da81290bdbab, 0xbfd9ef7943a8ed8a), (0xbc65b362cb974183, 0xbfdb5d1009e15cc0), (0xbc56850e59c37f8f, 0xbfdcc66e9931c45e), (0xbc5e0d891d3c6841, 0xbfde2b5d3806f63b), (0x3c32ec1fc1b776b8, 0xbfdf8ba4dbf89aba), (0x3c8a5a014347406c, 0xbfe073879922ffee), (0x3c8ef23b69abe4f1, 0xbfe11eb3541b4b23), (0xbc8b25dd267f6600, 0xbfe1c73b39ae68c8), (0x3c85da743ef3770c, 0xbfe26d054cdd12df), (0x3c6efcc626f74a6f, 0xbfe30ff7fce17035), (0xbc7e3e25e3954964, 0xbfe3affa292050b9), (0xbc68076a2cfdc6b3, 0xbfe44cf325091dd6), (0xbc63c293edceb327, 0xbfe4e6cabbe3e5e9), (0x3c875720992bfbb2, 0xbfe57d69348ceca0), (0x3c7251b352ff2a37, 0xbfe610b7551d2cdf), (0x3c8bdd3413b26456, 0xbfe6a09e667f3bcd), (0xbc80d4ef0f1d915c, 0xbfe72d0837efff96), (0x3c70f537acdf0ad7, 0xbfe7b5df226aafaf), (0x3c76f420f8ea3475, 0xbfe83b0e0bff976e), (0x3c82c5e12ed1336d, 0xbfe8bc806b151741), (0xbc83d419a920df0b, 0xbfe93a22499263fb), (0x3c830ee286712474, 0xbfe9b3e047f38741), (0x3c7128bb015df175, 0xbfea29a7a0462782), (0xbc39f630e8b6dac8, 0xbfea9b66290ea1a3), (0x3c8926da300ffcce, 0xbfeb090a58150200), (0x3c8bc69f324e6d61, 0xbfeb728345196e3e), (0x3c8825a732ac700a, 0xbfebd7c0ac6f952a), (0x3c76e0b1757c8d07, 0xbfec38b2f180bdb1), (0x3c52fb761e946603, 0xbfec954b213411f5), (0x3c5e7b6bb5ab58ae, 0xbfeced7af43cc773), (0x3c84ef5295d25af2, 0xbfed4134d14dc93a), (0xbc7457e610231ac2, 0xbfed906bcf328d46), (0xbc883c37c6107db3, 0xbfeddb13b6ccc23c), (0x3c8014c76c126527, 0xbfee212104f686e5), (0x3c616b56f2847754, 0xbfee6288ec48e112), (0xbc8760b1e2e3f81e, 0xbfee9f4156c62dda), (0xbc7e82c791f59cc2, 0xbfeed740e7684963), (0xbc752c7adc6b4989, 0xbfef0a7efb9230d7), (0x3c7d7bafb51f72e6, 0xbfef38f3ac64e589), (0xbc7562172a361fd3, 0xbfef6297cff75cb0), (0xbc7ab256778ffcb6, 0xbfef8764fa714ba9), (0x3c87a0a8ca13571f, 0xbfefa7557f08a517), (0xbc81ec8668ecacee, 0xbfefc26470e19fd3), (0x3c887df6378811c7, 0xbfefd88da3d12526), (0xbc6521ecd0c67e35, 0xbfefe9cdad01883a), (0x3c6c57bc2e24aa15, 0xbfeff621e3796d7e), (0x3c81354d4556e4cb, 0xbfeffd886084cd0d), (0x0000000000000000, 0xbff0000000000000), (0x3c81354d4556e4cb, 0xbfeffd886084cd0d), (0x3c6c57bc2e24aa15, 0xbfeff621e3796d7e), (0xbc6521ecd0c67e35, 0xbfefe9cdad01883a), (0x3c887df6378811c7, 0xbfefd88da3d12526), (0xbc81ec8668ecacee, 0xbfefc26470e19fd3), (0x3c87a0a8ca13571f, 0xbfefa7557f08a517), (0xbc7ab256778ffcb6, 0xbfef8764fa714ba9), (0xbc7562172a361fd3, 0xbfef6297cff75cb0), (0x3c7d7bafb51f72e6, 0xbfef38f3ac64e589), (0xbc752c7adc6b4989, 0xbfef0a7efb9230d7), (0xbc7e82c791f59cc2, 0xbfeed740e7684963), (0xbc8760b1e2e3f81e, 0xbfee9f4156c62dda), (0x3c616b56f2847754, 0xbfee6288ec48e112), (0x3c8014c76c126527, 0xbfee212104f686e5), (0xbc883c37c6107db3, 0xbfeddb13b6ccc23c), (0xbc7457e610231ac2, 0xbfed906bcf328d46), (0x3c84ef5295d25af2, 0xbfed4134d14dc93a), (0x3c5e7b6bb5ab58ae, 0xbfeced7af43cc773), (0x3c52fb761e946603, 0xbfec954b213411f5), (0x3c76e0b1757c8d07, 0xbfec38b2f180bdb1), (0x3c8825a732ac700a, 0xbfebd7c0ac6f952a), (0x3c8bc69f324e6d61, 0xbfeb728345196e3e), (0x3c8926da300ffcce, 0xbfeb090a58150200), (0xbc39f630e8b6dac8, 0xbfea9b66290ea1a3), (0x3c7128bb015df175, 0xbfea29a7a0462782), (0x3c830ee286712474, 0xbfe9b3e047f38741), (0xbc83d419a920df0b, 0xbfe93a22499263fb), (0x3c82c5e12ed1336d, 0xbfe8bc806b151741), (0x3c76f420f8ea3475, 0xbfe83b0e0bff976e), (0x3c70f537acdf0ad7, 0xbfe7b5df226aafaf), (0xbc80d4ef0f1d915c, 0xbfe72d0837efff96), (0x3c8bdd3413b26456, 0xbfe6a09e667f3bcd), (0x3c7251b352ff2a37, 0xbfe610b7551d2cdf), (0x3c875720992bfbb2, 0xbfe57d69348ceca0), (0xbc63c293edceb327, 0xbfe4e6cabbe3e5e9), (0xbc68076a2cfdc6b3, 0xbfe44cf325091dd6), (0xbc7e3e25e3954964, 0xbfe3affa292050b9), (0x3c6efcc626f74a6f, 0xbfe30ff7fce17035), (0x3c85da743ef3770c, 0xbfe26d054cdd12df), (0xbc8b25dd267f6600, 0xbfe1c73b39ae68c8), (0x3c8ef23b69abe4f1, 0xbfe11eb3541b4b23), (0x3c8a5a014347406c, 0xbfe073879922ffee), (0x3c32ec1fc1b776b8, 0xbfdf8ba4dbf89aba), (0xbc5e0d891d3c6841, 0xbfde2b5d3806f63b), (0xbc56850e59c37f8f, 0xbfdcc66e9931c45e), (0xbc65b362cb974183, 0xbfdb5d1009e15cc0), (0xbc66da81290bdbab, 0xbfd9ef7943a8ed8a), (0x3c672cedd3d5a610, 0xbfd87de2a6aea963), (0x3c744b19e0864c5d, 0xbfd7088530fa459f), (0x3c1efdc0d58cf620, 0xbfd58f9a75ab1fdd), (0xbc70c97c4afa2518, 0xbfd4135c94176601), (0x3c75d28da2c4612d, 0xbfd294062ed59f06), (0xbc7824c20ab7aa9a, 0xbfd111d262b1f677), (0x3c642deef11da2c4, 0xbfcf19f97b215f1b), (0x3c1af1439e521935, 0xbfcc0b826a7e4f63), (0x3c626d19b9ff8d82, 0xbfc8f8b83c69a60b), (0xbc6531ff779ddac6, 0xbfc5e214448b3fc6), (0xbc513000a89a11e0, 0xbfc2c8106e8e613a), (0xbc4a2704729ae56d, 0xbfbf564e56a9730e), (0x3c3e2718d26ed688, 0xbfb917a6bc29b42c), (0x3c49a088a8bf6b2c, 0xbfb2d52092ce19f6), (0x3c2912bd0d569a90, 0xbfa91f65f10dd814), (0x3bfb1d63091a0130, 0xbf992155f7a3667e), ]; pxfm-0.1.23/src/sinc.rs000064400000000000000000000134421046102023000127560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::dyad_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::DyadicFloat128; use crate::sin::{get_sin_k_rational, range_reduction_small, sincos_eval}; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::{range_reduction_small_f128, sincos_eval_dyadic}; use crate::sincos_reduce::LargeArgumentReduction; #[cold] #[inline(never)] fn sinc_refine(argument_reduction: &mut LargeArgumentReduction, x: f64, x_e: u64, k: u64) -> f64 { const EXP_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let u_f128 = if x_e < EXP_BIAS + 16 { range_reduction_small_f128(x) } else { argument_reduction.accurate() }; let sin_cos = sincos_eval_dyadic(&u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sin_k_f128 = get_sin_k_rational(k); let cos_k_f128 = get_sin_k_rational(k.wrapping_add(64)); // sin(x) = sin(k * pi/128 + u) // = sin(u) * cos(k*pi/128) + cos(u) * sin(k*pi/128) let r = (sin_k_f128 * sin_cos.v_cos) + (cos_k_f128 * sin_cos.v_sin); let reciprocal = DyadicFloat128::accurate_reciprocal(x); (r * reciprocal).fast_as_f64() } /// Computes sinc(x) /// /// Max ULP 0.5 pub fn f_sinc(x: f64) -> f64 { if !x.is_finite() { return f64::NAN; } let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff); if x_abs.to_bits() == 0 { return 1.0; } let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-26 if x_e < E_BIAS - 26 { // Signed zeros. if x == 0.0 { return x; } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. let p = dyad_fmla(x, f64::from_bits(0xbc90000000000000), x); let z = DoubleDouble::from_exact_div(p, x); return z.to_f64(); } // // Small range reduction. (y, k) = range_reduction_small(x); } else { // Inf or NaN if x_e > 2 * E_BIAS { // sin(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = DoubleDouble::div_dd_f64_newton_raphson(rr, x); let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return DoubleDouble::from_exact_add(rr.hi, rr.lo).hi; } sinc_refine(&mut argument_reduction, x, x_e, k) } #[cfg(test)] mod tests { use super::*; #[test] fn test_sinc() { assert_eq!(f_sinc(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004764135737289025), 1.); assert_eq!(f_sinc(0.1), 0.9983341664682815); assert_eq!(f_sinc(0.9), 0.870363232919426); assert_eq!(f_sinc(-0.1), 0.9983341664682815); assert_eq!(f_sinc(-0.9), 0.870363232919426); assert!(f_sinc(f64::INFINITY).is_nan()); assert!(f_sinc(f64::NEG_INFINITY).is_nan()); assert!(f_sinc(f64::NAN).is_nan()); } } pxfm-0.1.23/src/sincos.rs000064400000000000000000000153761046102023000133300ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::*; use crate::double_double::DoubleDouble; use crate::sin::{range_reduction_small, sincos_eval}; use crate::sin_helper::sincos_eval_dd; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_reduce::LargeArgumentReduction; use std::hint::black_box; /// Sine and cosine for double precision /// /// ULP 0.5 pub fn f_sincos(x: f64) -> (f64, f64) { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { // |x| < 2^-26 if x_e < E_BIAS - 7 { if x_e < E_BIAS - 27 { // Signed zeros. if x == 0.0 { return (x, 1.0); } // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. let s_sin = dyad_fmla(x, f64::from_bits(0xbc90000000000000), x); let s_cos = black_box(1.0) - min_normal_f64(); return (s_sin, s_cos); } k = 0; y = DoubleDouble::new(0.0, x); } else { // // Small range reduction. (y, k) = range_reduction_small(x); } } else { // Inf or NaN if x_e > 2 * E_BIAS { // sin(+-Inf) = NaN return (x + f64::NAN, x + f64::NAN); } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); let (sin_y, cos_y) = (r_sincos.v_sin, r_sincos.v_cos); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let msin_k = -sin_k; // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). // So k is an integer and -pi / 256 <= y <= pi / 256. // Then sin(x) = sin((k * pi/128 + y) // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) let sin_k_cos_y = DoubleDouble::quick_mult(cos_y, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(sin_y, cos_k); // cos(x) = cos((k * pi/128 + y) // = cos(y) * cos(k*pi/128) - sin(y) * sin(k*pi/128) let cos_k_cos_y = DoubleDouble::quick_mult(cos_y, cos_k); let msin_k_sin_y = DoubleDouble::quick_mult(sin_y, msin_k); let mut sin_dd = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); let mut cos_dd = DoubleDouble::from_full_exact_add(cos_k_cos_y.hi, msin_k_sin_y.hi); sin_dd.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; cos_dd.lo += msin_k_sin_y.lo + cos_k_cos_y.lo; let sin_lp = sin_dd.lo + r_sincos.err; let sin_lm = sin_dd.lo - r_sincos.err; let cos_lp = cos_dd.lo + r_sincos.err; let cos_lm = cos_dd.lo - r_sincos.err; let sin_upper = sin_dd.hi + sin_lp; let sin_lower = sin_dd.hi + sin_lm; let cos_upper = cos_dd.hi + cos_lp; let cos_lower = cos_dd.hi + cos_lm; // Ziv's rounding test. if sin_upper == sin_lower && cos_upper == cos_lower { return (sin_upper, cos_upper); } sincos_hard(y, sin_k, cos_k, sin_upper, sin_lower, cos_upper, cos_lower) } #[cold] #[inline(never)] #[allow(clippy::too_many_arguments)] fn sincos_hard( y: DoubleDouble, sin_k: DoubleDouble, cos_k: DoubleDouble, sin_upper: f64, sin_lower: f64, cos_upper: f64, cos_lower: f64, ) -> (f64, f64) { let r_sincos = sincos_eval_dd(y); let msin_k = -sin_k; let sin_x = if sin_upper == sin_lower { sin_upper } else { // sin(x) = sin((k * pi/128 + u) // = sin(u) * cos(k*pi/128) + cos(u) * sin(k*pi/128) DoubleDouble::mul_add(sin_k, r_sincos.v_cos, cos_k * r_sincos.v_sin).to_f64() }; let cos_x = if cos_upper == cos_lower { cos_upper } else { // cos(x) = cos((k * pi/128 + u) // = cos(u) * cos(k*pi/128) - sin(u) * sin(k*pi/128) DoubleDouble::mul_add(cos_k, r_sincos.v_cos, msin_k * r_sincos.v_sin).to_f64() }; (sin_x, cos_x) } #[cfg(test)] mod tests { use super::*; #[test] fn f_sincos_test() { let subnormal = f_sincos(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015708065354637772); assert_eq!(subnormal.0, 1.5708065354637772e-307); assert_eq!(subnormal.1, 1.0); let zx_0 = f_sincos(0.0); assert_eq!(zx_0.0, 0.0); assert_eq!(zx_0.1, 1.0); let zx_1 = f_sincos(1.0); assert_eq!(zx_1.0, 0.8414709848078965); assert_eq!(zx_1.1, 0.5403023058681398); let zx_0_p5 = f_sincos(-0.5); assert_eq!(zx_0_p5.0, -0.479425538604203); assert_eq!(zx_0_p5.1, 0.8775825618903728); } } pxfm-0.1.23/src/sincos_dyadic.rs000064400000000000000000000445171046102023000146440ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::sincos_reduce_tables::ONE_TWENTY_EIGHT_OVER_PI; pub(crate) fn range_reduction_small_f128(x: f64) -> DyadicFloat128 { const PI_OVER_128_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc90f_daa2_2168_c234_c4c6_628b_80dc_1cd1_u128, }; const ONE_TWENTY_EIGHT_OVER_PI_D: f64 = f64::from_bits(0x40445f306dc9c883); let prod_hi = x * ONE_TWENTY_EIGHT_OVER_PI_D; let kd = prod_hi.round(); let mk_f128 = DyadicFloat128::new_from_f64(-kd); let x_f128 = DyadicFloat128::new_from_f64(x); let over_pi3 = ONE_TWENTY_EIGHT_OVER_PI[3]; let p_hi = x_f128.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.0))); let p_mid = x_f128.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.1))); let p_lo = x_f128.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.2))); let s_hi = p_hi.quick_add(&mk_f128); let s_lo = p_mid.quick_add(&p_lo); let y = s_hi.quick_add(&s_lo); y.quick_mul(&PI_OVER_128_F128) } pub(crate) fn range_reduction_small_f128_f128(x: DyadicFloat128) -> (DyadicFloat128, i64) { const PI_OVER_128_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc90f_daa2_2168_c234_c4c6_628b_80dc_1cd1_u128, }; const ONE_TWENTY_EIGHT_OVER_PI_D: f64 = f64::from_bits(0x40445f306dc9c883); let prod_hi = x.fast_as_f64() * ONE_TWENTY_EIGHT_OVER_PI_D; let kd = prod_hi.round(); let mk_f128 = DyadicFloat128::new_from_f64(-kd); let over_pi3 = ONE_TWENTY_EIGHT_OVER_PI[3]; let p_hi = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.0))); let p_mid = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.1))); let p_lo = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.2))); let p_lo_lo = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.3))); let s_hi = p_hi.quick_add(&mk_f128); let s_lo = p_mid.quick_add(&p_lo); let y = (s_hi + s_lo) + p_lo_lo; (y.quick_mul(&PI_OVER_128_F128), kd as i64) } // pub(crate) fn range_reduction_small_f128_f128(x: DyadicFloat128) -> (DyadicFloat128, u64) { // const PI_OVER_128_F128: DyadicFloat128 = DyadicFloat128 { // sign: DyadicSign::Pos, // exponent: -133, // mantissa: 0xc90f_daa2_2168_c234_c4c6_628b_80dc_1cd1_u128, // }; // const ONE_TWENTY_EIGHT_OVER_PI_D: f64 = f64::from_bits(0x40445f306dc9c883); // let prod_hi = x.fast_as_f64() * ONE_TWENTY_EIGHT_OVER_PI_D; // let kd = prod_hi.round(); // // let mk_f128 = DyadicFloat128::new_from_f64(-kd); // let over_pi3 = ONE_TWENTY_EIGHT_OVER_PI[3]; // let p_hi = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.0))); // let p_mid = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.1))); // let p_lo = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.2))); // let p_lo_lo = x.quick_mul(&DyadicFloat128::new_from_f64(f64::from_bits(over_pi3.3))); // let s_hi = p_hi.quick_add(&mk_f128); // let s_lo = p_mid.quick_add(&p_lo); // let s_lo_lo = p_lo_lo.quick_add(&p_lo_lo); // let y = s_hi.quick_add(&s_lo).quick_add(&s_lo_lo); // (y.quick_mul(&PI_OVER_128_F128), (kd as i64) as u64) // } pub(crate) struct SinCosDyadic { pub(crate) v_sin: DyadicFloat128, pub(crate) v_cos: DyadicFloat128, } #[cold] pub(crate) fn sincos_eval_dyadic(u: &DyadicFloat128) -> SinCosDyadic { let u_sq = u.quick_mul(u); // sin(u) ~ x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - x^11/11! + x^13/13! static SIN_COEFFS: [DyadicFloat128; 7] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 1 DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, // -1/3! DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x88888888_88888888_88888888_88888889_u128, }, // 1/5! DyadicFloat128 { sign: DyadicSign::Neg, exponent: -140, mantissa: 0xd00d00d0_0d00d00d_00d00d00_d00d00d0_u128, }, // -1/7! DyadicFloat128 { sign: DyadicSign::Pos, exponent: -146, mantissa: 0xb8ef1d2a_b6399c7d_560e4472_800b8ef2_u128, }, // 1/9! DyadicFloat128 { sign: DyadicSign::Neg, exponent: -153, mantissa: 0xd7322b3f_aa271c7f_3a3f25c1_bee38f10_u128, }, // -1/11! DyadicFloat128 { sign: DyadicSign::Pos, exponent: -160, mantissa: 0xb092309d_43684be5_1c198e91_d7b4269e_u128, }, // 1/13! ]; // cos(u) ~ 1 - x^2/2 + x^4/4! - x^6/6! + x^8/8! - x^10/10! + x^12/12! static COS_COEFFS: [DyadicFloat128; 7] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 1.0 DyadicFloat128 { sign: DyadicSign::Neg, exponent: -128, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 1/2 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, // 1/4! DyadicFloat128 { sign: DyadicSign::Neg, exponent: -137, mantissa: 0xb60b60b6_0b60b60b_60b60b60_b60b60b6_u128, }, // 1/6! DyadicFloat128 { sign: DyadicSign::Pos, exponent: -143, mantissa: 0xd00d00d0_0d00d00d_00d00d00_d00d00d0_u128, }, // 1/8! DyadicFloat128 { sign: DyadicSign::Neg, exponent: -149, mantissa: 0x93f27dbb_c4fae397_780b69f5_333c725b_u128, }, // 1/10! DyadicFloat128 { sign: DyadicSign::Pos, exponent: -156, mantissa: 0x8f76c77f_c6c4bdaa_26d4c3d6_7f425f60_u128, }, // 1/12! ]; let mut sin_u = SIN_COEFFS[6]; for i in (0..7).rev() { sin_u = sin_u * u_sq + SIN_COEFFS[i]; } sin_u = sin_u * *u; let mut cos_u = COS_COEFFS[6]; for i in (0..7).rev() { cos_u = cos_u * u_sq + COS_COEFFS[i]; } SinCosDyadic { v_sin: sin_u, v_cos: cos_u, } } /* Sage math: # Sin K PI over 128 R = RealField(128) π = R.pi() def format_hex(value): l = hex(value)[2:] n = 4 x = [l[i:i + n] for i in range(0, len(l), n)] return "0x" + "_".join(x) + "_u128" def print_dyadic(value): (s, m, e) = RealField(128)(value).sign_mantissa_exponent(); print("DyadicFloat128 {") print(f" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},") print(f" exponent: {e},") print(f" mantissa: {format_hex(m)},") print("},") # Generate array entries print("pub(crate) static SIN_K_PI_OVER_128_F128: [DyadicFloat128; 65] = [") for k in range(65): value = R(k) * π / 128 print_dyadic(value.sin()) print("];") */ pub(crate) static SIN_K_PI_OVER_128_F128: [DyadicFloat128; 65] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc90a_afbd_1b33_efc9_c539_edcb_fda0_cf2c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xc8fb_2f88_6ec0_9f37_6a17_954b_2b7c_5171_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x96a9_0496_70cf_ae65_f775_7409_4d3c_35c4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xc8bd_35e1_4da1_5f0e_c739_6c89_4bbf_7389_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xfab2_72b5_4b98_71a2_7047_29ae_56d7_8a37_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9640_8374_7309_d113_000a_89a1_1e07_c1ff_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xaf10_a224_59fe_32a6_3fee_f3bb_58b1_f10d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xc7c5_c1e3_4d30_55b2_5cc8_c00e_4fcc_d850_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xe05c_1353_f27b_17e5_0ebc_61ad_e6ca_83cc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xf8cf_cbd9_0af8_d57a_4221_dc4b_a772_598d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x888e_9315_8fb3_bb04_9841_56f5_5334_4306_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x94a0_3176_acf8_2d45_ae4b_a773_da6b_f754_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa09a_e4a0_bb30_0a19_2f89_5f44_a303_cc0b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xac7c_d3ad_58fe_e7f0_811f_9539_84ef_f83e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb844_2987_d22c_f576_9cc3_ef36_746d_e3b8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xc3ef_1535_754b_168d_3122_c2a5_9efd_dc37_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcf7b_ca1d_476c_516d_a812_90bd_baad_62e4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xdae8_804f_0ae6_015b_362c_b974_182e_3030_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe633_74c9_8e22_f0b4_2872_ce1b_fc7a_d1cc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf15a_e9c0_37b1_d8f0_6c48_e9e3_420b_0f1d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xfc5d_26df_c4d5_cfda_27c0_7c91_1290_b8d1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x839c_3cc9_17ff_6cb4_bfd7_9717_f288_0abf_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x88f5_9aa0_da59_1421_b892_ca83_61d8_c84c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8e39_d9cd_7346_4364_bba4_cfec_bff5_4868_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9368_2a66_e896_f544_b178_2191_1e71_c16e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x987f_bfe7_0b81_a708_19ce_c845_ac87_a5c6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9d7f_d149_0285_c9e3_e25e_3954_9638_ae67_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa267_9928_48ee_b0c0_3b51_67ee_359a_234e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa736_55df_1f2f_489e_149f_6e75_9934_68a2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xabeb_49a4_6764_fd15_1bec_da80_89c1_a94c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb085_baa8_e966_f6da_e4ca_d00d_5c94_bcd1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb504_f333_f9de_6484_597d_89b3_754a_be9f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb968_41bf_7ffc_b21a_9de1_e3b2_2b8b_f4db_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbdae_f913_557d_76f0_ac85_320f_528d_6d5c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc1d8_705f_fcbb_6e90_bdf0_715c_b8b2_0bd7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc5e4_0358_a8ba_05a7_43da_25d9_9267_326b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc9d1_124c_931f_da7a_8335_241b_e169_3225_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xcd9f_023f_9c3a_059e_23af_31db_7179_a4a9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd14d_3d02_313c_0eed_744f_ea20_e8ab_ef92_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd4db_3148_750d_1819_f630_e8b6_dac8_3e68_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xd848_52c0_a80f_fcdb_24b9_fe00_6635_74a4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdb94_1a28_cb71_ec87_2c19_b632_53da_43fb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xdebe_0563_7ca9_4cfb_4b19_aa71_fec3_ae6c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe1c5_978c_05ed_8691_f4e8_a837_2f8c_5810_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe4aa_5909_a08f_a7b4_1227_85ae_67f5_515c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xe76b_d7a1_e63b_9786_1251_2952_9d48_a92f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xea09_a68a_6e49_cd62_15ad_45b4_a1b5_e823_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xec83_5e79_946a_3145_7e61_0231_ac1d_6181_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xeed8_9db6_6611_e307_86f8_c20f_b664_b01b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf109_0827_b437_25fd_6712_7db3_5b28_7315_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf314_4762_4708_8f74_a548_6bdc_455d_56a3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf4fa_0ab6_316e_d2ec_163c_5c7f_03b7_18c5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf6ba_073b_424b_19e8_2c79_1f59_cc1f_fc23_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf853_f7dc_9186_b952_c7ad_c6b4_9888_91ba_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xf9c7_9d63_272c_4628_4504_ae08_d19b_2981_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfb14_be7f_bae5_8156_2172_a361_fd2a_722f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfc3b_27d3_8a5d_49ab_2567_78ff_cb5c_1769_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfd3a_abf8_4528_b50b_eae6_bd95_1c1d_abbd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfe13_2387_0cfe_9a3d_90cd_1d95_9db6_74ef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xfec4_6d1e_8929_2cf0_4139_0efd_c726_e9ef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xff4e_6d68_0c41_d0a9_0f66_8633_f1ab_858a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xffb1_0f1b_cb6b_ef1d_421e_8eda_af59_453e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xffec_4304_2668_65d9_5657_5523_6696_1732_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, }, ]; pxfm-0.1.23/src/sincos_reduce.rs000064400000000000000000000461511046102023000146520ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::set_exponent_f64; use crate::common::{dd_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::sincos_reduce_tables::ONE_TWENTY_EIGHT_OVER_PI; #[derive(Debug)] pub(crate) struct AngleReduced { pub(crate) angle: DoubleDouble, } #[derive(Default)] pub(crate) struct LargeArgumentReduction { x_reduced: f64, idx: u64, y_hi: f64, y_lo: f64, // Low part of x * ONE_TWENTY_EIGHT_OVER_PI[idx][1]. y_mid: DoubleDouble, } // For large range |x| >= 2^16, we perform the range reduction computations as: // u = x - k * pi/128 = (pi/128) * (x * (128/pi) - k). // We use the exponent of x to find 4 double-chunks of 128/pi: // c_hi, c_mid, c_lo, c_lo_2 such that: // 1) ulp(round(x * c_hi, D, RN)) >= 2^8 = 256, // 2) If x * c_hi = ph_hi + ph_lo and x * c_mid = pm_hi + pm_lo, then // min(ulp(ph_lo), ulp(pm_hi)) >= 2^-53. // This will allow us to drop the high part ph_hi and the addition: // (ph_lo + pm_hi) mod 1 // can be exactly representable in a double precision. // This will allow us to do split the computations as: // (x * 256/pi) ~ x * (c_hi + c_mid + c_lo + c_lo_2) (mod 256) // ~ (ph_lo + pm_hi) + (pm_lo + x * c_lo) + x * c_lo_2. // Then, // round(x * 128/pi) = round(ph_lo + pm_hi) (mod 256) // And the high part of fractional part of (x * 128/pi) can simply be: // {x * 128/pi}_hi = {ph_lo + pm_hi}. // To prevent overflow when x is very large, we simply scale up // (c_hi, c_mid, c_lo, c_lo_2) by a fixed power of 2 (based on the index) and // scale down x by the same amount. impl LargeArgumentReduction { #[cold] pub(crate) fn accurate(&self) -> DyadicFloat128 { // Sage math: // R = RealField(128) // π = R.pi() // // def format_hex(value): // l = hex(value)[2:] // n = 4 // x = [l[i:i + n] for i in range(0, len(l), n)] // return "0x" + "_".join(x) + "_u128" // // def print_dyadic(value): // (s, m, e) = RealField(128)(value).sign_mantissa_exponent(); // print("DyadicFloat128 {") // print(f" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},") // print(f" exponent: {e},") // print(f" mantissa: {format_hex(m)},") // print("};") // // print_dyadic(π/128) const PI_OVER_128_F128: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xc90f_daa2_2168_c234_c4c6_628b_80dc_1cd1_u128, }; // y_lo = x * c_lo + pm.lo let one_pi_rot = ONE_TWENTY_EIGHT_OVER_PI[self.idx as usize]; let y_lo_0 = DyadicFloat128::new_from_f64(self.x_reduced * f64::from_bits(one_pi_rot.3)); let y_lo_1 = DyadicFloat128::new_from_f64(self.y_lo) + y_lo_0; let y_mid_f128 = DyadicFloat128::new_from_f64(self.y_mid.lo) + y_lo_1; let y_hi_f128 = DyadicFloat128::new_from_f64(self.y_hi) + DyadicFloat128::new_from_f64(self.y_mid.hi); let y = y_hi_f128 + y_mid_f128; y * PI_OVER_128_F128 } pub(crate) fn reduce(&mut self, x: f64) -> (u64, DoubleDouble) { const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let mut xbits = x.to_bits(); let x_e = ((x.to_bits() >> 52) & 0x7ff) as i64; let x_e_m62 = x_e.wrapping_sub(E_BIAS as i64 + 62); self.idx = (x_e_m62 >> 4).wrapping_add(3) as u64; // Scale x down by 2^(-(16 * (idx - 3)) xbits = set_exponent_f64( xbits, (x_e_m62 & 15) .wrapping_add(E_BIAS as i64) .wrapping_add(62i64) as u64, ); // 2^62 <= |x_reduced| < 2^(62 + 16) = 2^78 self.x_reduced = f64::from_bits(xbits); // x * c_hi = ph.hi + ph.lo exactly. let one_pi = ONE_TWENTY_EIGHT_OVER_PI[self.idx as usize]; let ph = DoubleDouble::from_exact_mult(self.x_reduced, f64::from_bits(one_pi.0)); // x * c_mid = pm.hi + pm.lo exactly. let pm = DoubleDouble::from_exact_mult(self.x_reduced, f64::from_bits(one_pi.1)); // x * c_lo = pl.hi + pl.lo exactly. let pl = DoubleDouble::from_exact_mult(self.x_reduced, f64::from_bits(one_pi.2)); // Extract integral parts and fractional parts of (ph.lo + pm.hi). let sum_hi = ph.lo + pm.hi; let kd = sum_hi.round(); // x * 128/pi mod 1 ~ y_hi + y_mid + y_lo self.y_hi = (ph.lo - kd) + pm.hi; // Exact self.y_mid = DoubleDouble::from_exact_add(pm.lo, pl.hi); self.y_lo = pl.lo; // y_l = x * c_lo_2 + pl.lo let y_l = dd_fmla(self.x_reduced, f64::from_bits(one_pi.3), self.y_lo); let mut y = DoubleDouble::from_exact_add(self.y_hi, self.y_mid.hi); y.lo += self.y_mid.lo + y_l; // Digits of pi/128, generated by SageMath with: // import struct // from sage.all import * // // def double_to_hex(f): // return "0x" + format(struct.unpack(' DoubleDouble { let mut c1 = c1; let mut c0 = c0; if c1 != 0 { let e = c1.leading_zeros(); if e != 0 { c1 = (c1 << e) | (c0 >> (64 - e)); c0 = c0.wrapping_shl(e); } let f = 0x3fe - e; let t_u = ((f as u64) << 52) | ((c1 << 1) >> 12); let hi = f64::from_bits(t_u); c0 = (c1 << 53) | (c0 >> 11); let l = if (c0) != 0 { let g = c0.leading_zeros(); if (g) != 0 { c0 = c0.wrapping_shl(g); } let t_u = (((f - 53 - g) as u64) << 52) | ((c0 << 1) >> 12); f64::from_bits(t_u) } else { 0. }; DoubleDouble::new(l, hi) } else if (c0) != 0 { let e = c0.leading_zeros(); let f = 0x3fe - 64 - e; c0 = c0.wrapping_shl(e + 1); // most significant bit shifted out /* put the upper 52 bits of c0 into h */ let t_u = ((f as u64) << 52) | (c0 >> 12); let hi = f64::from_bits(t_u); /* put the lower 12 bits of c0 into l */ c0 = c0.wrapping_shl(52); let l = if (c0) != 0 { let g = c0.leading_zeros(); c0 = c0.wrapping_shl(g + 1); let t_u = (((f - 64 - g) as u64) << 52) | (c0 >> 12); f64::from_bits(t_u) } else { 0. }; DoubleDouble::new(l, hi) } else { DoubleDouble::default() } } #[inline] fn frac_2pi(x: f64) -> DoubleDouble { if x <= f64::from_bits(0x401921fb54442d17) // x < 2*pi { /* | CH+CL - 1/(2pi) | < 2^-110.523 */ const C: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc66b01ec5417056), f64::from_bits(0x3fc45f306dc9c883), ); let mut z = DoubleDouble::quick_mult_f64(C, x); z.lo = f_fmla(C.lo, x, z.lo); z } else // x > 0x1.921fb54442d17p+2 { let t = x.to_bits(); let mut e = ((t >> 52) & 0x7ff) as i32; /* 1025 <= e <= 2046 */ let m = (1u64 << 52) | (t & 0xfffffffffffffu64); let mut c0: u64; let mut c1: u64; let mut c2: u64; // x = m/2^53 * 2^(e-1022) if e <= 1074 // 1025 <= e <= 1074: 2^2 <= x < 2^52 { let mut u = m as u128 * INVPI_2_62[1] as u128; c0 = u as u64; c1 = (u >> 64) as u64; u = m as u128 * INVPI_2_62[0] as u128; c1 = c1.wrapping_add(u as u64); c2 = (u >> 64) as u64 + (c1 < (u as u64)) as u64; e = 1075 - e; // 1 <= e <= 50 } else // 1075 <= e <= 2046, 2^52 <= x < 2^1024 { let i = (e - 1138 + 63) / 64; // i = ceil((e-1138)/64), 0 <= i <= 15 let mut u = m as u128 * INVPI_2_62[i as usize + 2] as u128; c0 = u as u64; c1 = (u >> 64) as u64; u = m as u128 * INVPI_2_62[i as usize + 1] as u128; c1 = c1.wrapping_add(u as u64); c2 = (u >> 64) as u64 + ((c1) < (u as u64)) as u64; u = m as u128 * INVPI_2_62[i as usize] as u128; c2 = c2.wrapping_add(u as u64); e = 1139 + (i << 6) - e; // 1 <= e <= 64 } if e == 64 { c0 = c1; c1 = c2; } else { c0 = (c1 << (64 - e)) | c0 >> e; c1 = (c2 << (64 - e)) | c1 >> e; } create_dd(c1, c0) } } /// Returns x mod 2*PI #[inline] pub(crate) fn rem2pi_any(x: f64) -> AngleReduced { const TWO_PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3cb1a62633145c07), f64::from_bits(0x401921fb54442d18), ); let a = frac_2pi(x); let z = DoubleDouble::quick_mult(a, TWO_PI); AngleReduced { angle: z } } /** Generated by SageMath: ```python def triple_double_split(x, n): VR = RealField(1000) R32 = RealField(n) hi = R32(x) rem1 = x - VR(hi) med = R32(rem1) rem2 = rem1 - VR(med) lo = R32(rem2) rem2 = rem1 - VR(med) lo = R32(rem2) return (hi, med, lo) hi, med, lo = triple_double_split((RealField(600).pi() * RealField(600)(2)), 51) print(double_to_hex(hi)) print(double_to_hex(med)) print(double_to_hex(lo)) ``` **/ #[inline] fn rem2pif_small(x: f32) -> f64 { const ONE_OVER_PI_2: f64 = f64::from_bits(0x3fc45f306dc9c883); const TWO_PI: [u64; 3] = [0x401921fb54440000, 0x3da68c234c4c0000, 0x3b498a2e03707345]; let dx = x as f64; let kd = (dx * ONE_OVER_PI_2).round(); let mut y = dd_fmla(-kd, f64::from_bits(TWO_PI[0]), dx); y = dd_fmla(-kd, f64::from_bits(TWO_PI[1]), y); y = dd_fmla(-kd, f64::from_bits(TWO_PI[2]), y); y } #[inline] pub(crate) fn rem2pif_any(x: f32) -> f64 { let x_abs = x.abs(); if x_abs.to_bits() < 0x5600_0000u32 { rem2pif_small(x_abs) } else { let p = rem2pi_any(x_abs as f64); p.angle.to_f64() } } pub(crate) fn frac2pi_d128(x: DyadicFloat128) -> DyadicFloat128 { let e = x.biased_exponent(); let mut fe = x; if e <= 1 // |X| < 2 { /* multiply by T[0]/2^64 + T[1]/2^128, where |T[0]/2^64 + T[1]/2^128 - 1/(2pi)| < 2^-130.22 */ let mut x_hi = (x.mantissa >> 64) as u64; let mut x_lo: u64; let mut u: u128 = x_hi as u128 * INVPI_2_62[1] as u128; let tiny: u64 = u as u64; x_lo = (u >> 64) as u64; u = x_hi as u128 * INVPI_2_62[0] as u128; x_lo = x_lo.wrapping_add(u as u64); x_hi = (u >> 64) as u64 + (x_lo < u as u64) as u64; /* hi + lo/2^64 + tiny/2^128 = hi_in * (T[0]/2^64 + T[1]/2^128) thus |hi + lo/2^64 + tiny/2^128 - hi_in/(2*pi)| < hi_in * 2^-130.22 Since X is normalized at input, hi_in >= 2^63, and since T[0] >= 2^61, we have hi >= 2^(63+61-64) = 2^60, thus the normalize() below perform a left shift by at most 3 bits */ let mut e = x.exponent; fe.mantissa = (x_hi as u128).wrapping_shl(64) | (x_lo as u128); fe.normalize(); e -= fe.exponent; // put the upper e bits of tiny into X->lo if (e) != 0 { x_hi = (fe.mantissa >> 64) as u64; x_lo = (fe.mantissa & 0xffff_ffff_ffff_ffff) as u64; x_lo |= tiny >> (64 - e); fe.mantissa = (x_hi as u128).wrapping_shl(64) | (x_lo as u128); } /* The error is bounded by 2^-130.22 (relative) + ulp(lo) (absolute). Since now X->hi >= 2^63, the absolute error of ulp(lo) converts into a relative error of less than 2^-127. This yields a maximal relative error of: (1 + 2^-130.22) * (1 + 2^-127) - 1 < 2^-126.852. */ return fe; } // now 2 <= e <= 1024 /* The upper 64-bit word X->hi corresponds to hi/2^64*2^e, if multiplied by T[i]/2^((i+1)*64) it yields hi*T[i]/2^128 * 2^(e-i*64). If e-64i <= -128, it contributes to less than 2^-128; if e-64i >= 128, it yields an integer, which is 0 modulo 1. We thus only consider the values of i such that -127 <= e-64i <= 127, i.e., (-127+e)/64 <= i <= (127+e)/64. Up to 4 consecutive values of T[i] can contribute (only 3 when e is a multiple of 64). */ let i = (if e < 127 { 0 } else { (e - 127 + 64 - 1) / 64 }) as usize; // ceil((e-127)/64) // 0 <= i <= 15 let mut c: [u64; 5] = [0u64; 5]; let mut x_hi = (x.mantissa >> 64) as u64; let mut x_lo: u64; let mut u: u128 = x_hi as u128 * INVPI_2_62[i + 3] as u128; // i+3 <= 18 c[0] = u as u64; c[1] = (u >> 64) as u64; u = x_hi as u128 * INVPI_2_62[i + 2] as u128; c[1] = c[1].wrapping_add(u as u64); c[2] = (u >> 64) as u64 + (c[1] < u as u64) as u64; u = x_hi as u128 * INVPI_2_62[i + 1] as u128; c[2] = c[2].wrapping_add(u as u64); c[3] = (u >> 64) as u64 + (c[2] < u as u64) as u64; u = x_hi as u128 * INVPI_2_62[i] as u128; c[3] = c[3].wrapping_add(u as u64); c[4] = (u >> 64) as u64 + (c[3] < u as u64) as u64; let f = e as i32 - 64 * i as i32; // hi*T[i]/2^128 is multiplied by 2^f /* {c, 5} = hi*(T[i]+T[i+1]/2^64+T[i+2]/2^128+T[i+3]/2^192) */ /* now shift c[0..4] by f bits to the left */ let tiny; if f < 64 { x_hi = (c[4] << f) | (c[3] >> (64 - f)); x_lo = (c[3] << f) | (c[2] >> (64 - f)); tiny = (c[2] << f) | (c[1] >> (64 - f)); /* the ignored part was less than 1 in c[1], thus less than 2^(f-64) <= 1/2 in tiny */ } else if f == 64 { x_hi = c[3]; x_lo = c[2]; tiny = c[1]; /* the ignored part was less than 1 in c[1], thus less than 1 in tiny */ } else /* 65 <= f <= 127: this case can only occur when e >= 65 */ { let g = f - 64; /* 1 <= g <= 63 */ /* we compute an extra term */ u = x_hi as u128 * INVPI_2_62[i + 4] as u128; // i+4 <= 19 u >>= 64; c[0] = c[0].wrapping_add(u as u64); c[1] += (c[0] < u as u64) as u64; c[2] += ((c[0] < u as u64) && c[1] == 0) as u64; c[3] += ((c[0] < u as u64) && c[1] == 0 && c[2] == 0) as u64; c[4] += ((c[0] < u as u64) && c[1] == 0 && c[2] == 0 && c[3] == 0) as u64; x_hi = (c[3] << g) | (c[2] >> (64 - g)); x_lo = (c[2] << g) | (c[1] >> (64 - g)); tiny = (c[1] << g) | (c[0] >> (64 - g)); /* the ignored part was less than 1 in c[0], thus less than 1/2 in tiny */ } let mut fe = x; fe.exponent = -127; fe.mantissa = (x_hi as u128).wrapping_shl(64) | (x_lo as u128); fe.normalize(); let ze = fe.biased_exponent(); if ze < 0 { x_hi = (fe.mantissa >> 64) as u64; x_lo = (fe.mantissa & 0xffff_ffff_ffff_ffff) as u64; x_lo |= tiny >> (64 + ze); fe.mantissa = (x_hi as u128).wrapping_shl(64) | (x_lo as u128); } fe } pub(crate) fn rem2pi_f128(x: DyadicFloat128) -> DyadicFloat128 { /* Generated by SageMath: ```python def double_to_hex(f): # Converts Python float (f64) to hex string packed = struct.pack('>d', float(f)) return '0x' + packed.hex() def format_dyadic_hex(value): l = hex(value)[2:] n = 8 x = [l[i:i + n] for i in range(0, len(l), n)] return "0x" + "_".join(x) + "_u128" def print_dyadic(value): (s, m, e) = RealField(128)(value).sign_mantissa_exponent(); print("DyadicFloat128 {") print(f" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},") print(f" exponent: {e},") print(f" mantissa: {format_dyadic_hex(m)},") print("},") print_dyadic(RealField(300).pi() * 2) ``` */ const TWO_PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -125, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let frac2pi = frac2pi_d128(x); TWO_PI * frac2pi } // #[cfg(test)] // mod tests { // use crate::dyadic_float::DyadicFloat128; // use crate::sincos_reduce::{frac_2pi, frac2pi_d128}; // // #[test] // fn test_reduce() { // let x = ..; // let reduced = frac_2pi(x); // let to_reduced2 = DyadicFloat128::new_from_f64(x); // let reduced2 = frac2pi_d128(to_reduced2); // println!("{:?}", reduced); // println!("{:?}", reduced2.fast_as_f64()); // } // } pxfm-0.1.23/src/sincos_reduce_tables.rs000064400000000000000000000442071046102023000162040ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ // Digits of 2^(16*i) / pi, generated by Sollya with: // > procedure ulp(x, n) { return 2^(floor(log2(abs(x))) - n); }; // > for i from 0 to 63 do { // if i < 3 then { pi_inv = 0.25 + 2^(16*(i - 3)) / pi; } // else { pi_inv = 2^(16*(i-3)) / pi; }; // pn = nearestint(pi_inv); // pi_frac = pi_inv - pn; // a = round(pi_frac, 51, RN); // b = round(pi_frac - a, 51, RN); // c = round(pi_frac - a - b, 51, RN); // d = round(pi_frac - a - b - c, D, RN); // print("{", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "},"); // }; // // Notice that for [0..2] the leading bit of 2^(16*(i - 3)) / pi is very small, // so we add 0.25 so that the conditions for the algorithms are still satisfied, // and one of those conditions guarantees that ulp(0.25 * x_reduced) >= 2, and // will safely be discarded. pub(crate) static ONE_TWENTY_EIGHT_OVER_PI: [(u64, u64, u64, u64); 128] = [ ( 0x4040000000000014, 0x3ce7cc1b727220a9, 0x3983f84eafa3ea6a, 0xb6211f924eb53362, ), ( 0x4040000000145f30, 0x3ceb727220a94fe1, 0x397d5f47d4d37703, 0x361b6295993c4390, ), ( 0x404000145f306dca, 0xbcdbbead603d8a83, 0x395f534ddc0db629, 0x35f664f10e4107f9, ), ( 0x40445f306dc9c883, 0xbce6b01ec5417056, 0xb986447e493ad4ce, 0x362e21c820ff28b2, ), ( 0xc03f246c6efab581, 0x3ca3abe8fa9a6ee0, 0x394b6c52b3278872, 0x35b07f9458eaf7af, ), ( 0x403391054a7f09d6, 0xbca70565911f924f, 0x3942b32788720840, 0xb5dae9c5421443aa, ), ( 0x401529fc2757d1f5, 0x3caa6ee06db14acd, 0xb948778df7c035d4, 0x35ed5ef5de2b0db9, ), ( 0xbfeec54170565912, 0x3c4b6c52b3278872, 0x38b07f9458eaf7af, 0xb52d4f246dc8e2df, ), ( 0xc04505c1596447e5, 0x3ceb14acc9e21c82, 0x395fe5163abdebbc, 0x35f586dc91b8e909, ), ( 0xc00596447e493ad5, 0x3c993c439041fe51, 0x3938eaf7aef1586e, 0xb5cb7238b7b645a4, ), ( 0x404bb81b6c52b328, 0xbcede37df00d74e3, 0x3987bd778ac36e49, 0xb611c5bdb22d1ffa, ), ( 0x404b6c52b3278872, 0x3cb07f9458eaf7af, 0xb92d4f246dc8e2df, 0x35b374b801924bbb, ), ( 0x4042b32788720840, 0xbcdae9c5421443aa, 0x395b7246e3a424dd, 0x35e700324977504f, ), ( 0xc048778df7c035d4, 0x3ced5ef5de2b0db9, 0x3971b8e909374b80, 0x35f924bba8274648, ), ( 0xc03bef806ba71508, 0xbcd443a9e48db91c, 0xb976f6c8b47fe6db, 0xb61115f62e6de302, ), ( 0xbfdae9c5421443aa, 0x3c5b7246e3a424dd, 0x38e700324977504f, 0xb58cdbc603c429c7, ), ( 0xc0438a84288753c9, 0xbccb7238b7b645a4, 0x38f924bba8274648, 0x359cfe1deb1cb12a, ), ( 0xc020a21d4f246dc9, 0x3cad2126e9700325, 0xb94a22bec5cdbc60, 0xb5de214e34ed658c, ), ( 0xc02d4f246dc8e2df, 0x3cb374b801924bbb, 0xb95f62e6de301e21, 0xb5f38d3b5963045e, ), ( 0xc03236e4716f6c8b, 0xbcd1ff9b6d115f63, 0x395921cfe1deb1cb, 0x35d29a73ee88235f, ), ( 0x403b8e909374b802, 0xbcdb6d115f62e6de, 0xb9680f10a71a76b3, 0x35fcfba208d7d4bb, ), ( 0x40309374b801924c, 0xbcd15f62e6de301e, 0xb960a71a76b2c609, 0x3601046bea5d7689, ), ( 0xc0268ffcdb688afb, 0xbca736f180f10a72, 0x39462534e7dd1047, 0xb5e0568a25dbd8b3, ), ( 0x3ff924bba8274648, 0x3c9cfe1deb1cb12a, 0xb9363045df7282b4, 0xb5d44bb7b16638fe, ), ( 0xc04a22bec5cdbc60, 0xbcde214e34ed658c, 0xb95177dca0ad144c, 0x35f213a671c09ad1, ), ( 0x4003a32439fc3bd6, 0x3c9cb129a73ee882, 0x392afa975da24275, 0xb5b8e3f652e82070, ), ( 0xc03b78c0788538d4, 0x3cd29a73ee88235f, 0x3974baed1213a672, 0xb60fb29741037d8d, ), ( 0x404fc3bd63962535, 0xbcc822efb9415a29, 0x396a24274ce38136, 0xb60741037d8cdc54, ), ( 0xc014e34ed658c117, 0xbcbf7282b4512edf, 0x394d338e04d68bf0, 0xb5dbec66e29c67cb, ), ( 0x40462534e7dd1047, 0xbce0568a25dbd8b3, 0xb96c7eca5d040df6, 0xb5f9b8a719f2b318, ), ( 0xc0363045df7282b4, 0xbcd44bb7b16638fe, 0x397ad17df904e647, 0x361639835339f49d, ), ( 0x404d1046bea5d769, 0xbcebd8b31c7eca5d, 0xb94037d8cdc538d0, 0x35ea99cfa4e422fc, ), ( 0x402afa975da24275, 0xbcb8e3f652e82070, 0x3953991d63983534, 0xb5f82d8dee81d108, ), ( 0xc04a28976f62cc72, 0x3ca35a2fbf209cc9, 0xb924e33e566305b2, 0x35c08bf177bf2507, ), ( 0xc0476f62cc71fb29, 0xbced040df633714e, 0xb979f2b3182d8def, 0x361f8bbdf9283b20, ), ( 0x404d338e04d68bf0, 0xbcdbec66e29c67cb, 0x3969cfa4e422fc5e, 0xb5e036be27003b40, ), ( 0x403c09ad17df904e, 0x3cd91d639835339f, 0x397272117e2ef7e5, 0xb617c4e007680022, ), ( 0x40468befc827323b, 0xbcdc67cacc60b638, 0x39717e2ef7e4a0ec, 0x361ff897ffde0598, ), ( 0xc04037d8cdc538d0, 0x3cea99cfa4e422fc, 0x39877bf250763ff1, 0x3617ffde05980fef, ), ( 0xc048cdc538cf9599, 0x3cdf49c845f8bbe0, 0xb97b5f13801da001, 0x361e05980fef2f12, ), ( 0xc024e33e566305b2, 0x3cc08bf177bf2507, 0x3968ffc4bffef02d, 0xb5ffc04343b9d298, ), ( 0xc03f2b3182d8dee8, 0xbcbd1081b5f13802, 0x3942fffbc0b301fe, 0xb5ca1dce94beb25c, ), ( 0xc048c16c6f740e88, 0xbce036be27003b40, 0xb920fd33f8086877, 0xb5bd297d64b824b2, ), ( 0x4043908bf177bf25, 0x3cad8ffc4bffef03, 0xb939fc04343b9d29, 0xb5df592e092c9813, ), ( 0x4037e2ef7e4a0ec8, 0xbc7da00087e99fc0, 0xb910d0ee74a5f593, 0x359f6d367ecf27cb, ), ( 0xc03081b5f13801da, 0xbc20fd33f8086877, 0xb8bd297d64b824b2, 0xb558130d834f648b, ), ( 0xc04af89c00ed0004, 0xbcdfa67f010d0ee7, 0xb97297d64b824b26, 0xb5d30d834f648b0c, ), ( 0xc04c00ed00043f4d, 0x3c8fde5e2316b415, 0xb912e092c98130d8, 0xb5aa7b24585ce04d, ), ( 0x4042fffbc0b301fe, 0xbcca1dce94beb25c, 0xb9425930261b069f, 0x35db74f463f669e6, ), ( 0xc020fd33f8086877, 0xbcbd297d64b824b2, 0xb958130d834f648b, 0xb5c738132c3402ba, ), ( 0xc039fc04343b9d29, 0xbcdf592e092c9813, 0xb94b069ec9161738, 0xb5c32c3402ba515b, ), ( 0xc010d0ee74a5f593, 0x3c9f6d367ecf27cb, 0x39036e9e8c7ecd3d, 0xb5a00ae9456c229c, ), ( 0xc04dce94beb25c12, 0xbce64c0986c1a7b2, 0xb98161738132c340, 0xb615d28ad8453814, ), ( 0xc044beb25c125930, 0xbcd30d834f648b0c, 0x3978fd9a797fa8b6, 0xb605b08a7028341d, ), ( 0x403b47db4d9fb3ca, 0xbcaa7b24585ce04d, 0x3943cbfd45aea4f7, 0x35e63f5f2f8bd9e8, ), ( 0xc0425930261b069f, 0x3cdb74f463f669e6, 0xb915d28ad8453814, 0xb59a0e84c2f8c608, ), ( 0x403fb3c9f2c26dd4, 0xbcc738132c3402ba, 0xb96456c229c0a0d0, 0xb60d0985f18c10eb, ), ( 0xc04b069ec9161738, 0xbcc32c3402ba515b, 0xb9314e050683a131, 0x35d0739f78a5292f, ), ( 0xc04ec9161738132c, 0xbcda015d28ad8454, 0x397faf97c5ecf41d, 0xb5f821d6b5b45650, ), ( 0xc0461738132c3403, 0x3ce16ba93dd63f5f, 0x3977c5ecf41ce7de, 0x3604a525d4d7f6bf, ), ( 0x402fb34f2ff516bb, 0xbccb08a7028341d1, 0x3969e839cfbc5295, 0xb60a2b2809409dc1, ), ( 0x4043cbfd45aea4f7, 0x3ce63f5f2f8bd9e8, 0x397ce7de294a4baa, 0xb61404a04ee072a3, ), ( 0xc015d28ad8453814, 0xbc9a0e84c2f8c608, 0xb93d6b5b45650128, 0xb5b3b81ca8bdea7f, ), ( 0xc0415b08a7028342, 0x3cd7b3d0739f78a5, 0x396497535fdafd89, 0xb5bca8bdea7f33ee, ), ( 0x0000000000000000, 0x0000000000000000, 0x3c5f938a73db97fb, 0x3f992155f7a3667c, ), ( 0xbc2912bd0d569a90, 0x3fa91f65f10dd814, 0x3c7ccbeeeae8129a, 0x3fb2d52092ce19f4, ), ( 0xbc3e2718d26ed688, 0x3fb917a6bc29b42c, 0xbc7cbb1f71aca352, 0x3fbf564e56a97310, ), ( 0xbc8dd9ffeaecbdc4, 0x3fc2c8106e8e613c, 0xbc8ab3802218894f, 0x3fc5e214448b3fc8, ), ( 0xbc849b466e7fe360, 0x3fc8f8b83c69a60c, 0xbc8035e2873ca432, 0x3fcc0b826a7e4f64, ), ( 0xbc850b7bbc4768b1, 0x3fcf19f97b215f1c, 0xbc83ed9efaa42ab3, 0x3fd111d262b1f678, ), ( 0x3c9a8b5c974ee7b5, 0x3fd294062ed59f04, 0x3c94325f12be8946, 0x3fd4135c94176600, ), ( 0x3c8fc2047e54e614, 0x3fd58f9a75ab1fdc, 0xbc9512c678219317, 0x3fd7088530fa45a0, ), ( 0xbc92e59dba7ab4c2, 0x3fd87de2a6aea964, 0xbc9d24afdade848b, 0x3fd9ef7943a8ed8c, ), ( 0x3c65b362cb974183, 0x3fdb5d1009e15cc0, 0xbc9e97af1a63c807, 0x3fdcc66e9931c460, ), ( 0xbc8c3e4edc5872f8, 0x3fde2b5d3806f63c, 0x3c9fb44f80f92225, 0x3fdf8ba4dbf89ab8, ), ( 0x3ca9697faf2e2fe5, 0x3fe073879922ffec, 0xbca7bc8eda6af93c, 0x3fe11eb3541b4b24, ), ( 0x3c8b25dd267f6600, 0x3fe1c73b39ae68c8, 0xbca5769d0fbcddc3, 0x3fe26d054cdd12e0, ), ( 0x3c9c20673b2116b2, 0x3fe30ff7fce17034, 0x3ca3c7c4bc72a92c, 0x3fe3affa292050b8, ), ( 0xbcae7f895d302395, 0x3fe44cf325091dd8, 0x3ca13c293edceb32, 0x3fe4e6cabbe3e5e8, ), ( 0xbc875720992bfbb2, 0x3fe57d69348ceca0, 0xbca24a366a5fe547, 0x3fe610b7551d2ce0, ), ( 0x3c921165f626cdd5, 0x3fe6a09e667f3bcc, 0xbcabcac43c389ba9, 0x3fe72d0837efff98, ), ( 0xbca21ea6f59be15b, 0x3fe7b5df226aafb0, 0x3cad217be0e2b971, 0x3fe83b0e0bff976c, ), ( 0x3c969d0f6897664a, 0x3fe8bc806b151740, 0xbc9615f32b6f907a, 0x3fe93a22499263fc, ), ( 0x3c96788ebcc76dc6, 0x3fe9b3e047f38740, 0x3caddae89fd441d1, 0x3fea29a7a0462780, ), ( 0xbc9f98273c5d2495, 0x3fea9b66290ea1a4, 0xbc8926da300ffcce, 0x3feb090a58150200, ), ( 0x3ca90e58336c64a8, 0x3feb728345196e3c, 0x3ca9f6963354e3fe, 0x3febd7c0ac6f9528, ), ( 0x3c9a47d3a2a0dcbe, 0x3fec38b2f180bdb0, 0x3c9ed0489e16b9a0, 0x3fec954b213411f4, ), ( 0xbca0f3db5dad5ac5, 0x3feced7af43cc774, 0x3caac42b5a8b6943, 0x3fed4134d14dc938, ), ( 0xbcad75033dfb9ca8, 0x3fed906bcf328d48, 0x3c883c37c6107db3, 0x3feddb13b6ccc23c, ), ( 0x3c97f59c49f6cd6d, 0x3fee212104f686e4, 0x3caee94a90d7b88b, 0x3fee6288ec48e110, ), ( 0xbcaa27d3874701f9, 0x3fee9f4156c62ddc, 0xbc985f4e1b8298d0, 0x3feed740e7684964, ), ( 0xbc9ab4e148e52d9e, 0x3fef0a7efb9230d8, 0x3c98a11412b82346, 0x3fef38f3ac64e588, ), ( 0x3c7562172a361fd3, 0x3fef6297cff75cb0, 0x3ca3564acef1ff97, 0x3fef8764fa714ba8, ), ( 0xbca5e82a3284d5c8, 0x3fefa7557f08a518, 0xbc9709bccb89a989, 0x3fefc26470e19fd4, ), ( 0x3ca9e082721dfb8e, 0x3fefd88da3d12524, 0xbcaeade132f3981d, 0x3fefe9cdad01883c, ), ( 0x3cae3a843d1db55f, 0x3feff621e3796d7c, 0x3c9765595d548d9a, 0x3feffd886084cd0c, ), ( 0x0000000000000000, 0x3ff0000000000000, 0x3c9765595d548d9a, 0x3feffd886084cd0c, ), ( 0x3cae3a843d1db55f, 0x3feff621e3796d7c, 0xbcaeade132f3981d, 0x3fefe9cdad01883c, ), ( 0x3ca9e082721dfb8e, 0x3fefd88da3d12524, 0xbc9709bccb89a989, 0x3fefc26470e19fd4, ), ( 0xbca5e82a3284d5c8, 0x3fefa7557f08a518, 0x3ca3564acef1ff97, 0x3fef8764fa714ba8, ), ( 0x3c7562172a361fd3, 0x3fef6297cff75cb0, 0x3c98a11412b82346, 0x3fef38f3ac64e588, ), ( 0xbc9ab4e148e52d9e, 0x3fef0a7efb9230d8, 0xbc985f4e1b8298d0, 0x3feed740e7684964, ), ( 0xbcaa27d3874701f9, 0x3fee9f4156c62ddc, 0x3caee94a90d7b88b, 0x3fee6288ec48e110, ), ( 0x3c97f59c49f6cd6d, 0x3fee212104f686e4, 0x3c883c37c6107db3, 0x3feddb13b6ccc23c, ), ( 0xbcad75033dfb9ca8, 0x3fed906bcf328d48, 0x3caac42b5a8b6943, 0x3fed4134d14dc938, ), ( 0xbca0f3db5dad5ac5, 0x3feced7af43cc774, 0x3c9ed0489e16b9a0, 0x3fec954b213411f4, ), ( 0x3c9a47d3a2a0dcbe, 0x3fec38b2f180bdb0, 0x3ca9f6963354e3fe, 0x3febd7c0ac6f9528, ), ( 0x3ca90e58336c64a8, 0x3feb728345196e3c, 0xbc8926da300ffcce, 0x3feb090a58150200, ), ( 0xbc9f98273c5d2495, 0x3fea9b66290ea1a4, 0x3caddae89fd441d1, 0x3fea29a7a0462780, ), ( 0x3c96788ebcc76dc6, 0x3fe9b3e047f38740, 0xbc9615f32b6f907a, 0x3fe93a22499263fc, ), ( 0x3c969d0f6897664a, 0x3fe8bc806b151740, 0x3cad217be0e2b971, 0x3fe83b0e0bff976c, ), ( 0xbca21ea6f59be15b, 0x3fe7b5df226aafb0, 0xbcabcac43c389ba9, 0x3fe72d0837efff98, ), ( 0x3c921165f626cdd5, 0x3fe6a09e667f3bcc, 0xbca24a366a5fe547, 0x3fe610b7551d2ce0, ), ( 0xbc875720992bfbb2, 0x3fe57d69348ceca0, 0x3ca13c293edceb32, 0x3fe4e6cabbe3e5e8, ), ( 0xbcae7f895d302395, 0x3fe44cf325091dd8, 0x3ca3c7c4bc72a92c, 0x3fe3affa292050b8, ), ( 0x3c9c20673b2116b2, 0x3fe30ff7fce17034, 0xbca5769d0fbcddc3, 0x3fe26d054cdd12e0, ), ( 0x3c8b25dd267f6600, 0x3fe1c73b39ae68c8, 0xbca7bc8eda6af93c, 0x3fe11eb3541b4b24, ), ( 0x3ca9697faf2e2fe5, 0x3fe073879922ffec, 0x3c9fb44f80f92225, 0x3fdf8ba4dbf89ab8, ), ( 0xbc8c3e4edc5872f8, 0x3fde2b5d3806f63c, 0xbc9e97af1a63c807, 0x3fdcc66e9931c460, ), ( 0x3c65b362cb974183, 0x3fdb5d1009e15cc0, 0xbc9d24afdade848b, 0x3fd9ef7943a8ed8c, ), ( 0xbc92e59dba7ab4c2, 0x3fd87de2a6aea964, 0xbc9512c678219317, 0x3fd7088530fa45a0, ), ( 0x3c8fc2047e54e614, 0x3fd58f9a75ab1fdc, 0x3c94325f12be8946, 0x3fd4135c94176600, ), ( 0x3c9a8b5c974ee7b5, 0x3fd294062ed59f04, 0xbc83ed9efaa42ab3, 0x3fd111d262b1f678, ), ( 0xbc850b7bbc4768b1, 0x3fcf19f97b215f1c, 0xbc8035e2873ca432, 0x3fcc0b826a7e4f64, ), ( 0xbc849b466e7fe360, 0x3fc8f8b83c69a60c, 0xbc8ab3802218894f, 0x3fc5e214448b3fc8, ), ( 0xbc8dd9ffeaecbdc4, 0x3fc2c8106e8e613c, 0xbc7cbb1f71aca352, 0x3fbf564e56a97310, ), ( 0xbc3e2718d26ed688, 0x3fb917a6bc29b42c, 0x3c7ccbeeeae8129a, 0x3fb2d52092ce19f4, ), ( 0xbc2912bd0d569a90, 0x3fa91f65f10dd814, 0x3c5f938a73db97fb, 0x3f992155f7a3667c, ), ]; pxfm-0.1.23/src/sincospi.rs000064400000000000000000001067501046102023000136560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::polyeval::{f_polyeval3, f_polyeval4}; use crate::pow::is_odd_integer; use crate::sin::SinCos; use crate::sincospi_tables::SINPI_K_PI_OVER_64; /** Cospi(x) on [0; 0.000244140625] Generated by Sollya: ```text d = [0, 0.000244140625]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8, 10|], [|107...|], d, relative, floating); ``` See ./notes/cospi_zero_dd.sollya **/ #[cold] fn as_cospi_zero(x: f64) -> f64 { const C: [(u64, u64); 5] = [ (0xbcb692b71366cc04, 0xc013bd3cc9be45de), (0xbcb32b33fb803bd5, 0x40103c1f081b5ac4), (0xbc9f5b752e98b088, 0xbff55d3c7e3cbff9), (0x3c30023d540b9350, 0x3fce1f506446cb66), (0x3c1a5d47937787d2, 0xbf8a9b062a36ba1c), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut p = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(C[3]), DoubleDouble::from_bit_pair(C[3]), ); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[0])); p = DoubleDouble::mul_add_f64(x2, p, 1.); p.to_f64() } /** Sinpi on range [0.0, 0.03515625] Generated poly by Sollya: ```text d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|107...|], d, relative, floating); ``` See ./notes/sinpi_zero_dd.sollya **/ #[cold] fn as_sinpi_zero(x: f64) -> f64 { const C: [(u64, u64); 6] = [ (0x3ca1a626311d9056, 0x400921fb54442d18), (0x3cb055f12c462211, 0xc014abbce625be53), (0xbc9789ea63534250, 0x400466bc6775aae1), (0xbc78b86de6962184, 0xbfe32d2cce62874e), (0x3c4eddf7cd887302, 0x3fb507833e2b781f), (0x3bf180c9d4af2894, 0xbf7e2ea4e143707e), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut p = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(C[5]), DoubleDouble::from_bit_pair(C[4]), ); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[0])); p = DoubleDouble::quick_mult_f64(p, x); p.to_f64() } // Return k and y, where // k = round(x * 64 / pi) and y = (x * 64 / pi) - k. #[inline] pub(crate) fn reduce_pi_64(x: f64) -> (f64, i64) { let kd = (x * 64.).round(); let y = dd_fmla(kd, -1. / 64., x); (y, kd as i64) } #[inline] pub(crate) fn sincospi_eval(x: f64) -> SinCos { let x2 = x * x; /* sinpi(pi*x) poly generated by Sollya: d = [0, 0.0078128]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6|], [|107, D...|], d, relative, floating); See ./notes/sinpi.sollya */ let sin_lop = f_polyeval3( x2, f64::from_bits(0xc014abbce625be4d), f64::from_bits(0x400466bc6767f259), f64::from_bits(0xbfe32d176b0b3baf), ) * x2; // We're splitting polynomial in two parts, since first term dominates // we compute: (a0_lo + a0_hi) * x + x * (a1 * x^2 + a2 + x^4) ... let sin_lo = dd_fmla(f64::from_bits(0x3ca1a5c04563817a), x, sin_lop * x); let sin_hi = x * f64::from_bits(0x400921fb54442d18); /* cospi(pi*x) poly generated by Sollya: d = [0, 0.015625]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|107, D...|], d, relative, floating); See ./notes/cospi.sollya */ let p = f_polyeval3( x2, f64::from_bits(0xc013bd3cc9be45cf), f64::from_bits(0x40103c1f08085ad1), f64::from_bits(0xbff55d1e43463fc3), ); // We're splitting polynomial in two parts, since first term dominates // we compute: (a0_lo + a0_hi) + (a1 * x^2 + a2 + x^4)... let cos_lo = dd_fmla(p, x2, f64::from_bits(0xbbdf72adefec0800)); let cos_hi = f64::from_bits(0x3ff0000000000000); let err = f_fmla( x2, f64::from_bits(0x3cb0000000000000), // 2^-52 f64::from_bits(0x3c40000000000000), // 2^-59 ); SinCos { v_sin: DoubleDouble::from_exact_add(sin_hi, sin_lo), v_cos: DoubleDouble::from_exact_add(cos_hi, cos_lo), err, } } #[inline] pub(crate) fn sincospi_eval_dd(x: f64) -> SinCos { let x2 = DoubleDouble::from_exact_mult(x, x); // Sin coeffs // poly sin(pi*x) generated by Sollya: // d = [0, 0.0078128]; // f_sin = sin(y*pi)/y; // Q = fpminimax(f_sin, [|0, 2, 4, 6, 8|], [|107...|], d, relative, floating); // see ./notes/sinpi_dd.sollya const SC: [(u64, u64); 5] = [ (0x3ca1a626330ccf19, 0x400921fb54442d18), (0x3cb05540f6323de9, 0xc014abbce625be53), (0xbc9050fdd1229756, 0x400466bc6775aadf), (0xbc780d406f3472e8, 0xbfe32d2cce5a7bf1), (0x3c4cfcf8b6b817f2, 0x3fb5077069d8a182), ]; let mut sin_y = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(SC[4]), DoubleDouble::from_bit_pair(SC[3]), ); sin_y = DoubleDouble::quick_mul_add(x2, sin_y, DoubleDouble::from_bit_pair(SC[2])); sin_y = DoubleDouble::quick_mul_add(x2, sin_y, DoubleDouble::from_bit_pair(SC[1])); sin_y = DoubleDouble::quick_mul_add(x2, sin_y, DoubleDouble::from_bit_pair(SC[0])); sin_y = DoubleDouble::quick_mult_f64(sin_y, x); // Cos coeffs // d = [0, 0.0078128]; // f_cos = cos(y*pi); // Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|107...|], d, relative, floating); // See ./notes/cospi_dd.sollya const CC: [(u64, u64); 5] = [ (0xbaaa70a580000000, 0x3ff0000000000000), (0xbcb69211d8dd1237, 0xc013bd3cc9be45de), (0xbcbd96cfd637eeb7, 0x40103c1f081b5abf), (0x3c994d75c577f029, 0xbff55d3c7e2e4ba5), (0xbc5c542d998a4e48, 0x3fce1f2f5f747411), ]; let mut cos_y = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(CC[4]), DoubleDouble::from_bit_pair(CC[3]), ); cos_y = DoubleDouble::quick_mul_add(x2, cos_y, DoubleDouble::from_bit_pair(CC[2])); cos_y = DoubleDouble::quick_mul_add(x2, cos_y, DoubleDouble::from_bit_pair(CC[1])); cos_y = DoubleDouble::quick_mul_add(x2, cos_y, DoubleDouble::from_bit_pair(CC[0])); SinCos { v_sin: sin_y, v_cos: cos_y, err: 0., } } #[cold] fn sinpi_dd(x: f64, sin_k: DoubleDouble, cos_k: DoubleDouble) -> f64 { let r_sincos = sincospi_eval_dd(x); let cos_k_sin_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_sin); let rr = DoubleDouble::mul_add(sin_k, r_sincos.v_cos, cos_k_sin_y); rr.to_f64() } #[cold] fn sincospi_dd( x: f64, sin_sin_k: DoubleDouble, sin_cos_k: DoubleDouble, cos_sin_k: DoubleDouble, cos_cos_k: DoubleDouble, ) -> (f64, f64) { let r_sincos = sincospi_eval_dd(x); let cos_k_sin_y = DoubleDouble::quick_mult(sin_cos_k, r_sincos.v_sin); let rr_sin = DoubleDouble::mul_add(sin_sin_k, r_sincos.v_cos, cos_k_sin_y); let cos_k_sin_y = DoubleDouble::quick_mult(cos_cos_k, r_sincos.v_sin); let rr_cos = DoubleDouble::mul_add(cos_sin_k, r_sincos.v_cos, cos_k_sin_y); (rr_sin.to_f64(), rr_cos.to_f64()) } // [sincospi_eval] gives precision around 2^-66 what is not enough for DD case this method gives 2^-84 #[inline] fn sincospi_eval_extended(x: f64) -> SinCos { let x2 = DoubleDouble::from_exact_mult(x, x); /* sinpi(pi*x) poly generated by Sollya: d = [0, 0.0078128]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8|], [|107, 107, D...|], d, relative, floating); See ./notes/sinpi.sollya */ let sin_lop = f_polyeval3( x2.hi, f64::from_bits(0x400466bc67763662), f64::from_bits(0xbfe32d2cce5aad86), f64::from_bits(0x3fb5077099a1f35b), ); let mut v_sin = DoubleDouble::mul_f64_add( x2, sin_lop, DoubleDouble::from_bit_pair((0x3cb0553d6ee5e8ec, 0xc014abbce625be53)), ); v_sin = DoubleDouble::mul_add( x2, v_sin, DoubleDouble::from_bit_pair((0x3ca1a626330dd130, 0x400921fb54442d18)), ); v_sin = DoubleDouble::quick_mult_f64(v_sin, x); /* cospi(pi*x) poly generated by Sollya: d = [0, 0.015625]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|107, 107, D...|], d, relative, floating); See ./notes/cospi_fast_dd.sollya */ let p = f_polyeval3( x2.hi, f64::from_bits(0x40103c1f081b5abf), f64::from_bits(0xbff55d3c7e2edd89), f64::from_bits(0x3fce1f2fd9d79484), ); let mut v_cos = DoubleDouble::mul_f64_add( x2, p, DoubleDouble::from_bit_pair((0xbcb69236a9b3ed73, 0xc013bd3cc9be45de)), ); v_cos = DoubleDouble::mul_add_f64(x2, v_cos, f64::from_bits(0x3ff0000000000000)); SinCos { v_sin: DoubleDouble::from_exact_add(v_sin.hi, v_sin.lo), v_cos: DoubleDouble::from_exact_add(v_cos.hi, v_cos.lo), err: 0., } } pub(crate) fn f_fast_sinpi_dd(x: f64) -> DoubleDouble { let ix = x.to_bits(); let ax = ix & 0x7fff_ffff_ffff_ffff; if ax == 0 { return DoubleDouble::new(0., 0.); } let e: i32 = (ax >> 52) as i32; let m0 = (ix & 0x000fffffffffffff) | (1u64 << 52); let sgn: i64 = (ix as i64) >> 63; let m = ((m0 as i64) ^ sgn).wrapping_sub(sgn); let mut s: i32 = 1063i32.wrapping_sub(e); if s < 0 { s = -s - 1; if s > 10 { return DoubleDouble::new(0., f64::copysign(0.0, x)); } let iq: u64 = (m as u64).wrapping_shl(s as u32); if (iq & 2047) == 0 { return DoubleDouble::new(0., f64::copysign(0.0, x)); } } if ax <= 0x3fa2000000000000u64 { // |x| <= 0.03515625 const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); if ax < 0x3c90000000000000 { // for x near zero, sinpi(x) = pi*x + O(x^3), thus worst cases are those // of the function pi*x, and if x is a worst case, then 2*x is another // one in the next binade. For this reason, worst cases are only included // for the binade [2^-1022, 2^-1021). For larger binades, // up to [2^-54,2^-53), worst cases should be deduced by multiplying // by some power of 2. if ax < 0x0350000000000000 { let t = x * f64::from_bits(0x4690000000000000); let z = DoubleDouble::quick_mult_f64(PI, t); let r = z.to_f64(); let rs = r * f64::from_bits(0x3950000000000000); let rt = rs * f64::from_bits(0x4690000000000000); return DoubleDouble::new( 0., dyad_fmla((z.hi - rt) + z.lo, f64::from_bits(0x3950000000000000), rs), ); } let z = DoubleDouble::quick_mult_f64(PI, x); return z; } /* Poly generated by Sollya: d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|107, 107, D...|], d, relative, floating); See ./notes/sinpi_zero_fast_dd.sollya */ const C: [u64; 4] = [ 0xbfe32d2cce62bd85, 0x3fb50783487eb73d, 0xbf7e3074f120ad1f, 0x3f3e8d9011340e5a, ]; let x2 = DoubleDouble::from_exact_mult(x, x); const C_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a626331457a4, 0x400921fb54442d18)); let p = f_polyeval4( x2.hi, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), ); let mut r = DoubleDouble::mul_f64_add( x2, p, DoubleDouble::from_bit_pair((0xbc96dd7ae221e58c, 0x400466bc6775aae2)), ); r = DoubleDouble::mul_add( x2, r, DoubleDouble::from_bit_pair((0x3cb05511c8a6c478, 0xc014abbce625be53)), ); r = DoubleDouble::mul_add(r, x2, C_PI); r = DoubleDouble::quick_mult_f64(r, x); let k = DoubleDouble::from_exact_add(r.hi, r.lo); return k; } let si = e.wrapping_sub(1011); if si >= 0 && (m0.wrapping_shl(si.wrapping_add(1) as u32)) == 0 { // x is integer or half-integer if (m0.wrapping_shl(si as u32)) == 0 { return DoubleDouble::new(0., f64::copysign(0.0, x)); // x is integer } let t = (m0.wrapping_shl((si - 1) as u32)) >> 63; // t = 0 if |x| = 1/2 mod 2, t = 1 if |x| = 3/2 mod 2 return DoubleDouble::new( 0., if t == 0 { f64::copysign(1.0, x) } else { -f64::copysign(1.0, x) }, ); } let (y, k) = reduce_pi_64(x); // // cos(k * pi/64) = sin(k * pi/64 + pi/2) = sin((k + 32) * pi/64). let sin_k = DoubleDouble::from_bit_pair(SINPI_K_PI_OVER_64[((k as u64) & 127) as usize]); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); let r_sincos = sincospi_eval_extended(y); let sin_k_cos_y = DoubleDouble::quick_mult(sin_k, r_sincos.v_cos); let cos_k_sin_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_sin); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; DoubleDouble::from_exact_add(rr.hi, rr.lo) } /// Computes sin(PI*x) /// /// Max ULP 0.5 pub fn f_sinpi(x: f64) -> f64 { let ix = x.to_bits(); let ax = ix & 0x7fff_ffff_ffff_ffff; if ax == 0 { return x; } let e: i32 = (ax >> 52) as i32; let m0 = (ix & 0x000fffffffffffff) | (1u64 << 52); let sgn: i64 = (ix as i64) >> 63; let m = ((m0 as i64) ^ sgn).wrapping_sub(sgn); let mut s: i32 = 1063i32.wrapping_sub(e); if s < 0 { if e == 0x7ff { if (ix << 12) == 0 { return f64::NAN; } return x + x; // case x=NaN } s = -s - 1; if s > 10 { return f64::copysign(0.0, x); } let iq: u64 = (m as u64).wrapping_shl(s as u32); if (iq & 2047) == 0 { return f64::copysign(0.0, x); } } if ax <= 0x3fa2000000000000u64 { // |x| <= 0.03515625 const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); if ax < 0x3c90000000000000 { // for x near zero, sinpi(x) = pi*x + O(x^3), thus worst cases are those // of the function pi*x, and if x is a worst case, then 2*x is another // one in the next binade. For this reason, worst cases are only included // for the binade [2^-1022, 2^-1021). For larger binades, // up to [2^-54,2^-53), worst cases should be deduced by multiplying // by some power of 2. if ax < 0x0350000000000000 { let t = x * f64::from_bits(0x4690000000000000); let z = DoubleDouble::quick_mult_f64(PI, t); let r = z.to_f64(); let rs = r * f64::from_bits(0x3950000000000000); let rt = rs * f64::from_bits(0x4690000000000000); return dyad_fmla((z.hi - rt) + z.lo, f64::from_bits(0x3950000000000000), rs); } let z = DoubleDouble::quick_mult_f64(PI, x); return z.to_f64(); } /* Poly generated by Sollya: d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|107, D...|], d, relative, floating); See ./notes/sinpi_zero.sollya */ let x2 = x * x; let x3 = x2 * x; let x4 = x2 * x2; let eps = x * f_fmla( x2, f64::from_bits(0x3d00000000000000), // 2^-47 f64::from_bits(0x3bd0000000000000), // 2^-66 ); const C: [u64; 4] = [ 0xc014abbce625be51, 0x400466bc67754b46, 0xbfe32d2cc12a51f4, 0x3fb5060540058476, ]; const C_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a67088eb1a46, 0x400921fb54442d18)); let mut z = DoubleDouble::quick_mult_f64(C_PI, x); let zl0 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0])); let zl1 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2])); z.lo = f_fmla(x3, f_fmla(x4, zl1, zl0), z.lo); let lb = z.hi + (z.lo - eps); let ub = z.hi + (z.lo + eps); if lb == ub { return lb; } return as_sinpi_zero(x); } let si = e.wrapping_sub(1011); if si >= 0 && (m0.wrapping_shl(si.wrapping_add(1) as u32)) == 0 { // x is integer or half-integer if (m0.wrapping_shl(si as u32)) == 0 { return f64::copysign(0.0, x); // x is integer } let t = (m0.wrapping_shl((si - 1) as u32)) >> 63; // t = 0 if |x| = 1/2 mod 2, t = 1 if |x| = 3/2 mod 2 return if t == 0 { f64::copysign(1.0, x) } else { -f64::copysign(1.0, x) }; } let (y, k) = reduce_pi_64(x); // cos(k * pi/64) = sin(k * pi/64 + pi/2) = sin((k + 32) * pi/64). let sin_k = DoubleDouble::from_bit_pair(SINPI_K_PI_OVER_64[((k as u64) & 127) as usize]); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); let r_sincos = sincospi_eval(y); let sin_k_cos_y = DoubleDouble::quick_mult(sin_k, r_sincos.v_cos); let cos_k_sin_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_sin); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; let ub = rr.hi + (rr.lo + r_sincos.err); // (rr.lo + ERR); let lb = rr.hi + (rr.lo - r_sincos.err); // (rr.lo - ERR); if ub == lb { return rr.to_f64(); } sinpi_dd(y, sin_k, cos_k) } /// Computes cos(PI*x) /// /// Max found ULP 0.5 pub fn f_cospi(x: f64) -> f64 { let ix = x.to_bits(); let ax = ix & 0x7fff_ffff_ffff_ffff; if ax == 0 { return 1.0; } let e: i32 = (ax >> 52) as i32; // e is the unbiased exponent, we have 2^(e-1023) <= |x| < 2^(e-1022) let m: i64 = ((ix & 0x000fffffffffffff) | (1u64 << 52)) as i64; let mut s = 1063i32.wrapping_sub(e); // 2^(40-s) <= |x| < 2^(41-s) if s < 0 { // |x| >= 2^41 if e == 0x7ff { // NaN or Inf if ix.wrapping_shl(12) == 0 { return f64::NAN; } return x + x; // NaN } s = -s - 1; // now 2^(41+s) <= |x| < 2^(42+s) if s > 11 { return 1.0; } // |x| >= 2^53 let iq: u64 = (m as u64).wrapping_shl(s as u32).wrapping_add(1024); if (iq & 2047) == 0 { return 0.0; } } if ax <= 0x3f30000000000000u64 { // |x| <= 2^-12, |x| <= 0.000244140625 if ax <= 0x3e2ccf6429be6621u64 { return 1.0 - f64::from_bits(0x3c80000000000000); } let x2 = x * x; let x4 = x2 * x2; let eps = x2 * f64::from_bits(0x3cfa000000000000); /* Generated by Sollya: d = [0, 0.000244140625]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|107, 107, D...|], d, relative, floating); See ./notes/cospi.sollya */ const C: [u64; 4] = [ 0xc013bd3cc9be45de, 0x40103c1f081b5ac4, 0xbff55d3c7ff79b60, 0x3fd24c7b6f7d0690, ]; let p0 = f_fmla(x2, f64::from_bits(C[3]), f64::from_bits(C[2])); let p1 = f_fmla(x2, f64::from_bits(C[1]), f64::from_bits(C[0])); let p = x2 * f_fmla(x4, p0, p1); let lb = (p - eps) + 1.; let ub = (p + eps) + 1.; if lb == ub { return lb; } return as_cospi_zero(x); } let si: i32 = e.wrapping_sub(1011); if si >= 0 && ((m as u64).wrapping_shl(si as u32) ^ 0x8000000000000000u64) == 0 { return 0.0; } let (y, k) = reduce_pi_64(x); // cos(k * pi/64) = sin(k * pi/64 + pi/2) = sin((k + 32) * pi/64). let msin_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(64) & 127) as usize], ); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); let r_sincos = sincospi_eval(y); let sin_k_cos_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_cos); let cos_k_sin_y = DoubleDouble::quick_mult(msin_k, r_sincos.v_sin); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; let ub = rr.hi + (rr.lo + r_sincos.err); // (rr.lo + ERR); let lb = rr.hi + (rr.lo - r_sincos.err); // (rr.lo - ERR); if ub == lb { return rr.to_f64(); } sinpi_dd(y, cos_k, msin_k) } /// Computes sin(PI*x) and cos(PI*x) /// /// Max found ULP 0.5 pub fn f_sincospi(x: f64) -> (f64, f64) { let ix = x.to_bits(); let ax = ix & 0x7fff_ffff_ffff_ffff; if ax == 0 { return (x, 1.0); } let e: i32 = (ax >> 52) as i32; // e is the unbiased exponent, we have 2^(e-1023) <= |x| < 2^(e-1022) let m0 = (ix & 0x000fffffffffffff) | (1u64 << 52); let m: i64 = ((ix & 0x000fffffffffffff) | (1u64 << 52)) as i64; let mut s = 1063i32.wrapping_sub(e); // 2^(40-s) <= |x| < 2^(41-s) if s < 0 { // |x| >= 2^41 if e == 0x7ff { // NaN or Inf if ix.wrapping_shl(12) == 0 { return (f64::NAN, f64::NAN); } return (x + x, x + x); // NaN } s = -s - 1; if s > 10 { static CF: [f64; 2] = [1., -1.]; let is_odd = is_odd_integer(f64::from_bits(ax)); let cos_x = CF[is_odd as usize]; return (f64::copysign(0.0, x), cos_x); } // |x| >= 2^53 let iq: u64 = (m as u64).wrapping_shl(s as u32); // sinpi = 0 when multiple of 2048 let sin_zero = (iq & 2047) == 0; // cospi = 0 when offset-by-half multiple of 2048 let cos_zero = ((m as u64).wrapping_shl(s as u32).wrapping_add(1024) & 2047) == 0; if sin_zero && cos_zero { // both zero (only possible if NaN or something degenerate) } else if sin_zero { static CF: [f64; 2] = [1., -1.]; let is_odd = is_odd_integer(f64::from_bits(ax)); let cos_x = CF[is_odd as usize]; return (0.0, cos_x); // sin = 0, cos = ±1 } else if cos_zero { // x = k / 2 * PI let si = e.wrapping_sub(1011); let t = (m0.wrapping_shl((si - 1) as u32)) >> 63; // making sin decision based on quadrant return if t == 0 { (f64::copysign(1.0, x), 0.0) } else { (-f64::copysign(1.0, x), 0.0) }; // sin = ±1, cos = 0 } } if ax <= 0x3f30000000000000u64 { // |x| <= 2^-12, |x| <= 0.000244140625 if ax <= 0x3c90000000000000u64 { const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); let sin_x = if ax < 0x0350000000000000 { let t = x * f64::from_bits(0x4690000000000000); let z = DoubleDouble::quick_mult_f64(PI, t); let r = z.to_f64(); let rs = r * f64::from_bits(0x3950000000000000); let rt = rs * f64::from_bits(0x4690000000000000); dyad_fmla((z.hi - rt) + z.lo, f64::from_bits(0x3950000000000000), rs) } else { let z = DoubleDouble::quick_mult_f64(PI, x); z.to_f64() }; return (sin_x, 1.0 - f64::from_bits(0x3c80000000000000)); } let x2 = x * x; let x4 = x2 * x2; let cos_eps = x2 * f64::from_bits(0x3cfa000000000000); /* Generated by Sollya: d = [0, 0.000244140625]; f_cos = cos(y*pi); Q = fpminimax(f_cos, [|0, 2, 4, 6, 8|], [|107, 107, D...|], d, relative, floating); See ./notes/cospi.sollya */ const COS_C: [u64; 4] = [ 0xc013bd3cc9be45de, 0x40103c1f081b5ac4, 0xbff55d3c7ff79b60, 0x3fd24c7b6f7d0690, ]; let p0 = f_fmla(x2, f64::from_bits(COS_C[3]), f64::from_bits(COS_C[2])); let p1 = f_fmla(x2, f64::from_bits(COS_C[1]), f64::from_bits(COS_C[0])); let p = x2 * f_fmla(x4, p0, p1); let cos_lb = (p - cos_eps) + 1.; let cos_ub = (p + cos_eps) + 1.; let cos_x = if cos_lb == cos_ub { cos_lb } else { as_cospi_zero(x) }; /* Poly generated by Sollya: d = [0, 0.03515625]; f_sin = sin(y*pi)/y; Q = fpminimax(f_sin, [|0, 2, 4, 6, 8, 10|], [|107, D...|], d, relative, floating); See ./notes/sinpi_zero.sollya */ const SIN_C: [u64; 4] = [ 0xc014abbce625be51, 0x400466bc67754b46, 0xbfe32d2cc12a51f4, 0x3fb5060540058476, ]; const C_PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a67088eb1a46, 0x400921fb54442d18)); let mut z = DoubleDouble::quick_mult_f64(C_PI, x); let x3 = x2 * x; let zl0 = f_fmla(x2, f64::from_bits(SIN_C[1]), f64::from_bits(SIN_C[0])); let zl1 = f_fmla(x2, f64::from_bits(SIN_C[3]), f64::from_bits(SIN_C[2])); let sin_eps = x * f_fmla( x2, f64::from_bits(0x3d00000000000000), // 2^-47 f64::from_bits(0x3bd0000000000000), // 2^-66 ); z.lo = f_fmla(x3, f_fmla(x4, zl1, zl0), z.lo); let sin_lb = z.hi + (z.lo - sin_eps); let sin_ub = z.hi + (z.lo + sin_eps); let sin_x = if sin_lb == sin_ub { sin_lb } else { as_sinpi_zero(x) }; return (sin_x, cos_x); } let si = e.wrapping_sub(1011); if si >= 0 && (m0.wrapping_shl(si.wrapping_add(1) as u32)) == 0 { // x is integer or half-integer if (m0.wrapping_shl(si as u32)) == 0 { static CF: [f64; 2] = [1., -1.]; let is_odd = is_odd_integer(f64::from_bits(ax)); let cos_x = CF[is_odd as usize]; return (f64::copysign(0.0, x), cos_x); // x is integer } // x is half-integer let t = (m0.wrapping_shl((si - 1) as u32)) >> 63; // t = 0 if |x| = 1/2 mod 2, t = 1 if |x| = 3/2 mod 2 return if t == 0 { (f64::copysign(1.0, x), 0.0) } else { (-f64::copysign(1.0, x), 0.0) }; } let (y, k) = reduce_pi_64(x); // cos(k * pi/64) = sin(k * pi/64 + pi/2) = sin((k + 32) * pi/64). let sin_k = DoubleDouble::from_bit_pair(SINPI_K_PI_OVER_64[((k as u64) & 127) as usize]); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); let msin_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(64) & 127) as usize], ); let r_sincos = sincospi_eval(y); let sin_k_cos_y = DoubleDouble::quick_mult(sin_k, r_sincos.v_cos); let cos_k_sin_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_sin); let mut rr_sin = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr_sin.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; let sin_ub = rr_sin.hi + (rr_sin.lo + r_sincos.err); // (rr.lo + ERR); let sin_lb = rr_sin.hi + (rr_sin.lo - r_sincos.err); // (rr.lo - ERR); let sin_k_cos_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_cos); let cos_k_sin_y = DoubleDouble::quick_mult(msin_k, r_sincos.v_sin); let mut rr_cos = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr_cos.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; let cos_ub = rr_cos.hi + (rr_cos.lo + r_sincos.err); // (rr.lo + ERR); let cos_lb = rr_cos.hi + (rr_cos.lo - r_sincos.err); // (rr.lo - ERR); if sin_ub == sin_lb && cos_lb == cos_ub { return (rr_sin.to_f64(), rr_cos.to_f64()); } sincospi_dd(y, sin_k, cos_k, cos_k, msin_k) } #[cfg(test)] mod tests { use super::*; #[test] fn test_sinpi() { assert_eq!(f_sinpi(262143.50006870925), -0.9999999767029883); assert_eq!(f_sinpi(7124076477593855.), 0.); assert_eq!(f_sinpi(-11235582092889474000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), -0.); assert_eq!(f_sinpi(-2.7430620343968443e303), -0.0); assert_eq!(f_sinpi(0.00003195557007273919), 0.00010039138401316004); assert_eq!(f_sinpi(-0.038357843137253766), -0.12021328061499763); assert_eq!(f_sinpi(1.0156097449358867), -0.04901980680173724); assert_eq!(f_sinpi(74.8593852519989), 0.42752597787896457); assert_eq!(f_sinpi(0.500091552734375), 0.9999999586369661); assert_eq!(f_sinpi(0.5307886532952182), 0.9953257438106751); assert_eq!(f_sinpi(3.1415926535897936), -0.43030121700009316); assert_eq!(f_sinpi(-0.5305172747685276), -0.9954077178320563); assert_eq!(f_sinpi(-0.03723630312089732), -0.1167146713267927); assert_eq!( f_sinpi(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022946074000077123), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007208721750737005 ); assert_eq!( f_sinpi(0.000000000000000000000000000000000000007413093439574428), 2.3288919890141717e-38 ); assert_eq!(f_sinpi(0.0031909299901270445), 0.0100244343161398578); assert_eq!(f_sinpi(0.11909245901270445), 0.36547215190661003); assert_eq!(f_sinpi(0.99909245901270445), 0.0028511202357662186); assert!(f_sinpi(f64::INFINITY).is_nan()); assert!(f_sinpi(f64::NEG_INFINITY).is_nan()); assert!(f_sinpi(f64::NAN).is_nan()); } #[test] fn test_sincospi() { let v0 = f_sincospi(1.0156097449358867); assert_eq!(v0.0, f_sinpi(1.0156097449358867)); assert_eq!(v0.1, f_cospi(1.0156097449358867)); let v1 = f_sincospi(4503599627370496.); assert_eq!(v1.0, f_sinpi(4503599627370496.)); assert_eq!(v1.1, f_cospi(4503599627370496.)); let v1 = f_sincospi(-108.); assert_eq!(v1.0, f_sinpi(-108.)); assert_eq!(v1.1, f_cospi(-108.)); let v1 = f_sincospi(3.); assert_eq!(v1.0, f_sinpi(3.)); assert_eq!(v1.1, f_cospi(3.)); let v1 = f_sincospi(13.5); assert_eq!(v1.0, f_sinpi(13.5)); assert_eq!(v1.1, f_cospi(13.5)); let v1 = f_sincospi(7124076477593855.); assert_eq!(v1.0, f_sinpi(7124076477593855.)); assert_eq!(v1.1, f_cospi(7124076477593855.)); let v1 = f_sincospi(2533419148247186.5); assert_eq!(v1.0, f_sinpi(2533419148247186.5)); assert_eq!(v1.1, f_cospi(2533419148247186.5)); let v1 = f_sincospi(2.2250653705240375E-308); assert_eq!(v1.0, f_sinpi(2.2250653705240375E-308)); assert_eq!(v1.1, f_cospi(2.2250653705240375E-308)); let v1 = f_sincospi(2533420818956351.); assert_eq!(v1.0, f_sinpi(2533420818956351.)); assert_eq!(v1.1, f_cospi(2533420818956351.)); let v1 = f_sincospi(2533822406803233.5); assert_eq!(v1.0, f_sinpi(2533822406803233.5)); assert_eq!(v1.1, f_cospi(2533822406803233.5)); let v1 = f_sincospi(-3040685725640478.5); assert_eq!(v1.0, f_sinpi(-3040685725640478.5)); assert_eq!(v1.1, f_cospi(-3040685725640478.5)); let v1 = f_sincospi(2533419148247186.5); assert_eq!(v1.0, f_sinpi(2533419148247186.5)); assert_eq!(v1.1, f_cospi(2533419148247186.5)); let v1 = f_sincospi(2533420819267583.5); assert_eq!(v1.0, f_sinpi(2533420819267583.5)); assert_eq!(v1.1, f_cospi(2533420819267583.5)); let v1 = f_sincospi(6979704728846336.); assert_eq!(v1.0, f_sinpi(6979704728846336.)); assert_eq!(v1.1, f_cospi(6979704728846336.)); let v1 = f_sincospi(7124076477593855.); assert_eq!(v1.0, f_sinpi(7124076477593855.)); assert_eq!(v1.1, f_cospi(7124076477593855.)); let v1 = f_sincospi(-0.00000000002728839192371484); assert_eq!(v1.0, f_sinpi(-0.00000000002728839192371484)); assert_eq!(v1.1, f_cospi(-0.00000000002728839192371484)); let v1 = f_sincospi(0.00002465398569495569); assert_eq!(v1.0, f_sinpi(0.00002465398569495569)); assert_eq!(v1.1, f_cospi(0.00002465398569495569)); } #[test] fn test_cospi() { assert_eq!(0.9999497540959953, f_cospi(0.0031909299901270445)); assert_eq!(0.9308216542079669, f_cospi(0.11909299901270445)); assert_eq!(-0.1536194873288318, f_cospi(0.54909299901270445)); assert!(f_cospi(f64::INFINITY).is_nan()); assert!(f_cospi(f64::NEG_INFINITY).is_nan()); assert!(f_cospi(f64::NAN).is_nan()); } } pxfm-0.1.23/src/sincospi_tables.rs000064400000000000000000000171651046102023000152110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** Generated by Sollya: ```python print("[") for k in range(128): k = RealField(150)(k) * RealField(150).pi() / RealField(150)(64) print_double_double("", k.sin()) print("];") ``` **/ pub(crate) static SINPI_K_PI_OVER_64: [(u64, u64); 128] = [ (0x0000000000000000, 0x0000000000000000), (0xbc2912bd0d569a90, 0x3fa91f65f10dd814), (0xbc3e2718d26ed688, 0x3fb917a6bc29b42c), (0x3c513000a89a11e0, 0x3fc2c8106e8e613a), (0xbc626d19b9ff8d82, 0x3fc8f8b83c69a60b), (0xbc642deef11da2c4, 0x3fcf19f97b215f1b), (0xbc75d28da2c4612d, 0x3fd294062ed59f06), (0xbc1efdc0d58cf620, 0x3fd58f9a75ab1fdd), (0xbc672cedd3d5a610, 0x3fd87de2a6aea963), (0x3c65b362cb974183, 0x3fdb5d1009e15cc0), (0x3c5e0d891d3c6841, 0x3fde2b5d3806f63b), (0xbc8a5a014347406c, 0x3fe073879922ffee), (0x3c8b25dd267f6600, 0x3fe1c73b39ae68c8), (0xbc6efcc626f74a6f, 0x3fe30ff7fce17035), (0x3c68076a2cfdc6b3, 0x3fe44cf325091dd6), (0xbc875720992bfbb2, 0x3fe57d69348ceca0), (0xbc8bdd3413b26456, 0x3fe6a09e667f3bcd), (0xbc70f537acdf0ad7, 0x3fe7b5df226aafaf), (0xbc82c5e12ed1336d, 0x3fe8bc806b151741), (0xbc830ee286712474, 0x3fe9b3e047f38741), (0x3c39f630e8b6dac8, 0x3fea9b66290ea1a3), (0xbc8bc69f324e6d61, 0x3feb728345196e3e), (0xbc76e0b1757c8d07, 0x3fec38b2f180bdb1), (0xbc5e7b6bb5ab58ae, 0x3feced7af43cc773), (0x3c7457e610231ac2, 0x3fed906bcf328d46), (0xbc8014c76c126527, 0x3fee212104f686e5), (0x3c8760b1e2e3f81e, 0x3fee9f4156c62dda), (0x3c752c7adc6b4989, 0x3fef0a7efb9230d7), (0x3c7562172a361fd3, 0x3fef6297cff75cb0), (0xbc87a0a8ca13571f, 0x3fefa7557f08a517), (0xbc887df6378811c7, 0x3fefd88da3d12526), (0xbc6c57bc2e24aa15, 0x3feff621e3796d7e), (0x0000000000000000, 0x3ff0000000000000), (0xbc6c57bc2e24aa15, 0x3feff621e3796d7e), (0xbc887df6378811c7, 0x3fefd88da3d12526), (0xbc87a0a8ca13571f, 0x3fefa7557f08a517), (0x3c7562172a361fd3, 0x3fef6297cff75cb0), (0x3c752c7adc6b4989, 0x3fef0a7efb9230d7), (0x3c8760b1e2e3f81e, 0x3fee9f4156c62dda), (0xbc8014c76c126527, 0x3fee212104f686e5), (0x3c7457e610231ac2, 0x3fed906bcf328d46), (0xbc5e7b6bb5ab58ae, 0x3feced7af43cc773), (0xbc76e0b1757c8d07, 0x3fec38b2f180bdb1), (0xbc8bc69f324e6d61, 0x3feb728345196e3e), (0x3c39f630e8b6dac8, 0x3fea9b66290ea1a3), (0xbc830ee286712474, 0x3fe9b3e047f38741), (0xbc82c5e12ed1336d, 0x3fe8bc806b151741), (0xbc70f537acdf0ad7, 0x3fe7b5df226aafaf), (0xbc8bdd3413b26456, 0x3fe6a09e667f3bcd), (0xbc875720992bfbb2, 0x3fe57d69348ceca0), (0x3c68076a2cfdc6b3, 0x3fe44cf325091dd6), (0xbc6efcc626f74a6f, 0x3fe30ff7fce17035), (0x3c8b25dd267f6600, 0x3fe1c73b39ae68c8), (0xbc8a5a014347406c, 0x3fe073879922ffee), (0x3c5e0d891d3c6841, 0x3fde2b5d3806f63b), (0x3c65b362cb974183, 0x3fdb5d1009e15cc0), (0xbc672cedd3d5a610, 0x3fd87de2a6aea963), (0xbc1efdc0d58cf620, 0x3fd58f9a75ab1fdd), (0xbc75d28da2c4612d, 0x3fd294062ed59f06), (0xbc642deef11da2c4, 0x3fcf19f97b215f1b), (0xbc626d19b9ff8d82, 0x3fc8f8b83c69a60b), (0x3c513000a89a11e0, 0x3fc2c8106e8e613a), (0xbc3e2718d26ed688, 0x3fb917a6bc29b42c), (0xbc2912bd0d569a90, 0x3fa91f65f10dd814), (0xb331056713b19377, 0xb69f77598338bfdf), (0x3c2912bd0d569a90, 0xbfa91f65f10dd814), (0x3c3e2718d26ed688, 0xbfb917a6bc29b42c), (0xbc513000a89a11e0, 0xbfc2c8106e8e613a), (0x3c626d19b9ff8d82, 0xbfc8f8b83c69a60b), (0x3c642deef11da2c4, 0xbfcf19f97b215f1b), (0x3c75d28da2c4612d, 0xbfd294062ed59f06), (0x3c1efdc0d58cf620, 0xbfd58f9a75ab1fdd), (0x3c672cedd3d5a610, 0xbfd87de2a6aea963), (0xbc65b362cb974183, 0xbfdb5d1009e15cc0), (0xbc5e0d891d3c6841, 0xbfde2b5d3806f63b), (0x3c8a5a014347406c, 0xbfe073879922ffee), (0xbc8b25dd267f6600, 0xbfe1c73b39ae68c8), (0x3c6efcc626f74a6f, 0xbfe30ff7fce17035), (0xbc68076a2cfdc6b3, 0xbfe44cf325091dd6), (0x3c875720992bfbb2, 0xbfe57d69348ceca0), (0x3c8bdd3413b26456, 0xbfe6a09e667f3bcd), (0x3c70f537acdf0ad7, 0xbfe7b5df226aafaf), (0x3c82c5e12ed1336d, 0xbfe8bc806b151741), (0x3c830ee286712474, 0xbfe9b3e047f38741), (0xbc39f630e8b6dac8, 0xbfea9b66290ea1a3), (0x3c8bc69f324e6d61, 0xbfeb728345196e3e), (0x3c76e0b1757c8d07, 0xbfec38b2f180bdb1), (0x3c5e7b6bb5ab58ae, 0xbfeced7af43cc773), (0xbc7457e610231ac2, 0xbfed906bcf328d46), (0x3c8014c76c126527, 0xbfee212104f686e5), (0xbc8760b1e2e3f81e, 0xbfee9f4156c62dda), (0xbc752c7adc6b4989, 0xbfef0a7efb9230d7), (0xbc7562172a361fd3, 0xbfef6297cff75cb0), (0x3c87a0a8ca13571f, 0xbfefa7557f08a517), (0x3c887df6378811c7, 0xbfefd88da3d12526), (0x3c6c57bc2e24aa15, 0xbfeff621e3796d7e), (0x0000000000000000, 0xbff0000000000000), (0x3c6c57bc2e24aa15, 0xbfeff621e3796d7e), (0x3c887df6378811c7, 0xbfefd88da3d12526), (0x3c87a0a8ca13571f, 0xbfefa7557f08a517), (0xbc7562172a361fd3, 0xbfef6297cff75cb0), (0xbc752c7adc6b4989, 0xbfef0a7efb9230d7), (0xbc8760b1e2e3f81e, 0xbfee9f4156c62dda), (0x3c8014c76c126527, 0xbfee212104f686e5), (0xbc7457e610231ac2, 0xbfed906bcf328d46), (0x3c5e7b6bb5ab58ae, 0xbfeced7af43cc773), (0x3c76e0b1757c8d07, 0xbfec38b2f180bdb1), (0x3c8bc69f324e6d61, 0xbfeb728345196e3e), (0xbc39f630e8b6dac8, 0xbfea9b66290ea1a3), (0x3c830ee286712474, 0xbfe9b3e047f38741), (0x3c82c5e12ed1336d, 0xbfe8bc806b151741), (0x3c70f537acdf0ad7, 0xbfe7b5df226aafaf), (0x3c8bdd3413b26456, 0xbfe6a09e667f3bcd), (0x3c875720992bfbb2, 0xbfe57d69348ceca0), (0xbc68076a2cfdc6b3, 0xbfe44cf325091dd6), (0x3c6efcc626f74a6f, 0xbfe30ff7fce17035), (0xbc8b25dd267f6600, 0xbfe1c73b39ae68c8), (0x3c8a5a014347406c, 0xbfe073879922ffee), (0xbc5e0d891d3c6841, 0xbfde2b5d3806f63b), (0xbc65b362cb974183, 0xbfdb5d1009e15cc0), (0x3c672cedd3d5a610, 0xbfd87de2a6aea963), (0x3c1efdc0d58cf620, 0xbfd58f9a75ab1fdd), (0x3c75d28da2c4612d, 0xbfd294062ed59f06), (0x3c642deef11da2c4, 0xbfcf19f97b215f1b), (0x3c626d19b9ff8d82, 0xbfc8f8b83c69a60b), (0xbc513000a89a11e0, 0xbfc2c8106e8e613a), (0x3c3e2718d26ed688, 0xbfb917a6bc29b42c), (0x3c2912bd0d569a90, 0xbfa91f65f10dd814), ]; pxfm-0.1.23/src/sincpi.rs000064400000000000000000000241421046102023000133060ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::polyeval::f_estrin_polyeval5; use crate::sincospi::reduce_pi_64; use crate::sincospi_tables::SINPI_K_PI_OVER_64; /** Sinpi on range [0.0, 0.03515625] Generated poly by Sollya: ```text d = [0, 0.03515625]; f_sincpi = sin(y*pi)/(y*pi); Q = fpminimax(f_sincpi, [|0, 2, 4, 6, 8, 10, 12|], [|107...|], d, relative, floating); ``` See ./notes/sincpi_at_zero_dd.sollya **/ #[cold] fn as_sincpi_zero(x: f64) -> f64 { const C: [(u64, u64); 7] = [ (0xb9d3080000000000, 0x3ff0000000000000), (0xbc81873d86314302, 0xbffa51a6625307d3), (0x3c84871b4ffeefae, 0x3fe9f9cb402bc46c), (0xbc5562d6ae037010, 0xbfc86a8e4720db66), (0xbc386c93f4549bac, 0x3f9ac6805cf31ffd), (0x3c0dbda368edfa40, 0xbf633816a3399d4e), (0xbbcf22ccc18f27a9, 0x3f23736e6a59edd9), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut p = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(C[6]), DoubleDouble::from_bit_pair(C[5]), ); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[4])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::quick_mul_add(x2, p, DoubleDouble::from_bit_pair(C[0])); p.to_f64() } /// Computes sin(PI*x)/(PI*x) /// /// Produces normalized sinc. /// /// Max ULP 0.5 pub fn f_sincpi(x: f64) -> f64 { let ix = x.to_bits(); let ax = ix & 0x7fff_ffff_ffff_ffff; if ax == 0 { return 1.; } let e: i32 = (ax >> 52) as i32; let m0 = (ix & 0x000fffffffffffff) | (1u64 << 52); let sgn: i64 = (ix as i64) >> 63; let m = ((m0 as i64) ^ sgn).wrapping_sub(sgn); let mut s: i32 = 1063i32.wrapping_sub(e); if s < 0 { if e == 0x7ff { if (ix << 12) == 0 { return f64::NAN; } return x + x; // case x=NaN } s = -s - 1; if s > 10 { return f64::copysign(0.0, x); } let iq: u64 = (m as u64).wrapping_shl(s as u32); if (iq & 2047) == 0 { return f64::copysign(0.0, x); } } if ax <= 0x3fa2000000000000u64 { // |x| <= 0.03515625 if ax < 0x3c90000000000000 { const M_SQR_PI_OVER_6: f64 = f64::from_bits(0xbffa51a6625307d3); // Small values approximated with Taylor poly // sincpi(x) ~ 1 - x^2*Pi^2/6 + O(x^4) let x2 = x * x; let p = f_fmla(x2, M_SQR_PI_OVER_6, 1.); return p; } // Poly generated by Sollya: // d = [0, 0.03515625]; // f_sincpi = sin(y*pi)/(y*pi); // Q = fpminimax(f_sincpi, [|0, 2, 4, 6, 8, 10|], [|107, D...|], d, relative, floating); // See ./notes/sincpi_at_zero.sollya let x2 = x * x; let eps = x * f_fmla( x2, f64::from_bits(0x3d00000000000000), // 2^-47 f64::from_bits(0x3bd0000000000000), // 2^-66 ); const C: [u64; 5] = [ 0xbffa51a6625307d3, 0x3fe9f9cb402bbeaa, 0xbfc86a8e466bbb5b, 0x3f9ac66d887e2f38, 0xbf628473a38d289a, ]; const F: DoubleDouble = DoubleDouble::from_bit_pair((0xbb93f0a925810000, 0x3ff0000000000000)); let p = f_estrin_polyeval5( x2, f64::from_bits(C[0]), f64::from_bits(C[1]), f64::from_bits(C[2]), f64::from_bits(C[3]), f64::from_bits(C[4]), ); let v = DoubleDouble::from_exact_mult(p, x2); let z = DoubleDouble::add(F, v); let lb = z.hi + (z.lo - eps); let ub = z.hi + (z.lo + eps); if lb == ub { return lb; } return as_sincpi_zero(x); } let si = e.wrapping_sub(1011); if si >= 0 && (m0.wrapping_shl(si.wrapping_add(1) as u32)) == 0 { // x is integer or half-integer if (m0.wrapping_shl(si as u32)) == 0 { return f64::copysign(0.0, x); // x is integer } let t = (m0.wrapping_shl((si - 1) as u32)) >> 63; // t = 0 if |x| = 1/2 mod 2, t = 1 if |x| = 3/2 mod 2 #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let num = if t == 0 { f64::copysign(1.0, x) } else { -f64::copysign(1.0, x) }; const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18)); let r = DoubleDouble::quick_mult_f64(PI, x); let v = DoubleDouble::from_f64_div_dd(num, r); return v.to_f64(); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::two_product_compatible; if two_product_compatible(x) { let num = if t == 0 { f64::copysign(1.0, x) } else { -f64::copysign(1.0, x) }; const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18)); let r = DoubleDouble::quick_mult_f64(PI, x); let v = DoubleDouble::from_f64_div_dd(num, r); return v.to_f64(); } else { use crate::dyadic_float::{DyadicFloat128, DyadicSign}; let num = DyadicFloat128::new_from_f64(if t == 0 { f64::copysign(1.0, x) } else { -f64::copysign(1.0, x) }); const PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -126, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; let dx = DyadicFloat128::new_from_f64(x); let r = (PI * dx).reciprocal(); return (num * r).fast_as_f64(); } } } let (y, k) = reduce_pi_64(x); // cos(k * pi/64) = sin(k * pi/64 + pi/2) = sin((k + 32) * pi/64). let sin_k = DoubleDouble::from_bit_pair(SINPI_K_PI_OVER_64[((k as u64) & 127) as usize]); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); let r_sincos = crate::sincospi::sincospi_eval(y); const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18)); let scale = DoubleDouble::quick_mult_f64(PI, x); let sin_k_cos_y = DoubleDouble::quick_mult(sin_k, r_sincos.v_cos); let cos_k_sin_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_sin); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = DoubleDouble::from_exact_add(rr.hi, rr.lo); rr = DoubleDouble::div(rr, scale); let ub = rr.hi + (rr.lo + r_sincos.err); // (rr.lo + ERR); let lb = rr.hi + (rr.lo - r_sincos.err); // (rr.lo - ERR); if ub == lb { return rr.to_f64(); } sincpi_dd(y, sin_k, cos_k, scale) } #[cold] fn sincpi_dd(x: f64, sin_k: DoubleDouble, cos_k: DoubleDouble, scale: DoubleDouble) -> f64 { let r_sincos = crate::sincospi::sincospi_eval_dd(x); let cos_k_sin_y = DoubleDouble::quick_mult(cos_k, r_sincos.v_sin); let mut rr = DoubleDouble::mul_add(sin_k, r_sincos.v_cos, cos_k_sin_y); rr = DoubleDouble::div(rr, scale); rr.to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_sincpi_zero() { assert_eq!(f_sincpi(0.007080019335262543), 0.9999175469662566); assert_eq!(f_sincpi(0.05468860710998057), 0.9950875152844803); assert_eq!(f_sincpi(0.5231231231), 0.6068750737806441); assert_eq!(f_sincpi(1.), 0.); assert_eq!(f_sincpi(-1.), 0.); assert_eq!(f_sincpi(-2.), 0.); assert_eq!(f_sincpi(-3.), 0.); assert!(f_sincpi(f64::INFINITY).is_nan()); assert!(f_sincpi(f64::NEG_INFINITY).is_nan()); assert!(f_sincpi(f64::NAN).is_nan()); } } pxfm-0.1.23/src/sinmx.rs000064400000000000000000000175601046102023000131650ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::polyeval::f_estrin_polyeval5; use crate::sin::{range_reduction_small, sincos_eval}; use crate::sin_helper::sincos_eval_dd; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_reduce::LargeArgumentReduction; #[cold] #[inline(never)] fn sinmx_accurate(y: DoubleDouble, sin_k: DoubleDouble, cos_k: DoubleDouble, x: f64) -> f64 { let r_sincos = sincos_eval_dd(y); // k is an integer and -pi / 256 <= y <= pi / 256. // Then sin(x) = sin((k * pi/128 + y) // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = DoubleDouble::from_exact_add(rr.hi, rr.lo); rr = DoubleDouble::full_add_f64(rr, -x); rr.to_f64() } #[cold] fn sinmx_near_zero_hard(x: f64) -> f64 { const C: [(u64, u64); 8] = [ (0xb37137ef120d4bbd, 0xb6db8d4e2aa9f813), (0xbc6555555554e720, 0xbfc5555555555555), (0x3c01110fff8e3ea0, 0x3f81111111111111), (0xbb6314569388b856, 0xbf2a01a01a01a01a), (0xbb61f946e615f3cd, 0x3ec71de3a556c723), (0x3a8998bc94bd3bf0, 0xbe5ae64567f2d4df), (0xba702e73490290eb, 0x3de61245e54b6747), (0xba0182df5b1ffd4c, 0xbd6ae4894bb27213), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut p = DoubleDouble::mul_add( x2, DoubleDouble::from_bit_pair(C[7]), DoubleDouble::from_bit_pair(C[6]), ); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[5])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[4])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[3])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[2])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[1])); p = DoubleDouble::mul_add(x2, p, DoubleDouble::from_bit_pair(C[0])); p = DoubleDouble::quick_mult_f64(p, x); p.to_f64() } /// Computes sin(x) - x /// /// ULP 0.5 pub fn f_sinmx(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) if x_e < E_BIAS + 16 { if x_e < E_BIAS - 6 { // |x| < 2^-6 if x_e < E_BIAS - 32 { // |x| < 2^-32 // Signed zeros. if x == 0.0 { return x; } // For |x| < 2^-32, taylor series sin(x) - x ~ -x^3/6 let x2 = x * x; let c = f_fmla( x2, f64::from_bits(0x3f81111111111111), f64::from_bits(0xbfc5555555555555), ) * x2; return c * x; } // Generated by Sollya: // d = [2^-26, pi/16]; // f_sinmx = (sin(x) - x)/x; // Q = fpminimax(f_sinmx, [|0, 2, 4, 6, 8, 10, 12|], [|127, 127, D...|], d); let x2 = DoubleDouble::from_exact_mult(x, x); let p = f_estrin_polyeval5( x2.hi, f64::from_bits(0x3f81111111111111), f64::from_bits(0xbf2a01a01a019d2f), f64::from_bits(0x3ec71de3a5269512), f64::from_bits(0xbe5ae642b76ba0f5), f64::from_bits(0x3de6035da3c7eaed), ); let mut c = DoubleDouble::mul_f64_add( x2, p, DoubleDouble::from_bit_pair((0xbc655542976eb2af, 0xbfc5555555555555)), ); c = DoubleDouble::mul_add( x2, c, DoubleDouble::from_bit_pair((0x34b215c35dc9e9be, 0xb832bde584573661)), ); c = DoubleDouble::quick_mult_f64(c, x); let err = f_fmla( x2.hi, f64::from_bits(0x3cc0000000000000), // 2^-51 f64::from_bits(0x3bc0000000000000), // 2^-67 ); let ub = c.hi + (c.lo + err); let lb = c.hi + (c.lo - err); if ub == lb { return c.to_f64(); } return sinmx_near_zero_hard(x); } // // Small range reduction. (y, k) = range_reduction_small(x); } else { // Inf or NaN if x_e > 2 * E_BIAS { // sin(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let r_sincos = sincos_eval(y); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let sin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let sin_k_cos_y = DoubleDouble::quick_mult(r_sincos.v_cos, sin_k); let cos_k_sin_y = DoubleDouble::quick_mult(r_sincos.v_sin, cos_k); let mut rr = DoubleDouble::from_full_exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; rr = DoubleDouble::from_exact_add(rr.hi, rr.lo); rr = DoubleDouble::full_add_f64(rr, -x); let rlp = rr.lo + r_sincos.err; let rlm = rr.lo - r_sincos.err; let r_upper = rr.hi + rlp; // (rr.lo + ERR); let r_lower = rr.hi + rlm; // (rr.lo - ERR); // Ziv's accuracy test if r_upper == r_lower { return rr.to_f64(); } sinmx_accurate(y, sin_k, cos_k, x) } #[cfg(test)] mod tests { use super::*; #[test] fn f_sinf_test() { assert_eq!(f_sinmx(0.0), 0.0); assert_eq!(f_sinmx(1.0), -0.1585290151921035); assert_eq!(f_sinmx(0.3), -0.0044797933386604245); assert_eq!(f_sinmx(-1.0), 0.1585290151921035); assert_eq!(f_sinmx(-0.3), 0.0044797933386604245); assert_eq!(f_sinmx(std::f64::consts::PI / 2.), -0.5707963267948966); assert!(f_sinmx(f64::INFINITY).is_nan()); assert!(f_sinmx(f64::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/square_root/mod.rs000064400000000000000000000033371046102023000151460ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod rsqrt; mod rsqrtf; mod sqrtf; pub use rsqrt::f_rsqrt; pub use rsqrtf::f_rsqrtf; pub use sqrtf::sqrtf; pxfm-0.1.23/src/square_root/rsqrt.rs000064400000000000000000000136351046102023000155440ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; /// Computes 1/sqrt(x) /// /// Max ULP 0.5 pub fn f_rsqrt(x: f64) -> f64 { let ix = x.to_bits(); let r: f64 = if ix < 1u64 << 52 { // 0 <= x < 0x1p-1022 if ix != 0 { // x <> +0 x.sqrt() / x } else { return f64::INFINITY; // case x = +0 } } else if ix >= 0x7ffu64 << 52 { // NaN, Inf, x <= 0 if ix.wrapping_shl(1) == 0 { return f64::NEG_INFINITY; // x=-0 } if ix > 0xfff0000000000000u64 { return x + x; } // -NaN if (ix >> 63) != 0 { // x < 0 return f64::NAN; } if ix.wrapping_shl(12) == 0 { return 0.0; } // +/-Inf return x + x; // +NaN } else { // 0x1p-1022 <= x < 2^1024 if ix > 0x7fd000000000000u64 { // x > 2^1022 // avoid spurious underflow in 1/x (4.0 / x) * (0.25 * x.sqrt()) } else { (1.0 / x) * x.sqrt() } }; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let d2x = DoubleDouble::from_exact_mult(r, x); use crate::common::f_fmla; let h = f_fmla(r, d2x.lo, f_fmla(r, d2x.hi, -1.0)); let dr = (r * 0.5) * h; r - dr } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::two_product_compatible; if !two_product_compatible(x) { recip_hard_dyadic(x, r) } else { let d2x = DoubleDouble::from_exact_mult(r, x); let DoubleDouble { hi: h, lo: pr } = DoubleDouble::quick_mult_f64(d2x, r); let DoubleDouble { hi: p, lo: q } = DoubleDouble::from_full_exact_add(-1.0, h); let h = DoubleDouble::from_exact_add(p, pr + q); let dr = DoubleDouble::quick_mult_f64(h, r * 0.5); r - dr.hi - dr.lo } } } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] #[cold] #[inline(never)] fn recip_hard_dyadic(x: f64, r: f64) -> f64 { use crate::dyadic_float::{DyadicFloat128, DyadicSign}; let dx = DyadicFloat128::new_from_f64(x); let dr = DyadicFloat128::new_from_f64(r); const M_ONE: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }; let d2 = dx * dr; let h = d2 * dr + M_ONE; let mut half_dr = dr; half_dr.exponent -= 1; // * 0.5; let ddr = half_dr * h; (dr - ddr).fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_rsqrt() { assert_eq!(f_rsqrt(7518001163502890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011533172976634968); assert_eq!(f_rsqrt(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001984274103353), 709903255474595300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.); assert_eq!(f_rsqrt(0.0), f64::INFINITY); assert_eq!(f_rsqrt(4.0), 0.5); assert_eq!(f_rsqrt(9.0), 1. / 3.); assert_eq!(f_rsqrt(-0.0), f64::NEG_INFINITY); assert!(f_rsqrt(f64::NAN).is_nan()); } } pxfm-0.1.23/src/square_root/rsqrtf.rs000064400000000000000000000046621046102023000157120ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /// Computes 1/sqrt(x) /// /// Max ULP 0.5 #[inline] pub fn f_rsqrtf(x: f32) -> f32 { let ix = x.to_bits(); // filter out exceptional cases if ix >= 0xffu32 << 23 || ix == 0 { if ix.wrapping_shl(1) == 0 { return 1.0 / x; // +/-0 } if (ix >> 31) != 0 { return f32::NAN; } if ix.wrapping_shl(9) == 0 { return 0.; } return x + x; // nan } let dx = x as f64; ((1. / dx) * dx.sqrt()) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_rsqrtf() { assert_eq!(f_rsqrtf(0.0), f32::INFINITY); assert_eq!(f_rsqrtf(4.0), 0.5); assert_eq!(f_rsqrtf(9.0), 1. / 3.); assert_eq!(f_rsqrtf(-0.0), f32::NEG_INFINITY); assert!(f_rsqrtf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/square_root/sqrtf.rs000064400000000000000000000060111046102023000155160ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /// Computes Square root. /// Most of CPU have built-in instruction with higher precision, /// prefer use this only for const contexts. #[inline] pub const fn sqrtf(d: f32) -> f32 { let mut q = 0.5f32; let mut d = if d < 0f32 { f32::NAN } else { d }; if d < 5.2939559203393770e-23f32 { d *= 1.8889465931478580e+22f32; q = 7.2759576141834260e-12f32; } if d > 1.8446744073709552e+19f32 { d *= 5.4210108624275220e-20f32; q = 4294967296.0f32; } // http://en.wikipedia.org/wiki/Fast_inverse_square_root let mut x = f32::from_bits(0x5f375a86 - ((d + 1e-45).to_bits() >> 1)) as f64; x = x * (1.5 - 0.5 * (d as f64) * x * x); x = x * (1.5 - 0.5 * (d as f64) * x * x); x = x * (1.5 - 0.5 * (d as f64) * x * x) * (d as f64); let d2 = ((d as f64) + x * x) * (1. / x); if d.is_infinite() { return f32::INFINITY; } (d2 * q as f64) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn sqrtf_test() { assert!( (sqrtf(4f32) - 2f32).abs() < 1e-6, "Invalid result {}", sqrtf(4f32) ); assert!( (sqrtf(9f32) - 3f32).abs() < 1e-6, "Invalid result {}", sqrtf(9f32) ); assert_eq!(sqrtf(4.), 2.); assert_eq!(sqrtf(9.), 3.); assert_eq!(sqrtf(16.), 4.); assert_eq!(sqrtf(25.), 5.); } } pxfm-0.1.23/src/tangent/atan.rs000064400000000000000000000342551046102023000144120ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::shared_eval::poly_dd_3; pub(crate) static ATAN_CIRCLE: [[u16; 3]; 31] = [ [419, 81, 0], [500, 81, 0], [582, 163, 0], [745, 163, 0], [908, 326, 0], [1234, 326, 0], [1559, 651, 0], [2210, 650, 1], [2860, 1299, 3], [4156, 1293, 4], [5444, 2569, 24], [7989, 2520, 32], [10476, 4917, 168], [15224, 4576, 200], [19601, 8341, 838], [27105, 6648, 731], [33036, 10210, 1998], [41266, 6292, 1117], [46469, 7926, 2048], [52375, 4038, 849], [55587, 4591, 1291], [58906, 2172, 479], [60612, 2390, 688], [62325, 1107, 247], [63192, 1207, 349], [64056, 556, 124], [64491, 605, 175], [64923, 278, 62], [65141, 303, 88], [65358, 139, 31], [65467, 151, 44], ]; pub(crate) static ATAN_REDUCE: [(u64, u64); 129] = [ (0x0000000000000000, 0x0000000000000000), (0x3f89224e047e368e, 0x3c1a3ca6c727c59d), (0x3f992346247a91f0, 0x3bf138b0ef96a186), (0x3fa2dbaae9a05db0, 0x3c436e7f8a3f5e42), (0x3fa927278a3b1162, 0xbbfac986efb92662), (0x3faf7495ea3f3783, 0x3c406ec8011ee816), (0x3fb2e239ccff3831, 0xbc5858437d431332), (0x3fb60b9f7597fdec, 0xbc3cebd13eb7c513), (0x3fb936bb8c5b2da2, 0xbc5840cac0d81db5), (0x3fbc63ce377fc802, 0x3c5400b0fdaa109e), (0x3fbf93183a8db9e9, 0x3c40e04e06c86e72), (0x3fc1626d85a91e70, 0x3c4f7ad829163ca7), (0x3fc2fcac73a60640, 0xbc52680735ce2cd8), (0x3fc4986a74cf4e57, 0xbc690559690b42e4), (0x3fc635c990ce0d36, 0x3c591d29110b41aa), (0x3fc7d4ec54fb5968, 0xbc4ea90e27182780), (0x3fc975f5e0553158, 0xbc2dc82ac14e3e1c), (0x3fcb1909efd8b762, 0xbc573a10fd13daaf), (0x3fccbe4ceb4b4cf2, 0xbc63a7ffbeabda0b), (0x3fce65e3f27c9f2a, 0xbc6db6627a24d523), (0x3fd007fa758626ae, 0xbc645f97dd3099f6), (0x3fd0de53475f3b3c, 0xbc66293f68741816), (0x3fd1b6103d3597e9, 0xbc6ab240d40633e9), (0x3fd28f459ecad74d, 0xbc2de34d14e832e0), (0x3fd36a08355c63dc, 0x3c6af540d9fb4926), (0x3fd4466d542bac92, 0x3c6da60fdbc82ac4), (0x3fd5248ae1701b17, 0xbc792a601170138a), (0x3fd604775fbb27df, 0xbc67f1fca1d5d15b), (0x3fd6e649f7d78649, 0xbc64e223ea716c7b), (0x3fd7ca1a832d0f84, 0x3c7b24c824ac51fc), (0x3fd8b00196b3d022, 0x3c64314cd132ba43), (0x3fd998188e816bf0, 0xbc711f1e0817879a), (0x3fda827999fcef32, 0xbc6c3dea4dbad538), (0x3fdb6f3fc8c61e5b, 0x3c660d1b780ee3eb), (0x3fdc5e87185e67b6, 0xbc4ab5edb7dfa545), (0x3fdd506c82a2c800, 0xbc68e1437048b5bd), (0x3fde450e0d273e7a, 0xbc706951c97b050f), (0x3fdf3c8ad985d9ee, 0xbc414af9522ab518), (0x3fe01b819b5a7cf7, 0xbc7aba0d7d97d1f2), (0x3fe09a4c59bd0d4d, 0x3c4095bc4ebc2c42), (0x3fe11ab7190834ec, 0x3c8798826fa27774), (0x3fe19cd3fe8e405d, 0x3c8008f6258fc98f), (0x3fe220b5ef047825, 0xbc5462af7ceb7de6), (0x3fe2a6709a74f289, 0xbc71184dfd78b472), (0x3fe32e1889047ffd, 0x3c79141876dc40c5), (0x3fe3b7c3289ed6f3, 0x3c8481c20189726c), (0x3fe44386db9ce5db, 0x3c82e851bd025441), (0x3fe4d17b087b265d, 0x3c713ada9b8bc419), (0x3fe561b82ab7f990, 0xbc805b4c3c4cbee8), (0x3fe5f457e4f4812e, 0xbc85619249bd96f1), (0x3fe6897514751db6, 0xbc6b0a0fbcafc671), (0x3fe7212be621be6d, 0xbc819ff2dc66da45), (0x3fe7bb99ed2990cf, 0x3c81320449592d92), (0x3fe858de3b716571, 0xbc81fddcd2f3da8e), (0x3fe8f9197bf85eeb, 0x3c6d44a42e35cc97), (0x3fe99c6e0f634394, 0xbc7585a178b4a18d), (0x3fea43002ae42850, 0x3c6f95a531b3a970), (0x3feaecf5f9ba35a6, 0xbc396c2d43ca3392), (0x3feb9a77c18c1af2, 0xbc6a5bed94b05def), (0x3fec4bb009e77983, 0x3c454509d2bff511), (0x3fed00cbc7384d2e, 0xbc6b4c867cef300c), (0x3fedb9fa89953fcf, 0xbc1ddfac663d6bc6), (0x3fee776eafc91706, 0xbc7a510683ff7cb6), (0x3fef395d9f0e3c92, 0x3c44fdcd8e4e8710), (0x3ff0000000000000, 0x0000000000000000), (0x3ff065c900aaf2d8, 0xbc8deec7fc9042ad), (0x3ff0ce29d0883c99, 0xbc8395ae45e0657d), (0x3ff139447e6a86ee, 0x3c8332cf301a97f3), (0x3ff1a73d55278c4b, 0xbc86cc8c4b78213b), (0x3ff2183b0c4573ff, 0x3c870a90841da57a), (0x3ff28c66fdaf8f09, 0xbc6ba39bad450ee0), (0x3ff303ed61109e20, 0xbc88692946d9f93c), (0x3ff37efd8d87607e, 0x3c63b711bf765b58), (0x3ff3fdca42847507, 0x3c7c21387985b081), (0x3ff48089f8bf42cc, 0xbc87ddb19d3d0efc), (0x3ff507773c537ead, 0xbc7f5e354cf971f3), (0x3ff592d11142fa55, 0xbc700f0ad675330d), (0x3ff622db63c8ecc2, 0xbc82c93f50ab2c0e), (0x3ff6b7df86265200, 0x3c7bec391adc37d5), (0x3ff7522cbdd428a8, 0xbc69686ddc9ffcf5), (0x3ff7f218e25a7461, 0xbc78d16529514246), (0x3ff89801106cc709, 0xbc8092f51e9c2803), (0x3ff9444a7462122a, 0xbc807c06755404c4), (0x3ff9f7632fa9e871, 0x3c802e0d43abc92b), (0x3ffab1c35d8a74ea, 0x3c5d0184e48af6f7), (0x3ffb73ee3c3ef16a, 0x3c773be957380bc2), (0x3ffc3e738086bc0f, 0xbc702b6e26c84462), (0x3ffd11f0dae40609, 0x3c525c4f3ffa6e1f), (0x3ffdef13b73c1406, 0xbc5e302db3c6823f), (0x3ffed69b4153a45d, 0x3c73207830326c0e), (0x3fffc95abad6cf4a, 0xbc66308cee7927bf), (0x4000641e192ceab3, 0xbc70147ebf0df4c5), (0x4000ea21d716fbf7, 0xbc7168533cc41d8b), (0x40017749711a6679, 0xbc652a0b0333e9c5), (0x40020c36c6a7f38e, 0x3c68659eece35395), (0x4002a99f50fd4f4f, 0x3c820fcad18cb36f), (0x4003504f333f9de6, 0xbc752afdbd5a8c74), (0x4004012ce2586a17, 0xbc79747a792907d7), (0x4004bd3d87fe0650, 0x3c790c59393b52c8), (0x400585aa4e1530fa, 0x3c7af6934f13a3a8), (0x40065bc6cc825147, 0xbc48534dcab5ad3e), (0x40074118e4b6a7c8, 0xbc7555aa8bfca9a1), (0x400837626d70fdb8, 0xbc556b3fee9ca72b), (0x400940ad30abc792, 0x3c54b3fdd4fdc06c), (0x400a5f59e90600dd, 0x3c6285d367c55ddc), (0x400b9633283b6d14, 0xbc48712976f17a16), (0x400ce885653127e7, 0xbc3abe8ab65d49fc), (0x400e5a3de972a377, 0x3c5cd9be81ad764b), (0x400ff01305ecd8dc, 0x3c4742c2922656fa), (0x4010d7dc7cff4c9e, 0xbc77c842978bee09), (0x4011d0143e71565f, 0x3c67bc7dea7c3c03), (0x4012e4ff1626b949, 0x3c4aefbe25b404e9), (0x40141bfee2424771, 0xbc34bcfaaa95cb2c), (0x40157be4eaa5e11b, 0x3c50fe741e4ec679), (0x40170d751908c1b1, 0x3c5fe74a5b0ec709), (0x4018dc25c117782b, 0x3c50ca1c19f710ef), (0x401af73f4ca3310f, 0x3c52867b40ba77d6), (0x401d7398d15e70db, 0x3c60fd4e0d4b1547), (0x4020372fb36b87e2, 0x3c5c16c9ecc1621d), (0x402208dbdae055ef, 0x3c56b81a36e75e8c), (0x40244e6c595afdcc, 0xbc57c22045771848), (0x4027398c57f3f1ad, 0x3c5970503be105c0), (0x402b1d03c03d2f7f, 0xbc3f299d010aead2), (0x403046e9fe60a77e, 0x3c5d2b61deff33ec), (0x40345affed201b55, 0x3bf0e84d9567203a), (0x403b267195b1ffae, 0xbbfad44b44b92653), (0x40445e2455e4aaa7, 0xbc3296d577b5e21d), (0x40545eed6854ce99, 0x3c02db53886013ca), (0x0000000000000000, 0x0000000000000000), ]; #[cold] fn atan_refine(x: f64, a: f64) -> f64 { const CH: [(u64, u64); 3] = [ (0xbfd5555555555555, 0xbc75555555555555), (0x3fc999999999999a, 0xbc6999999999bcb8), (0xbfc2492492492492, 0xbc6249242093c016), ]; const CL: [u64; 4] = [ 0x3fbc71c71c71c71c, 0xbfb745d1745d1265, 0x3fb3b13b115bcbc4, 0xbfb1107c41ad3253, ]; let phi = f_fmla(a.abs(), f64::from_bits(0x40545f306dc9c883), 256.5).to_bits(); let i = ((phi >> (52 - 8)) & 0xff) as i64; let h: DoubleDouble = if i == 128 { DoubleDouble::from_quick_recip(-x) } else { let ta = f64::copysign(f64::from_bits(ATAN_REDUCE[i as usize].0), x); let dzt = DoubleDouble::from_exact_mult(x, ta); let zmta = x - ta; let v = 1.0 + dzt.hi; let d = 1.0 - v; let ev = (d + dzt.hi) - ((d + v) - 1.0) + dzt.lo; let r = 1.0 / v; let rl = f_fmla(-ev, r, dd_fmla(r, -v, 1.0)) * r; DoubleDouble::quick_mult_f64(DoubleDouble::new(rl, r), zmta) }; let h2 = DoubleDouble::quick_mult(h, h); let h3 = DoubleDouble::quick_mult(h, h2); let h4 = h2.hi * h2.hi; let zw0 = f_fmla(h2.hi, f64::from_bits(CL[3]), f64::from_bits(CL[2])); let zw1 = f_fmla(h2.hi, f64::from_bits(CL[1]), f64::from_bits(CL[0])); let zfl = f_fmla(h2.hi, zw1, h4 * zw0); let mut f = poly_dd_3(h2, CH, zfl); f = DoubleDouble::quick_mult(h3, f); let (ah, mut az); if i == 0 { ah = h.hi; az = f; } else { let mut df = 0.; if i < 128 { df = f64::copysign(1.0, x) * f64::from_bits(ATAN_REDUCE[i as usize].1); } let id = f64::copysign(i as f64, x); ah = f64::from_bits(0x3f8921fb54442d00) * id; az = DoubleDouble::new( f64::from_bits(0xb97fc8f8cbb5bf80) * id, f64::from_bits(0x3c88469898cc5180) * id, ); az = DoubleDouble::add(az, DoubleDouble::new(0., df)); az = DoubleDouble::add(az, h); az = DoubleDouble::add(az, f); } let v0 = DoubleDouble::from_exact_add(ah, az.hi); let v1 = DoubleDouble::from_exact_add(v0.lo, az.lo); v1.hi + v0.hi } /// Computes atan in double precision /// /// ULP 0.5 pub fn f_atan(x: f64) -> f64 { const CH: [u64; 4] = [ 0x3ff0000000000000, 0xbfd555555555552b, 0x3fc9999999069c20, 0xbfc248d2c8444ac6, ]; let t = x.to_bits(); let at = t & 0x7fffffffffffffff; // at encodes |x| let mut i = (at.wrapping_shr(51) as i64).wrapping_sub(2030i64); // -2030 <= i <= 2065 if at < 0x3f7b21c475e6362au64 { // |x| < 0x1.b21c475e6362ap-8 if at == 0 { return x; } // atan(+/-0) = +/-0 const CH2: [u64; 4] = [ 0xbfd5555555555555, 0x3fc99999999998c1, 0xbfc249249176aec0, 0x3fbc711fd121ae80, ]; if at < 0x3e40000000000000u64 { // |x| < 0x1p-27 /* underflow when 0 < |x| < 2^-1022 or when |x| = 2^-1022 and rounding towards zero. */ return dyad_fmla(f64::from_bits(0xbc90000000000000), x, x); } let x2 = x * x; let x3 = x * x2; let x4 = x2 * x2; let w0 = f_fmla(x2, f64::from_bits(CH2[3]), f64::from_bits(CH2[2])); let w1 = f_fmla(x2, f64::from_bits(CH2[1]), f64::from_bits(CH2[0])); let f = x3 * f_fmla(x4, w0, w1); let ub = f_fmla(f, f64::from_bits(0x3cd2000000000000), f) + x; let lb = f_fmla(-f, f64::from_bits(0x3cc4000000000000), f) + x; // Ziv's accuracy test if ub != lb { return atan_refine(x, ub); } return ub; } let h; let ah; let mut al; if at > 0x4062ded8e34a9035u64 { // |x| > 0x4062ded8e34a9035 ah = f64::copysign(f64::from_bits(0x3ff921fb54442d18), x); al = f64::copysign(f64::from_bits(0x3c91a62633145c07), x); if at >= 0x434d02967c31cdb5u64 { // |x| >= 1.63312e+16 if at > (0x7ffu64 << 52) { return x + x; } // NaN return ah + al; } h = -1.0 / x; } else { // now 0.006624 <= |x| <= 150.964 thus 1<=i<=30 let u: u64 = t & 0x0007ffffffffffff; let ut: u64 = u.wrapping_shr(51 - 16); let ut2: u64 = (ut * ut).wrapping_shr(16); let lc = ATAN_CIRCLE[i as usize]; i = (((lc[0] as u64) .wrapping_shl(16) .wrapping_add(ut * lc[1] as u64) .wrapping_sub(ut2 * lc[2] as u64)) >> (16 + 9)) as i64; let la = ATAN_REDUCE[i as usize]; let ta = f64::copysign(1.0, x) * f64::from_bits(la.0); let id = f64::copysign(1.0, x) * i as f64; al = dd_fmla( f64::copysign(1.0, x), f64::from_bits(la.1), f64::from_bits(0x3c88469898cc5170) * id, ); h = (x - ta) / f_fmla(x, ta, 1.0); ah = f64::from_bits(0x3f8921fb54442d00) * id; } let h2 = h * h; let h4 = h2 * h2; let f0 = f_fmla(h2, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let f1 = f_fmla(h2, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let f = f_fmla(h4, f0, f1); al = dd_fmla(h, f, al); let ub = f_fmla(h, f64::from_bits(0x3ccf800000000000), al) + ah; let lb = f_fmla(-h, f64::from_bits(0x3ccf800000000000), al) + ah; // Ziv's accuracy test if lb != ub { return atan_refine(x, ub); } ub } #[cfg(test)] mod tests { use super::*; #[test] fn atan_test() { assert_eq!(f_atan(7.7877585082074305E-308), 7.78775850820743e-308); assert_eq!(f_atan(0.0), 0.0); assert_eq!(f_atan(1.0), 0.7853981633974483096156608458198); assert_eq!(f_atan(35.9), 1.542948374599341097473183563168947); assert_eq!(f_atan(-35.9), -1.542948374599341097473183563168947); assert_eq!(f_atan(f64::INFINITY), 1.5707963267948966); } } pxfm-0.1.23/src/tangent/atan2.rs000064400000000000000000000663741046102023000145030ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval4; // atan(i/64) with i = 0..64, generated by Sollya with: // > for i from 0 to 64 do { // a = round(atan(i/64), D, RN); // b = round(atan(i/64) - a, D, RN); // print("{", b, ",", a, "},"); // }; pub(crate) static ATAN_I: [(u64, u64); 65] = [ (0x0000000000000000, 0x0000000000000000), (0xbc2220c39d4dff50, 0x3f8fff555bbb729b), (0xbc35ec431444912c, 0x3f9ffd55bba97625), (0xbc086ef8f794f105, 0x3fa7fb818430da2a), (0xbc3c934d86d23f1d, 0x3faff55bb72cfdea), (0x3c5ac4ce285df847, 0x3fb3f59f0e7c559d), (0xbc5cfb654c0c3d98, 0x3fb7ee182602f10f), (0x3c5f7b8f29a05987, 0x3fbbe39ebe6f07c3), (0xbc4cd37686760c17, 0x3fbfd5ba9aac2f6e), (0xbc4b485914dacf8c, 0x3fc1e1fafb043727), (0x3c661a3b0ce9281b, 0x3fc3d6eee8c6626c), (0xbc5054ab2c010f3d, 0x3fc5c9811e3ec26a), (0x3c5347b0b4f881ca, 0x3fc7b97b4bce5b02), (0x3c4cf601e7b4348e, 0x3fc9a6a8e96c8626), (0x3c217b10d2e0e5ab, 0x3fcb90d7529260a2), (0x3c6c648d1534597e, 0x3fcd77d5df205736), (0x3c68ab6e3cf7afbd, 0x3fcf5b75f92c80dd), (0x3c762e47390cb865, 0x3fd09dc597d86362), (0x3c630ca4748b1bf9, 0x3fd18bf5a30bf178), (0xbc7077cdd36dfc81, 0x3fd278372057ef46), (0xbc6963a544b672d8, 0x3fd362773707ebcc), (0xbc75d5e43c55b3ba, 0x3fd44aa436c2af0a), (0xbc62566480884082, 0x3fd530ad9951cd4a), (0xbc7a725715711f00, 0x3fd614840309cfe2), (0xbc7c63aae6f6e918, 0x3fd6f61941e4def1), (0x3c769c885c2b249a, 0x3fd7d5604b63b3f7), (0x3c7b6d0ba3748fa8, 0x3fd8b24d394a1b25), (0x3c79e6c988fd0a77, 0x3fd98cd5454d6b18), (0xbc724dec1b50b7ff, 0x3fda64eec3cc23fd), (0x3c7ae187b1ca5040, 0x3fdb3a911da65c6c), (0xbc7cc1ce70934c34, 0x3fdc0db4c94ec9f0), (0xbc7a2cfa4418f1ad, 0x3fdcde53432c1351), (0x3c7a2b7f222f65e2, 0x3fddac670561bb4f), (0x3c70e53dc1bf3435, 0x3fde77eb7f175a34), (0xbc6a3992dc382a23, 0x3fdf40dd0b541418), (0xbc8b32c949c9d593, 0x3fe0039c73c1a40c), (0xbc7d5b495f6349e6, 0x3fe0657e94db30d0), (0x3c5974fa13b5404f, 0x3fe0c6145b5b43da), (0xbc52bdaee1c0ee35, 0x3fe1255d9bfbd2a9), (0x3c8c621cec00c301, 0x3fe1835a88be7c13), (0xbc5928df287a668f, 0x3fe1e00babdefeb4), (0x3c6c421c9f38224e, 0x3fe23b71e2cc9e6a), (0xbc709e73b0c6c087, 0x3fe2958e59308e31), (0x3c8c5d5e9ff0cf8d, 0x3fe2ee628406cbca), (0x3c81021137c71102, 0x3fe345f01cce37bb), (0xbc82304331d8bf46, 0x3fe39c391cd4171a), (0x3c7ecf8b492644f0, 0x3fe3f13fb89e96f4), (0xbc7f76d0163f79c8, 0x3fe445065b795b56), (0x3c72419a87f2a458, 0x3fe4978fa3269ee1), (0x3c84a33dbeb3796c, 0x3fe4e8de5bb6ec04), (0xbc81bb74abda520c, 0x3fe538f57b89061f), (0xbc75e5c9d8c5a950, 0x3fe587d81f732fbb), (0x3c60028e4bc5e7ca, 0x3fe5d58987169b18), (0xbc62b785350ee8c1, 0x3fe6220d115d7b8e), (0xbc76ea6febe8bbba, 0x3fe66d663923e087), (0xbc8a80386188c50e, 0x3fe6b798920b3d99), (0xbc78c34d25aadef6, 0x3fe700a7c5784634), (0x3c47b2a6165884a1, 0x3fe748978fba8e0f), (0x3c8406a089803740, 0x3fe78f6bbd5d315e), (0x3c8560821e2f3aa9, 0x3fe7d528289fa093), (0xbc7bf76229d3b917, 0x3fe819d0b7158a4d), (0x3c66b66e7fc8b8c3, 0x3fe85d69576cc2c5), (0xbc855b9a5e177a1b, 0x3fe89ff5ff57f1f8), (0xbc7ec182ab042f61, 0x3fe8e17aa99cc05e), (0x3c81a62633145c07, 0x3fe921fb54442d18), ]; // Sage math: // print("pub(crate) static ATAN_RATIONAL_128: [DyadicFloat128; 65] = [") // for i in range(65): // x = D3(i)/D3(64) // v = atan(x) // print_dyadic(v) // // print("];") pub(crate) static ATAN_RATIONAL_128: [DyadicFloat128; 65] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0x0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0xfffaaadd_db94d5bb_e78c5640_15f76048_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xffeaaddd_4bb12542_779d776d_da8c6214_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xbfdc0c21_86d14fcf_220e10d6_1df56ec7_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xffaaddb9_67ef4e36_cb2792dc_0e2e0d51_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0x9facf873_e2aceb58_99c50bbf_08e6cdf6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xbf70c130_17887460_93567e78_4cf83676_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xdf1cf5f3_783e1bef_71e5340b_30e5d9ef_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xfeadd4d5_617b6e32_c897989f_3e888ef8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x8f0fd7d8_21b93725_bd375929_83a0af9a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x9eb77746_331362c3_47619d25_0360fe85_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xae4c08f1_f6134efa_b54d3fef_0c2de994_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xbdcbda5e_72d81134_7b0b4f88_1c9c7488_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xcd35474b_643130e7_b00f3da1_a46eeb3b_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xdc86ba94_93051022_f621a5c1_cb552f03_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xebbeaef9_02b9b38c_91a2a68b_2fbd78e8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xfadbafc9_6406eb15_6dc79ef5_f7a217e6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x84ee2cbe_c31b12c5_c8e72197_0cabd3a3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x8c5fad18_5f8bc130_ca4748b1_bf88298d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x93c1b902_bf7a2df1_06459240_6fe1447a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0x9b13b9b8_3f5e5e69_c5abb498_d27af328_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa25521b6_15784d45_43787549_88b8d9e3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xa9856cca_8e6a4eda_99b7f77b_f7d9e8c1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb0a42018_4e7f0cb1_b51d51dc_200a0fc3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xb7b0ca0f_26f78473_8aa32122_dcfe4483_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xbeab025b_1d9fbad3_910b8564_93411026_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xc59269ca_50d92b6d_a1746e91_f50a28de_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xcc66aa2a_6b58c33c_d9311fa1_4ed9b7c4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xd327761e_611fe5b6_427c95e9_001e7136_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xd9d488ed_32e3635c_30f6394a_0806345d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe06da64a_764f7c67_c631ed96_798cb804_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xe6f29a19_609a84ba_60b77ce1_ca6dc2c8_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xed63382b_0dda7b45_6fe445ec_bc3a8d03_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xf3bf5bf8_bad1a21c_a7b837e6_86adf3fa_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xfa06e85a_a0a0be5c_66d23c7d_5dc8ecc2_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x801ce39e_0d205c99_a6d6c6c5_4d938596_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x832bf4a6_d9867e2a_4b6a09cb_61a515c1_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8630a2da_da1ed065_d3e84ed5_013ca37e_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x892aecdf_de9547b5_094478fc_472b4afc_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8c1ad445_f3e09b8c_439d8018_60205921_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x8f005d5e_f7f59f9b_5c835e16_65c43748_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x91db8f16_64f350e2_10e4f9c1_126e0220_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x94ac72c9_847186f6_18c4f393_f78a32f9_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x97731420_365e538b_abd3fe19_f1aeb6b3_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9a2f80e6_71bdda20_4226f8e2_204ff3bd_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9ce1c8e6_a0b8cdb9_f799c4e8_174cf11c_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0x9f89fdc4_f4b7a1ec_f8b49264_4f0701e0_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa22832db_cadaae08_92fe9c08_637af0e6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa4bc7d19_34f70924_19a87f2a_457dac9f_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa746f2dd_b7602294_67b7d66f_2d74e019_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xa9c7abdc_4830f5c8_916a84b5_be7933f6_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xac3ec0fb_997dd6a1_a36273a5_6afa8ef4_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xaeac4c38_b4d8c080_14725e2f_3e52070a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb110688a_ebdc6f6a_43d65788_b9f6a7b5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb36b31c9_1f043691_59014174_4462f93a_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb5bcc490_59ecc4af_f8f3cee7_5e3907d5_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xb8053e2b_c2319e73_cb2da552_10a4443d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xba44bc7d_d470782f_654c2cb1_0942e386_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbc7b5dea_e98af280_d4113006_e80fb290_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xbea94144_fd049aac_1043c5e7_55282e7d_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc0ce85b8_ac526640_89dd62c4_6e92fa25_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc2eb4abb_661628b5_b373fe45_c61bb9fb_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc4ffaffa_bf8fbd54_8cb43d10_bc9e0221_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc70bd54c_e602ee13_e7d54fbd_09f2be38_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -128, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }, ]; // Approximate atan(x) for |x| <= 2^-7. // Using degree-9 Taylor polynomial: // P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9; // Then the absolute error is bounded by: // |atan(x) - P(x)| < |x|^11/11 < 2^(-7*11) / 11 < 2^-80. // And the relative error is bounded by: // |(atan(x) - P(x))/atan(x)| < |x|^10 / 10 < 2^-73. // For x = x_hi + x_lo, fully expand the polynomial and drop any terms less than // ulp(x_hi^3 / 3) gives us: // P(x) ~ x_hi - x_hi^3/3 + x_hi^5/5 - x_hi^7/7 + x_hi^9/9 + // + x_lo * (1 - x_hi^2 + x_hi^4) // Since p.lo is ~ x^3/3, the relative error from rounding is bounded by: // |(atan(x) - P(x))/atan(x)| < ulp(x^2) <= 2^(-14-52) = 2^-66. #[inline] pub(crate) fn atan_eval(x: DoubleDouble) -> DoubleDouble { let p_hi = x.hi; let x_hi_sq = x.hi * x.hi; // c0 ~ x_hi^2 * 1/5 - 1/3 let c0 = f_fmla( x_hi_sq, f64::from_bits(0x3fc999999999999a), f64::from_bits(0xbfd5555555555555), ); // c1 ~ x_hi^2 * 1/9 - 1/7 let c1 = f_fmla( x_hi_sq, f64::from_bits(0x3fbc71c71c71c71c), f64::from_bits(0xbfc2492492492492), ); // x_hi^3 let x_hi_3 = x_hi_sq * x.hi; // x_hi^4 let x_hi_4 = x_hi_sq * x_hi_sq; // d0 ~ 1/3 - x_hi^2 / 5 + x_hi^4 / 7 - x_hi^6 / 9 let d0 = f_fmla(x_hi_4, c1, c0); // x_lo - x_lo * x_hi^2 + x_lo * x_hi^4 let d1 = f_fmla(x_hi_4 - x_hi_sq, x.lo, x.lo); // p.lo ~ -x_hi^3/3 + x_hi^5/5 - x_hi^7/7 + x_hi^9/9 + // + x_lo * (1 - x_hi^2 + x_hi^4) let p_lo = f_fmla(x_hi_3, d0, d1); DoubleDouble::new(p_lo, p_hi) } #[inline] fn atan_eval_hard(x: DyadicFloat128) -> DyadicFloat128 { // let x_hi_sq = x * x; // c0 ~ x_hi^2 * 1/5 - 1/3 const C: [DyadicFloat128; 4] = [ DyadicFloat128 { sign: DyadicSign::Neg, exponent: -129, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0xcccccccc_cccccccc_cccccccc_cccccccd_u128, }, DyadicFloat128 { sign: DyadicSign::Neg, exponent: -130, mantissa: 0x92492492_49249249_24924924_92492492_u128, }, DyadicFloat128 { sign: DyadicSign::Pos, exponent: -131, mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128, }, ]; let dx2 = x * x; // Taylor polynomial // P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9; let p = f_polyeval4(dx2, C[0], C[1], C[2], C[3]); x + dx2 * x * p } #[cold] #[inline(never)] pub(crate) fn atan2_hard(y: f64, x: f64) -> DyadicFloat128 { /* Sage math: from sage.all import * def format_dyadic_hex(value): l = hex(value)[2:] n = 8 x = [l[i:i + n] for i in range(0, len(l), n)] return "0x" + "_".join(x) + "_u128" def print_dyadic(value): (s, m, e) = RealField(128)(value).sign_mantissa_exponent(); print("DyadicFloat128 {") print(f" sign: DyadicSign::{'Pos' if s >= 0 else 'Neg'},") print(f" exponent: {e},") print(f" mantissa: {format_dyadic_hex(m)},") print("},") D3 = RealField(157) print("Minus Pi") print_dyadic(-D3.pi()) print("\nPI over 2") print_dyadic(D3.pi() / 2) print("\nMinus PI over 2") print_dyadic(-D3.pi() / 2) */ static ZERO: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: 0, mantissa: 0_u128, }; static MINUS_PI: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -126, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; static PI_OVER_2: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; static MPI_OVER_2: DyadicFloat128 = DyadicFloat128 { sign: DyadicSign::Neg, exponent: -127, mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128, }; static CONST_ADJ: [[[DyadicFloat128; 2]; 2]; 2] = [ [[ZERO, MPI_OVER_2], [ZERO, MPI_OVER_2]], [[MINUS_PI, PI_OVER_2], [MINUS_PI, PI_OVER_2]], ]; let x_sign = x.is_sign_negative() as usize; let y_sign = y.is_sign_negative() as usize; let x_bits = x.to_bits() & 0x7fff_ffff_ffff_ffff; let y_bits = y.to_bits() & 0x7fff_ffff_ffff_ffff; let x_abs = x_bits; let y_abs = y_bits; let recip = x_abs < y_abs; let min_abs = if recip { x_abs } else { y_abs }; let max_abs = if !recip { x_abs } else { y_abs }; let min_exp = min_abs.wrapping_shr(52); let max_exp = max_abs.wrapping_shr(52); let mut num = f64::from_bits(min_abs); let mut den = f64::from_bits(max_abs); if max_exp > 0x7ffu64 - 128u64 || min_exp < 128u64 { let scale_up = min_exp < 128u64; let scale_down = max_exp > 0x7ffu64 - 128u64; // At least one input is denormal, multiply both numerator and denominator // by some large enough power of 2 to normalize denormal inputs. if scale_up { num *= f64::from_bits(0x43f0000000000000); if !scale_down { den *= f64::from_bits(0x43f0000000000000) } } else if scale_down { den *= f64::from_bits(0x3bf0000000000000); if !scale_up { num *= f64::from_bits(0x3bf0000000000000); } } } static IS_NEG: [DyadicSign; 2] = [DyadicSign::Pos, DyadicSign::Neg]; let final_sign = IS_NEG[((x_sign != y_sign) != recip) as usize]; let const_term = CONST_ADJ[x_sign][y_sign][recip as usize]; let num = DyadicFloat128::new_from_f64(num); let den = DyadicFloat128::new_from_f64(den); let den_recip0 = den.reciprocal(); let mut k_product = num * den_recip0; k_product.exponent += 6; let mut k = k_product.round_to_nearest_f64(); let idx = k as u64; // k = idx / 64 k *= f64::from_bits(0x3f90000000000000); // Range reduction: // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64))) // = atan((n - d * k/64)) / (d + n * k/64)) let k_rational128 = DyadicFloat128::new_from_f64(k); let num_k = num * k_rational128; let den_k = den * k_rational128; // num_dd = n - d * k let num_rational128 = num - den_k; // den_dd = d + n * k let den_rational128 = den + num_k; // q = (n - d * k) / (d + n * k) let den_rational128_recip = den_rational128.reciprocal(); let q = num_rational128 * den_rational128_recip; let p = atan_eval_hard(q); let vl = ATAN_RATIONAL_128[idx as usize]; let mut r = p + vl + const_term; r.sign = r.sign.mult(final_sign); r } /// Computes atan(x) /// /// Max found ULP 0.5 pub fn f_atan2(y: f64, x: f64) -> f64 { static IS_NEG: [f64; 2] = [1.0, -1.0]; const ZERO: DoubleDouble = DoubleDouble::new(0.0, 0.0); const MZERO: DoubleDouble = DoubleDouble::new(-0.0, -0.0); const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); const MPI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbca1a62633145c07), f64::from_bits(0xc00921fb54442d18), ); const PI_OVER_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c91a62633145c07), f64::from_bits(0x3ff921fb54442d18), ); const MPI_OVER_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc91a62633145c07), f64::from_bits(0xbff921fb54442d18), ); const PI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c81a62633145c07), f64::from_bits(0x3fe921fb54442d18), ); const THREE_PI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c9a79394c9e8a0a), f64::from_bits(0x4002d97c7f3321d2), ); // Adjustment for constant term: // CONST_ADJ[x_sign][y_sign][recip] static CONST_ADJ: [[[DoubleDouble; 2]; 2]; 2] = [ [[ZERO, MPI_OVER_2], [MZERO, MPI_OVER_2]], [[MPI, PI_OVER_2], [MPI, PI_OVER_2]], ]; let x_sign = x.is_sign_negative() as usize; let y_sign = y.is_sign_negative() as usize; let x_bits = x.to_bits() & 0x7fff_ffff_ffff_ffff; let y_bits = y.to_bits() & 0x7fff_ffff_ffff_ffff; let x_abs = x_bits; let y_abs = y_bits; let recip = x_abs < y_abs; let mut min_abs = if recip { x_abs } else { y_abs }; let mut max_abs = if !recip { x_abs } else { y_abs }; let mut min_exp = min_abs.wrapping_shr(52); let mut max_exp = max_abs.wrapping_shr(52); let mut num = f64::from_bits(min_abs); let mut den = f64::from_bits(max_abs); // Check for exceptional cases, whether inputs are 0, inf, nan, or close to // overflow, or close to underflow. if max_exp > 0x7ffu64 - 128u64 || min_exp < 128u64 { if x.is_nan() || y.is_nan() { return f64::NAN; } let x_except = if x == 0.0 { 0 } else if x.is_infinite() { 2 } else { 1 }; let y_except = if y == 0.0 { 0 } else if y.is_infinite() { 2 } else { 1 }; // Exceptional cases: // EXCEPT[y_except][x_except][x_is_neg] // with x_except & y_except: // 0: zero // 1: finite, non-zero // 2: infinity static EXCEPTS: [[[DoubleDouble; 2]; 3]; 3] = [ [[ZERO, PI], [ZERO, PI], [ZERO, PI]], [[PI_OVER_2, PI_OVER_2], [ZERO, ZERO], [ZERO, PI]], [ [PI_OVER_2, PI_OVER_2], [PI_OVER_2, PI_OVER_2], [PI_OVER_4, THREE_PI_OVER_4], ], ]; if (x_except != 1) || (y_except != 1) { let r = EXCEPTS[y_except][x_except][x_sign]; return f_fmla(IS_NEG[y_sign], r.hi, IS_NEG[y_sign] * r.lo); } let scale_up = min_exp < 128u64; let scale_down = max_exp > 0x7ffu64 - 128u64; // At least one input is denormal, multiply both numerator and denominator // by some large enough power of 2 to normalize denormal inputs. // if scale_up || scale_down { // return atan2_hard(y, x).fast_as_f64(); // } if scale_up { num *= f64::from_bits(0x43f0000000000000); if !scale_down { den *= f64::from_bits(0x43f0000000000000); } } else if scale_down { den *= f64::from_bits(0x3bf0000000000000); if !scale_up { num *= f64::from_bits(0x3bf0000000000000); } } min_abs = num.to_bits(); max_abs = den.to_bits(); min_exp = min_abs.wrapping_shr(52); max_exp = max_abs.wrapping_shr(52); } let final_sign = IS_NEG[((x_sign != y_sign) != recip) as usize]; let const_term = CONST_ADJ[x_sign][y_sign][recip as usize]; let exp_diff = max_exp - min_exp; // We have the following bound for normalized n and d: // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1). if exp_diff > 54 { return f_fmla( final_sign, const_term.hi, final_sign * (const_term.lo + num / den), ); } let mut k = (64.0 * num / den).round(); let idx = k as u64; // k = idx / 64 k *= f64::from_bits(0x3f90000000000000); // Range reduction: // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64))) // = atan((n - d * k/64)) / (d + n * k/64)) let num_k = DoubleDouble::from_exact_mult(num, k); let den_k = DoubleDouble::from_exact_mult(den, k); // num_dd = n - d * k let num_dd = DoubleDouble::from_exact_add(num - den_k.hi, -den_k.lo); // den_dd = d + n * k let mut den_dd = DoubleDouble::from_exact_add(den, num_k.hi); den_dd.lo += num_k.lo; // q = (n - d * k) / (d + n * k) let q = DoubleDouble::div(num_dd, den_dd); // p ~ atan(q) let p = atan_eval(q); let vl = ATAN_I[idx as usize]; let vlo = DoubleDouble::from_bit_pair(vl); let mut r = DoubleDouble::add(const_term, DoubleDouble::add(vlo, p)); let err = f_fmla( p.hi, f64::from_bits(0x3bd0000000000000), f64::from_bits(0x3c00000000000000), ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { r.hi *= final_sign; r.lo *= final_sign; return r.to_f64(); } atan2_hard(y, x).fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_atan2() { assert_eq!( f_atan2(0.05474853958030223, 0.9999995380640253), 0.05469396182367716 ); assert_eq!(f_atan2(-5., 2.), -1.1902899496825317); assert_eq!(f_atan2(2., -5.), 2.761086276477428); assert_eq!( f_atan2(1.220342145227879E-321, 6.9806238698201653E-309), 0.00000000000017481849301519772 ); } } pxfm-0.1.23/src/tangent/atan2f.rs000064400000000000000000000246561046102023000146460ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::shared_eval::poly_dekker_generic; static ATAN2F_TABLE: [(u64, u64); 32] = [ (0x3ff0000000000000, 0xba88c1dac5492248), (0xbfd5555555555555, 0xbc755553bf3a2abe), (0x3fc999999999999a, 0xbc699deed1ec9071), (0xbfc2492492492492, 0xbc5fd99c8d18269a), (0x3fbc71c71c71c717, 0xbc2651eee4c4d9d0), (0xbfb745d1745d1649, 0xbc5632683d6c44a6), (0x3fb3b13b13b11c63, 0x3c5bf69c1f8af41d), (0xbfb11111110e6338, 0x3c23c3e431e8bb68), (0x3fae1e1e1dc45c4a, 0xbc4be2db05c77bbf), (0xbfaaf286b8164b4f, 0x3c2a4673491f0942), (0x3fa86185e9ad4846, 0x3c4e12e32d79fcee), (0xbfa642c6d5161fae, 0x3c43ce76c1ca03f0), (0x3fa47ad6f277e5bf, 0xbc3abd8d85bdb714), (0xbfa2f64a2ee8896d, 0x3c2ef87d4b615323), (0x3fa1a6a2b31741b5, 0x3c1a5d9d973547ee), (0xbfa07fbdad65e0a6, 0xbc265ac07f5d35f4), (0x3f9ee9932a9a5f8b, 0x3c2f8b9623f6f55a), (0xbf9ce8b5b9584dc6, 0x3c2fe5af96e8ea2d), (0x3f9ac9cb288087b7, 0xbc3450cdfceaf5ca), (0xbf984b025351f3e6, 0x3c2579561b0d73da), (0x3f952f5b8ecdd52b, 0x3c3036bd2c6fba47), (0xbf9163a8c44909dc, 0x3c318f735ffb9f16), (0x3f8a400dce3eea6f, 0xbc2c90569c0c1b5c), (0xbf81caa78ae6db3a, 0xbc24c60f8161ea09), (0x3f752672453c0731, 0x3c1834efb598c338), (0xbf65850c5be137cf, 0xbc0445fc150ca7f5), (0x3f523eb98d22e1ca, 0xbbf388fbaf1d7830), (0xbf38f4e974a40741, 0x3bd271198a97da34), (0x3f1a5cf2e9cf76e5, 0xbbb887eb4a63b665), (0xbef420c270719e32, 0x3b8efd595b27888b), (0x3ec3ba2d69b51677, 0xbb64fb06829cdfc7), (0xbe829b7e6f676385, 0xbb2a783b6de718fb), ]; #[cold] fn atan2f_tiny(y: f32, x: f32) -> f32 { let dy = y as f64; let dx = x as f64; let z = dy / dx; let mut e = f_fmla(-z, x as f64, y as f64); /* z * x + e = y thus y/x = z + e/x */ const C: f64 = f64::from_bits(0xbfd5555555555555); /* -1/3 rounded to nearest */ let zz = z * z; let cz = C * z; e = e / x as f64 + cz * zz; let mut t = z.to_bits(); if (t & 0xfffffffu64) == 0 { /* boundary case */ /* If z and e are of same sign (resp. of different signs), we increase (resp. decrease) the significand of t by 1 to avoid a double-rounding issue when rounding t.f to binary32. */ if z * e > 0. { t = t.wrapping_add(1); } else { t = t.wrapping_sub(1); } } f64::from_bits(t) as f32 } #[allow(clippy::too_many_arguments)] #[cold] fn atan2f_refine(ay: u32, ax: u32, y: f32, x: f32, zy: f64, zx: f64, gt: usize, i: u32) -> f32 { const PI: f64 = f64::from_bits(0x400921fb54442d18); const PI2: f64 = f64::from_bits(0x3ff921fb54442d18); const PI2L: f64 = f64::from_bits(0x3c91a62633145c07); static OFF: [f64; 8] = [0.0, PI2, PI, PI2, -0.0, -PI2, -PI, -PI2]; static OFFL: [f64; 8] = [0.0, PI2L, 2. * PI2L, PI2L, -0.0, -PI2L, -2. * PI2L, -PI2L]; static SGN: [f64; 2] = [1., -1.]; /* check tiny y/x */ if ay < ax && ((ax - ay) >> 23 >= 25) { return atan2f_tiny(y, x); } let mut zh; let mut zl; if gt == 0 { zh = zy / zx; zl = f_fmla(zh, -zx, zy) / zx; } else { zh = zx / zy; zl = f_fmla(zh, -zy, zx) / zy; } let z2 = DoubleDouble::quick_mult(DoubleDouble::new(zl, zh), DoubleDouble::new(zl, zh)); let mut p = poly_dekker_generic(z2, ATAN2F_TABLE); zh *= SGN[gt]; zl *= SGN[gt]; p = DoubleDouble::quick_mult(DoubleDouble::new(zl, zh), p); let sh = p.hi + OFF[i as usize]; let sl = ((OFF[i as usize] - sh) + p.hi) + p.lo + OFFL[i as usize]; let rf = sh as f32; let th = rf as f64; let dh = sh - th; let mut tm: f64 = dh + sl; let mut tth = th.to_bits(); if th + th * f64::from_bits(0x3c30000000000000) == th - th * f64::from_bits(0x3c30000000000000) { tth &= 0x7ffu64 << 52; tth = tth.wrapping_sub(24 << 52); if tm.abs() > f64::from_bits(tth) { tm *= 1.25; } else { tm *= 0.75; } } let r = th + tm; r as f32 } /// Computes atan2 /// /// Max found ULP 0.49999842 #[inline] pub fn f_atan2f(y: f32, x: f32) -> f32 { const M: [f64; 2] = [0., 1.]; const PI: f64 = f64::from_bits(0x400921fb54442d18); const PI2: f64 = f64::from_bits(0x3ff921fb54442d18); const PI2L: f64 = f64::from_bits(0x3c91a62633145c07); static OFF: [f64; 8] = [0.0, PI2, PI, PI2, -0.0, -PI2, -PI, -PI2]; static OFFL: [f64; 8] = [0.0, PI2L, 2. * PI2L, PI2L, -0.0, -PI2L, -2. * PI2L, -PI2L]; static SGN: [f64; 2] = [1., -1.]; let tx = x.to_bits(); let ty = y.to_bits(); let ux = tx; let uy = ty; let ax = ux & 0x7fffffff; let ay = uy & 0x7fffffff; if ay >= (0xff << 23) || ax >= (0xff << 23) { // x or y is nan or inf /* we use x+y below so that the invalid exception is set for (x,y) = (qnan,snan) or (snan,qnan) */ if ay > (0xff << 23) { return x + y; } // case y nan if ax > (0xff << 23) { return x + y; } // case x nan let yinf = ay == (0xff << 23); let xinf = ax == (0xff << 23); if yinf & xinf { return if (ux >> 31) != 0 { (f64::from_bits(0x4002d97c7f3321d2) * SGN[(uy >> 31) as usize]) as f32 // +/-3pi/4 } else { (f64::from_bits(0x3fe921fb54442d18) * SGN[(uy >> 31) as usize]) as f32 // +/-pi/4 }; } if xinf { return if (ux >> 31) != 0 { (PI * SGN[(uy >> 31) as usize]) as f32 } else { (0.0 * SGN[(uy >> 31) as usize]) as f32 }; } if yinf { return (PI2 * SGN[(uy >> 31) as usize]) as f32; } } if ay == 0 { if ax == 0 { let i = (uy >> 31) .wrapping_mul(4) .wrapping_add((ux >> 31).wrapping_mul(2)); return if (ux >> 31) != 0 { (OFF[i as usize] + OFFL[i as usize]) as f32 } else { OFF[i as usize] as f32 }; } if (ux >> 31) == 0 { return (0.0 * SGN[(uy >> 31) as usize]) as f32; } } let gt = (ay > ax) as usize; let i = (uy >> 31) .wrapping_mul(4) .wrapping_add((ux >> 31).wrapping_mul(2)) .wrapping_add(gt as u32); let zx = x as f64; let zy = y as f64; let mut z = f_fmla(M[gt], zx, M[1usize.wrapping_sub(gt)] * zy) / f_fmla(M[gt], zy, M[1usize.wrapping_sub(gt)] * zx); // z = x/y if |y| > |x|, and z = y/x otherwise let mut r; let d = ax as i32 - ay as i32; if d < (27 << 23) && d > (-(27 << 23)) { let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; /* z2 cannot underflow, since for |y|=0x1p-149 and |x|=0x1.fffffep+127 we get |z| > 2^-277 thus z2 > 2^-554, but z4 and z8 might underflow, which might give spurious underflow exceptions. */ const CN: [u64; 7] = [ 0x3ff0000000000000, 0x40040e0698f94c35, 0x400248c5da347f0d, 0x3fed873386572976, 0x3fc46fa40b20f1d0, 0x3f833f5e041eed0f, 0x3f1546bbf28667c5, ]; const CD: [u64; 7] = [ 0x3ff0000000000000, 0x4006b8b143a3f6da, 0x4008421201d18ed5, 0x3ff8221d086914eb, 0x3fd670657e3a07ba, 0x3fa0f4951fd1e72d, 0x3f4b3874b8798286, ]; let mut cn0 = f_fmla(z2, f64::from_bits(CN[1]), f64::from_bits(CN[0])); let cn2 = f_fmla(z2, f64::from_bits(CN[3]), f64::from_bits(CN[2])); let mut cn4 = f_fmla(z2, f64::from_bits(CN[5]), f64::from_bits(CN[4])); let cn6 = f64::from_bits(CN[6]); cn0 = f_fmla(z4, cn2, cn0); cn4 = f_fmla(z4, cn6, cn4); cn0 = f_fmla(z8, cn4, cn0); let mut cd0 = f_fmla(z2, f64::from_bits(CD[1]), f64::from_bits(CD[0])); let cd2 = f_fmla(z2, f64::from_bits(CD[3]), f64::from_bits(CD[2])); let mut cd4 = f_fmla(z2, f64::from_bits(CD[5]), f64::from_bits(CD[4])); let cd6 = f64::from_bits(CD[6]); cd0 = f_fmla(z4, cd2, cd0); cd4 = f_fmla(z4, cd6, cd4); cd0 = f_fmla(z8, cd4, cd0); r = cn0 / cd0; } else { r = 1.; } z *= SGN[gt]; r = f_fmla(z, r, OFF[i as usize]); let res = r.to_bits(); if ((res.wrapping_add(8)) & 0xfffffff) <= 16 { return atan2f_refine(ay, ax, y, x, zy, zx, gt, i); } r as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_atan2_test() { assert_eq!( f_atan2f( 0.000000000000000000000000000000000000017907922, 170141180000000000000000000000000000000. ), 0. ); assert_eq!(f_atan2f(-3590000000., -15437000.), -1.5750962); assert_eq!(f_atan2f(-5., 2.), -1.19029); } } pxfm-0.1.23/src/tangent/atan2pi.rs000064400000000000000000000253071046102023000150230ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::acospi::{INV_PI_DD, INV_PI_F128}; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::dyadic_float::DyadicFloat128; use crate::tangent::atan2::{ATAN_I, atan_eval, atan2_hard}; /// If one of arguments is too huge or too small, extended precision is required for /// case with big exponent difference #[cold] fn atan2pi_big_exp_difference_hard( num: f64, den: f64, x_sign: usize, y_sign: usize, recip: bool, final_sign: f64, ) -> f64 { const ZERO: DoubleDouble = DoubleDouble::new(0.0, 0.0); const MZERO: DoubleDouble = DoubleDouble::new(-0.0, -0.0); static CONST_ADJ_INV_PI: [[[DoubleDouble; 2]; 2]; 2] = [ [ [ZERO, DoubleDouble::new(0., -1. / 2.)], [MZERO, DoubleDouble::new(0., -1. / 2.)], ], [ [DoubleDouble::new(0., -1.), DoubleDouble::new(0., 1. / 2.)], [DoubleDouble::new(0., -1.), DoubleDouble::new(0., 1. / 2.)], ], ]; let const_term = CONST_ADJ_INV_PI[x_sign][y_sign][recip as usize]; let scaled_div = DyadicFloat128::from_div_f64(num, den) * INV_PI_F128; let sign_f128 = DyadicFloat128::new_from_f64(final_sign); let p = DyadicFloat128::new_from_f64(const_term.hi * final_sign); let p1 = sign_f128 * (DyadicFloat128::new_from_f64(const_term.lo) + scaled_div); let r = p + p1; r.fast_as_f64() } /// Computes atan(x)/PI /// /// Max found ULP 0.5 pub fn f_atan2pi(y: f64, x: f64) -> f64 { static IS_NEG: [f64; 2] = [1.0, -1.0]; const ZERO: DoubleDouble = DoubleDouble::new(0.0, 0.0); const MZERO: DoubleDouble = DoubleDouble::new(-0.0, -0.0); const PI: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3ca1a62633145c07), f64::from_bits(0x400921fb54442d18), ); const MPI: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbca1a62633145c07), f64::from_bits(0xc00921fb54442d18), ); const PI_OVER_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c91a62633145c07), f64::from_bits(0x3ff921fb54442d18), ); const MPI_OVER_2: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc91a62633145c07), f64::from_bits(0xbff921fb54442d18), ); const PI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c81a62633145c07), f64::from_bits(0x3fe921fb54442d18), ); const THREE_PI_OVER_4: DoubleDouble = DoubleDouble::new( f64::from_bits(0x3c9a79394c9e8a0a), f64::from_bits(0x4002d97c7f3321d2), ); // Adjustment for constant term: // CONST_ADJ[x_sign][y_sign][recip] static CONST_ADJ: [[[DoubleDouble; 2]; 2]; 2] = [ [[ZERO, MPI_OVER_2], [MZERO, MPI_OVER_2]], [[MPI, PI_OVER_2], [MPI, PI_OVER_2]], ]; let x_sign = x.is_sign_negative() as usize; let y_sign = y.is_sign_negative() as usize; let x_bits = x.to_bits() & 0x7fff_ffff_ffff_ffff; let y_bits = y.to_bits() & 0x7fff_ffff_ffff_ffff; let x_abs = x_bits; let y_abs = y_bits; let recip = x_abs < y_abs; let mut min_abs = if recip { x_abs } else { y_abs }; let mut max_abs = if !recip { x_abs } else { y_abs }; let mut min_exp = min_abs.wrapping_shr(52); let mut max_exp = max_abs.wrapping_shr(52); let mut num = f64::from_bits(min_abs); let mut den = f64::from_bits(max_abs); // Check for exceptional cases, whether inputs are 0, inf, nan, or close to // overflow, or close to underflow. if max_exp > 0x7ffu64 - 128u64 || min_exp < 128u64 { if x.is_nan() || y.is_nan() { return f64::NAN; } let x_except = if x == 0.0 { 0 } else if x.is_infinite() { 2 } else { 1 }; let y_except = if y == 0.0 { 0 } else if y.is_infinite() { 2 } else { 1 }; // Exceptional cases: // EXCEPT[y_except][x_except][x_is_neg] // with x_except & y_except: // 0: zero // 1: finite, non-zero // 2: infinity static EXCEPTS: [[[DoubleDouble; 2]; 3]; 3] = [ [[ZERO, PI], [ZERO, PI], [ZERO, PI]], [[PI_OVER_2, PI_OVER_2], [ZERO, ZERO], [ZERO, PI]], [ [PI_OVER_2, PI_OVER_2], [PI_OVER_2, PI_OVER_2], [PI_OVER_4, THREE_PI_OVER_4], ], ]; if (x_except != 1) || (y_except != 1) { let mut r = EXCEPTS[y_except][x_except][x_sign]; r = DoubleDouble::quick_mult(r, INV_PI_DD); return f_fmla(IS_NEG[y_sign], r.hi, IS_NEG[y_sign] * r.lo); } let scale_up = min_exp < 128u64; let scale_down = max_exp > 0x7ffu64 - 128u64; // At least one input is denormal, multiply both numerator and denominator // by some large enough power of 2 to normalize denormal inputs. if scale_up { num *= f64::from_bits(0x43f0000000000000); if !scale_down { den *= f64::from_bits(0x43f0000000000000); } } else if scale_down { den *= f64::from_bits(0x3bf0000000000000); if !scale_up { num *= f64::from_bits(0x3bf0000000000000); } } min_abs = num.to_bits(); max_abs = den.to_bits(); min_exp = min_abs.wrapping_shr(52); max_exp = max_abs.wrapping_shr(52); } let final_sign = IS_NEG[((x_sign != y_sign) != recip) as usize]; let const_term = CONST_ADJ[x_sign][y_sign][recip as usize]; let exp_diff = max_exp - min_exp; // We have the following bound for normalized n and d: // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1). if exp_diff > 54 { if max_exp >= 1075 || min_exp < 970 { return atan2pi_big_exp_difference_hard(num, den, x_sign, y_sign, recip, final_sign); } let z = DoubleDouble::from_exact_mult(final_sign, const_term.hi); let mut divided = DoubleDouble::from_exact_div(num, den); divided = DoubleDouble::f64_add(const_term.lo, divided); divided = DoubleDouble::quick_mult_f64(divided, final_sign); let r = DoubleDouble::add(z, divided); let p = DoubleDouble::quick_mult(INV_PI_DD, r); return p.to_f64(); } let mut k = (64.0 * num / den).round(); let idx = k as u64; // k = idx / 64 k *= f64::from_bits(0x3f90000000000000); // Range reduction: // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64))) // = atan((n - d * k/64)) / (d + n * k/64)) let num_k = DoubleDouble::from_exact_mult(num, k); let den_k = DoubleDouble::from_exact_mult(den, k); // num_dd = n - d * k let num_dd = DoubleDouble::from_exact_add(num - den_k.hi, -den_k.lo); // den_dd = d + n * k let mut den_dd = DoubleDouble::from_exact_add(den, num_k.hi); den_dd.lo += num_k.lo; // q = (n - d * k) / (d + n * k) let q = DoubleDouble::div(num_dd, den_dd); // p ~ atan(q) let p = atan_eval(q); let vl = ATAN_I[idx as usize]; let vlo = DoubleDouble::from_bit_pair(vl); let mut r = DoubleDouble::add(const_term, DoubleDouble::add(vlo, p)); r = DoubleDouble::quick_mult(r, INV_PI_DD); let err = f_fmla( p.hi, f64::from_bits(0x3bd0000000000000), f64::from_bits(0x3c00000000000000), ); let ub = r.hi + (r.lo + err); let lb = r.hi + (r.lo - err); if ub == lb { r.hi *= final_sign; r.lo *= final_sign; return r.to_f64(); } (atan2_hard(y, x) * INV_PI_F128).fast_as_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_atan2pi() { assert_eq!( f_atan2pi(-0.000000000000010659658919444194, 2088960.4374061823), -0.0000000000000000000016242886924270424 ); assert_eq!(f_atan2pi(-3.9999999981625933, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003577142133480227), -0.5); assert_eq!(f_atan2pi(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000472842255026406, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008045886150098693 ),1.8706499392673612e-162); assert_eq!(f_atan2pi(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002670088630208647, 2.0000019071157054 ), 4.249573987697093e-307); assert_eq!(f_atan2pi(-5., 2.), -0.3788810584091566); assert_eq!(f_atan2pi(2., -5.), 0.8788810584091566); } } pxfm-0.1.23/src/tangent/atan2pif.rs000064400000000000000000000123441046102023000151660ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; static OFF: [f32; 8] = [0.0, 0.5, 1.0, 0.5, -0.0, -0.5, -1.0, -0.5]; static SGNF: [f32; 2] = [1., -1.]; static SGN: [f64; 2] = [1., -1.]; /// Computes atan(x/y) / PI /// /// Max found ULP 0.5 #[inline] pub fn f_atan2pif(y: f32, x: f32) -> f32 { let tx = x.to_bits(); let ty: u32 = y.to_bits(); let ux: u32 = tx; let uy: u32 = ty; let ax: u32 = ux & 0x7fff_ffff; let ay = uy & 0x7fff_ffff; if ay >= (0xff << 23) || ax >= (0xff << 23) { if ay > (0xff << 23) { return x + y; } // nan if ax > (0xff << 23) { return x + y; } // nan let yinf = ay == (0xff << 23); let xinf = ax == (0xff << 23); if yinf & xinf { return if (ux >> 31) != 0 { 0.75 * SGNF[(uy >> 31) as usize] } else { 0.25 * SGNF[(uy >> 31) as usize] }; } if xinf { return if (ux >> 31) != 0 { SGNF[(uy >> 31) as usize] } else { 0.0 * SGNF[(uy >> 31) as usize] }; } if yinf { return 0.5 * SGNF[(uy >> 31) as usize]; } } if ay == 0 { if (ay | ax) == 0 { let i: u32 = (uy >> 31) * 4 + (ux >> 31) * 2; return OFF[i as usize]; } if (ux >> 31) == 0 { return 0.0 * SGNF[(uy >> 31) as usize]; } } if ax == ay { static S: [f32; 4] = [0.25, 0.75, -0.25, -0.75]; let i = (uy >> 31) * 2 + (ux >> 31); return S[i as usize]; } let gt: usize = (ay > ax) as usize; let i: u32 = (uy >> 31) * 4 + (ux >> 31) * 2 + gt as u32; let zx = x as f64; let zy = y as f64; static M: [f64; 2] = [0., 1.]; let mut z = f_fmla(M[gt], zx, M[1 - gt] * zy) / f_fmla(M[gt], zy, M[1 - gt] * zx); const CN: [u64; 7] = [ 0x3fd45f306dc9c883, 0x3fe988d83a142ada, 0x3fe747bebf492057, 0x3fd2cc5645094ff3, 0x3faa0521c711ab66, 0x3f6881b8058b9a0d, 0x3efb16ff514a0af0, ]; let mut r = f64::from_bits(CN[0]); let z2 = z * z; z *= SGN[gt]; // avoid spurious underflow in the polynomial evaluation excluding tiny arguments if z2 > f64::from_bits(0x3c90000000000000) { let z4 = z2 * z2; let z8 = z4 * z4; let mut cn0 = f_fmla(z2, f64::from_bits(CN[1]), r); let cn2 = f_fmla(z2, f64::from_bits(CN[3]), f64::from_bits(CN[2])); let mut cn4 = f_fmla(z2, f64::from_bits(CN[5]), f64::from_bits(CN[4])); let cn6 = f64::from_bits(CN[6]); cn0 += z4 * cn2; cn4 += z4 * cn6; cn0 += z8 * cn4; const CD: [u64; 7] = [ 0x3ff0000000000000, 0x4006b8b143a3f6da, 0x4008421201d18ed5, 0x3ff8221d086914eb, 0x3fd670657e3a07ba, 0x3fa0f4951fd1e72d, 0x3f4b3874b8798286, ]; let mut cd0 = f_fmla(z2, f64::from_bits(CD[1]), f64::from_bits(CD[0])); let cd2 = f_fmla(z2, f64::from_bits(CD[3]), f64::from_bits(CD[2])); let mut cd4 = f_fmla(z2, f64::from_bits(CD[5]), f64::from_bits(CD[4])); let cd6 = f64::from_bits(CD[6]); cd0 += z4 * cd2; cd4 += z4 * cd6; cd0 += z8 * cd4; r = cn0 / cd0; } f_fmla(z, r, OFF[i as usize] as f64) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_atan2pif() { assert_eq!(f_atan2pif(0.32131, 0.987565), 0.10012555); assert_eq!(f_atan2pif(532.32131, 12.987565), 0.49223542); assert_eq!(f_atan2pif(-754.32131, 12.987565), -0.494520042); } } pxfm-0.1.23/src/tangent/atanf.rs000064400000000000000000000130031046102023000145440ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 4/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{f_fmla, f_fmlaf}; /// Computes atan /// /// Max found ULP 0.49999973 #[inline] pub fn f_atanf(x: f32) -> f32 { const PI2: f64 = f64::from_bits(0x3ff921fb54442d18); let t = x.to_bits(); let e = (t >> 23) & 0xff; let gt = e >= 127; let ta = t & 0x7fffffff; if ta >= 0x4c700518u32 { // |x| >= 6.29198e+07 if ta > 0x7f800000u32 { return x + x; } // nan return f32::copysign(PI2 as f32, x); // inf or |x| >= 6.29198e+07 } if e < 127 - 13 { // |x| < 2^-13 if e < 127 - 25 { // |x| < 2^-25 if t << 1 == 0 { return x; } let res = f_fmlaf(-x, x.abs(), x); return res; } return f_fmlaf(-f64::from_bits(0x3fd5555560000000) as f32 * x, x * x, x); } /* now |x| >= 0.00012207 */ let mut z = x as f64; if gt { z = 1.0 / z; } /* gt is non-zero for |x| >= 1 */ let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; /* polynomials generated using rminimax (https://gitlab.inria.fr/sfilip/rminimax) with the following command: ./ratapprox --function="atan(x)" --dom=[0.000122070,1] --num=[x,x^3,x^5,x^7,x^9,x^11,x^13] --den=[1,x^2,x^4,x^6,x^8,x^10,x^12] --output=atanf.sollya --log (see output atanf.sollya) The coefficient cd[0] was slightly reduced from the original value 0.330005 to avoid an exceptional case for |x| = 0.069052 and rounding to nearest. */ const CN: [u64; 7] = [ 0x3fd51eccde075d67, 0x3fea76bb5637f2f2, 0x3fe81e0eed20de88, 0x3fd376c8ca67d11d, 0x3faaec7b69202ac6, 0x3f69561899acc73e, 0x3efbf9fa5b67e600, ]; const CD: [u64; 7] = [ 0x3fd51eccde075d66, 0x3fedfbdd7b392d28, 0x3ff0000000000000, 0x3fdfd22bf0e89b54, 0x3fbd91ff8b576282, 0x3f8653ea99fc9bb0, 0x3f31e7fcc202340a, ]; let mut cn0 = f_fmla(z2, f64::from_bits(CN[1]), f64::from_bits(CN[0])); let cn2 = f_fmla(z2, f64::from_bits(CN[3]), f64::from_bits(CN[2])); let mut cn4 = f_fmla(z2, f64::from_bits(CN[5]), f64::from_bits(CN[4])); let cn6 = f64::from_bits(CN[6]); cn0 = f_fmla(z4, cn2, cn0); cn4 = f_fmla(z4, cn6, cn4); cn0 = f_fmla(z8, cn4, cn0); cn0 *= z; let mut cd0 = f_fmla(z2, f64::from_bits(CD[1]), f64::from_bits(CD[0])); let cd2 = f_fmla(z2, f64::from_bits(CD[3]), f64::from_bits(CD[2])); let mut cd4 = f_fmla(z2, f64::from_bits(CD[5]), f64::from_bits(CD[4])); let cd6 = f64::from_bits(CD[6]); cd0 = f_fmla(z4, cd2, cd0); cd4 = f_fmla(z4, cd6, cd4); cd0 = f_fmla(z8, cd4, cd0); let r = cn0 / cd0; if !gt { return r as f32; } /* for |x| < 1, (float) r is correctly rounded */ const PI_OVER2_H: f64 = f64::from_bits(0x3ff9000000000000); const PI_OVER2_L: f64 = f64::from_bits(0x3f80fdaa22168c23); /* now r approximates atan(1/x), we use atan(x) + atan(1/x) = sign(x)*pi/2, where PI_OVER2_H + PI_OVER2_L approximates pi/2. With sign(z)*L + (-r + sign(z)*H), it fails for x=0x1.98c252p+12 and rounding upward. With sign(z)*PI - r, where PI is a double approximation of pi to nearest, it fails for x=0x1.ddf9f6p+0 and rounding upward. */ ((f64::copysign(PI_OVER2_L, z) - r) + f64::copysign(PI_OVER2_H, z)) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_atan_test() { assert!( (f_atanf(1.0) - std::f32::consts::PI / 4f32).abs() < 1e-6, "Invalid result {}", f_atanf(1f32) ); assert!( (f_atanf(2f32) - 1.107148717794090503017065f32).abs() < 1e-6, "Invalid result {}", f_atanf(2f32) ); assert!( (f_atanf(5f32) - 1.3734007669450158608612719264f32).abs() < 1e-6, "Invalid result {}", f_atanf(5f32) ); } } pxfm-0.1.23/src/tangent/atanpi.rs000064400000000000000000000321401046102023000147320ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dd_fmla, dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::shared_eval::poly_dd_3; use crate::tangent::atan::{ATAN_CIRCLE, ATAN_REDUCE}; const ONE_OVER_PI_DD: DoubleDouble = DoubleDouble::new( f64::from_bits(0xbc76b01ec5417056), f64::from_bits(0x3fd45f306dc9c883), ); const ONE_OVER_3PI: f64 = f64::from_bits(0x3fbb2995e7b7b604); // approximates 1/(3pi) fn atanpi_small(x: f64) -> f64 { if x == 0. { return x; } if x.abs() == f64::from_bits(0x0015cba89af1f855) { return if x > 0. { f_fmla( f64::from_bits(0x9a70000000000000), f64::from_bits(0x1a70000000000000), f64::from_bits(0x0006f00f7cd3a40b), ) } else { f_fmla( f64::from_bits(0x1a70000000000000), f64::from_bits(0x1a70000000000000), f64::from_bits(0x8006f00f7cd3a40b), ) }; } // generic worst case let mut v = x.to_bits(); if (v & 0xfffffffffffff) == 0x59af9a1194efe // +/-0x1.59af9a1194efe*2^e { let e = v >> 52; if (e & 0x7ff) > 2 { v = ((e - 2) << 52) | 0xb824198b94a89; return if x > 0. { dd_fmla( f64::from_bits(0x9a70000000000000), f64::from_bits(0x1a70000000000000), f64::from_bits(v), ) } else { dd_fmla( f64::from_bits(0x1a70000000000000), f64::from_bits(0x1a70000000000000), f64::from_bits(v), ) }; } } let h = x * ONE_OVER_PI_DD.hi; /* Assuming h = x*ONE_OVER_PI_DD.hi - e, the correction term is e + x * ONE_OVER_PIL, but we need to scale values to avoid underflow. */ let mut corr = dd_fmla( x * f64::from_bits(0x4690000000000000), ONE_OVER_PI_DD.hi, -h * f64::from_bits(0x4690000000000000), ); corr = dd_fmla( x * f64::from_bits(0x4690000000000000), ONE_OVER_PI_DD.lo, corr, ); // now return h + corr * 2^-106 dyad_fmla(corr, f64::from_bits(0x3950000000000000), h) } /* Deal with the case where |x| is large: for x > 0, atanpi(x) = 1/2 - 1/pi * 1/x + 1/(3pi) * 1/x^3 + O(1/x^5) for x < 0, atanpi(x) = -1/2 - 1/pi * 1/x + 1/(3pi) * 1/x^3 + O(1/x^5). The next term 1/5*x^5/pi is smaller than 2^-107 * atanpi(x) when |x| > 0x1.bep20. */ fn atanpi_asympt(x: f64) -> f64 { let h = f64::copysign(0.5, x); // approximate 1/x as yh + yl let rcy = DoubleDouble::from_quick_recip(x); let mut m = DoubleDouble::quick_mult(rcy, ONE_OVER_PI_DD); // m + l ~ 1/pi * 1/x m.hi = -m.hi; m.lo = dd_fmla(ONE_OVER_3PI * rcy.hi, rcy.hi * rcy.hi, -m.lo); // m + l ~ - 1/pi * 1/x + 1/(3pi) * 1/x^3 let vh = DoubleDouble::from_exact_add(h, m.hi); m.hi = vh.hi; m = DoubleDouble::from_exact_add(vh.lo, m.lo); if m.hi.abs() == f64::from_bits(0x3c80000000000000) { // this is 1/2 ulp(atan(x)) m.hi = if m.hi * m.lo > 0. { f64::copysign(f64::from_bits(0x3c80000000000001), m.hi) } else { f64::copysign(f64::from_bits(0x3c7fffffffffffff), m.hi) }; } vh.hi + m.hi } #[inline] fn atanpi_tiny(x: f64) -> f64 { let mut dx = DoubleDouble::quick_mult_f64(ONE_OVER_PI_DD, x); dx.lo = dd_fmla(-ONE_OVER_3PI * x, x * x, dx.lo); dx.to_f64() } #[cold] fn as_atanpi_refine2(x: f64, a: f64) -> f64 { if x.abs() > f64::from_bits(0x413be00000000000) { return atanpi_asympt(x); } if x.abs() < f64::from_bits(0x3e4c700000000000) { return atanpi_tiny(x); } const CH: [(u64, u64); 3] = [ (0xbfd5555555555555, 0xbc75555555555555), (0x3fc999999999999a, 0xbc6999999999bcb8), (0xbfc2492492492492, 0xbc6249242093c016), ]; const CL: [u64; 4] = [ 0x3fbc71c71c71c71c, 0xbfb745d1745d1265, 0x3fb3b13b115bcbc4, 0xbfb1107c41ad3253, ]; let phi = ((a.abs()) * f64::from_bits(0x40545f306dc9c883) + 256.5).to_bits(); let i: i64 = ((phi >> (52 - 8)) & 0xff) as i64; let dh: DoubleDouble = if i == 128 { DoubleDouble::from_quick_recip(-x) } else { let ta = f64::copysign(f64::from_bits(ATAN_REDUCE[i as usize].0), x); let dzta = DoubleDouble::from_exact_mult(x, ta); let zmta = x - ta; let v = 1. + dzta.hi; let d = 1. - v; let ev = (d + dzta.hi) - ((d + v) - 1.) + dzta.lo; let r = 1.0 / v; let rl = f_fmla(-ev, r, dd_fmla(r, -v, 1.0)) * r; DoubleDouble::quick_mult_f64(DoubleDouble::new(rl, r), zmta) }; let d2 = DoubleDouble::quick_mult(dh, dh); let h4 = d2.hi * d2.hi; let h3 = DoubleDouble::quick_mult(dh, d2); let fl0 = f_fmla(d2.hi, f64::from_bits(CL[1]), f64::from_bits(CL[0])); let fl1 = f_fmla(d2.hi, f64::from_bits(CL[3]), f64::from_bits(CL[2])); let fl = d2.hi * f_fmla(h4, fl1, fl0); let mut f = poly_dd_3(d2, CH, fl); f = DoubleDouble::quick_mult(h3, f); let (ah, mut al, mut at); if i == 0 { ah = dh.hi; al = f.hi; at = f.lo; } else { let mut df = 0.; if i < 128 { df = f64::copysign(1.0, x) * f64::from_bits(ATAN_REDUCE[i as usize].1); } let id = f64::copysign(i as f64, x); ah = f64::from_bits(0x3f8921fb54442d00) * id; al = f64::from_bits(0x3c88469898cc5180) * id; at = f64::from_bits(0xb97fc8f8cbb5bf80) * id; let v0 = DoubleDouble::add(DoubleDouble::new(at, al), DoubleDouble::new(0., df)); let v1 = DoubleDouble::add(v0, dh); let v2 = DoubleDouble::add(v1, f); al = v2.hi; at = v2.lo; } let v2 = DoubleDouble::from_exact_add(ah, al); let v1 = DoubleDouble::from_exact_add(v2.lo, at); let z0 = DoubleDouble::quick_mult(DoubleDouble::new(v1.hi, v2.hi), ONE_OVER_PI_DD); // atanpi_end z0.to_f64() } /// Computes atan(x) / pi /// /// Max ULP 0.5 pub fn f_atanpi(x: f64) -> f64 { const CH: [u64; 4] = [ 0x3ff0000000000000, 0xbfd555555555552b, 0x3fc9999999069c20, 0xbfc248d2c8444ac6, ]; let t = x.to_bits(); let at: u64 = t & 0x7fff_ffff_ffff_ffff; let mut i = (at >> 51).wrapping_sub(2030u64); if at < 0x3f7b21c475e6362au64 { // |x| < 0.006624 if at < 0x3c90000000000000u64 { // |x| < 2^-54 return atanpi_small(x); } if x == 0. { return x; } const CH2: [u64; 4] = [ 0xbfd5555555555555, 0x3fc99999999998c1, 0xbfc249249176aec0, 0x3fbc711fd121ae80, ]; let x2 = x * x; let x3 = x * x2; let x4 = x2 * x2; let f0 = f_fmla(x2, f64::from_bits(CH2[3]), f64::from_bits(CH2[2])); let f1 = f_fmla(x2, f64::from_bits(CH2[1]), f64::from_bits(CH2[0])); let f = x3 * f_fmla(x4, f0, f1); // begin_atanpi /* Here x+f approximates atan(x), with absolute error bounded by 0x4.8p-52*f (see atan.c). After multiplying by 1/pi this error will be bounded by 0x1.6fp-52*f. For |x| < 0x1.b21c475e6362ap-8 we have |f| < 2^-16*|x|, thus the error is bounded by 0x1.6fp-52*2^-16*|x| < 0x1.6fp-68. */ // multiply x + f by 1/pi let hy = DoubleDouble::quick_mult(DoubleDouble::new(f, x), ONE_OVER_PI_DD); /* The rounding error in muldd and the approximation error between 1/pi and ONE_OVER_PIH + ONE_OVER_PIL are covered by the difference between 0x4.8p-52*pi and 0x1.6fp-52, which is > 2^-61.8. */ let mut ub = hy.hi + dd_fmla(f64::from_bits(0x3bb6f00000000000), x, hy.lo); let lb = hy.hi + dd_fmla(f64::from_bits(0xbbb6f00000000000), x, hy.lo); if ub == lb { return ub; } // end_atanpi ub = (f + f * f64::from_bits(0x3cd2000000000000)) + x; // atanpi_specific, original value in atan return as_atanpi_refine2(x, ub); } // now |x| >= 0x1.b21c475e6362ap-8 let h; let mut a: DoubleDouble; if at > 0x4062ded8e34a9035u64 { // |x| > 0x1.2ded8e34a9035p+7, atanpi|x| > 0.49789 if at >= 0x43445f306dc9c883u64 { // |x| >= 0x1.45f306dc9c883p+53, atanpi|x| > 0.5 - 0x1p-55 if at >= (0x7ffu64 << 52) { // case Inf or NaN if at == 0x7ffu64 << 52 { // Inf return f64::copysign(0.5, x); } // atanpi_specific return x + x; // NaN } return f64::copysign(0.5, x) - f64::copysign(f64::from_bits(0x3c70000000000000), x); } h = -1.0 / x; a = DoubleDouble::new( f64::copysign(f64::from_bits(0x3c91a62633145c07), x), f64::copysign(f64::from_bits(0x3ff921fb54442d18), x), ); } else { // 0x1.b21c475e6362ap-8 <= |x| <= 0x1.2ded8e34a9035p+7 /* we need to deal with |x| = 1 separately since in this case h=0 below, and the error is measured in terms of multiple of h */ if at == 0x3ff0000000000000 { // |x| = 1 return f64::copysign(f64::from_bits(0x3fd0000000000000), x); } let u: u64 = t & 0x0007ffffffffffff; let ut = u >> (51 - 16); let ut2 = (ut * ut) >> 16; let vc = ATAN_CIRCLE[i as usize]; i = (((vc[0] as u64).wrapping_shl(16)) + ut * (vc[1] as u64) - ut2 * (vc[2] as u64)) >> (16 + 9); let va = ATAN_REDUCE[i as usize]; let ta = f64::copysign(1.0, x) * f64::from_bits(va.0); let id = f64::copysign(1.0, x) * i as f64; h = (x - ta) / (1. + x * ta); a = DoubleDouble::new( f64::copysign(1.0, x) * f64::from_bits(va.1) + f64::from_bits(0x3c88469898cc5170) * id, f64::from_bits(0x3f8921fb54442d00) * id, ); } let h2 = h * h; let h4 = h2 * h2; let f0 = f_fmla(h2, f64::from_bits(CH[3]), f64::from_bits(CH[2])); let f1 = f_fmla(h2, f64::from_bits(CH[1]), f64::from_bits(CH[0])); let f = f_fmla(h4, f0, f1); a.lo = dd_fmla(h, f, a.lo); // begin_atanpi /* Now ah + al approximates atan(x) with error bounded by 0x3.fp-52*h (see atan.c), thus by 0x1.41p-52*h after multiplication by 1/pi. We normalize ah+al so that the rounding error in muldd is negligible below. */ let e0 = h * f64::from_bits(0x3ccf800000000000); // original value in atan.c let ub0 = (a.lo + e0) + a.hi; // original value in atan.c a = DoubleDouble::from_exact_add(a.hi, a.lo); a = DoubleDouble::quick_mult(a, ONE_OVER_PI_DD); /* The rounding error in muldd() and the approximation error between 1/pi and ONE_OVER_PIH+ONE_OVER_PIL are absorbed when rounding up 0x3.fp-52*pi to 0x1.41p-52. */ let e = h * f64::from_bits(0x3cb4100000000000); // atanpi_specific // end_atanpi let ub = (a.lo + e) + a.hi; let lb = (a.lo - e) + a.hi; if ub == lb { return ub; } as_atanpi_refine2(x, ub0) } #[cfg(test)] mod tests { use super::*; #[test] fn atanpi_test() { assert_eq!(f_atanpi(119895888825197.97), 0.49999999999999734); assert_eq!(f_atanpi(1.5610674235815122E-307), 4.969031939254545e-308); assert_eq!(f_atanpi(0.00004577636903266291), 0.000014571070806516354); assert_eq!(f_atanpi(-0.00004577636903266291), -0.000014571070806516354); assert_eq!(f_atanpi(-0.4577636903266291), -0.13664770469904508); assert_eq!(f_atanpi(0.9876636903266291), 0.24802445507819193); } } pxfm-0.1.23/src/tangent/atanpif.rs000064400000000000000000000111431046102023000151000ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; /// Computes atan(x)/PI /// /// Max ULP 0.5 #[inline] pub fn f_atanpif(x: f32) -> f32 { let t = x.to_bits(); let e: i32 = ((t >> 23) & 0xff) as i32; let gt = e >= 127; if e > 127 + 24 { // |x| >= 2^25 let f = f32::copysign(0.5, x); if e == 0xff { if (t.wrapping_shl(9)) != 0 { return x + x; } // nan return f; // inf } // Warning: 0x1.45f306p-2f / x underflows for |x| >= 0x1.45f306p+124 return if x.abs() >= f32::from_bits(0x7da2f983) { f - f32::copysign(f32::from_bits(0x32800000), x) } else { f - f32::from_bits(0x3ea2f983) / x }; } let mut z = x as f64; if e < 127 - 13 { // |x| < 2^-13 let sx = z * f64::from_bits(0x3fd45f306dc9c883); if e < 127 - 25 { // |x| < 2^-25 return sx as f32; } let zz0 = sx - (f64::from_bits(0x3fd5555555555555) * sx) * (x as f64 * x as f64); return zz0 as f32; } let ax = t & 0x7fff_ffff; if ax == 0x3fa267ddu32 { return f32::copysign(f32::from_bits(0x3e933802), x) - f32::copysign(f32::from_bits(0x24000000), x); }; if ax == 0x3f693531u32 { return f32::copysign(f32::from_bits(0x3e70d331), x) + f32::copysign(f32::from_bits(0x31800000), x); }; if ax == 0x3f800000u32 { return f32::copysign(f32::from_bits(0x3e800000), x); }; if gt { z = 1. / z; } let z2 = z * z; let z4 = z2 * z2; let z8 = z4 * z4; const CN: [u64; 6] = [ 0x3fd45f306dc9c882, 0x3fe733b561bc23d5, 0x3fe28d9805bdfbf2, 0x3fc8c3ba966ae287, 0x3f994a7f81ee634b, 0x3f4a6bbf6127a6df, ]; let mut cn0 = f_fmla(z2, f64::from_bits(CN[1]), f64::from_bits(CN[0])); let cn2 = f_fmla(z2, f64::from_bits(CN[3]), f64::from_bits(CN[2])); let cn4 = f_fmla(z2, f64::from_bits(CN[5]), f64::from_bits(CN[4])); cn0 += z4 * cn2; cn0 += z8 * cn4; cn0 *= z; const CD: [u64; 7] = [ 0x3ff0000000000000, 0x4004e3b3ecc2518f, 0x4003ef4a360ff063, 0x3ff0f1dc55bad551, 0x3fc8da0fecc018a4, 0x3f88fa87803776bf, 0x3f1dadf2ca0acb43, ]; let mut cd0 = f_fmla(z2, f64::from_bits(CD[1]), f64::from_bits(CD[0])); let cd2 = f_fmla(z2, f64::from_bits(CD[3]), f64::from_bits(CD[2])); let mut cd4 = f_fmla(z2, f64::from_bits(CD[5]), f64::from_bits(CD[4])); let cd6 = f64::from_bits(CD[6]); cd0 += z4 * cd2; cd4 += z4 * cd6; cd0 += z8 * cd4; let mut r = cn0 / cd0; if gt { r = f64::copysign(0.5, z) - r; } r as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_atanpif() { assert_eq!(f_atanpif(0.0), 0.0); assert_eq!(f_atanpif(1.0), 0.25); assert_eq!(f_atanpif(1.5), 0.31283295); assert_eq!(f_atanpif(-1.0), -0.25); assert_eq!(f_atanpif(-1.5), -0.31283295); } } pxfm-0.1.23/src/tangent/cot.rs000064400000000000000000000161631046102023000142520ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::EXP_MASK; use crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::sin::{get_sin_k_rational, range_reduction_small}; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::range_reduction_small_f128; use crate::sincos_reduce::LargeArgumentReduction; use crate::tangent::tan::{newton_raphson_div, tan_eval, tan_eval_rational}; #[cold] fn cot_accurate( x: f64, k: u64, argument_reduction: &mut LargeArgumentReduction, den_dd: DoubleDouble, ) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let u_f128 = if x_e < E_BIAS + 16 { range_reduction_small_f128(x) } else { argument_reduction.accurate() }; let tan_u = tan_eval_rational(&u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sin_k_f128 = get_sin_k_rational(k); let cos_k_f128 = get_sin_k_rational(k.wrapping_add(64)); let msin_k_f128 = get_sin_k_rational(k.wrapping_add(128)); // num_f128 = sin(k*pi/128) + tan(y) * cos(k*pi/128) let num_f128 = sin_k_f128 + (cos_k_f128 * tan_u); // den_f128 = cos(k*pi/128) - tan(y) * sin(k*pi/128) let den_f128 = cos_k_f128 + (msin_k_f128 * tan_u); // tan(x) = (sin(k*pi/128) + tan(y) * cos(k*pi/128)) / // / (cos(k*pi/128) - tan(y) * sin(k*pi/128)) // num and den is shuffled for cot let result = newton_raphson_div(&den_f128, &num_f128, 1.0 / den_dd.hi); result.fast_as_f64() } /// Cotangent in double precision /// /// ULP 0.5 pub fn f_cot(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^16 if x_e < E_BIAS + 16 { // |x| < 2^-7 if x_e < E_BIAS - 7 { // |x| < 2^-27, |cot(x) - x| < ulp(x)/2. if x_e < E_BIAS - 27 { // Signed zeros. if x == 0.0 { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } if x_e < E_BIAS - 53 { return 1. / x; } let dx = DoubleDouble::from_quick_recip(x); // taylor order 3 return DoubleDouble::f64_mul_f64_add(x, f64::from_bits(0xbfd5555555555555), dx) .to_f64(); } // No range reduction needed. k = 0; y = DoubleDouble::new(0., x); } else { // Small range reduction. (y, k) = range_reduction_small(x); } } else { // Inf or NaN if x_e > 2 * E_BIAS { if x.is_nan() { return f64::NAN; } // tan(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let (tan_y, err) = tan_eval(y); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let cos_k_tan_y = DoubleDouble::quick_mult(tan_y, cos_k); let msin_k_tan_y = DoubleDouble::quick_mult(tan_y, msin_k); // num_dd = sin(k*pi/128) + tan(y) * cos(k*pi/128) let mut num_dd = DoubleDouble::from_full_exact_add(cos_k_tan_y.hi, -msin_k.hi); // den_dd = cos(k*pi/128) - tan(y) * sin(k*pi/128) let mut den_dd = DoubleDouble::from_full_exact_add(msin_k_tan_y.hi, cos_k.hi); num_dd.lo += cos_k_tan_y.lo - msin_k.lo; den_dd.lo += msin_k_tan_y.lo + cos_k.lo; // num and den is shuffled for cot let tan_x = DoubleDouble::div(den_dd, num_dd); // Simple error bound: |1 / den_dd| < 2^(1 + floor(-log2(den_dd)))). let den_inv = ((E_BIAS + 1) << (52 + 1)) - (den_dd.hi.to_bits() & EXP_MASK); // For tan_x = (num_dd + err) / (den_dd + err), the error is bounded by: // | tan_x - num_dd / den_dd | <= err * ( 1 + | tan_x * den_dd | ). let tan_err = err * f_fmla(f64::from_bits(den_inv), tan_x.hi.abs(), 1.0); let err_higher = tan_x.lo + tan_err; let err_lower = tan_x.lo - tan_err; let tan_upper = tan_x.hi + err_higher; let tan_lower = tan_x.hi + err_lower; // Ziv_s rounding test. if tan_upper == tan_lower { return tan_upper; } cot_accurate(x, k, &mut argument_reduction, num_dd) } #[cfg(test)] mod tests { use super::*; #[test] fn cot_test() { assert_eq!(f_cot(2.3006805685393681E-308), 4.346539948546049e307); assert_eq!(f_cot(5070552515158872000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.), 25.068466719883585); assert_eq!(f_cot(4.9406564584124654E-324), f64::INFINITY); assert_eq!(f_cot(0.0), f64::INFINITY); assert_eq!(f_cot(1.0), 0.6420926159343308); assert_eq!(f_cot(-0.5), -1.830487721712452); assert_eq!(f_cot(12.0), -1.5726734063976893); assert_eq!(f_cot(-12.0), 1.5726734063976893); assert!(f_cot(f64::INFINITY).is_nan()); assert!(f_cot(f64::NEG_INFINITY).is_nan()); assert!(f_cot(f64::NAN).is_nan()); } } pxfm-0.1.23/src/tangent/cotf.rs000064400000000000000000000104501046102023000144110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::tanf_eval; /// Computes cotangent /// /// Max found ULP 0.4999999 #[inline] pub fn f_cotf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| < pi/32 if x_abs <= 0x3dc9_0fdbu32 { // |x| < 0.000244141 if x_abs < 0x3980_0000u32 { if x_abs == 0 { return 1. / x; } // When |x| < 2^-12, the relative error of the approximation cot(x) // is: let ddx = x as f64; let dx = 1. / ddx; // taylor order 3 return f_fmla(ddx, f64::from_bits(0xbfd5555555555555), dx) as f32; } let xsqr = xd * xd; /* Generated by Sollya: f_cotf = x/tan(x); Q = fpminimax(f_cotf, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); See ./notes/cotf.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0xbfd5555555555466), f64::from_bits(0xbf96c16c16fb8937), f64::from_bits(0xbf6156688756cd43), f64::from_bits(0xbf2bce669d7cd742), ); return (p / xd) as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // For |x| >= pi/32, we use the definition of cot(x) function: // hence tan(A+y)=(cos(A)−tan(y)⋅sinA)/(sin(A)+tan(y)⋅cos(A)), // then cot(A+y)=(sin(A)+tan(y)⋅cos(A))/(cos(A)−tan(y)⋅sinA) // tanpif_eval returns: // - rs.tan_y = tan(y) -> tangent of the remainder // - rs.msin_k = sin(pi/32 * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi/32 * k) -> cosine of the main angle multiple let rs = tanf_eval(xd, x_abs); // num = sin(k*pi/32) + tan(y) * cos(k*pi/32) let num = f_fmla(rs.tan_y, rs.cos_k, -rs.msin_k); // den = cos(k*pi/32) - tan(y) * sin(k*pi/32) let den = f_fmla(rs.tan_y, rs.msin_k, rs.cos_k); // tan(x) = num(x) / den(x) (den / num) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn cotf_test() { assert_eq!(f_cotf(0.0010348097), 966.36084); assert_eq!(f_cotf(0.0020286469), 492.93872); assert_eq!(f_cotf(-0.0020286469), -492.93872); assert_eq!(f_cotf(1.0020286469), 0.63923126); assert_eq!(f_cotf(-1.0020286469), -0.63923126); assert_eq!(f_cotf(0.0), f32::INFINITY); assert_eq!(f_cotf(-0.0), f32::NEG_INFINITY); assert!(f_cotf(f32::INFINITY).is_nan()); assert!(f_cotf(f32::NEG_INFINITY).is_nan()); assert!(f_cotf(f32::NAN).is_nan()); } } pxfm-0.1.23/src/tangent/cotpi.rs000064400000000000000000000170761046102023000146070ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::sincospi::reduce_pi_64; use crate::sincospi_tables::SINPI_K_PI_OVER_64; use crate::tangent::tanpi::tanpi_eval; #[cold] fn cotpi_hard(x: f64, msin_k: DoubleDouble, cos_k: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 6] = [ (0x3ca1a62632712fc8, 0x400921fb54442d18), (0xbcc052338fbb4528, 0x4024abbce625be53), (0x3ced42454c5f85b3, 0x404466bc6775aad9), (0xbd00c7d6a971a560, 0x40645fff9b4b244d), (0x3d205970eff53274, 0x40845f46e96c3a0b), (0xbd3589489ad24fc4, 0x40a4630551cd123d), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut tan_y = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(C[5]), DoubleDouble::from_bit_pair(C[4]), ); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[3])); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[2])); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[1])); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[0])); tan_y = DoubleDouble::quick_mult_f64(tan_y, x); // num = sin(k*pi) + tan(y*pi) * cos(k*pi) let num = DoubleDouble::mul_add(tan_y, cos_k, -msin_k); // den = cos(k*pi) - tan(y*pi) * sin(k*pi) let den = DoubleDouble::mul_add(tan_y, msin_k, cos_k); // cot = den / num DoubleDouble::div(den, num) } /// Computes cotangent 1/tan(PI*x) /// /// ulp 0.5 pub fn f_cotpi(x: f64) -> f64 { if x == 0. { return if x.is_sign_negative() { f64::NEG_INFINITY } else { f64::INFINITY }; } let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff; if ax >= (0x7ffu64 << 52) { // NaN, Inf if ax > (0x7ffu64 << 52) { return x + x; } // NaN return f64::NAN; // x=Inf } let e: i32 = (ax >> 52) as i32 - 1023; if e > 0 { if e >= 52 { // when |x| > 2^53 it's always an integer return f64::copysign(f64::INFINITY, x); } // |x| > 1 and |x| < 2^53 let m = (ax & ((1u64 << 52) - 1)) | (1u64 << 52); // mantissa with hidden 1 let shift = 52 - e; let frac = m & ((1u64 << shift) - 1); if frac == (1u64 << (shift - 1)) { // |x| is always integer.5 means it's inf return f64::copysign(0., x); } } if ax <= 0x3cb0000000000000 { // for tiny x ( |x| < f64::EPSILON ) just small taylor expansion // cot(PI*x) ~ 1/(PI*x) + O(x^3) const ONE_OVER_PI: DoubleDouble = DoubleDouble::from_bit_pair((0xbc76b01ec5417056, 0x3fd45f306dc9c883)); if ax <= 0x3ca0000000000000 { // |x| <= 2^-53, renormalize value let e: i32 = (ax >> 52) as i32; let sc = f64::from_bits((2045i64 - e as i64).wrapping_shl(52) as u64); let dx = x * sc; let q0 = DoubleDouble::quick_mult(ONE_OVER_PI, DoubleDouble::from_quick_recip(dx)); let r = q0.to_f64() * sc; return r; } let q0 = DoubleDouble::quick_mult(ONE_OVER_PI, DoubleDouble::from_quick_recip(x)); let r = q0.to_f64(); return r; } // argument reduction let (y, k) = reduce_pi_64(x); if y == 0.0 { let km = (k.abs() & 63) as i32; // k mod 64 match km { 0 => return f64::copysign(f64::INFINITY, x), // cotpi(n) = 0 32 => return f64::copysign(0., x), // cotpi(n+0.5) = ±∞ 16 => return f64::copysign(1.0, x), // cotpi(n+0.25) = ±1 48 => return -f64::copysign(1.0, x), // cotpi(n+0.75) = ∓1 _ => {} } } let msin_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(64) & 127) as usize], ); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); // tanpi_eval returns: // - rs.tan_y = tan(pi * y) -> tangent of the remainder // - rs.msin_k = sin(pi * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi * k) -> cosine of the main angle multiple let tan_y = tanpi_eval(y); // num = sin(k*pi) + tan(y*pi) * cos(k*pi) let num = DoubleDouble::mul_add(tan_y, cos_k, -msin_k); // den = cos(k*pi) - tan(y*pi) * sin(k*pi) let den = DoubleDouble::mul_add(tan_y, msin_k, cos_k); // cot = den / num let tan_value = DoubleDouble::div(den, num); let err = f_fmla( tan_value.hi, f64::from_bits(0x3bf0000000000000), // 2^-64 f64::from_bits(0x3b60000000000000), // 2^-73 ); let ub = tan_value.hi + (tan_value.lo + err); let lb = tan_value.hi + (tan_value.lo - err); if ub == lb { return tan_value.to_f64(); } cotpi_hard(y, msin_k, cos_k).to_f64() } #[inline] pub(crate) fn cotpi_core(x: f64) -> DoubleDouble { // argument reduction let (y, k) = reduce_pi_64(x); let msin_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(64) & 127) as usize], ); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); // tanpi_eval returns: // - rs.tan_y = tan(pi * y) -> tangent of the remainder // - rs.msin_k = sin(pi * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi * k) -> cosine of the main angle multiple let tan_y = tanpi_eval(y); // num = sin(k*pi) + tan(y*pi) * cos(k*pi) let num = DoubleDouble::mul_add(tan_y, cos_k, -msin_k); // den = cos(k*pi) - tan(y*pi) * sin(k*pi) let den = DoubleDouble::mul_add(tan_y, msin_k, cos_k); // cot = den / num DoubleDouble::div(den, num) } #[cfg(test)] mod tests { use super::*; #[test] fn test_cotpi() { assert_eq!(f_cotpi(3.382112265043898e-306), 9.411570676518013e304); } } pxfm-0.1.23/src/tangent/cotpif.rs000064400000000000000000000123441046102023000147460ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 8/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::sin_cosf::{ArgumentReducerPi, tanpif_eval}; /// Computes 1/tan(PI*x) /// /// Max found ULP 0.5 #[inline] pub fn f_cotpif(x: f32) -> f32 { let ix = x.to_bits(); let e = ix & (0xff << 23); if e > (150 << 23) { // |x| > 2^23 if e == (0xff << 23) { // x = nan or inf if (ix.wrapping_shl(9)) == 0 { // x = inf return f32::NAN; } return x + x; // x = nan } return f32::INFINITY; } let argument_reduction = ArgumentReducerPi { x: x as f64 }; let (y, k) = argument_reduction.reduce(); if y == 0.0 { let km = (k.abs() & 31) as i32; // k mod 32 match km { 0 => return f32::copysign(f32::INFINITY, x), // cotpi(n) = ∞ 16 => return 0.0f32.copysign(x), // cotpi(n+0.5) = 0 8 => return f32::copysign(1.0, x), // cotpi(n+0.25) = 1 24 => return -f32::copysign(1.0, x), // cotpi(n+0.75) = -1 _ => {} } } let ax = ix & 0x7fff_ffff; if ax < 0x3bc49ba6u32 { // taylor series for cot(PI*x) where |x| < 0.006 let dx = x as f64; let dx_sqr = dx * dx; // cot(PI*x) ~ 1/(PI*x) - PI*x/3 - PI^3*x^3/45 + O(x^5) const ONE_OVER_PI: f64 = f64::from_bits(0x3fd45f306dc9c883); let r = f_fmla( dx_sqr, f64::from_bits(0xbfe60c8539c1dc14), f64::from_bits(0xbff0c152382d7366), ); let rcp = 1. / dx; return f_fmla(rcp, ONE_OVER_PI, r * dx) as f32; } // tanpif_eval returns: // - rs.tan_y = tan(pi/32 * y) -> tangent of the remainder // - rs.msin_k = sin(pi/32 * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi/32 * k) -> cosine of the main angle multiple let rs = tanpif_eval(y, k); // num = sin(k*pi/32) + tan(y*pi/32) * cos(k*pi/32) let num = f_fmla(rs.tan_y, rs.cos_k, -rs.msin_k); // den = cos(k*pi/32) - tan(y*pi/32) * sin(k*pi/32) let den = f_fmla(rs.tan_y, rs.msin_k, rs.cos_k); // hence tan = num / den then // cot = den / num (den / num) as f32 } #[inline] pub(crate) fn cotpif_core(x: f64) -> f64 { let argument_reduction = ArgumentReducerPi { x }; let (y, k) = argument_reduction.reduce(); // tanpif_eval returns: // - rs.tan_y = tan(pi/32 * y) -> tangent of the remainder // - rs.msin_k = sin(pi/32 * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi/32 * k) -> cosine of the main angle multiple let rs = tanpif_eval(y, k); // num = sin(k*pi/32) + tan(y*pi/32) * cos(k*pi/32) let num = f_fmla(rs.tan_y, rs.cos_k, -rs.msin_k); // den = cos(k*pi/32) - tan(y*pi/32) * sin(k*pi/32) let den = f_fmla(rs.tan_y, rs.msin_k, rs.cos_k); // hence tan = num / den then // cot = den / num den / num } #[cfg(test)] mod tests { use super::*; #[test] fn test_cotpif() { println!("0x{:8x}", 0.006f32.to_bits()); assert_eq!(f_cotpif(0.00046277765), 687.82416); assert_eq!(f_cotpif(2.3588752e-6), 134941.39); assert_eq!(f_cotpif(10775313000000000000000000000000.), f32::INFINITY); assert_eq!(f_cotpif(5.5625), -0.19891237); assert_eq!(f_cotpif(-29.75), 1.0); assert_eq!(f_cotpif(-21.5625), 0.19891237); assert_eq!(f_cotpif(-15.611655), 0.3659073); assert_eq!(f_cotpif(115.30706), 0.693186); assert_eq!(f_cotpif(0.), f32::INFINITY); assert!(f_cotpif(f32::INFINITY).is_nan()); assert!(f_cotpif(f32::NAN).is_nan()); } } pxfm-0.1.23/src/tangent/mod.rs000064400000000000000000000043671046102023000142470ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod atan; mod atan2; mod atan2f; mod atan2pi; mod atan2pif; mod atanf; mod atanpi; mod atanpif; mod cot; mod cotf; mod cotpi; mod cotpif; mod tan; mod tanf; mod tanpi; mod tanpif; pub use atan::f_atan; pub use atan2::f_atan2; pub use atan2f::f_atan2f; pub use atan2pi::f_atan2pi; pub use atan2pif::f_atan2pif; pub use atanf::f_atanf; pub use atanpi::f_atanpi; pub use atanpif::f_atanpif; pub use cot::f_cot; pub use cotf::f_cotf; pub(crate) use cotpi::cotpi_core; pub use cotpi::f_cotpi; pub(crate) use cotpif::cotpif_core; pub use cotpif::f_cotpif; pub use tan::f_tan; pub use tanf::f_tanf; pub use tanpi::f_tanpi; pub use tanpif::f_tanpif; pxfm-0.1.23/src/tangent/tan.rs000064400000000000000000000271301046102023000142430ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::EXP_MASK; use crate::common::{dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use crate::dyadic_float::{DyadicFloat128, DyadicSign}; use crate::polyeval::f_polyeval9; use crate::sin::{get_sin_k_rational, range_reduction_small}; use crate::sin_table::SIN_K_PI_OVER_128; use crate::sincos_dyadic::range_reduction_small_f128; use crate::sincos_reduce::LargeArgumentReduction; #[inline] pub(crate) fn tan_eval(u: DoubleDouble) -> (DoubleDouble, f64) { // Evaluate tan(y) = tan(x - k * (pi/128)) // We use the degree-9 Taylor approximation: // tan(y) ~ P(y) = y + y^3/3 + 2*y^5/15 + 17*y^7/315 + 62*y^9/2835 // Then the error is bounded by: // |tan(y) - P(y)| < 2^-6 * |y|^11 < 2^-6 * 2^-66 = 2^-72. // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms // < ulp(u_hi^3) gives us: // P(y) = y + y^3/3 + 2*y^5/15 + 17*y^7/315 + 62*y^9/2835 = ... // ~ u_hi + u_hi^3 * (1/3 + u_hi^2 * (2/15 + u_hi^2 * (17/315 + // + u_hi^2 * 62/2835))) + // + u_lo (1 + u_hi^2 * (1 + u_hi^2 * 2/3)) let u_hi_sq = u.hi * u.hi; // Error < ulp(u_hi^2) < 2^(-6 - 52) = 2^-58. // p1 ~ 17/315 + u_hi^2 62 / 2835. let p1 = f_fmla( u_hi_sq, f64::from_bits(0x3f9664f4882c10fa), f64::from_bits(0x3faba1ba1ba1ba1c), ); // p2 ~ 1/3 + u_hi^2 2 / 15. let p2 = f_fmla( u_hi_sq, f64::from_bits(0x3fc1111111111111), f64::from_bits(0x3fd5555555555555), ); // q1 ~ 1 + u_hi^2 * 2/3. let q1 = f_fmla(u_hi_sq, f64::from_bits(0x3fe5555555555555), 1.0); let u_hi_3 = u_hi_sq * u.hi; let u_hi_4 = u_hi_sq * u_hi_sq; // p3 ~ 1/3 + u_hi^2 * (2/15 + u_hi^2 * (17/315 + u_hi^2 * 62/2835)) let p3 = f_fmla(u_hi_4, p1, p2); // q2 ~ 1 + u_hi^2 * (1 + u_hi^2 * 2/3) let q2 = f_fmla(u_hi_sq, q1, 1.0); let tan_lo = f_fmla(u_hi_3, p3, u.lo * q2); // Overall, |tan(y) - (u_hi + tan_lo)| < ulp(u_hi^3) <= 2^-71. // And the relative errors is: // |(tan(y) - (u_hi + tan_lo)) / tan(y) | <= 2*ulp(u_hi^2) < 2^-64 let err = f_fmla( u_hi_3.abs(), f64::from_bits(0x3cc0000000000000), f64::from_bits(0x3990000000000000), ); (DoubleDouble::from_exact_add(u.hi, tan_lo), err) } #[inline] pub(crate) fn tan_eval_rational(u: &DyadicFloat128) -> DyadicFloat128 { let u_sq = u.quick_mul(u); // tan(x) ~ x + x^3/3 + x^5 * 2/15 + x^7 * 17/315 + x^9 * 62/2835 + // + x^11 * 1382/155925 + x^13 * 21844/6081075 + // + x^15 * 929569/638512875 + x^17 * 6404582/10854718875 // Relative errors < 2^-127 for |u| < pi/256. const TAN_COEFFS: [DyadicFloat128; 9] = [ DyadicFloat128 { sign: DyadicSign::Pos, exponent: -127, mantissa: 0x80000000_00000000_00000000_00000000_u128, }, // 1 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -129, mantissa: 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaab_u128, }, // 1 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -130, mantissa: 0x88888888_88888888_88888888_88888889_u128, }, // 2/15 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -132, mantissa: 0xdd0dd0dd_0dd0dd0d_d0dd0dd0_dd0dd0dd_u128, }, // 17/315 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -133, mantissa: 0xb327a441_6087cf99_6b5dd24e_ec0b327a_u128, }, // 62/2835 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -134, mantissa: 0x91371aaf_3611e47a_da8e1cba_7d900eca_u128, }, // 1382/155925 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -136, mantissa: 0xeb69e870_abeefdaf_e606d2e4_d1e65fbc_u128, }, // 21844/6081075 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -137, mantissa: 0xbed1b229_5baf15b5_0ec9af45_a2619971_u128, }, // 929569/638512875 DyadicFloat128 { sign: DyadicSign::Pos, exponent: -138, mantissa: 0x9aac1240_1b3a2291_1b2ac7e3_e4627d0a_u128, }, // 6404582/10854718875 ]; u.quick_mul(&f_polyeval9( u_sq, TAN_COEFFS[0], TAN_COEFFS[1], TAN_COEFFS[2], TAN_COEFFS[3], TAN_COEFFS[4], TAN_COEFFS[5], TAN_COEFFS[6], TAN_COEFFS[7], TAN_COEFFS[8], )) } // Calculation a / b = a * (1/b) for Float128. // Using the initial approximation of q ~ (1/b), then apply 2 Newton-Raphson // iterations, before multiplying by a. #[inline] pub(crate) fn newton_raphson_div(a: &DyadicFloat128, b: &DyadicFloat128, q: f64) -> DyadicFloat128 { let q0 = DyadicFloat128::new_from_f64(q); const TWO: DyadicFloat128 = DyadicFloat128::new_from_f64(2.0); let mut b = *b; b.sign = if b.sign == DyadicSign::Pos { DyadicSign::Neg } else { DyadicSign::Pos }; let q1 = q0.quick_mul(&TWO.quick_add(&b.quick_mul(&q0))); let q2 = q1.quick_mul(&TWO.quick_add(&b.quick_mul(&q1))); a.quick_mul(&q2) } #[cold] fn tan_accurate( x: f64, k: u64, argument_reduction: &mut LargeArgumentReduction, den_dd: DoubleDouble, ) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let u_f128 = if x_e < E_BIAS + 16 { range_reduction_small_f128(x) } else { argument_reduction.accurate() }; let tan_u = tan_eval_rational(&u_f128); // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sin_k_f128 = get_sin_k_rational(k); let cos_k_f128 = get_sin_k_rational(k.wrapping_add(64)); let msin_k_f128 = get_sin_k_rational(k.wrapping_add(128)); // num_f128 = sin(k*pi/128) + tan(y) * cos(k*pi/128) let num_f128 = sin_k_f128 + (cos_k_f128 * tan_u); // den_f128 = cos(k*pi/128) - tan(y) * sin(k*pi/128) let den_f128 = cos_k_f128 + (msin_k_f128 * tan_u); // tan(x) = (sin(k*pi/128) + tan(y) * cos(k*pi/128)) / // / (cos(k*pi/128) - tan(y) * sin(k*pi/128)) // reused from DoubleDouble fputil::div in the fast pass. let result = newton_raphson_div(&num_f128, &den_f128, 1.0 / den_dd.hi); result.fast_as_f64() } /// Tangent in double precision /// /// ULP 0.5 pub fn f_tan(x: f64) -> f64 { let x_e = (x.to_bits() >> 52) & 0x7ff; const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64; let y: DoubleDouble; let k; let mut argument_reduction = LargeArgumentReduction::default(); // |x| < 2^16 if x_e < E_BIAS + 16 { // |x| < 2^-7 if x_e < E_BIAS - 7 { // |x| < 2^-27, |tan(x) - x| < ulp(x)/2. if x_e < E_BIAS - 27 { // Signed zeros. if x == 0.0 { return x + x; } return dyad_fmla(x, f64::from_bits(0x3c90000000000000), x); } // No range reduction needed. k = 0; y = DoubleDouble::new(0., x); } else { // Small range reduction. (y, k) = range_reduction_small(x); } } else { // Inf or NaN if x_e > 2 * E_BIAS { if x.is_nan() { return f64::NAN; } // tan(+-Inf) = NaN return x + f64::NAN; } // Large range reduction. (k, y) = argument_reduction.reduce(x); } let (tan_y, err) = tan_eval(y); // Fast look up version, but needs 256-entry table. // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). let sk = SIN_K_PI_OVER_128[(k.wrapping_add(128) & 255) as usize]; let ck = SIN_K_PI_OVER_128[((k.wrapping_add(64)) & 255) as usize]; let msin_k = DoubleDouble::from_bit_pair(sk); let cos_k = DoubleDouble::from_bit_pair(ck); let cos_k_tan_y = DoubleDouble::quick_mult(tan_y, cos_k); let msin_k_tan_y = DoubleDouble::quick_mult(tan_y, msin_k); // num_dd = sin(k*pi/128) + tan(y) * cos(k*pi/128) let mut num_dd = DoubleDouble::from_full_exact_add(cos_k_tan_y.hi, -msin_k.hi); // den_dd = cos(k*pi/128) - tan(y) * sin(k*pi/128) let mut den_dd = DoubleDouble::from_full_exact_add(msin_k_tan_y.hi, cos_k.hi); num_dd.lo += cos_k_tan_y.lo - msin_k.lo; den_dd.lo += msin_k_tan_y.lo + cos_k.lo; let tan_x = DoubleDouble::div(num_dd, den_dd); // Simple error bound: |1 / den_dd| < 2^(1 + floor(-log2(den_dd)))). let den_inv = ((E_BIAS + 1) << (52 + 1)) - (den_dd.hi.to_bits() & EXP_MASK); // For tan_x = (num_dd + err) / (den_dd + err), the error is bounded by: // | tan_x - num_dd / den_dd | <= err * ( 1 + | tan_x * den_dd | ). let tan_err = err * f_fmla(f64::from_bits(den_inv), tan_x.hi.abs(), 1.0); let err_higher = tan_x.lo + tan_err; let err_lower = tan_x.lo - tan_err; let tan_upper = tan_x.hi + err_higher; let tan_lower = tan_x.hi + err_lower; // Ziv_s rounding test. if tan_upper == tan_lower { return tan_upper; } tan_accurate(x, k, &mut argument_reduction, den_dd) } #[cfg(test)] mod tests { use super::*; #[test] fn tan_test() { assert_eq!(f_tan(0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007291122019556397), 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007291122019556397); assert_eq!(f_tan(0.0), 0.0); assert_eq!(f_tan(1.0), 1.5574077246549023); assert_eq!(f_tan(-0.5), -0.5463024898437905); } } pxfm-0.1.23/src/tangent/tanf.rs000064400000000000000000000113471046102023000144140ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::polyeval::f_polyeval5; use crate::sin_cosf::tanf_eval; /// Computes tan /// /// Max found ULP 0.4999999 #[inline] pub fn f_tanf(x: f32) -> f32 { let x_abs = x.to_bits() & 0x7fff_ffffu32; let xd = x as f64; // |x| < pi/32 if x_abs <= 0x3dc9_0fdbu32 { // |x| < 0.000244141 if x_abs < 0x3980_0000u32 { if x_abs == 0 { return x; } // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x // is: // |tan(x) - x| / |tan(x)| < |x^3| / (3|x|) // = x^2 / 3 // < 2^-25 // < epsilon(1)/2. #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmlaf; return f_fmlaf(x, f32::from_bits(0xb3000000), x); } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { return f_fmla(xd, f64::from_bits(0xbe60000000000000), xd) as f32; } } let xsqr = xd * xd; /* Generated by Sollya: f_tan = tan(x)/x; Q = fpminimax(f_tan, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); See ./notes/tanf_at_zero.sollya */ let p = f_polyeval5( xsqr, f64::from_bits(0x3ff0000000000000), f64::from_bits(0x3fd555555553d022), f64::from_bits(0x3fc111111ce442c1), f64::from_bits(0x3faba180a6bbdecd), f64::from_bits(0x3f969c0a88a0b71f), ); return (xd * p) as f32; } if x_abs >= 0x7f80_0000u32 { return x + f32::NAN; } // For |x| >= pi/32, we use the definition of tan(x) function: // tan(A+y)=(cos(A)−tan(y)⋅sinA)/(sin(A)+tan(y)⋅cos(A)) // tanpif_eval returns: // - rs.tan_y = tan(y) -> tangent of the remainder // - rs.msin_k = sin(pi/32 * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi/32 * k) -> cosine of the main angle multiple let rs = tanf_eval(xd, x_abs); // num = sin(k*pi/32) + tan(y) * cos(k*pi/32) let num = f_fmla(rs.tan_y, rs.cos_k, -rs.msin_k); // den = cos(k*pi/32) - tan(y) * sin(k*pi/32) let den = f_fmla(rs.tan_y, rs.msin_k, rs.cos_k); // tan(x) = num(x) / den(x) (num / den) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn f_tanf_test() { assert_eq!(f_tanf(0.0), 0.0); assert_eq!(f_tanf(1.0), 1.5574077); assert_eq!(f_tanf(-1.0), -1.5574077); assert_eq!(f_tanf(10.0), 0.64836085); assert_eq!(f_tanf(-10.0), -0.64836085); } } pxfm-0.1.23/src/tangent/tanpi.rs000064400000000000000000000205711046102023000145760ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use crate::sincospi::reduce_pi_64; use crate::sincospi_tables::SINPI_K_PI_OVER_64; #[inline] pub(crate) fn tanpi_eval(x: f64) -> DoubleDouble { let x2 = DoubleDouble::from_exact_mult(x, x); // tan(pi*x) generated by Sollya: // d = [0, 0.0078128]; // f_tan = tan(y*pi)/y; // Q = fpminimax(f_tan, [|0, 2, 4, 6, 8|], [|107, D...|], d, relative, floating); const C: [u64; 4] = [ 0x4024abbce625be51, 0x404466bc677698e5, 0x40645fff70379ae3, 0x4084626b091b7fd0, ]; const C0: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a6444aa5b996, 0x400921fb54442d18)); // polyeval 4, estrin scheme let u0 = f_fmla(x2.hi, f64::from_bits(C[1]), f64::from_bits(C[0])); // a0 + a1*x let u1 = f_fmla(x2.hi, f64::from_bits(C[3]), f64::from_bits(C[2])); // a2 + a3*x let tan_poly_lo = f_fmla(x2.hi * x2.hi, u1, u0); // We're splitting polynomial in two parts, since first term dominates // we compute: (a0_lo + a0_hi) * x + x * (a1 * x^2 + a2 + x^4) ... let r_lo = DoubleDouble::quick_mult_f64(x2, tan_poly_lo); let tan_lo = f_fmla(r_lo.lo, x, r_lo.hi * x); let tan_hi = DoubleDouble::quick_mult_f64(C0, x); DoubleDouble::full_add_f64(tan_hi, tan_lo) } #[cold] fn tanpi_hard(x: f64, msin_k: DoubleDouble, cos_k: DoubleDouble) -> DoubleDouble { const C: [(u64, u64); 6] = [ (0x3ca1a62632712fc8, 0x400921fb54442d18), (0xbcc052338fbb4528, 0x4024abbce625be53), (0x3ced42454c5f85b3, 0x404466bc6775aad9), (0xbd00c7d6a971a560, 0x40645fff9b4b244d), (0x3d205970eff53274, 0x40845f46e96c3a0b), (0xbd3589489ad24fc4, 0x40a4630551cd123d), ]; let x2 = DoubleDouble::from_exact_mult(x, x); let mut tan_y = DoubleDouble::quick_mul_add( x2, DoubleDouble::from_bit_pair(C[5]), DoubleDouble::from_bit_pair(C[4]), ); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[3])); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[2])); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[1])); tan_y = DoubleDouble::quick_mul_add(x2, tan_y, DoubleDouble::from_bit_pair(C[0])); tan_y = DoubleDouble::quick_mult_f64(tan_y, x); // num = sin(k*pi) + tan(y*pi) * cos(k*pi) let num = DoubleDouble::mul_add(tan_y, cos_k, -msin_k); // den = cos(k*pi) - tan(y*pi) * sin(k*pi) let den = DoubleDouble::mul_add(tan_y, msin_k, cos_k); // tan = num / den DoubleDouble::div(num, den) } /// Computes tan(PI*x) /// /// Max found ULP 0.5 pub fn f_tanpi(x: f64) -> f64 { if x == 0. { return x; } let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff; if ax >= (0x7ffu64 << 52) { // NaN, Inf if ax > (0x7ffu64 << 52) { return x + x; } // NaN return f64::NAN; // x=Inf } let e: i32 = (ax >> 52) as i32 - 1023; if e > 0 { if e >= 52 { // when |x| > 2^53 it's always an integer return f64::copysign(0., x); } // |x| > 1 and |x| < 2^53 let m = (ax & ((1u64 << 52) - 1)) | (1u64 << 52); // mantissa with hidden 1 let shift = 52 - e; let frac = m & ((1u64 << shift) - 1); if frac == (1u64 << (shift - 1)) { // |x| is always integer.5 means it's inf return f64::INFINITY; } } if ax <= 0x3cb0000000000000 { // for tiny x ( |x| < f64::EPSILON ) just small taylor expansion // tan(PI*x) ~ PI*x + PI^3*x^3/3 + O(x^5) const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18)); if ax <= 0x3ca0000000000000 { // |x| <= 2^-53, renormalize value let e: i32 = (ax >> 52) as i32; let sc = f64::from_bits((2045i64 - e as i64).wrapping_shl(52) as u64); let isc = f64::from_bits(1i64.wrapping_add(e as i64).wrapping_shl(52) as u64); let dx = x * sc; let q0 = DoubleDouble::quick_mult_f64(PI, dx); let r = q0.to_f64() * isc; return r; } let q0 = DoubleDouble::quick_mult_f64(PI, x); let r = q0.to_f64(); return r; } // argument reduction let (y, k) = reduce_pi_64(x); if y == 0.0 { let km = (k.abs() & 63) as i32; // k mod 64 match km { 0 => return f64::copysign(0f64, x), // tanpi(n) = 0 32 => return f64::copysign(f64::INFINITY, x), // tanpi(n+0.5) = ±∞ 16 => return f64::copysign(1.0, x), // tanpi(n+0.25) = ±1 48 => return -f64::copysign(1.0, x), // tanpi(n+0.75) = ∓1 _ => {} } } let msin_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(64) & 127) as usize], ); let cos_k = DoubleDouble::from_bit_pair( SINPI_K_PI_OVER_64[((k as u64).wrapping_add(32) & 127) as usize], ); // tanpi_eval returns: // - rs.tan_y = tan(pi * y) -> tangent of the remainder // - rs.msin_k = sin(pi * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi * k) -> cosine of the main angle multiple let tan_y = tanpi_eval(y); // num = sin(k*pi) + tan(y*pi) * cos(k*pi) let num = DoubleDouble::mul_add(tan_y, cos_k, -msin_k); // den = cos(k*pi) - tan(y*pi) * sin(k*pi) let den = DoubleDouble::mul_add(tan_y, msin_k, cos_k); // tan = num / den let tan_value = DoubleDouble::div(num, den); let err = f_fmla( tan_value.hi, f64::from_bits(0x3bf0000000000000), // 2^-64 f64::from_bits(0x3b60000000000000), // 2^-73 ); let ub = tan_value.hi + (tan_value.lo + err); let lb = tan_value.hi + (tan_value.lo - err); if ub == lb { return tan_value.to_f64(); } tanpi_hard(y, msin_k, cos_k).to_f64() } #[cfg(test)] mod tests { use super::*; #[test] fn test_tanpi() { assert_eq!(f_tanpi(0.4999999999119535), 3615246871.564404); assert_eq!(f_tanpi(7119681148991743.0), 0.); assert_eq!(f_tanpi(63.5), f64::INFINITY); assert_eq!(f_tanpi(63.99935913085936), -0.0020133525045719896); assert_eq!(f_tanpi(3.3821122649309461E-306), 1.0625219045122997E-305); assert_eq!(f_tanpi(1.8010707049867402E-255), 5.6582304953821333E-255); assert_eq!(f_tanpi(1.001000000061801), 0.0031416031832113213); assert_eq!(f_tanpi(-0.5000000000000226), 14054316517702.594); assert_eq!(f_tanpi(0.5000000000000001), -2867080569611329.5); assert_eq!(f_tanpi(0.02131), 0.06704753721009375); assert!(f_tanpi(f64::INFINITY).is_nan()); assert!(f_tanpi(f64::NAN).is_nan()); assert!(f_tanpi(f64::NEG_INFINITY).is_nan()); } } pxfm-0.1.23/src/tangent/tanpif.rs000064400000000000000000000102741046102023000147430ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::sin_cosf::{ArgumentReducerPi, tanpif_eval}; /// Computes tan(PI*x) /// /// Max found ULP 0.5 #[inline] pub fn f_tanpif(x: f32) -> f32 { let ix = x.to_bits(); let e = ix & (0xff << 23); if e > (150 << 23) { // |x| > 2^23 if e == (0xff << 23) { // x = nan or inf if (ix.wrapping_shl(9)) == 0 { // x = inf return f32::NAN; } return x + x; // x = nan } return f32::copysign(0.0, x); } let argument_reduction = ArgumentReducerPi { x: x as f64 }; let (y, k) = argument_reduction.reduce(); if y == 0.0 { let km = (k.abs() & 31) as i32; // k mod 32 match km { 0 => return 0.0f32.copysign(x), // tanpi(n) = 0 16 => return f32::copysign(f32::INFINITY, x), // tanpi(n+0.5) = ±∞ 8 => return f32::copysign(1.0, x), // tanpi(n+0.25) = ±1 24 => return -f32::copysign(1.0, x), // tanpi(n+0.75) = ∓1 _ => {} } } let ax = ix & 0x7fff_ffff; if ax < 0x38d1b717u32 { // taylor series for tan(PI*x) where |x| < 0.0001 let dx = x as f64; let dx_sqr = dx * dx; // tan(PI*x) ~ PI*x + PI^3*x^3/3 + O(x^5) let r = f_fmla( dx_sqr, f64::from_bits(0x4024abbce625be53), f64::from_bits(0x400921fb54442d18), ); return (r * dx) as f32; } // tanpif_eval returns: // - rs.tan_y = tan(pi/32 * y) -> tangent of the remainder // - rs.msin_k = sin(pi/32 * k) -> sine of the main angle multiple // - rs.cos_k = cos(pi/32 * k) -> cosine of the main angle multiple let rs = tanpif_eval(y, k); // num = sin(k*pi/32) + tan(y*pi/32) * cos(k*pi/32) let num = f_fmla(rs.tan_y, rs.cos_k, -rs.msin_k); // den = cos(k*pi/32) - tan(y*pi/32) * sin(k*pi/32) let den = f_fmla(rs.tan_y, rs.msin_k, rs.cos_k); // tan = num / den (num / den) as f32 } #[cfg(test)] mod tests { use super::*; #[test] fn test_tanpif() { assert_eq!(f_tanpif(3.666738e-5), 0.00011519398); assert_eq!(f_tanpif(1.0355987e-25), 3.2534293e-25); assert_eq!(f_tanpif(5.5625), -5.0273395); assert_eq!(f_tanpif(-29.75), 1.0); assert_eq!(f_tanpif(-21.5625), 5.0273395); assert_eq!(f_tanpif(-15.611655), 2.7329326); assert_eq!(f_tanpif(115.30706), 1.4426143); assert!(f_tanpif(f32::INFINITY).is_nan()); assert!(f_tanpif(f32::NAN).is_nan()); } } pxfm-0.1.23/src/triangle/cathetus.rs000064400000000000000000000156551046102023000154570ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::double_double::DoubleDouble; /// Computes the missing leg of a right triangle /// /// Given a hypotenuse `x` and a known leg `y`, returns /// `sqrt(x^2 - y^2)` = the length of the other leg. /// /// Domain: requires `|x| >= |y|`. Returns NaN if the input /// is outside this range. pub fn f_cathetus(x: f64, y: f64) -> f64 { let x_abs = x.abs(); let y_abs = y.abs(); let x_bits = x_abs.to_bits(); let y_bits = y_abs.to_bits(); let a_u = x_bits.max(y_bits); let mut dx = x; let mut dy = y; const EXP_MASK_F64: u64 = 0x7FF0_0000_0000_0000; if a_u >= EXP_MASK_F64 { // x or y is inf or nan if f64::from_bits(x_bits).is_nan() || f64::from_bits(y_bits).is_nan() { return f64::NAN; } if f64::from_bits(x_bits).is_infinite() || f64::from_bits(y_bits).is_infinite() { if f64::from_bits(x_bits).is_infinite() && f64::from_bits(y_bits).is_infinite() { // ∞² - ∞² is undefined return f64::NAN; } return f64::INFINITY; } return f64::from_bits(x_bits); } if x_abs < y_abs { // Would yield sqrt(negative), undefined return f64::NAN; } if x_abs == y_abs { // sqrt(c² - c²) = 0 return 0.0; } let e_x = x_bits >> 52; let e_y = y_bits >> 52; let unbiased_e_x = (e_x as i32).wrapping_sub(1023); let mut scale = 1f64; if e_y == 0 { if e_x - e_y > 52 { // y is too small to make difference, so result is just |x| return x_abs; } dx *= f64::from_bits(0x6bb0000000000000); // 2^700 dy *= f64::from_bits(0x6bb0000000000000); // 2^700 scale = f64::from_bits(0x1430000000000000); // 2^(-700 / 2) } else if unbiased_e_x >= 510 { dx *= f64::from_bits(0x1430000000000000); // 2^-700 dy *= f64::from_bits(0x1430000000000000); // 2^-700 scale = f64::from_bits(0x6bb0000000000000); // 2^(700 / 2) } else if unbiased_e_x <= -450 { dx *= f64::from_bits(0x6bb0000000000000); // 2^700 dy *= f64::from_bits(0x6bb0000000000000); // 2^700 scale = f64::from_bits(0x1430000000000000); // 2^(-700) } let dy2 = DoubleDouble::from_exact_mult(dy, dy); let dx2 = DoubleDouble::from_exact_mult(dx, dx); let p = DoubleDouble::sub(dx2, dy2); let cath = p.fast_sqrt(); // sqrt(x^2 - y^2) cath.to_f64() * scale } #[cfg(test)] mod tests { use super::*; #[test] fn test_cathethus() { assert_eq!( f_cathetus(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002248996583584318, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002842248694776204), 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002248996583584318 ); assert_eq!( f_cathetus(0.00003241747618121237, 0.00003241747618121195), 5.219099637789996e-12 ); assert_eq!(f_cathetus(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003382112264930946, -0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005284550413954603), 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003381699384228079); assert_eq!(f_cathetus(5., 3.), 4.); assert_eq!(f_cathetus(5., 4.), 3.); assert_eq!(f_cathetus(13., 12.), 5.); assert_eq!(f_cathetus(65., 16.), 63.); assert_eq!(f_cathetus(25., 24.), 7.); assert!(f_cathetus(24., 25.).is_nan()); } #[test] fn test_cathetus_edge_cases() { assert_eq!(f_cathetus(0.0, 0.0), 0.0); assert_eq!(f_cathetus(f64::INFINITY, 0.0), f64::INFINITY); assert_eq!(f_cathetus(0.0, f64::INFINITY), f64::INFINITY); assert!(f_cathetus(f64::INFINITY, f64::INFINITY).is_nan()); assert_eq!(f_cathetus(f64::NEG_INFINITY, 0.0), f64::INFINITY); assert_eq!(f_cathetus(0.0, f64::NEG_INFINITY), f64::INFINITY); assert!(f_cathetus(f64::NEG_INFINITY, f64::NEG_INFINITY).is_nan()); assert!(f_cathetus(f64::NAN, 1.0).is_nan()); assert!(f_cathetus(1.0, f64::NAN).is_nan()); } } pxfm-0.1.23/src/triangle/cathetusf.rs000064400000000000000000000120261046102023000156120ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::EXP_MASK_F32; /// Computes the missing leg of a right triangle /// /// Given a hypotenuse `x` and a known leg `y`, returns /// `sqrt(x^2 - y^2)` = the length of the other leg. /// /// Domain: requires `|x| >= |y|`. Returns NaN if the input /// is outside this range. pub fn f_cathetusf(x: f32, y: f32) -> f32 { let x_abs = x.abs(); let y_abs = y.abs(); let x_bits = x_abs.to_bits(); let y_bits = y_abs.to_bits(); let a_u = x_bits.max(y_bits); if a_u >= EXP_MASK_F32 { // x or y is inf or nan if f32::from_bits(x_bits).is_nan() || f32::from_bits(y_bits).is_nan() { return f32::NAN; } if f32::from_bits(x_bits).is_infinite() || f32::from_bits(y_bits).is_infinite() { if f32::from_bits(x_bits).is_infinite() && f32::from_bits(y_bits).is_infinite() { // ∞² - ∞² is undefined return f32::NAN; } return f32::INFINITY; } return f32::from_bits(x_bits); } if x_abs < y_abs { // Would yield sqrt(negative), undefined return f32::NAN; } if x_abs == y_abs { // sqrt(c² - c²) = 0 return 0.0; } let dx = x as f64; let dy = y as f64; #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { use crate::common::f_fmla; // for FMA environment we're using Kahan style summation which is short and reliable. let w = dy * dy; // RN(bc) let e = f_fmla(-dy, dy, w); // RN(w − bc) let f = f_fmla(dx, dx, -w); // RN(ad − w) let r = e + f; // RN(f + e) let cath = r.sqrt(); // sqrt(x^2 - y^2) cath as f32 } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { use crate::double_double::DoubleDouble; let dy2 = DoubleDouble::from_exact_mult(dy, dy); let fdx = DoubleDouble::from_exact_mult(dx, dx); // element must follow condition |x| > |y| so it always follows fasttwosum requirements let f = DoubleDouble::add_f64(fdx, -dy2.hi).to_f64(); let r = dy2.lo + f; let cath = r.sqrt(); cath as f32 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_cathetusf_edge() { assert_eq!(f_cathetusf(5., 3.), 4.); assert_eq!(f_cathetusf(5., 4.), 3.); assert_eq!(f_cathetusf(13., 12.), 5.); assert_eq!(f_cathetusf(65., 16.), 63.); assert_eq!(f_cathetusf(25., 24.), 7.); assert!(f_cathetusf(24., 25.).is_nan()); } #[test] fn test_cathetusf_edge_cases() { assert_eq!(f_cathetusf(0.0, 0.0), 0.0); assert_eq!(f_cathetusf(f32::INFINITY, 0.0), f32::INFINITY); assert_eq!(f_cathetusf(0.0, f32::INFINITY), f32::INFINITY); assert!(f_cathetusf(f32::INFINITY, f32::INFINITY).is_nan()); assert_eq!(f_cathetusf(f32::NEG_INFINITY, 0.0), f32::INFINITY); assert_eq!(f_cathetusf(0.0, f32::NEG_INFINITY), f32::INFINITY); assert!(f_cathetusf(f32::NEG_INFINITY, f32::NEG_INFINITY).is_nan()); assert!(f_cathetusf(f32::NAN, 1.0).is_nan()); assert!(f_cathetusf(1.0, f32::NAN).is_nan()); } } pxfm-0.1.23/src/triangle/hypot.rs000064400000000000000000000251051046102023000147710ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::{dyad_fmla, f_fmla}; use crate::double_double::DoubleDouble; use std::hint::black_box; // case hypot(x,y) >= 2^1024 #[cold] fn hypot_overflow() -> f64 { const Z: f64 = f64::from_bits(0x7fefffffffffffff); black_box(Z) + black_box(Z) } #[cold] fn hypot_denorm(a: u64, b: u64) -> f64 { let mut a = a; let mut b = b; let af = (a as i64) as f64; let bf = (b as i64) as f64; let mut underflow; // af and bf are x and y multiplied by 2^1074, thus integers a = a.wrapping_shl(1); b = b.wrapping_shl(1); let mut rm = f_fmla(af, af, bf * bf).sqrt() as u64; let mut tm: i64 = rm.wrapping_shl(1) as i64; let mut denom: i64 = a .wrapping_mul(a) .wrapping_add(b.wrapping_mul(b)) .wrapping_sub((tm as u64).wrapping_mul(tm as u64)) as i64; // D = a^2+b^2 - tm^2 while denom > 2 * tm { // tm too small denom -= 2 * tm + 1; // (tm+1)^2 = tm^2 + 2*tm + 1 tm = tm.wrapping_add(1); } while denom < 0 { // tm too large denom += 2 * tm - 1; // (tm-1)^2 = tm^2 - 2*tm + 1 tm = tm.wrapping_sub(1); } // tm = floor(sqrt(a^2+b^2)) and 0 <= D = a^2+b^2 - tm^2 < 2*tm+1 // if D=0 and tm is even, the result is exact // if D=0 and tm is odd, the result is a midpoint let rb: i32 = (tm & 1) as i32; // round bit for rm let rb2: i32 = (denom >= tm) as i32; // round bit for tm let sb: i32 = (denom != 0) as i32; // sticky bit for rm rm = (tm >> 1) as u64; // truncate the low bit underflow = rm < 0x10000000000000u64; if rb != 0 || sb != 0 { let op = 1.0 + f64::from_bits(0x3c90000000000000); let om = 1.0 - f64::from_bits(0x3c90000000000000); if op == om { // rounding to nearest if sb != 0 { rm = rm.wrapping_add(rb as u64); // we have no underflow when rm is now 2^52 and rb2 != 0 // Remark: we cannot have a^2+b^2 = (tm+1/2)^2 exactly // since this would mean a^2+b^2 = tm^2+tm+1/4, // thus a^2+b^2 would be an odd multiple of 2^-1077 // (since ulp(tm) = 2^-1075) if rm >> 52 != 0 && rb2 != 0 { underflow = false; } } else { // sticky bit is 0, round bit is 1: underflow doos not change rm += rm & 1; // even rounding } } else if op > 1.0 { // rounding upwards rm = rm.wrapping_add(1); // we have no underflow when rm is now 2^52 and tm was odd if (rm >> 52) != 0 && (tm & 1) != 0 { underflow = false; } } if underflow { // trigger underflow exception _after_ rounding for inexact results let trig_uf = black_box(f64::from_bits(0x0010000000000000)); _ = black_box(black_box(trig_uf) * black_box(trig_uf)); // triggers underflow } } // else the result is exact, and we have no underflow f64::from_bits(rm) } /* Here the square root is refined by Newton iterations: x^2+y^2 is exact and fits in a 128-bit integer, so the approximation is squared (which also fits in a 128-bit integer), compared and adjusted if necessary using the exact value of x^2+y^2. */ #[cold] fn hypot_hard(x: f64, y: f64) -> f64 { let op = 1.0 + f64::from_bits(0x3c90000000000000); let om = 1.0 - f64::from_bits(0x3c90000000000000); let mut xi = x.to_bits(); let yi = y.to_bits(); let mut bm = (xi & 0x000fffffffffffff) | (1u64 << 52); let mut lm = (yi & 0x000fffffffffffff) | (1u64 << 52); let be: i32 = (xi >> 52) as i32; let le: i32 = (yi >> 52) as i32; let ri = f_fmla(x, x, y * y).sqrt().to_bits(); const BS: u32 = 2; let mut rm: u64 = ri & 0x000fffffffffffff; let mut re: i32 = ((ri >> 52) as i32).wrapping_sub(0x3ff); rm |= 1u64 << 52; for _ in 0..3 { if rm == (1u64 << 52) { rm = 0x001fffffffffffff; re = re.wrapping_sub(1); } else { rm = rm.wrapping_sub(1); } } bm = bm.wrapping_shl(BS); let mut m2: u64 = bm.wrapping_mul(bm); let de: i32 = be.wrapping_sub(le); let mut ls: i32 = (BS as i32).wrapping_sub(de); if ls >= 0 { lm <<= ls; m2 = m2.wrapping_add(lm.wrapping_mul(lm)); } else { let lm2: u128 = (lm as u128).wrapping_mul(lm as u128); ls = ls.wrapping_mul(2); m2 = m2.wrapping_add((lm2 >> -ls) as u64); // since ls < 0, the shift by -ls is legitimate m2 |= ((lm2.wrapping_shl((128 + ls) as u32)) != 0) as u64; } let k: i32 = (BS as i32).wrapping_add(re); let mut denom: i64; loop { rm += 1 + (rm >= (1u64 << 53)) as u64; let tm: u64 = rm.wrapping_shl(k as u32); let rm2: u64 = tm.wrapping_mul(tm); denom = (m2 as i64).wrapping_sub(rm2 as i64); if denom <= 0 { break; } } if denom != 0 { if op == om { let ssm = if rm <= (1u64 << 53) { 1 } else { 0 }; let tm: u64 = (rm << k) - (1 << (k - ssm)); denom = (m2 as i64).wrapping_sub(tm.wrapping_mul(tm) as i64); if denom != 0 { rm = rm.wrapping_add((denom >> 63) as u64); } else { rm = rm.wrapping_sub(rm & 1); } } else { let ssm = if rm > (1u64 << 53) { 1u32 } else { 0 }; let pdm = if op == 1. { 1u64 } else { 0 }; rm = rm.wrapping_sub(pdm.wrapping_shl(ssm)); } } if rm >= (1u64 << 53) { rm >>= 1; re = re.wrapping_add(1); } let e: i64 = be.wrapping_sub(1).wrapping_add(re) as i64; xi = (e as u64).wrapping_shl(52).wrapping_add(rm); f64::from_bits(xi) } /// Computes hypot /// /// Max ULP 0.5 pub fn f_hypot(x: f64, y: f64) -> f64 { let xi = x.to_bits(); let yi = y.to_bits(); let emsk = 0x7ffu64 << 52; let mut ex = xi & emsk; let mut ey = yi & emsk; let mut x = x.abs(); let mut y = y.abs(); if ex == emsk || ey == emsk { /* Either x or y is NaN or Inf */ let wx = xi.wrapping_shl(1); let wy = yi.wrapping_shl(1); let wm = emsk.wrapping_shl(1); let ninf: i32 = ((wx == wm) ^ (wy == wm)) as i32; let nqnn: i32 = (((wx >> 52) == 0xfff) ^ ((wy >> 52) == 0xfff)) as i32; /* ninf is 1 when only one of x and y is +/-Inf nqnn is 1 when only one of x and y is qNaN IEEE 754 says that hypot(+/-Inf,qNaN)=hypot(qNaN,+/-Inf)=+Inf. */ if ninf != 0 && nqnn != 0 { return if wx == wm { x * x } else { y * y }; } return x + y; /* inf, nan */ } let u = f64::max(x, y); let v = f64::min(x, y); let mut xd = u.to_bits(); let mut yd = v.to_bits(); ey = yd; if (ey >> 52) == 0 { // y is subnormal if (yd) == 0 { return f64::from_bits(xd); } ex = xd; if (ex >> 52) == 0 { // x is subnormal too if ex == 0 { return 0.; } return hypot_denorm(ex, ey); } let nz = ey.leading_zeros(); ey = ey.wrapping_shl(nz - 11); ey &= u64::MAX >> 12; ey = ey.wrapping_sub(((nz as u64).wrapping_sub(12u64)) << 52); let t = ey; yd = t; } let de = xd.wrapping_sub(yd); if de > (27u64 << 52) { return dyad_fmla(f64::from_bits(0x3e40000000000000), v, u); } let off: i64 = ((0x3ffu64 << 52) as i64).wrapping_sub((xd & emsk) as i64); xd = xd.wrapping_add(off as u64); yd = yd.wrapping_add(off as u64); x = f64::from_bits(xd); y = f64::from_bits(yd); let x2 = DoubleDouble::from_exact_mult(x, x); let y2 = DoubleDouble::from_exact_mult(y, y); let r2 = x2.hi + y2.hi; let ir2 = 0.5 / r2; let dr2 = ((x2.hi - r2) + y2.hi) + (x2.lo + y2.lo); let mut th = r2.sqrt(); let rsqrt = DoubleDouble::from_exact_mult(th, ir2); let dz = dr2 - rsqrt.lo; let mut tl = rsqrt.hi * dz; let p = DoubleDouble::from_exact_add(th, tl); th = p.hi; tl = p.lo; let mut thd = th.to_bits(); let tld = tl.abs().to_bits(); ex = thd; ey = tld; ex &= 0x7ffu64 << 52; let aidr = ey.wrapping_add(0x3feu64 << 52).wrapping_sub(ex); let mid = (aidr.wrapping_sub(0x3c90000000000000).wrapping_add(16)) >> 5; if mid == 0 || aidr < 0x39b0000000000000u64 || aidr > 0x3c9fffffffffff80u64 { thd = hypot_hard(x, y).to_bits(); } thd = thd.wrapping_sub(off as u64); if thd >= (0x7ffu64 << 52) { return hypot_overflow(); } f64::from_bits(thd) } #[cfg(test)] mod tests { use super::*; #[test] fn test_hypot() { assert_eq!( f_hypot(2.8480945070593211E-306, 2.1219950320804403E-314), 2.848094507059321e-306 ); assert_eq!( f_hypot(3.5601181736115222E-307, 1.0609978954826362E-314), 3.560118173611524e-307 ); assert_eq!(f_hypot(2., 4.), 4.47213595499958); } } pxfm-0.1.23/src/triangle/hypotf.rs000064400000000000000000000132531046102023000151400ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::EXP_MASK_F32; #[inline] pub fn f_hypot3f(x: f32, y: f32, z: f32) -> f32 { let x = x.abs(); let y = y.abs(); let z = z.abs(); let max = x.max(y).max(z); if max == 0.0 { return 0.0; } let recip_max = 1. / max; let norm_x = x * recip_max; let norm_y = y * recip_max; let norm_z = z * recip_max; max * (norm_x * norm_x + norm_y * norm_y + norm_z * norm_z).sqrt() // if x == f32::INFINITY || y == f32::INFINITY || z == f32::INFINITY { // f32::INFINITY // } else if x.is_nan() || y.is_nan() || z.is_nan() || ret.is_nan() { // f32::NAN // // } else { // ret // } } /// Hypot function /// /// Max ULP 0.5 #[inline] pub fn f_hypotf(x: f32, y: f32) -> f32 { let x_abs = x.abs(); let y_abs = y.abs(); let a_bits = x_abs.to_bits().max(y_abs.to_bits()); let b_bits = x_abs.to_bits().min(y_abs.to_bits()); let a_u = a_bits; let b_u = b_bits; if a_u >= EXP_MASK_F32 { // x or y is inf or nan if f32::from_bits(a_bits).is_nan() || f32::from_bits(b_bits).is_nan() { return f32::NAN; } if f32::from_bits(a_bits).is_infinite() || f32::from_bits(b_bits).is_infinite() { return f32::INFINITY; } return f32::from_bits(a_bits); } if a_u.wrapping_sub(b_u) >= ((23u32 + 2) << 23) { return x_abs + y_abs; } #[cfg(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") ))] { let ad = x as f64; let bd = y as f64; use crate::common::f_fmla; // for FMA environment we're using Kahan style summation which is short and reliable. let w = bd * bd; // RN(bc) let e = f_fmla(-bd, bd, w); // RN(w − bc) let f = f_fmla(ad, ad, w); // RN(ad + w) let r = e + f; // RN(f + e) let hyp = r.sqrt(); // sqrt(x^2 + y^2) hyp as f32 } #[cfg(not(any( all( any(target_arch = "x86", target_arch = "x86_64"), target_feature = "fma" ), all(target_arch = "aarch64", target_feature = "neon") )))] { let ad = f32::from_bits(a_bits) as f64; let bd = f32::from_bits(b_bits) as f64; use crate::double_double::DoubleDouble; let dy2 = DoubleDouble::from_exact_mult(bd, bd); let fdx = DoubleDouble::from_exact_mult(ad, ad); // elements are always sorted thus fdx.hi > dy2.hi, thus fasttwosum requirements is fulfilled let f = DoubleDouble::add_f64(fdx, dy2.hi).to_f64(); let r = dy2.lo + f; let cath = r.sqrt(); cath as f32 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_hypotf() { assert_eq!( f_hypotf( 0.000000000000000000000000000000000000000091771, 0.000000000000000000000000000000000000011754585 ), 0.000000000000000000000000000000000000011754944 ); assert_eq!( f_hypotf(9.177e-41, 1.1754585e-38), 0.000000000000000000000000000000000000011754944 ); let dx = (f_hypotf(1f32, 1f32) - (1f32 * 1f32 + 1f32 * 1f32).sqrt()).abs(); assert!(dx < 1e-5); let dx = (f_hypotf(5f32, 5f32) - (5f32 * 5f32 + 5f32 * 5f32).sqrt()).abs(); assert!(dx < 1e-5); } #[test] fn test_hypotf_edge_cases() { assert_eq!(f_hypotf(0.0, 0.0), 0.0); assert_eq!(f_hypotf(f32::INFINITY, 0.0), f32::INFINITY); assert_eq!(f_hypotf(0.0, f32::INFINITY), f32::INFINITY); assert_eq!(f_hypotf(f32::INFINITY, f32::INFINITY), f32::INFINITY); assert_eq!(f_hypotf(f32::NEG_INFINITY, 0.0), f32::INFINITY); assert_eq!(f_hypotf(0.0, f32::NEG_INFINITY), f32::INFINITY); assert_eq!( f_hypotf(f32::NEG_INFINITY, f32::NEG_INFINITY), f32::INFINITY ); assert!(f_hypotf(f32::NAN, 1.0).is_nan()); assert!(f_hypotf(1.0, f32::NAN).is_nan()); } } pxfm-0.1.23/src/triangle/mod.rs000064400000000000000000000034461046102023000144110ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 9/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ mod cathetus; mod cathetusf; mod hypot; mod hypotf; pub use cathetus::f_cathetus; pub use cathetusf::f_cathetusf; pub use hypot::f_hypot; pub use hypotf::{f_hypot3f, f_hypotf}; pxfm-0.1.23/src/triple_double.rs000064400000000000000000000334251046102023000146560ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::common::f_fmla; use crate::double_double::DoubleDouble; use std::ops::Neg; #[derive(Clone, Copy, Debug)] pub(crate) struct TripleDouble { pub(crate) hi: f64, pub(crate) mid: f64, pub(crate) lo: f64, } // impl TripleDouble { // #[inline] // pub(crate) fn mul_dd_add_f64(p0: TripleDouble, p1: DoubleDouble, p2: f64) -> TripleDouble { // let q0 = TripleDouble::quick_mul_dd(p0, p1); // TripleDouble::add_f64(p2, q0) // } // } impl TripleDouble { // #[inline] // pub(crate) fn mul_dd_add(p0: TripleDouble, p1: DoubleDouble, p2: TripleDouble) -> TripleDouble { // let q0 = TripleDouble::quick_mul_dd(p0, p1); // TripleDouble::add(q0, p2) // } // #[inline] // pub(crate) fn mul_dd_add_dd( // p0: TripleDouble, // p1: DoubleDouble, // p2: DoubleDouble, // ) -> TripleDouble { // let q0 = TripleDouble::quick_mul_dd(p0, p1); // TripleDouble::add_dd(p2, q0) // } } impl TripleDouble { #[inline] pub(crate) fn f64_mul_dd_add(p0: f64, p1: DoubleDouble, p2: TripleDouble) -> TripleDouble { let q0 = TripleDouble::from_quick_mult_dd_f64(p1, p0); TripleDouble::add(q0, p2) } #[inline] pub(crate) fn f64_mul_add(p0: f64, p1: TripleDouble, p2: TripleDouble) -> TripleDouble { let q0 = TripleDouble::quick_mult_f64(p1, p0); TripleDouble::add(q0, p2) } } impl TripleDouble { #[inline] pub(crate) const fn from_bit_pair(p0: (u64, u64, u64)) -> TripleDouble { TripleDouble { hi: f64::from_bits(p0.2), mid: f64::from_bits(p0.1), lo: f64::from_bits(p0.0), } } } #[inline] fn add12(a: f64, b: f64) -> DoubleDouble { DoubleDouble::from_full_exact_add(a, b) } #[inline] fn mul12(a: f64, b: f64) -> DoubleDouble { DoubleDouble::from_exact_mult(a, b) } #[inline] pub(crate) fn add22(a: DoubleDouble, b: DoubleDouble) -> DoubleDouble { let DoubleDouble { hi: v1, lo: v2 } = DoubleDouble::from_full_exact_add(a.hi, b.hi); let v3 = a.lo + b.lo; let v4 = v2 + v3; DoubleDouble::from_full_exact_add(v1, v4) } impl TripleDouble { // #[inline] // pub(crate) fn from_quick_mult_dd(a: DoubleDouble, b: DoubleDouble) -> TripleDouble { // /* // (rh , t1) ← Mul12 (ah , bh ) // (t2, t3) ← Mul12 (ah , bl ) // (t4, t5) ← Mul12 (al , bh ) // t6 ← al ⊗ bl // (t7, t8) ← Add22 (t2, t3, t4, t5) // (t9, t10) ← Add12 (t1, t6) // (rm , rl ) ← Add22 (t7, t8, t9, t10) // */ // let DoubleDouble { hi: rh, lo: t1 } = mul12(a.hi, b.hi); // let r0 = mul12(a.hi, b.lo); // let r1 = mul12(a.lo, b.hi); // let t6 = a.lo * b.lo; // let q0 = add22(r0, r1); // let q1 = add12(t1, t6); // let DoubleDouble { hi: rm, lo: rl } = add22(q0, q1); // TripleDouble { // hi: rh, // mid: rm, // lo: rl, // } // } #[inline] pub(crate) fn from_quick_mult_dd_f64(a: DoubleDouble, b: f64) -> TripleDouble { let DoubleDouble { hi: rh, lo: t1 } = mul12(a.hi, b); let DoubleDouble { hi: t2, lo: t3 } = mul12(a.lo, b); let DoubleDouble { hi: t5, lo: t4 } = add12(t1, t2); let t6 = t3 + t4; let DoubleDouble { hi: rm, lo: rl } = add12(t5, t6); TripleDouble::new(rl, rm, rh) } #[inline] pub(crate) fn quick_mult_f64(a: TripleDouble, b: f64) -> TripleDouble { let DoubleDouble { hi: rh, lo: t2 } = mul12(a.hi, b); let DoubleDouble { hi: t3, lo: t4 } = mul12(a.mid, b); let DoubleDouble { hi: t9, lo: t7 } = add12(t2, t3); let t8 = f_fmla(a.lo, b, t4); let t10 = t7 + t8; let DoubleDouble { hi: rm, lo: rl } = add12(t9, t10); TripleDouble::new(rl, rm, rh) } #[inline] pub(crate) fn quick_mult(b: TripleDouble, a: TripleDouble) -> TripleDouble { /* Mul12((resh),&_t1,(ah),(bh)); Mul12(&_t2,&_t3,(ah),(bm)); Mul12(&_t4,&_t5,(am),(bh)); Mul12(&_t6,&_t7,(am),(bm)); _t8 = (ah) * (bl); _t9 = (al) * (bh); _t10 = (am) * (bl); _t11 = (al) * (bm); _t12 = _t8 + _t9; _t13 = _t10 + _t11; Add12Cond(_t14,_t15,_t1,_t6); _t16 = _t7 + _t15; _t17 = _t12 + _t13; _t18 = _t16 + _t17; Add12Cond(_t19,_t20,_t14,_t18); Add22Cond(&_t21,&_t22,_t2,_t3,_t4,_t5); Add22Cond((resm),(resl),_t21,_t22,_t19,_t20); */ let DoubleDouble { hi: rh, lo: t1 } = DoubleDouble::from_exact_mult(a.hi, b.hi); let DoubleDouble { hi: t2, lo: t3 } = DoubleDouble::from_exact_mult(a.hi, b.mid); let DoubleDouble { hi: t4, lo: t5 } = DoubleDouble::from_exact_mult(a.mid, b.hi); let DoubleDouble { hi: t6, lo: t7 } = DoubleDouble::from_exact_mult(a.mid, b.mid); let t12 = f_fmla(a.hi, b.lo, a.lo * b.hi); let t13 = f_fmla(a.mid, b.lo, a.lo * b.mid); let DoubleDouble { hi: t14, lo: t15 } = add12(t1, t6); let t16 = t7 + t15; let t17 = t12 + t13; let t18 = t16 + t17; let DoubleDouble { hi: t19, lo: t20 } = add12(t14, t18); let DoubleDouble { hi: t21, lo: t22 } = add22(DoubleDouble::new(t3, t2), DoubleDouble::new(t4, t5)); let DoubleDouble { hi: rm, lo: rl } = add22(DoubleDouble::new(t22, t21), DoubleDouble::new(t20, t19)); TripleDouble::new(rl, rm, rh) } #[inline] pub(crate) fn quick_mult_dd(b: TripleDouble, a: DoubleDouble) -> TripleDouble { /* (rh , t1) ← Mul12 (ah , bh ) (t2, t3) ← Mul12 (ah , bm ) (t4, t5) ← Mul12 (ah , bl ) (t6, t7) ← Mul12 (al , bh ) (t8, t9) ← Mul12 (al , bm ) t10 ← al ⊗ bl (t11, t12) ← Add22 (t2, t3, t4, t5) (t13, t14) ← Add22 (t6, t7, t8, t9) (t15, t16) ← Add22 (t11, t12, t13, t14) (t17, t18) ← Add12 (t1, t10) (rm , rl ) ← Add22 (t17, t18, t15, t16) */ let DoubleDouble { hi: rh, lo: t1 } = mul12(a.hi, b.hi); let DoubleDouble { hi: t2, lo: t3 } = mul12(a.hi, b.mid); let DoubleDouble { hi: t4, lo: t5 } = mul12(a.hi, b.lo); let DoubleDouble { hi: t6, lo: t7 } = mul12(a.lo, b.hi); let DoubleDouble { hi: t8, lo: t9 } = mul12(a.lo, b.mid); let t10 = a.lo * b.lo; let z0 = add22(DoubleDouble::new(t3, t2), DoubleDouble::new(t4, t5)); let z1 = add22(DoubleDouble::new(t6, t7), DoubleDouble::new(t8, t9)); let q0 = add22(z0, z1); let q1 = add12(t1, t10); let DoubleDouble { hi: rm, lo: rl } = add22(q1, q0); TripleDouble { hi: rh, mid: rm, lo: rl, } } pub(crate) fn add(a: TripleDouble, b: TripleDouble) -> TripleDouble { /* (rh , t1) ← Add12 (ah , bh ) (t2, t3) ← Add12 (am , bm ) (t7, t4) ← Add12 (t1, t2) t6 ← al ⊕ bl t5 ← t3 ⊕ t4 t8 ← t5 ⊕ t6 (rm , rl ) ← Add12 (t7, t8) */ let DoubleDouble { hi: rh, lo: t1 } = add12(a.hi, b.hi); let DoubleDouble { hi: t2, lo: t3 } = add12(a.mid, b.mid); let t6 = a.lo + b.lo; let DoubleDouble { hi: t7, lo: t4 } = add12(t1, t2); let t5 = t3 + t4; let t8 = t5 + t6; let DoubleDouble { hi: rm, lo: rl } = add12(t7, t8); TripleDouble { hi: rh, mid: rm, lo: rl, } } // #[inline] // pub(crate) fn add_dd(a: DoubleDouble, b: TripleDouble) -> TripleDouble { // /* // (rh , t1) ← Add12 (ah , bh ) // (t2, t3) ← Add12 (al , bm ) // (t4, t5) ← Add12 (t1, t2) // t6 ← t3 ⊕ bl // t7 ← t6 ⊕ t5 // (rm , rl ) ← Add12 (t4, t7) // */ // let DoubleDouble { hi: rh, lo: t1 } = add12(a.hi, b.hi); // let DoubleDouble { hi: t2, lo: t3 } = add12(a.hi, b.mid); // let DoubleDouble { hi: t4, lo: t5 } = add12(t1, t2); // let t6 = t3 + b.lo; // let t7 = t6 + t5; // let DoubleDouble { hi: rm, lo: rl } = add12(t4, t7); // TripleDouble { // hi: rh, // mid: rm, // lo: rl, // } // } #[inline] pub(crate) fn add_f64(a: f64, b: TripleDouble) -> TripleDouble { let DoubleDouble { hi: rh, lo: t1 } = add12(a, b.hi); let DoubleDouble { hi: t2, lo: t3 } = add12(t1, b.mid); let t4 = t3 + b.lo; let DoubleDouble { hi: rm, lo: rl } = add12(t2, t4); TripleDouble::new(rl, rm, rh) } // #[inline] // pub(crate) fn to_dd(self) -> DoubleDouble { // let DoubleDouble { hi: t1, lo: t2 } = add12(self.hi, self.mid); // let t3 = t2 + self.lo; // DoubleDouble::new(t3, t1) // } #[inline] pub(crate) const fn new(lo: f64, mid: f64, hi: f64) -> Self { Self { hi, mid, lo } } #[inline] pub(crate) fn to_f64(self) -> f64 { let DoubleDouble { hi: t1, lo: t2 } = add12(self.hi, self.mid); let t3 = t2 + self.lo; t1 + t3 } #[inline] pub(crate) fn from_full_exact_add(a: f64, b: f64) -> Self { let DoubleDouble { hi: rh, lo: t1 } = add12(a, b); TripleDouble::new(0., t1, rh).renormalize() } #[inline] pub(crate) fn renormalize(self) -> Self { /* double _t1h, _t1l, _t2l; Add12(_t1h, _t1l, (am), (al)); Add12((*(resh)), _t2l, (ah), (_t1h)); Add12((*(resm)), (*(resl)), _t2l, _t1l); */ let DoubleDouble { hi: t1h, lo: t1l } = DoubleDouble::from_exact_add(self.mid, self.lo); let DoubleDouble { hi: rh, lo: t2l } = DoubleDouble::from_exact_add(self.hi, t1h); let zml = DoubleDouble::from_exact_add(t2l, t1l); TripleDouble::new(zml.lo, zml.hi, rh) } #[inline] pub(crate) fn recip(self) -> Self { /* _rec_r1 = 1.0 / (dh); Mul12(&_rec_t1,&_rec_t2,_rec_r1,(dh)); _rec_t3 = _rec_t1 - 1.0; Add12Cond(_rec_t4,_rec_t5,_rec_t3,_rec_t2); Mul12(&_rec_t6,&_rec_t7,_rec_r1,(dm)); Add12(_rec_t8,_rec_t9,-1.0,_rec_t6); _rec_t10 = _rec_t9 + _rec_t7; Add12(_rec_t11,_rec_t12,_rec_t8,_rec_t10); _rec_r1 = -_rec_r1; Add22Cond(&_rec_t13,&_rec_t14,_rec_t4,_rec_t5,_rec_t11,_rec_t12); Mul122(&_rec_r2h,&_rec_r2l,_rec_r1,_rec_t13,_rec_t14); Mul233(&_rec_t15,&_rec_t16,&_rec_t17,_rec_r2h,_rec_r2l,(dh),(dm),(dl)); Renormalize3(&_rec_t18,&_rec_t19,&_rec_t20,_rec_t15,_rec_t16,_rec_t17); _rec_t18 = -1.0; Mul233(&_rec_t21,&_rec_t22,&_rec_t23,_rec_r2h,_rec_r2l,_rec_t18,_rec_t19,_rec_t20); _rec_t21 = -_rec_t21; _rec_t22 = -_rec_t22; _rec_t23 = -_rec_t23; Renormalize3((resh),(resm),(resl),_rec_t21,_rec_t22,_rec_t23); */ let mut r1 = 1. / self.hi; let DoubleDouble { hi: rec_t1, lo: rec_t2, } = DoubleDouble::from_exact_mult(r1, self.hi); let rec_t3 = rec_t1 - 1.0; let DoubleDouble { hi: rec_t4, lo: rec_t5, } = add12(rec_t3, rec_t2); let DoubleDouble { hi: rec_t6, lo: rec_t7, } = mul12(r1, self.mid); let DoubleDouble { hi: rec_t8, lo: rec_t9, } = add12(-1.0, rec_t6); let rec_t10 = rec_t9 + rec_t7; r1 = -r1; let DoubleDouble { hi: rec_t11, lo: rec_t12, } = add12(rec_t8, rec_t10); let z0 = add22( DoubleDouble::new(rec_t5, rec_t4), DoubleDouble::new(rec_t12, rec_t11), ); let r2hl = DoubleDouble::quick_mult_f64(z0, r1); let rec15_16_17 = TripleDouble::quick_mult_dd(self, r2hl); let rec18_19_20 = rec15_16_17.renormalize(); let rec_t18 = -1.0; let rec_21_22_23 = -TripleDouble::quick_mult_dd( TripleDouble::new(rec18_19_20.lo, rec18_19_20.mid, rec_t18), r2hl, ); rec_21_22_23.renormalize() } } impl Neg for TripleDouble { type Output = Self; #[inline] fn neg(self) -> Self::Output { TripleDouble::new(-self.lo, -self.mid, -self.hi) } } pxfm-0.1.23/src/trunc.rs000064400000000000000000000104271046102023000131550ustar 00000000000000/* * // Copyright (c) Radzivon Bartoshyk 6/2025. 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. * // * // 3. Neither the name of the copyright holder nor the names of its * // contributors may be used to endorse or promote products derived from * // this software without specific prior written permission. * // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 crate::bits::{get_exponent_f32, get_exponent_f64}; #[inline] pub const fn truncf(x: f32) -> f32 { // If x is infinity or NaN, return it. // If it is zero also we should return it as is, but the logic // later in this function takes care of it. But not doing a zero // check, we improve the run time of non-zero values. if x.is_infinite() || x.is_nan() { return x; } const FRACTION_LENGTH: u32 = 23; let exponent = get_exponent_f32(x); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. if exponent >= FRACTION_LENGTH as i32 { return x; } // If the exponent is such that abs(x) is less than 1, then return 0. if exponent <= -1 { return if x.is_sign_negative() { -0.0 } else { 0.0 }; } const FRACTION_MASK: u32 = (1 << FRACTION_LENGTH) - 1; let trim_size = FRACTION_LENGTH as i32 - exponent; let trunc_mantissa = ((x.to_bits() & FRACTION_MASK) >> trim_size).wrapping_shl(trim_size as u32); let prepared_bits = x.to_bits() & 0xFF800000; f32::from_bits(prepared_bits | trunc_mantissa) } #[inline] pub const fn trunc(x: f64) -> f64 { // If x is infinity or NaN, return it. // If it is zero also we should return it as is, but the logic // later in this function takes care of it. But not doing a zero // check, we improve the run time of non-zero values. if x.is_infinite() || x.is_nan() { return x; } const FRACTION_LENGTH: u32 = 52; let exponent = get_exponent_f64(x); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. if exponent >= FRACTION_LENGTH as i64 { return x; } // If the exponent is such that abs(x) is less than 1, then return 0. if exponent <= -1 { return if x.is_sign_negative() { -0.0 } else { 0.0 }; } const FRACTION_MASK: u64 = (1 << FRACTION_LENGTH) - 1; let trim_size = FRACTION_LENGTH as i64 - exponent; let trunc_mantissa = ((x.to_bits() & FRACTION_MASK) >> trim_size).wrapping_shl(trim_size as u32); let prepared_bits = x.to_bits() & 0xFFF0000000000000; f64::from_bits(prepared_bits | trunc_mantissa) } #[cfg(test)] mod tests { use super::*; #[test] fn test_truncf() { assert_eq!(truncf(-1.0), -1.0); assert_eq!(truncf(1.0), 1.0); assert_eq!(truncf(1.234211), 1.0); assert_eq!(truncf(-1.234211), -1.0); } #[test] fn test_trunc() { assert_eq!(trunc(-1.0), -1.0); assert_eq!(trunc(1.0), 1.0); assert_eq!(trunc(1.234211), 1.0); assert_eq!(trunc(-1.234211), -1.0); } } pxfm-0.1.23/src/u256.rs000064400000000000000000000234751046102023000125320ustar 00000000000000// /* // * // Copyright (c) Radzivon Bartoshyk 7/2025. 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. // * // // * // 3. Neither the name of the copyright holder nor the names of its // * // contributors may be used to endorse or promote products derived from // * // this software without specific prior written permission. // * // // * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 core::ops; // use std::cmp::Ordering; // use std::ops::{Add, BitAnd, BitOrAssign}; // // 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)] // pub(crate) struct u256 { // pub lo: u128, // pub hi: u128, // } // // impl PartialEq for u256 { // #[inline] // fn eq(&self, other: &Self) -> bool { // self.hi == other.hi && self.lo == other.lo // } // } // // impl Eq for u256 {} // // impl PartialOrd for u256 { // #[inline] // fn partial_cmp(&self, other: &Self) -> Option { // Some(self.cmp(other)) // } // } // // impl Ord for u256 { // #[inline] // fn cmp(&self, other: &Self) -> Ordering { // match self.hi.cmp(&other.hi) { // Ordering::Equal => self.lo.cmp(&other.lo), // ord => ord, // } // } // } // // pub(crate) fn mulhi_u256(a: u256, b: u256) -> u256 { // // // Products // let lo_lo = a.lo.expanding_mul(b.lo); // a.lo * b.lo // let lo_hi = a.lo.expanding_mul(b.hi); // a.lo * b.hi // let hi_lo = a.hi.expanding_mul(b.lo); // a.hi * b.lo // let hi_hi = a.hi.expanding_mul(b.hi); // a.hi * b.hi // // let carry = u256::from_u128(lo_lo.hi) // .add(u256::from_u128(lo_hi.lo)) // .add(u256::from_u128(hi_lo.lo)); // let mid = u256::from_u128(lo_hi.hi) // .add(u256::from_u128(hi_lo.hi)) // .add(u256::from_u128(carry.hi)); // hi_hi.add(mid) // } // // impl u256 { // #[inline] // pub(crate) fn view_as_slice(self) -> [u8; 32] { // // [(self.hi >> 64) as u64, (self.hi & 0xffff_ffff_ffff_ffff) as u64, (self.lo >> 64) as u64, (self.lo & 0xffff_ffff_ffff_ffff) as u64] // let mut out = [0u8; 32]; // out[16..32].copy_from_slice(&self.hi.to_le_bytes()); // out[0..16].copy_from_slice(&self.lo.to_le_bytes()); // out // } // // pub(crate) const MAX: Self = Self { // lo: u128::MAX, // hi: u128::MAX, // }; // // pub(crate) const ZERO: Self = Self { lo: 0, hi: 0 }; // // pub(crate) const ONE: Self = Self { lo: 0, hi: 1 }; // // #[inline] // pub(crate) const fn from_u128(value: u128) -> Self { // Self { lo: value, hi: 0 } // } // // #[inline] // pub(crate) const fn from_u64(value: u64) -> Self { // Self { // lo: value as u128, // hi: 0, // } // } // // #[inline] // pub(crate) const fn from_u32(value: u32) -> Self { // Self { // lo: value as u128, // hi: 0, // } // } // // #[inline] // pub(crate) const fn leading_zeros(self) -> u32 { // let mut leading = self.hi.leading_zeros(); // if leading > 64 { // leading += self.lo.leading_zeros(); // } // leading // } // // #[inline] // pub(crate) fn lo_u64(self) -> u64 { // (self.lo & 0xffff_ffff_ffff_ffff) as u64 // } // // #[inline] // pub(crate) fn to_u64(self) -> u64 { // self.lo as u64 // } // // #[inline] // pub(crate) fn to_u32(self) -> u32 { // self.lo as u32 // } // } // // 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 u256 { // #[inline] // pub(crate) const fn wrapping_shl(self, shift: u32) -> Self { // match shift { // 0 => self, // s if s < 128 => { // let hi = (self.hi << s) | (self.lo >> (128 - s)); // let lo = self.lo << s; // u256 { lo, hi } // } // s if s < 256 => { // let lo = 0; // let hi = self.lo << (s - 128); // u256 { lo, hi } // } // _ => u256 { lo: 0, hi: 0 }, // } // } // // #[inline] // pub(crate) fn wrapping_sub(self, rhs: Self) -> Self { // let (lo, carry) = self.lo.overflowing_sub(rhs.lo); // let hi = self.hi.wrapping_sub(carry as u128).wrapping_sub(rhs.hi); // // Self { lo, hi } // } // // #[inline] // pub(crate) fn overflowing_add(self, rhs: Self) -> (Self, bool) { // let (lo, carry_lo) = self.lo.overflowing_add(rhs.lo); // let (hi_intermediate, carry_hi1) = self.hi.overflowing_add(rhs.hi); // let (hi, carry_hi2) = hi_intermediate.overflowing_add(carry_lo as u128); // // let overflow = carry_hi1 || carry_hi2; // (Self { lo, hi }, overflow) // } // } // // impl_common!(u256); // // impl ops::Add for u256 { // type Output = Self; // // #[inline] // 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 BitOrAssign for u256 { // #[inline] // fn bitor_assign(&mut self, rhs: Self) { // self.lo |= rhs.lo; // self.hi |= rhs.hi; // } // } // // impl ops::Shr for u256 { // type Output = Self; // // #[inline] // fn shr(mut self, rhs: u32) -> Self::Output { // debug_assert!(rhs < 256, "attempted to shift right with overflow"); // if rhs >= 256 { // return Self { lo: 0, hi: 0 }; // } // // 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 BitAnd for u256 { // type Output = Self; // // #[inline] // fn bitand(self, rhs: Self) -> Self::Output { // Self { // hi: self.hi & rhs.hi, // lo: self.lo & rhs.lo, // } // } // } // // trait WideningMul { // type Output; // fn expanding_mul(self, rhs: Self) -> Self::Output; // } // // impl WideningMul for u128 { // type Output = u256; // // #[inline] // fn expanding_mul(self, rhs: Self) -> u256 { // 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.wrapping_mul(l1); // let p_lh: u128 = l0.wrapping_mul(h1); // let p_hl: u128 = h0.wrapping_mul(l1); // let p_hh: u128 = h0.wrapping_mul(h1); // // 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 } // } // } // // #[cfg(test)] // mod tests { // use super::*; // #[test] // fn test_overflowing_add() { // let z0 = u256::MAX; // let z1 = u256::MAX; // let (k, overflowed) = z0.overflowing_add(z1); // assert!(overflowed); // assert_eq!(k.lo, u128::MAX - 1); // } // // #[test] // fn test_mulhi() { // let z0 = u256::MAX; // let z1 = u256::MAX; // let product = mulhi_u256(z0, z1); // assert_eq!(product.lo, u128::MAX - 1); // assert_eq!(product.hi, u128::MAX); // } // }