diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/ryu | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/ryu')
26 files changed, 3769 insertions, 0 deletions
diff --git a/third_party/rust/ryu/.cargo-checksum.json b/third_party/rust/ryu/.cargo-checksum.json new file mode 100644 index 0000000000..6f6f63322c --- /dev/null +++ b/third_party/rust/ryu/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"b5f6a8d622e52ec6b8818eba97aaaf94bcb60a9d79aaffb3542acada6474e587","Cargo.toml":"ae5e72bf5e666e219d92d8dfff0e13499e74001f1f25080b5933943fc578baae","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-BOOST":"c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566","README.md":"66e8c5353ae528e44f178e783586720b152d023b632b0d9f1fed6d7d1453bad8","benches/bench.rs":"dabe26b848af09fbc2df83dce367edcc9f78dd77a130d588db6cba6622f02ee8","build.rs":"cc3565b28217b481459cf47b6191fb0cbddbbf510a72260be75ff54d7f050d3d","examples/upstream_benchmark.rs":"19db581f4653e1c8e23a933e845a24b1ded192a9850126cfa9c82a81cd6b3349","src/buffer/mod.rs":"aeef965f409fd659e94e8611fc3fa4cf9ebfd404090f91f7da881e4bb5053d29","src/common.rs":"860895e4b787c722467bf6f118669e346399051de4df4a40f8ecf2c5a49c16ce","src/d2s.rs":"69d7318592b5bb0ca923332ee54e1acc64e5c0bcd6f8ca6b22b0f4b08c653b11","src/d2s_full_table.rs":"7f7e475c54ae69d834574603bde9dcbe9f0d7cb09cfc3cda025319c903996bf8","src/d2s_intrinsics.rs":"3c5e1323e85500b628aaa74d3e9699d772c88348b14f4591dde32711c73c3714","src/d2s_small_table.rs":"3c035701e940cf7d03b1e22a0bf353ed87b68c7afd35ca15721c453cdb5fa0a1","src/digit_table.rs":"02351ca54cb8cb3679f635115dd094f32fd91750e9f66103c1ee9ec3db507072","src/f2s.rs":"5d04c8c8268049d401536495e9abcd0ea7101a23d93e4d67da6ccb4efc62e65c","src/lib.rs":"bdbe4f17e20550fc896850378fb0c2bf0a485dd32aec72ba5d0716a004a35f9b","src/pretty/exponent.rs":"15fd163fdb81573d331f24fda37f5403931512ffb08715a2695f0a0256b69b84","src/pretty/mantissa.rs":"7b0ea97069ee597f3bc0c8f2f3354c75be93d01c6a8135104ae82cd83df318e0","src/pretty/mod.rs":"005f381ab27392fe7273da551da38aacfce6998fd4fc101ae283ea88c3f4d9b8","tests/d2s_table_test.rs":"7012a7a47327fe1d9b46364d6e444a0ab863fd8c2e345ca48b98ca4a46372a40","tests/d2s_test.rs":"04e62fc5b0c723b5deddc8cf082d735427e1c74792493d04549affca67a5edfc","tests/exhaustive.rs":"8f265d8e3d7ff9cbaf1b433eb0040136eec829b87a03dae8dfc67d062b755b4b","tests/f2s_test.rs":"4b4ba8dad4ff85c643deaf99f05914094bf89e7abf55672b1583a52ae1aae53f","tests/macros/mod.rs":"8e90a674b3960f9516cb38f4eea0e0981ff902c3b33572ebdb6c5528d3ffa72c"},"package":"bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"}
\ No newline at end of file diff --git a/third_party/rust/ryu/Cargo.lock b/third_party/rust/ryu/Cargo.lock new file mode 100644 index 0000000000..5615dada19 --- /dev/null +++ b/third_party/rust/ryu/Cargo.lock @@ -0,0 +1,144 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bitflags" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "no-panic" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ryu" +version = "1.0.2" +dependencies = [ + "no-panic 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum no-panic 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "98df96f963035dd2f8184e531675e9e3f84675144dca726882eed105f8317964" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/rust/ryu/Cargo.toml b/third_party/rust/ryu/Cargo.toml new file mode 100644 index 0000000000..08e16d5701 --- /dev/null +++ b/third_party/rust/ryu/Cargo.toml @@ -0,0 +1,35 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "ryu" +version = "1.0.2" +authors = ["David Tolnay <dtolnay@gmail.com>"] +build = "build.rs" +description = "Fast floating point to string conversion" +documentation = "https://docs.rs/ryu" +readme = "README.md" +license = "Apache-2.0 OR BSL-1.0" +repository = "https://github.com/dtolnay/ryu" +[dependencies.no-panic] +version = "0.1" +optional = true +[dev-dependencies.num_cpus] +version = "1.8" + +[dev-dependencies.rand] +version = "0.5" + +[features] +small = [] +[badges.travis-ci] +repository = "dtolnay/ryu" diff --git a/third_party/rust/ryu/LICENSE-APACHE b/third_party/rust/ryu/LICENSE-APACHE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/third_party/rust/ryu/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/third_party/rust/ryu/LICENSE-BOOST b/third_party/rust/ryu/LICENSE-BOOST new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/third_party/rust/ryu/LICENSE-BOOST @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/ryu/README.md b/third_party/rust/ryu/README.md new file mode 100644 index 0000000000..cc34dc2383 --- /dev/null +++ b/third_party/rust/ryu/README.md @@ -0,0 +1,114 @@ +# Ryū + +[![Build Status](https://api.travis-ci.org/dtolnay/ryu.svg?branch=master)](https://travis-ci.org/dtolnay/ryu) +[![Latest Version](https://img.shields.io/crates/v/ryu.svg)](https://crates.io/crates/ryu) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/ryu) +[![Rustc Version 1.15+](https://img.shields.io/badge/rustc-1.15+-lightgray.svg)](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html) + +Pure Rust implementation of Ryū, an algorithm to quickly convert floating point +numbers to decimal strings. + +The PLDI'18 paper [*Ryū: fast float-to-string conversion*][paper] by Ulf Adams +includes a complete correctness proof of the algorithm. The paper is available +under the creative commons CC-BY-SA license. + +This Rust implementation is a line-by-line port of Ulf Adams' implementation in +C, [https://github.com/ulfjack/ryu][upstream]. + +*Requirements: this crate supports any compiler version back to rustc 1.15; it +uses nothing from the Rust standard library so is usable from no_std crates.* + +[paper]: https://dl.acm.org/citation.cfm?id=3192369 +[upstream]: https://github.com/ulfjack/ryu/tree/688f43b62276b400728baad54afc32c3ab9c1a95 + +```toml +[dependencies] +ryu = "1.0" +``` + +## Example + +```rust +fn main() { + let mut buffer = ryu::Buffer::new(); + let printed = buffer.format(1.234); + assert_eq!(printed, "1.234"); +} +``` + +## Performance + +You can run upstream's benchmarks with: + +```console +$ git clone https://github.com/ulfjack/ryu c-ryu +$ cd c-ryu +$ bazel run -c opt //ryu/benchmark +``` + +And the same benchmark against our implementation with: + +```console +$ git clone https://github.com/dtolnay/ryu rust-ryu +$ cd rust-ryu +$ cargo run --example upstream_benchmark --release +``` + +These benchmarks measure the average time to print a 32-bit float and average +time to print a 64-bit float, where the inputs are distributed as uniform random +bit patterns 32 and 64 bits wide. + +The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API +all perform the same, taking around 21 nanoseconds to format a 32-bit float and +31 nanoseconds to format a 64-bit float. + +There is also a Rust-specific benchmark comparing this implementation to the +standard library which you can run with: + +```console +$ cargo bench +``` + +The benchmark shows Ryu approximately 4-10x faster than the standard library +across a range of f32 and f64 inputs. Measurements are in nanoseconds per +iteration; smaller is better. + +| type=f32 | 0.0 | 0.1234 | 2.718281828459045 | f32::MAX | +|:--------:|:----:|:------:|:-----------------:|:--------:| +| RYU | 3ns | 28ns | 23ns | 22ns | +| STD | 40ns | 106ns | 128ns | 110ns | + +| type=f64 | 0.0 | 0.1234 | 2.718281828459045 | f64::MAX | +|:--------:|:----:|:------:|:-----------------:|:--------:| +| RYU | 3ns | 50ns | 35ns | 32ns | +| STD | 39ns | 105ns | 128ns | 202ns | + +## Formatting + +This library tends to produce more human-readable output than the standard +library's to\_string, which never uses scientific notation. Here are two +examples: + +- *ryu:* 1.23e40, *std:* 12300000000000000000000000000000000000000 +- *ryu:* 1.23e-40, *std:* 0.000000000000000000000000000000000000000123 + +Both libraries print short decimals such as 0.0000123 without scientific +notation. + +<br> + +#### License + +<sup> +Licensed under either of <a href="LICENSE-APACHE">Apache License, Version +2.0</a> or <a href="LICENSE-BOOST">Boost Software License 1.0</a> at your +option. +</sup> + +<br> + +<sub> +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. +</sub> diff --git a/third_party/rust/ryu/benches/bench.rs b/third_party/rust/ryu/benches/bench.rs new file mode 100644 index 0000000000..04d9bee818 --- /dev/null +++ b/third_party/rust/ryu/benches/bench.rs @@ -0,0 +1,58 @@ +// cargo bench + +#![feature(test)] + +extern crate ryu; +extern crate test; + +macro_rules! benches { + ($($name:ident($value:expr),)*) => { + mod bench_ryu { + use test::{Bencher, black_box}; + $( + #[bench] + fn $name(b: &mut Bencher) { + use ryu; + + let mut buf = ryu::Buffer::new(); + + b.iter(move || { + let value = black_box($value); + let formatted = buf.format_finite(value); + black_box(formatted); + }); + } + )* + } + + mod bench_std_fmt { + use test::{Bencher, black_box}; + $( + #[bench] + fn $name(b: &mut Bencher) { + use std::io::Write; + + let mut buf = Vec::with_capacity(20); + + b.iter(|| { + buf.clear(); + let value = black_box($value); + write!(&mut buf, "{}", value).unwrap(); + black_box(buf.as_slice()); + }); + } + )* + } + } +} + +benches!( + bench_0_f64(0f64), + bench_short_f64(0.1234f64), + bench_e_f64(2.718281828459045f64), + bench_max_f64(::std::f64::MAX), + bench_0_f32(0f32), + bench_short_f32(0.1234f32), + bench_e_f32(2.718281828459045f32), + bench_max_f32(::std::f32::MAX), +); diff --git a/third_party/rust/ryu/build.rs b/third_party/rust/ryu/build.rs new file mode 100644 index 0000000000..7b639e72f5 --- /dev/null +++ b/third_party/rust/ryu/build.rs @@ -0,0 +1,66 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // 128-bit integers stabilized in Rust 1.26: + // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html + // + // Disabled on Emscripten targets as Emscripten doesn't + // currently support integers larger than 64 bits. + if minor >= 26 && !emscripten { + println!("cargo:rustc-cfg=integer128"); + } + + // #[must_use] on functions stabilized in Rust 1.27: + // https://blog.rust-lang.org/2018/06/21/Rust-1.27.html + if minor >= 27 { + println!("cargo:rustc-cfg=must_use_return"); + } + + // MaybeUninit<T> stabilized in Rust 1.36: + // https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html + if minor >= 36 { + println!("cargo:rustc-cfg=maybe_uninit"); + } +} + +fn rustc_minor_version() -> Option<u32> { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + u32::from_str(next).ok() +} diff --git a/third_party/rust/ryu/examples/upstream_benchmark.rs b/third_party/rust/ryu/examples/upstream_benchmark.rs new file mode 100644 index 0000000000..c9ef3aea8d --- /dev/null +++ b/third_party/rust/ryu/examples/upstream_benchmark.rs @@ -0,0 +1,88 @@ +// cargo run --example upstream_benchmark --release + +extern crate rand; +extern crate ryu; + +use rand::{Rng, SeedableRng}; + +const SAMPLES: usize = 10000; +const ITERATIONS: usize = 1000; + +struct MeanAndVariance { + n: i64, + mean: f64, + m2: f64, +} + +impl MeanAndVariance { + fn new() -> Self { + MeanAndVariance { + n: 0, + mean: 0.0, + m2: 0.0, + } + } + + fn update(&mut self, x: f64) { + self.n += 1; + let d = x - self.mean; + self.mean += d / self.n as f64; + let d2 = x - self.mean; + self.m2 += d * d2; + } + + fn variance(&self) -> f64 { + self.m2 / (self.n - 1) as f64 + } + + fn stddev(&self) -> f64 { + self.variance().sqrt() + } +} + +macro_rules! benchmark { + ($name:ident, $ty:ident) => { + fn $name() -> usize { + let mut rng = rand::prng::XorShiftRng::from_seed([123u8; 16]); + let mut mv = MeanAndVariance::new(); + let mut throwaway = 0; + for _ in 0..SAMPLES { + let f = loop { + let f = $ty::from_bits(rng.gen()); + if f.is_finite() { + break f; + } + }; + + let t1 = std::time::SystemTime::now(); + for _ in 0..ITERATIONS { + throwaway += ryu::Buffer::new().format_finite(f).len(); + } + let duration = t1.elapsed().unwrap(); + let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; + mv.update(nanos as f64 / ITERATIONS as f64); + } + println!( + "{:12} {:8.3} {:8.3}", + concat!(stringify!($name), ":"), + mv.mean, + mv.stddev(), + ); + throwaway + } + }; +} + +benchmark!(pretty32, f32); +benchmark!(pretty64, f64); + +fn main() { + println!("{:>20}{:>9}", "Average", "Stddev"); + let mut throwaway = 0; + throwaway += pretty32(); + throwaway += pretty64(); + if std::env::var_os("ryu-benchmark").is_some() { + // Prevent the compiler from optimizing the code away. + println!("{}", throwaway); + } +} diff --git a/third_party/rust/ryu/src/buffer/mod.rs b/third_party/rust/ryu/src/buffer/mod.rs new file mode 100644 index 0000000000..881858ce71 --- /dev/null +++ b/third_party/rust/ryu/src/buffer/mod.rs @@ -0,0 +1,199 @@ +use core::{mem, slice, str}; + +#[cfg(maybe_uninit)] +use core::mem::MaybeUninit; + +use raw; + +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +const NAN: &'static str = "NaN"; +const INFINITY: &'static str = "inf"; +const NEG_INFINITY: &'static str = "-inf"; + +/// Safe API for formatting floating point numbers to text. +/// +/// ## Example +/// +/// ```edition2018 +/// let mut buffer = ryu::Buffer::new(); +/// let printed = buffer.format_finite(1.234); +/// assert_eq!(printed, "1.234"); +/// ``` +#[derive(Copy, Clone)] +pub struct Buffer { + #[cfg(maybe_uninit)] + bytes: [MaybeUninit<u8>; 24], + #[cfg(not(maybe_uninit))] + bytes: [u8; 24], +} + +impl Buffer { + /// This is a cheap operation; you don't need to worry about reusing buffers + /// for efficiency. + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn new() -> Self { + // assume_init is safe here, since this is an array of MaybeUninit, which does not need + // to be initialized. + #[cfg(maybe_uninit)] + let bytes = unsafe { MaybeUninit::uninit().assume_init() }; + #[cfg(not(maybe_uninit))] + let bytes = unsafe { mem::uninitialized() }; + + Buffer { bytes: bytes } + } + + /// Print a floating point number into this buffer and return a reference to + /// its string representation within the buffer. + /// + /// # Special cases + /// + /// This function formats NaN as the string "NaN", positive infinity as + /// "inf", and negative infinity as "-inf" to match std::fmt. + /// + /// If your input is known to be finite, you may get better performance by + /// calling the `format_finite` method instead of `format` to avoid the + /// checks for special cases. + #[cfg_attr(feature = "no-panic", inline)] + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn format<F: Float>(&mut self, f: F) -> &str { + if f.is_nonfinite() { + f.format_nonfinite() + } else { + self.format_finite(f) + } + } + + /// Print a floating point number into this buffer and return a reference to + /// its string representation within the buffer. + /// + /// # Special cases + /// + /// This function **does not** check for NaN or infinity. If the input + /// number is not a finite float, the printed representation will be some + /// correctly formatted but unspecified numerical value. + /// + /// Please check [`is_finite`] yourself before calling this function, or + /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. + /// + /// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite + /// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan + /// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn format_finite<F: Float>(&mut self, f: F) -> &str { + unsafe { + let n = f.write_to_ryu_buffer(self.first_byte_pointer_mut()); + debug_assert!(n <= self.bytes.len()); + let slice = slice::from_raw_parts(self.first_byte_pointer(), n); + str::from_utf8_unchecked(slice) + } + } + + #[inline] + #[cfg(maybe_uninit)] + fn first_byte_pointer(&self) -> *const u8 { + self.bytes[0].as_ptr() + } + + #[inline] + #[cfg(not(maybe_uninit))] + fn first_byte_pointer(&self) -> *const u8 { + &self.bytes[0] as *const u8 + } + + #[inline] + #[cfg(maybe_uninit)] + fn first_byte_pointer_mut(&mut self) -> *mut u8 { + self.bytes[0].as_mut_ptr() + } + + #[inline] + #[cfg(not(maybe_uninit))] + fn first_byte_pointer_mut(&mut self) -> *mut u8 { + &mut self.bytes[0] as *mut u8 + } +} + +impl Default for Buffer { + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + fn default() -> Self { + Buffer::new() + } +} + +/// A floating point number, f32 or f64, that can be written into a +/// [`ryu::Buffer`][Buffer]. +/// +/// This trait is sealed and cannot be implemented for types outside of the +/// `ryu` crate. +pub trait Float: Sealed {} +impl Float for f32 {} +impl Float for f64 {} + +pub trait Sealed: Copy { + fn is_nonfinite(self) -> bool; + fn format_nonfinite(self) -> &'static str; + unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize; +} + +impl Sealed for f32 { + #[inline] + fn is_nonfinite(self) -> bool { + const EXP_MASK: u32 = 0x7f800000; + let bits = unsafe { mem::transmute::<f32, u32>(self) }; + bits & EXP_MASK == EXP_MASK + } + + #[cold] + #[cfg_attr(feature = "no-panic", inline)] + fn format_nonfinite(self) -> &'static str { + const MANTISSA_MASK: u32 = 0x007fffff; + const SIGN_MASK: u32 = 0x80000000; + let bits = unsafe { mem::transmute::<f32, u32>(self) }; + if bits & MANTISSA_MASK != 0 { + NAN + } else if bits & SIGN_MASK != 0 { + NEG_INFINITY + } else { + INFINITY + } + } + + #[inline] + unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { + raw::format32(self, result) + } +} + +impl Sealed for f64 { + #[inline] + fn is_nonfinite(self) -> bool { + const EXP_MASK: u64 = 0x7ff0000000000000; + let bits = unsafe { mem::transmute::<f64, u64>(self) }; + bits & EXP_MASK == EXP_MASK + } + + #[cold] + #[cfg_attr(feature = "no-panic", inline)] + fn format_nonfinite(self) -> &'static str { + const MANTISSA_MASK: u64 = 0x000fffffffffffff; + const SIGN_MASK: u64 = 0x8000000000000000; + let bits = unsafe { mem::transmute::<f64, u64>(self) }; + if bits & MANTISSA_MASK != 0 { + NAN + } else if bits & SIGN_MASK != 0 { + NEG_INFINITY + } else { + INFINITY + } + } + + #[inline] + unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { + raw::format64(self, result) + } +} diff --git a/third_party/rust/ryu/src/common.rs b/third_party/rust/ryu/src/common.rs new file mode 100644 index 0000000000..29e5cc591b --- /dev/null +++ b/third_party/rust/ryu/src/common.rs @@ -0,0 +1,75 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +#[cfg_attr(feature = "no-panic", inline)] +pub fn decimal_length9(v: u32) -> u32 { + // Function precondition: v is not a 10-digit number. + // (f2s: 9 digits are sufficient for round-tripping.) + debug_assert!(v < 1000000000); + + if v >= 100000000 { + 9 + } else if v >= 10000000 { + 8 + } else if v >= 1000000 { + 7 + } else if v >= 100000 { + 6 + } else if v >= 10000 { + 5 + } else if v >= 1000 { + 4 + } else if v >= 100 { + 3 + } else if v >= 10 { + 2 + } else { + 1 + } +} + +// Returns e == 0 ? 1 : ceil(log_2(5^e)). +#[cfg_attr(feature = "no-panic", inline)] +pub fn pow5bits(e: i32) -> i32 { + // This approximation works up to the point that the multiplication overflows at e = 3529. + // If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater + // than 2^9297. + debug_assert!(e >= 0); + debug_assert!(e <= 3528); + (((e as u32 * 1217359) >> 19) + 1) as i32 +} + +// Returns floor(log_10(2^e)). +#[cfg_attr(feature = "no-panic", inline)] +pub fn log10_pow2(e: i32) -> u32 { + // The first value this approximation fails for is 2^1651 which is just greater than 10^297. + debug_assert!(e >= 0); + debug_assert!(e <= 1650); + (e as u32 * 78913) >> 18 +} + +// Returns floor(log_10(5^e)). +#[cfg_attr(feature = "no-panic", inline)] +pub fn log10_pow5(e: i32) -> u32 { + // The first value this approximation fails for is 5^2621 which is just greater than 10^1832. + debug_assert!(e >= 0); + debug_assert!(e <= 2620); + (e as u32 * 732923) >> 20 +} diff --git a/third_party/rust/ryu/src/d2s.rs b/third_party/rust/ryu/src/d2s.rs new file mode 100644 index 0000000000..cebef968e6 --- /dev/null +++ b/third_party/rust/ryu/src/d2s.rs @@ -0,0 +1,412 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use core::ptr; + +#[cfg(maybe_uninit)] +use core::mem::MaybeUninit; + +#[cfg(not(maybe_uninit))] +use core::mem; + +use common::*; +#[cfg(not(feature = "small"))] +use d2s_full_table::*; +use d2s_intrinsics::*; +#[cfg(feature = "small")] +use d2s_small_table::*; + +pub const DOUBLE_MANTISSA_BITS: u32 = 52; +pub const DOUBLE_EXPONENT_BITS: u32 = 11; + +const DOUBLE_BIAS: i32 = 1023; +const DOUBLE_POW5_INV_BITCOUNT: i32 = 122; +const DOUBLE_POW5_BITCOUNT: i32 = 121; + +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +fn mul_shift(m: u64, mul: &(u64, u64), j: u32) -> u64 { + let b0 = m as u128 * mul.0 as u128; + let b2 = m as u128 * mul.1 as u128; + (((b0 >> 64) + b2) >> (j - 64)) as u64 +} + +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +unsafe fn mul_shift_all( + m: u64, + mul: &(u64, u64), + j: u32, + vp: *mut u64, + vm: *mut u64, + mm_shift: u32, +) -> u64 { + ptr::write(vp, mul_shift(4 * m + 2, mul, j)); + ptr::write(vm, mul_shift(4 * m - 1 - mm_shift as u64, mul, j)); + mul_shift(4 * m, mul, j) +} + +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +unsafe fn mul_shift_all( + mut m: u64, + mul: &(u64, u64), + j: u32, + vp: *mut u64, + vm: *mut u64, + mm_shift: u32, +) -> u64 { + m <<= 1; + // m is maximum 55 bits + let (lo, tmp) = umul128(m, mul.0); + let (mut mid, mut hi) = umul128(m, mul.1); + mid = mid.wrapping_add(tmp); + hi = hi.wrapping_add((mid < tmp) as u64); // overflow into hi + + let lo2 = lo.wrapping_add(mul.0); + let mid2 = mid.wrapping_add(mul.1).wrapping_add((lo2 < lo) as u64); + let hi2 = hi.wrapping_add((mid2 < mid) as u64); + ptr::write(vp, shiftright128(mid2, hi2, j - 64 - 1)); + + if mm_shift == 1 { + let lo3 = lo.wrapping_sub(mul.0); + let mid3 = mid.wrapping_sub(mul.1).wrapping_sub((lo3 > lo) as u64); + let hi3 = hi.wrapping_sub((mid3 > mid) as u64); + ptr::write(vm, shiftright128(mid3, hi3, j - 64 - 1)); + } else { + let lo3 = lo + lo; + let mid3 = mid.wrapping_add(mid).wrapping_add((lo3 < lo) as u64); + let hi3 = hi.wrapping_add(hi).wrapping_add((mid3 < mid) as u64); + let lo4 = lo3.wrapping_sub(mul.0); + let mid4 = mid3.wrapping_sub(mul.1).wrapping_sub((lo4 > lo3) as u64); + let hi4 = hi3.wrapping_sub((mid4 > mid3) as u64); + ptr::write(vm, shiftright128(mid4, hi4, j - 64)); + } + + shiftright128(mid, hi, j - 64 - 1) +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn decimal_length17(v: u64) -> u32 { + // This is slightly faster than a loop. + // The average output length is 16.38 digits, so we check high-to-low. + // Function precondition: v is not an 18, 19, or 20-digit number. + // (17 digits are sufficient for round-tripping.) + debug_assert!(v < 100000000000000000); + + if v >= 10000000000000000 { + 17 + } else if v >= 1000000000000000 { + 16 + } else if v >= 100000000000000 { + 15 + } else if v >= 10000000000000 { + 14 + } else if v >= 1000000000000 { + 13 + } else if v >= 100000000000 { + 12 + } else if v >= 10000000000 { + 11 + } else if v >= 1000000000 { + 10 + } else if v >= 100000000 { + 9 + } else if v >= 10000000 { + 8 + } else if v >= 1000000 { + 7 + } else if v >= 100000 { + 6 + } else if v >= 10000 { + 5 + } else if v >= 1000 { + 4 + } else if v >= 100 { + 3 + } else if v >= 10 { + 2 + } else { + 1 + } +} + +// A floating decimal representing m * 10^e. +pub struct FloatingDecimal64 { + pub mantissa: u64, + // Decimal exponent's range is -324 to 308 + // inclusive, and can fit in i16 if needed. + pub exponent: i32, +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { + let (e2, m2) = if ieee_exponent == 0 { + ( + // We subtract 2 so that the bounds computation has 2 additional bits. + 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2, + ieee_mantissa, + ) + } else { + ( + ieee_exponent as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2, + (1u64 << DOUBLE_MANTISSA_BITS) | ieee_mantissa, + ) + }; + let even = (m2 & 1) == 0; + let accept_bounds = even; + + // Step 2: Determine the interval of valid decimal representations. + let mv = 4 * m2; + // Implicit bool -> int conversion. True is 1, false is 0. + let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32; + // We would compute mp and mm like this: + // uint64_t mp = 4 * m2 + 2; + // uint64_t mm = mv - 1 - mm_shift; + + // Step 3: Convert to a decimal power base using 128-bit arithmetic. + let mut vr: u64; + let mut vp: u64; + let mut vm: u64; + #[cfg(not(maybe_uninit))] + { + vp = unsafe { mem::uninitialized() }; + vm = unsafe { mem::uninitialized() }; + } + #[cfg(maybe_uninit)] + let mut vp_uninit: MaybeUninit<u64> = MaybeUninit::uninit(); + #[cfg(maybe_uninit)] + let mut vm_uninit: MaybeUninit<u64> = MaybeUninit::uninit(); + let e10: i32; + let mut vm_is_trailing_zeros = false; + let mut vr_is_trailing_zeros = false; + if e2 >= 0 { + // I tried special-casing q == 0, but there was no effect on performance. + // This expression is slightly faster than max(0, log10_pow2(e2) - 1). + let q = log10_pow2(e2) - (e2 > 3) as u32; + e10 = q as i32; + let k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1; + let i = -e2 + q as i32 + k; + vr = unsafe { + mul_shift_all( + m2, + #[cfg(feature = "small")] + &compute_inv_pow5(q), + #[cfg(not(feature = "small"))] + { + debug_assert!(q < DOUBLE_POW5_INV_SPLIT.len() as u32); + DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize) + }, + i as u32, + #[cfg(maybe_uninit)] + { + vp_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vp + }, + #[cfg(maybe_uninit)] + { + vm_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vm + }, + mm_shift, + ) + }; + #[cfg(maybe_uninit)] + { + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; + } + if q <= 21 { + // This should use q <= 22, but I think 21 is also safe. Smaller values + // may still be safe, but it's more difficult to reason about them. + // Only one of mp, mv, and mm can be a multiple of 5, if any. + let mv_mod5 = (mv as u32).wrapping_sub(5u32.wrapping_mul(div5(mv) as u32)); + if mv_mod5 == 0 { + vr_is_trailing_zeros = multiple_of_power_of_5(mv, q); + } else if accept_bounds { + // Same as min(e2 + (~mm & 1), pow5_factor(mm)) >= q + // <=> e2 + (~mm & 1) >= q && pow5_factor(mm) >= q + // <=> true && pow5_factor(mm) >= q, since e2 >= q. + vm_is_trailing_zeros = multiple_of_power_of_5(mv - 1 - mm_shift as u64, q); + } else { + // Same as min(e2 + 1, pow5_factor(mp)) >= q. + vp -= multiple_of_power_of_5(mv + 2, q) as u64; + } + } + } else { + // This expression is slightly faster than max(0, log10_pow5(-e2) - 1). + let q = log10_pow5(-e2) - (-e2 > 1) as u32; + e10 = q as i32 + e2; + let i = -e2 - q as i32; + let k = pow5bits(i) - DOUBLE_POW5_BITCOUNT; + let j = q as i32 - k; + vr = unsafe { + mul_shift_all( + m2, + #[cfg(feature = "small")] + &compute_pow5(i as u32), + #[cfg(not(feature = "small"))] + { + debug_assert!(i < DOUBLE_POW5_SPLIT.len() as i32); + DOUBLE_POW5_SPLIT.get_unchecked(i as usize) + }, + j as u32, + #[cfg(maybe_uninit)] + { + vp_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vp + }, + #[cfg(maybe_uninit)] + { + vm_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vm + }, + mm_shift, + ) + }; + #[cfg(maybe_uninit)] + { + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; + } + if q <= 1 { + // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. + // mv = 4 * m2, so it always has at least two trailing 0 bits. + vr_is_trailing_zeros = true; + if accept_bounds { + // mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1. + vm_is_trailing_zeros = mm_shift == 1; + } else { + // mp = mv + 2, so it always has at least one trailing 0 bit. + vp -= 1; + } + } else if q < 63 { + // TODO(ulfjack): Use a tighter bound here. + // We want to know if the full product has at least q trailing zeros. + // We need to compute min(p2(mv), p5(mv) - e2) >= q + // <=> p2(mv) >= q && p5(mv) - e2 >= q + // <=> p2(mv) >= q (because -e2 >= q) + vr_is_trailing_zeros = multiple_of_power_of_2(mv, q); + } + } + + // Step 4: Find the shortest decimal representation in the interval of valid representations. + let mut removed = 0i32; + let mut last_removed_digit = 0u8; + // On average, we remove ~2 digits. + let output = if vm_is_trailing_zeros || vr_is_trailing_zeros { + // General case, which happens rarely (~0.7%). + loop { + let vp_div10 = div10(vp); + let vm_div10 = div10(vm); + if vp_div10 <= vm_div10 { + break; + } + let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32)); + let vr_div10 = div10(vr); + let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32)); + vm_is_trailing_zeros &= vm_mod10 == 0; + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = vr_mod10 as u8; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; + removed += 1; + } + if vm_is_trailing_zeros { + loop { + let vm_div10 = div10(vm); + let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32)); + if vm_mod10 != 0 { + break; + } + let vp_div10 = div10(vp); + let vr_div10 = div10(vr); + let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32)); + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = vr_mod10 as u8; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; + removed += 1; + } + } + if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 { + // Round even if the exact number is .....50..0. + last_removed_digit = 4; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) + as u64 + } else { + // Specialized for the common case (~99.3%). Percentages below are relative to this. + let mut round_up = false; + let vp_div100 = div100(vp); + let vm_div100 = div100(vm); + // Optimization: remove two digits at a time (~86.2%). + if vp_div100 > vm_div100 { + let vr_div100 = div100(vr); + let vr_mod100 = (vr as u32).wrapping_sub(100u32.wrapping_mul(vr_div100 as u32)); + round_up = vr_mod100 >= 50; + vr = vr_div100; + vp = vp_div100; + vm = vm_div100; + removed += 2; + } + // Loop iterations below (approximately), without optimization above: + // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02% + // Loop iterations below (approximately), with optimization above: + // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02% + loop { + let vp_div10 = div10(vp); + let vm_div10 = div10(vm); + if vp_div10 <= vm_div10 { + break; + } + let vr_div10 = div10(vr); + let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32)); + round_up = vr_mod10 >= 5; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; + removed += 1; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + (vr == vm || round_up) as u64 + }; + let exp = e10 + removed; + + FloatingDecimal64 { + exponent: exp, + mantissa: output, + } +} diff --git a/third_party/rust/ryu/src/d2s_full_table.rs b/third_party/rust/ryu/src/d2s_full_table.rs new file mode 100644 index 0000000000..eac50dcfc8 --- /dev/null +++ b/third_party/rust/ryu/src/d2s_full_table.rs @@ -0,0 +1,643 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +pub static DOUBLE_POW5_INV_SPLIT: [(u64, u64); 292] = [ + (1, 288230376151711744), + (3689348814741910324, 230584300921369395), + (2951479051793528259, 184467440737095516), + (17118578500402463900, 147573952589676412), + (12632330341676300947, 236118324143482260), + (10105864273341040758, 188894659314785808), + (15463389048156653253, 151115727451828646), + (17362724847566824558, 241785163922925834), + (17579528692795369969, 193428131138340667), + (6684925324752475329, 154742504910672534), + (18074578149087781173, 247588007857076054), + (18149011334012135262, 198070406285660843), + (3451162622983977240, 158456325028528675), + (5521860196774363583, 253530120045645880), + (4417488157419490867, 202824096036516704), + (7223339340677503017, 162259276829213363), + (7867994130342094503, 259614842926741381), + (2605046489531765280, 207691874341393105), + (2084037191625412224, 166153499473114484), + (10713157136084480204, 265845599156983174), + (12259874523609494487, 212676479325586539), + (13497248433629505913, 170141183460469231), + (14216899864323388813, 272225893536750770), + (11373519891458711051, 217780714829400616), + (5409467098425058518, 174224571863520493), + (4965798542738183305, 278759314981632789), + (7661987648932456967, 223007451985306231), + (2440241304404055250, 178405961588244985), + (3904386087046488400, 285449538541191976), + (17880904128604832013, 228359630832953580), + (14304723302883865611, 182687704666362864), + (15133127457049002812, 146150163733090291), + (16834306301794583852, 233840261972944466), + (9778096226693756759, 187072209578355573), + (15201174610838826053, 149657767662684458), + (2185786488890659746, 239452428260295134), + (5437978005854438120, 191561942608236107), + (15418428848909281466, 153249554086588885), + (6222742084545298729, 245199286538542217), + (16046240111861969953, 196159429230833773), + (1768945645263844993, 156927543384667019), + (10209010661905972635, 251084069415467230), + (8167208529524778108, 200867255532373784), + (10223115638361732810, 160693804425899027), + (1599589762411131202, 257110087081438444), + (4969020624670815285, 205688069665150755), + (3975216499736652228, 164550455732120604), + (13739044029062464211, 263280729171392966), + (7301886408508061046, 210624583337114373), + (13220206756290269483, 168499666669691498), + (17462981995322520850, 269599466671506397), + (6591687966774196033, 215679573337205118), + (12652048002903177473, 172543658669764094), + (9175230360419352987, 276069853871622551), + (3650835473593572067, 220855883097298041), + (17678063637842498946, 176684706477838432), + (13527506561580357021, 282695530364541492), + (3443307619780464970, 226156424291633194), + (6443994910566282300, 180925139433306555), + (5155195928453025840, 144740111546645244), + (15627011115008661990, 231584178474632390), + (12501608892006929592, 185267342779705912), + (2622589484121723027, 148213874223764730), + (4196143174594756843, 237142198758023568), + (10735612169159626121, 189713759006418854), + (12277838550069611220, 151771007205135083), + (15955192865369467629, 242833611528216133), + (1696107848069843133, 194266889222572907), + (12424932722681605476, 155413511378058325), + (1433148282581017146, 248661618204893321), + (15903913885032455010, 198929294563914656), + (9033782293284053685, 159143435651131725), + (14454051669254485895, 254629497041810760), + (11563241335403588716, 203703597633448608), + (16629290697806691620, 162962878106758886), + (781423413297334329, 260740604970814219), + (4314487545379777786, 208592483976651375), + (3451590036303822229, 166873987181321100), + (5522544058086115566, 266998379490113760), + (4418035246468892453, 213598703592091008), + (10913125826658934609, 170878962873672806), + (10082303693170474728, 273406340597876490), + (8065842954536379782, 218725072478301192), + (17520720807854834795, 174980057982640953), + (5897060404116273733, 279968092772225526), + (1028299508551108663, 223974474217780421), + (15580034865808528224, 179179579374224336), + (17549358155809824511, 286687326998758938), + (2971440080422128639, 229349861599007151), + (17134547323305344204, 183479889279205720), + (13707637858644275364, 146783911423364576), + (14553522944347019935, 234854258277383322), + (4264120725993795302, 187883406621906658), + (10789994210278856888, 150306725297525326), + (9885293106962350374, 240490760476040522), + (529536856086059653, 192392608380832418), + (7802327114352668369, 153914086704665934), + (1415676938738538420, 246262538727465495), + (1132541550990830736, 197010030981972396), + (15663428499760305882, 157608024785577916), + (17682787970132668764, 252172839656924666), + (10456881561364224688, 201738271725539733), + (15744202878575200397, 161390617380431786), + (17812026976236499989, 258224987808690858), + (3181575136763469022, 206579990246952687), + (13613306553636506187, 165263992197562149), + (10713244041592678929, 264422387516099439), + (12259944048016053467, 211537910012879551), + (6118606423670932450, 169230328010303641), + (2411072648389671274, 270768524816485826), + (16686253377679378312, 216614819853188660), + (13349002702143502650, 173291855882550928), + (17669055508687693916, 277266969412081485), + (14135244406950155133, 221813575529665188), + (240149081334393137, 177450860423732151), + (11452284974360759988, 283921376677971441), + (5472479164746697667, 227137101342377153), + (11756680961281178780, 181709681073901722), + (2026647139541122378, 145367744859121378), + (18000030682233437097, 232588391774594204), + (18089373360528660001, 186070713419675363), + (3403452244197197031, 148856570735740291), + (16513570034941246220, 238170513177184465), + (13210856027952996976, 190536410541747572), + (3189987192878576934, 152429128433398058), + (1414630693863812771, 243886605493436893), + (8510402184574870864, 195109284394749514), + (10497670562401807014, 156087427515799611), + (9417575270359070576, 249739884025279378), + (14912757845771077107, 199791907220223502), + (4551508647133041040, 159833525776178802), + (10971762650154775986, 255733641241886083), + (16156107749607641435, 204586912993508866), + (9235537384944202825, 163669530394807093), + (11087511001168814197, 261871248631691349), + (12559357615676961681, 209496998905353079), + (13736834907283479668, 167597599124282463), + (18289587036911657145, 268156158598851941), + (10942320814787415393, 214524926879081553), + (16132554281313752961, 171619941503265242), + (11054691591134363444, 274591906405224388), + (16222450902391311402, 219673525124179510), + (12977960721913049122, 175738820099343608), + (17075388340318968271, 281182112158949773), + (2592264228029443648, 224945689727159819), + (5763160197165465241, 179956551781727855), + (9221056315464744386, 287930482850764568), + (14755542681855616155, 230344386280611654), + (15493782960226403247, 184275509024489323), + (1326979923955391628, 147420407219591459), + (9501865507812447252, 235872651551346334), + (11290841220991868125, 188698121241077067), + (1653975347309673853, 150958496992861654), + (10025058185179298811, 241533595188578646), + (4330697733401528726, 193226876150862917), + (14532604630946953951, 154581500920690333), + (1116074521063664381, 247330401473104534), + (4582208431592841828, 197864321178483627), + (14733813189500004432, 158291456942786901), + (16195403473716186445, 253266331108459042), + (5577625149489128510, 202613064886767234), + (8151448934333213131, 162090451909413787), + (16731667109675051333, 259344723055062059), + (17074682502481951390, 207475778444049647), + (6281048372501740465, 165980622755239718), + (6360328581260874421, 265568996408383549), + (8777611679750609860, 212455197126706839), + (10711438158542398211, 169964157701365471), + (9759603424184016492, 271942652322184754), + (11497031554089123517, 217554121857747803), + (16576322872755119460, 174043297486198242), + (11764721337440549842, 278469275977917188), + (16790474699436260520, 222775420782333750), + (13432379759549008416, 178220336625867000), + (3045063541568861850, 285152538601387201), + (17193446092222730773, 228122030881109760), + (13754756873778184618, 182497624704887808), + (18382503128506368341, 145998099763910246), + (3586563302416817083, 233596959622256395), + (2869250641933453667, 186877567697805116), + (17052795772514404226, 149502054158244092), + (12527077977055405469, 239203286653190548), + (17400360011128145022, 191362629322552438), + (2852241564676785048, 153090103458041951), + (15631632947708587046, 244944165532867121), + (8815957543424959314, 195955332426293697), + (18120812478965698421, 156764265941034957), + (14235904707377476180, 250822825505655932), + (4010026136418160298, 200658260404524746), + (17965416168102169531, 160526608323619796), + (2919224165770098987, 256842573317791675), + (2335379332616079190, 205474058654233340), + (1868303466092863352, 164379246923386672), + (6678634360490491686, 263006795077418675), + (5342907488392393349, 210405436061934940), + (4274325990713914679, 168324348849547952), + (10528270399884173809, 269318958159276723), + (15801313949391159694, 215455166527421378), + (1573004715287196786, 172364133221937103), + (17274202803427156150, 275782613155099364), + (17508711057483635243, 220626090524079491), + (10317620031244997871, 176500872419263593), + (12818843235250086271, 282401395870821749), + (13944423402941979340, 225921116696657399), + (14844887537095493795, 180736893357325919), + (15565258844418305359, 144589514685860735), + (6457670077359736959, 231343223497377177), + (16234182506113520537, 185074578797901741), + (9297997190148906106, 148059663038321393), + (11187446689496339446, 236895460861314229), + (12639306166338981880, 189516368689051383), + (17490142562555006151, 151613094951241106), + (2158786396894637579, 242580951921985771), + (16484424376483351356, 194064761537588616), + (9498190686444770762, 155251809230070893), + (11507756283569722895, 248402894768113429), + (12895553841597688639, 198722315814490743), + (17695140702761971558, 158977852651592594), + (17244178680193423523, 254364564242548151), + (10105994129412828495, 203491651394038521), + (4395446488788352473, 162793321115230817), + (10722063196803274280, 260469313784369307), + (1198952927958798777, 208375451027495446), + (15716557601334680315, 166700360821996356), + (17767794532651667857, 266720577315194170), + (14214235626121334286, 213376461852155336), + (7682039686155157106, 170701169481724269), + (1223217053622520399, 273121871170758831), + (15735968901865657612, 218497496936607064), + (16278123936234436413, 174797997549285651), + (219556594781725998, 279676796078857043), + (7554342905309201445, 223741436863085634), + (9732823138989271479, 178993149490468507), + (815121763415193074, 286389039184749612), + (11720143854957885429, 229111231347799689), + (13065463898708218666, 183288985078239751), + (6763022304224664610, 146631188062591801), + (3442138057275642729, 234609900900146882), + (13821756890046245153, 187687920720117505), + (11057405512036996122, 150150336576094004), + (6623802375033462826, 240240538521750407), + (16367088344252501231, 192192430817400325), + (13093670675402000985, 153753944653920260), + (2503129006933649959, 246006311446272417), + (13070549649772650937, 196805049157017933), + (17835137349301941396, 157444039325614346), + (2710778055689733971, 251910462920982955), + (2168622444551787177, 201528370336786364), + (5424246770383340065, 161222696269429091), + (1300097203129523457, 257956314031086546), + (15797473021471260058, 206365051224869236), + (8948629602435097724, 165092040979895389), + (3249760919670425388, 264147265567832623), + (9978506365220160957, 211317812454266098), + (15361502721659949412, 169054249963412878), + (2442311466204457120, 270486799941460606), + (16711244431931206989, 216389439953168484), + (17058344360286875914, 173111551962534787), + (12535955717491360170, 276978483140055660), + (10028764573993088136, 221582786512044528), + (15401709288678291155, 177266229209635622), + (9885339602917624555, 283625966735416996), + (4218922867592189321, 226900773388333597), + (14443184738299482427, 181520618710666877), + (4175850161155765295, 145216494968533502), + (10370709072591134795, 232346391949653603), + (15675264887556728482, 185877113559722882), + (5161514280561562140, 148701690847778306), + (879725219414678777, 237922705356445290), + (703780175531743021, 190338164285156232), + (11631070584651125387, 152270531428124985), + (162968861732249003, 243632850284999977), + (11198421533611530172, 194906280227999981), + (5269388412147313814, 155925024182399985), + (8431021459435702103, 249480038691839976), + (3055468352806651359, 199584030953471981), + (17201769941212962380, 159667224762777584), + (16454785461715008838, 255467559620444135), + (13163828369372007071, 204374047696355308), + (17909760324981426303, 163499238157084246), + (2830174816776909822, 261598781051334795), + (2264139853421527858, 209279024841067836), + (16568707141704863579, 167423219872854268), + (4373838538276319787, 267877151796566830), + (3499070830621055830, 214301721437253464), + (6488605479238754987, 171441377149802771), + (3003071137298187333, 274306203439684434), + (6091805724580460189, 219444962751747547), + (15941491023890099121, 175555970201398037), + (10748990379256517301, 280889552322236860), + (8599192303405213841, 224711641857789488), + (14258051472207991719, 179769313486231590), +]; + +pub static DOUBLE_POW5_SPLIT: [(u64, u64); 326] = [ + (0, 72057594037927936), + (0, 90071992547409920), + (0, 112589990684262400), + (0, 140737488355328000), + (0, 87960930222080000), + (0, 109951162777600000), + (0, 137438953472000000), + (0, 85899345920000000), + (0, 107374182400000000), + (0, 134217728000000000), + (0, 83886080000000000), + (0, 104857600000000000), + (0, 131072000000000000), + (0, 81920000000000000), + (0, 102400000000000000), + (0, 128000000000000000), + (0, 80000000000000000), + (0, 100000000000000000), + (0, 125000000000000000), + (0, 78125000000000000), + (0, 97656250000000000), + (0, 122070312500000000), + (0, 76293945312500000), + (0, 95367431640625000), + (0, 119209289550781250), + (4611686018427387904, 74505805969238281), + (10376293541461622784, 93132257461547851), + (8358680908399640576, 116415321826934814), + (612489549322387456, 72759576141834259), + (14600669991935148032, 90949470177292823), + (13639151471491547136, 113686837721616029), + (3213881284082270208, 142108547152020037), + (4314518811765112832, 88817841970012523), + (781462496279003136, 111022302462515654), + (10200200157203529728, 138777878078144567), + (13292654125893287936, 86736173798840354), + (7392445620511834112, 108420217248550443), + (4628871007212404736, 135525271560688054), + (16728102434789916672, 84703294725430033), + (7075069988205232128, 105879118406787542), + (18067209522111315968, 132348898008484427), + (8986162942105878528, 82718061255302767), + (6621017659204960256, 103397576569128459), + (3664586055578812416, 129246970711410574), + (16125424340018921472, 80779356694631608), + (1710036351314100224, 100974195868289511), + (15972603494424788992, 126217744835361888), + (9982877184015493120, 78886090522101180), + (12478596480019366400, 98607613152626475), + (10986559581596820096, 123259516440783094), + (2254913720070624656, 77037197775489434), + (12042014186943056628, 96296497219361792), + (15052517733678820785, 120370621524202240), + (9407823583549262990, 75231638452626400), + (11759779479436578738, 94039548065783000), + (14699724349295723422, 117549435082228750), + (4575641699882439235, 73468396926392969), + (10331238143280436948, 91835496157991211), + (8302361660673158281, 114794370197489014), + (1154580038986672043, 143492962746861268), + (9944984561221445835, 89683101716788292), + (12431230701526807293, 112103877145985365), + (1703980321626345405, 140129846432481707), + (17205888765512323542, 87581154020301066), + (12283988920035628619, 109476442525376333), + (1519928094762372062, 136845553156720417), + (12479170105294952299, 85528470722950260), + (15598962631618690374, 106910588403687825), + (5663645234241199255, 133638235504609782), + (17374836326682913246, 83523897190381113), + (7883487353071477846, 104404871487976392), + (9854359191339347308, 130506089359970490), + (10770660513014479971, 81566305849981556), + (13463325641268099964, 101957882312476945), + (2994098996302961243, 127447352890596182), + (15706369927971514489, 79654595556622613), + (5797904354682229399, 99568244445778267), + (2635694424925398845, 124460305557222834), + (6258995034005762182, 77787690973264271), + (3212057774079814824, 97234613716580339), + (17850130272881932242, 121543267145725423), + (18073860448192289507, 75964541966078389), + (8757267504958198172, 94955677457597987), + (6334898362770359811, 118694596821997484), + (13182683513586250689, 74184123013748427), + (11866668373555425458, 92730153767185534), + (5609963430089506015, 115912692208981918), + (17341285199088104971, 72445432630613698), + (12453234462005355406, 90556790788267123), + (10954857059079306353, 113195988485333904), + (13693571323849132942, 141494985606667380), + (17781854114260483896, 88434366004167112), + (3780573569116053255, 110542957505208891), + (114030942967678664, 138178696881511114), + (4682955357782187069, 86361685550944446), + (15077066234082509644, 107952106938680557), + (5011274737320973344, 134940133673350697), + (14661261756894078100, 84337583545844185), + (4491519140835433913, 105421979432305232), + (5614398926044292391, 131777474290381540), + (12732371365632458552, 82360921431488462), + (6692092170185797382, 102951151789360578), + (17588487249587022536, 128688939736700722), + (15604490549419276989, 80430587335437951), + (14893927168346708332, 100538234169297439), + (14005722942005997511, 125672792711621799), + (15671105866394830300, 78545495444763624), + (1142138259283986260, 98181869305954531), + (15262730879387146537, 122727336632443163), + (7233363790403272633, 76704585395276977), + (13653390756431478696, 95880731744096221), + (3231680390257184658, 119850914680120277), + (4325643253124434363, 74906821675075173), + (10018740084832930858, 93633527093843966), + (3300053069186387764, 117041908867304958), + (15897591223523656064, 73151193042065598), + (10648616992549794273, 91438991302581998), + (4087399203832467033, 114298739128227498), + (14332621041645359599, 142873423910284372), + (18181260187883125557, 89295889943927732), + (4279831161144355331, 111619862429909666), + (14573160988285219972, 139524828037387082), + (13719911636105650386, 87203017523366926), + (7926517508277287175, 109003771904208658), + (684774848491833161, 136254714880260823), + (7345513307948477581, 85159196800163014), + (18405263671790372785, 106448996000203767), + (18394893571310578077, 133061245000254709), + (13802651491282805250, 83163278125159193), + (3418256308821342851, 103954097656448992), + (4272820386026678563, 129942622070561240), + (2670512741266674102, 81214138794100775), + (17173198981865506339, 101517673492625968), + (3019754653622331308, 126897091865782461), + (4193189667727651020, 79310682416114038), + (14464859121514339583, 99138353020142547), + (13469387883465536574, 123922941275178184), + (8418367427165960359, 77451838296986365), + (15134645302384838353, 96814797871232956), + (471562554271496325, 121018497339041196), + (9518098633274461011, 75636560836900747), + (7285937273165688360, 94545701046125934), + (18330793628311886258, 118182126307657417), + (4539216990053847055, 73863828942285886), + (14897393274422084627, 92329786177857357), + (4786683537745442072, 115412232722321697), + (14520892257159371055, 72132645451451060), + (18151115321449213818, 90165806814313825), + (8853836096529353561, 112707258517892282), + (1843923083806916143, 140884073147365353), + (12681666973447792349, 88052545717103345), + (2017025661527576725, 110065682146379182), + (11744654113764246714, 137582102682973977), + (422879793461572340, 85988814176858736), + (528599741826965425, 107486017721073420), + (660749677283706782, 134357522151341775), + (7330497575943398595, 83973451344588609), + (13774807988356636147, 104966814180735761), + (3383451930163631472, 131208517725919702), + (15949715511634433382, 82005323578699813), + (6102086334260878016, 102506654473374767), + (3015921899398709616, 128133318091718459), + (18025852251620051174, 80083323807324036), + (4085571240815512351, 100104154759155046), + (14330336087874166247, 125130193448943807), + (15873989082562435760, 78206370905589879), + (15230800334775656796, 97757963631987349), + (5203442363187407284, 122197454539984187), + (946308467778435600, 76373409087490117), + (5794571603150432404, 95466761359362646), + (16466586540792816313, 119333451699203307), + (7985773578781816244, 74583407312002067), + (5370530955049882401, 93229259140002584), + (6713163693812353001, 116536573925003230), + (18030785363914884337, 72835358703127018), + (13315109668038829614, 91044198378908773), + (2808829029766373305, 113805247973635967), + (17346094342490130344, 142256559967044958), + (6229622945628943561, 88910349979403099), + (3175342663608791547, 111137937474253874), + (13192550366365765242, 138922421842817342), + (3633657960551215372, 86826513651760839), + (18377130505971182927, 108533142064701048), + (4524669058754427043, 135666427580876311), + (9745447189362598758, 84791517238047694), + (2958436949848472639, 105989396547559618), + (12921418224165366607, 132486745684449522), + (12687572408530742033, 82804216052780951), + (11247779492236039638, 103505270065976189), + (224666310012885835, 129381587582470237), + (2446259452971747599, 80863492239043898), + (12281196353069460307, 101079365298804872), + (15351495441336825384, 126349206623506090), + (14206370669262903769, 78968254139691306), + (8534591299723853903, 98710317674614133), + (15279925143082205283, 123387897093267666), + (14161639232853766206, 77117435683292291), + (13090363022639819853, 96396794604115364), + (16362953778299774816, 120495993255144205), + (12532689120651053212, 75309995784465128), + (15665861400813816515, 94137494730581410), + (10358954714162494836, 117671868413226763), + (4168503687137865320, 73544917758266727), + (598943590494943747, 91931147197833409), + (5360365506546067587, 114913933997291761), + (11312142901609972388, 143642417496614701), + (9375932322719926695, 89776510935384188), + (11719915403399908368, 112220638669230235), + (10038208235822497557, 140275798336537794), + (10885566165816448877, 87672373960336121), + (18218643725697949000, 109590467450420151), + (18161618638695048346, 136988084313025189), + (13656854658398099168, 85617552695640743), + (12459382304570236056, 107021940869550929), + (1739169825430631358, 133777426086938662), + (14922039196176308311, 83610891304336663), + (14040862976792997485, 104513614130420829), + (3716020665709083144, 130642017663026037), + (4628355925281870917, 81651261039391273), + (10397130925029726550, 102064076299239091), + (8384727637859770284, 127580095374048864), + (5240454773662356427, 79737559608780540), + (6550568467077945534, 99671949510975675), + (3576524565420044014, 124589936888719594), + (6847013871814915412, 77868710555449746), + (17782139376623420074, 97335888194312182), + (13004302183924499284, 121669860242890228), + (17351060901807587860, 76043662651806392), + (3242082053549933210, 95054578314757991), + (17887660622219580224, 118818222893447488), + (11179787888887237640, 74261389308404680), + (13974734861109047050, 92826736635505850), + (8245046539531533005, 116033420794382313), + (16682369133275677888, 72520887996488945), + (7017903361312433648, 90651109995611182), + (17995751238495317868, 113313887494513977), + (8659630992836983623, 141642359368142472), + (5412269370523114764, 88526474605089045), + (11377022731581281359, 110658093256361306), + (4997906377621825891, 138322616570451633), + (14652906532082110942, 86451635356532270), + (9092761128247862869, 108064544195665338), + (2142579373455052779, 135080680244581673), + (12868327154477877747, 84425425152863545), + (2250350887815183471, 105531781441079432), + (2812938609768979339, 131914726801349290), + (6369772649532999991, 82446704250843306), + (17185587848771025797, 103058380313554132), + (3035240737254230630, 128822975391942666), + (6508711479211282048, 80514359619964166), + (17359261385868878368, 100642949524955207), + (17087390713908710056, 125803686906194009), + (3762090168551861929, 78627304316371256), + (4702612710689827411, 98284130395464070), + (15101637925217060072, 122855162994330087), + (16356052730901744401, 76784476871456304), + (1998321839917628885, 95980596089320381), + (7109588318324424010, 119975745111650476), + (13666864735807540814, 74984840694781547), + (12471894901332038114, 93731050868476934), + (6366496589810271835, 117163813585596168), + (3979060368631419896, 73227383490997605), + (9585511479216662775, 91534229363747006), + (2758517312166052660, 114417786704683758), + (12671518677062341634, 143022233380854697), + (1002170145522881665, 89388895863034186), + (10476084718758377889, 111736119828792732), + (13095105898447972362, 139670149785990915), + (5878598177316288774, 87293843616244322), + (16571619758500136775, 109117304520305402), + (11491152661270395161, 136396630650381753), + (264441385652915120, 85247894156488596), + (330551732066143900, 106559867695610745), + (5024875683510067779, 133199834619513431), + (10058076329834874218, 83249896637195894), + (3349223375438816964, 104062370796494868), + (4186529219298521205, 130077963495618585), + (14145795808130045513, 81298727184761615), + (13070558741735168987, 101623408980952019), + (11726512408741573330, 127029261226190024), + (7329070255463483331, 79393288266368765), + (13773023837756742068, 99241610332960956), + (17216279797195927585, 124052012916201195), + (8454331864033760789, 77532508072625747), + (5956228811614813082, 96915635090782184), + (7445286014518516353, 121144543863477730), + (9264989777501460624, 75715339914673581), + (16192923240304213684, 94644174893341976), + (1794409976670715490, 118305218616677471), + (8039035263060279037, 73940761635423419), + (5437108060397960892, 92425952044279274), + (16019757112352226923, 115532440055349092), + (788976158365366019, 72207775034593183), + (14821278253238871236, 90259718793241478), + (9303225779693813237, 112824648491551848), + (11629032224617266546, 141030810614439810), + (11879831158813179495, 88144256634024881), + (1014730893234310657, 110180320792531102), + (10491785653397664129, 137725400990663877), + (8863209042587234033, 86078375619164923), + (6467325284806654637, 107597969523956154), + (17307528642863094104, 134497461904945192), + (10817205401789433815, 84060913690590745), + (18133192770664180173, 105076142113238431), + (18054804944902837312, 131345177641548039), + (18201782118205355176, 82090736025967524), + (4305483574047142354, 102613420032459406), + (14605226504413703751, 128266775040574257), + (2210737537617482988, 80166734400358911), + (16598479977304017447, 100208418000448638), + (11524727934775246001, 125260522500560798), + (2591268940807140847, 78287826562850499), + (17074144231291089770, 97859783203563123), + (16730994270686474309, 122324729004453904), + (10456871419179046443, 76452955627783690), + (3847717237119032246, 95566194534729613), + (9421332564826178211, 119457743168412016), + (5888332853016361382, 74661089480257510), + (16583788103125227536, 93326361850321887), + (16118049110479146516, 116657952312902359), + (16991309721690548428, 72911220195563974), + (12015765115258409727, 91139025244454968), + (15019706394073012159, 113923781555568710), + (9551260955736489391, 142404726944460888), + (5969538097335305869, 89002954340288055), + (2850236603241744433, 111253692925360069), +]; diff --git a/third_party/rust/ryu/src/d2s_intrinsics.rs b/third_party/rust/ryu/src/d2s_intrinsics.rs new file mode 100644 index 0000000000..ca95aa4345 --- /dev/null +++ b/third_party/rust/ryu/src/d2s_intrinsics.rs @@ -0,0 +1,105 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +// Returns (lo, hi). +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub fn umul128(a: u64, b: u64) -> (u64, u64) { + let a_lo = a as u32; + let a_hi = (a >> 32) as u32; + let b_lo = b as u32; + let b_hi = (b >> 32) as u32; + + let b00 = a_lo as u64 * b_lo as u64; + let b01 = a_lo as u64 * b_hi as u64; + let b10 = a_hi as u64 * b_lo as u64; + let b11 = a_hi as u64 * b_hi as u64; + + let b00_lo = b00 as u32; + let b00_hi = (b00 >> 32) as u32; + + let mid1 = b10 + b00_hi as u64; + let mid1_lo = mid1 as u32; + let mid1_hi = (mid1 >> 32) as u32; + + let mid2 = b01 + mid1_lo as u64; + let mid2_lo = mid2 as u32; + let mid2_hi = (mid2 >> 32) as u32; + + let p_hi = b11 + mid1_hi as u64 + mid2_hi as u64; + let p_lo = ((mid2_lo as u64) << 32) | b00_lo as u64; + + (p_lo, p_hi) +} + +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 { + // We don't need to handle the case dist >= 64 here (see above). + debug_assert!(dist > 0); + debug_assert!(dist < 64); + (hi << (64 - dist)) | (lo >> dist) +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div5(x: u64) -> u64 { + x / 5 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div10(x: u64) -> u64 { + x / 10 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div100(x: u64) -> u64 { + x / 100 +} + +#[cfg_attr(feature = "no-panic", inline)] +fn pow5_factor(mut value: u64) -> u32 { + let mut count = 0u32; + loop { + debug_assert!(value != 0); + let q = div5(value); + let r = (value as u32).wrapping_sub(5u32.wrapping_mul(q as u32)); + if r != 0 { + break; + } + value = q; + count += 1; + } + count +} + +// Returns true if value is divisible by 5^p. +#[cfg_attr(feature = "no-panic", inline)] +pub fn multiple_of_power_of_5(value: u64, p: u32) -> bool { + // I tried a case distinction on p, but there was no performance difference. + pow5_factor(value) >= p +} + +// Returns true if value is divisible by 2^p. +#[cfg_attr(feature = "no-panic", inline)] +pub fn multiple_of_power_of_2(value: u64, p: u32) -> bool { + debug_assert!(value != 0); + // return __builtin_ctzll(value) >= p; + (value & ((1u64 << p) - 1)) == 0 +} diff --git a/third_party/rust/ryu/src/d2s_small_table.rs b/third_party/rust/ryu/src/d2s_small_table.rs new file mode 100644 index 0000000000..fc4a1a2a3b --- /dev/null +++ b/third_party/rust/ryu/src/d2s_small_table.rs @@ -0,0 +1,206 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use common::*; +#[cfg(not(integer128))] +use d2s_intrinsics::*; + +pub static DOUBLE_POW5_TABLE: [u64; 26] = [ + 1, + 5, + 25, + 125, + 625, + 3125, + 15625, + 78125, + 390625, + 1953125, + 9765625, + 48828125, + 244140625, + 1220703125, + 6103515625, + 30517578125, + 152587890625, + 762939453125, + 3814697265625, + 19073486328125, + 95367431640625, + 476837158203125, + 2384185791015625, + 11920928955078125, + 59604644775390625, + 298023223876953125, +]; + +pub static DOUBLE_POW5_SPLIT2: [(u64, u64); 13] = [ + (0, 72057594037927936), + (10376293541461622784, 93132257461547851), + (15052517733678820785, 120370621524202240), + (6258995034005762182, 77787690973264271), + (14893927168346708332, 100538234169297439), + (4272820386026678563, 129942622070561240), + (7330497575943398595, 83973451344588609), + (18377130505971182927, 108533142064701048), + (10038208235822497557, 140275798336537794), + (7017903361312433648, 90651109995611182), + (6366496589810271835, 117163813585596168), + (9264989777501460624, 75715339914673581), + (17074144231291089770, 97859783203563123), +]; + +// Unfortunately, the results are sometimes off by one. We use an additional +// lookup table to store those cases and adjust the result. +pub static POW5_OFFSETS: [u32; 13] = [ + 0x00000000, 0x00000000, 0x00000000, 0x033c55be, 0x03db77d8, 0x0265ffb2, 0x00000800, 0x01a8ff56, + 0x00000000, 0x0037a200, 0x00004000, 0x03fffffc, 0x00003ffe, +]; + +pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 13] = [ + (1, 288230376151711744), + (7661987648932456967, 223007451985306231), + (12652048002903177473, 172543658669764094), + (5522544058086115566, 266998379490113760), + (3181575136763469022, 206579990246952687), + (4551508647133041040, 159833525776178802), + (1116074521063664381, 247330401473104534), + (17400360011128145022, 191362629322552438), + (9297997190148906106, 148059663038321393), + (11720143854957885429, 229111231347799689), + (15401709288678291155, 177266229209635622), + (3003071137298187333, 274306203439684434), + (17516772882021341108, 212234145163966538), +]; + +pub static POW5_INV_OFFSETS: [u32; 20] = [ + 0x51505404, 0x55054514, 0x45555545, 0x05511411, 0x00505010, 0x00000004, 0x00000000, 0x00000000, + 0x55555040, 0x00505051, 0x00050040, 0x55554000, 0x51659559, 0x00001000, 0x15000010, 0x55455555, + 0x41404051, 0x00001010, 0x00000014, 0x00000000, +]; + +// Computes 5^i in the form required by Ryu. +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { + let base = i / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = i - base2; + debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize); + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let b0 = m as u128 * mul.0 as u128; + let b2 = m as u128 * mul.1 as u128; + let delta = pow5bits(i as i32) - pow5bits(base2 as i32); + debug_assert!(base < POW5_OFFSETS.len() as u32); + let shifted_sum = (b0 >> delta) + + (b2 << (64 - delta)) + + ((*POW5_OFFSETS.get_unchecked(base as usize) >> offset) & 1) as u128; + (shifted_sum as u64, (shifted_sum >> 64) as u64) +} + +// Computes 5^-i in the form required by Ryu. +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { + let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = base2 - i; + debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2 + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); // 5^offset + let b0 = m as u128 * (mul.0 - 1) as u128; + let b2 = m as u128 * mul.1 as u128; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i + let delta = pow5bits(base2 as i32) - pow5bits(i as i32); + debug_assert!(base < POW5_INV_OFFSETS.len() as u32); + let shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + + 1 + + ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u128; + (shifted_sum as u64, (shifted_sum >> 64) as u64) +} + +// Computes 5^i in the form required by Ryu, and stores it in the given pointer. +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { + let base = i / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = i - base2; + debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize); + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let (low1, mut high1) = umul128(m, mul.1); + let (low0, high0) = umul128(m, mul.0); + let sum = high0 + low1; + if sum < high0 { + high1 += 1; // overflow into high1 + } + // high1 | sum | low0 + let delta = pow5bits(i as i32) - pow5bits(base2 as i32); + debug_assert!(base < POW5_OFFSETS.len() as u32); + ( + shiftright128(low0, sum, delta as u32) + + ((*POW5_OFFSETS.get_unchecked(base as usize) >> offset) & 1) as u64, + shiftright128(sum, high1, delta as u32), + ) +} + +// Computes 5^-i in the form required by Ryu, and stores it in the given pointer. +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { + let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = base2 - i; + debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2 + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let (low1, mut high1) = umul128(m, mul.1); + let (low0, high0) = umul128(m, mul.0 - 1); + let sum = high0 + low1; + if sum < high0 { + high1 += 1; // overflow into high1 + } + // high1 | sum | low0 + let delta = pow5bits(base2 as i32) - pow5bits(i as i32); + debug_assert!(base < POW5_INV_OFFSETS.len() as u32); + ( + shiftright128(low0, sum, delta as u32) + + 1 + + ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u64, + shiftright128(sum, high1, delta as u32), + ) +} diff --git a/third_party/rust/ryu/src/digit_table.rs b/third_party/rust/ryu/src/digit_table.rs new file mode 100644 index 0000000000..d871f03f77 --- /dev/null +++ b/third_party/rust/ryu/src/digit_table.rs @@ -0,0 +1,28 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +// A table of all two-digit numbers. This is used to speed up decimal digit +// generation by copying pairs of digits into the final output. +pub static DIGIT_TABLE: [u8; 200] = *b"\ + 0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; diff --git a/third_party/rust/ryu/src/f2s.rs b/third_party/rust/ryu/src/f2s.rs new file mode 100644 index 0000000000..4ad50a1bce --- /dev/null +++ b/third_party/rust/ryu/src/f2s.rs @@ -0,0 +1,323 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use common::*; + +pub const FLOAT_MANTISSA_BITS: u32 = 23; +pub const FLOAT_EXPONENT_BITS: u32 = 8; + +const FLOAT_BIAS: i32 = 127; +const FLOAT_POW5_INV_BITCOUNT: i32 = 59; +const FLOAT_POW5_BITCOUNT: i32 = 61; + +// This table is generated by PrintFloatLookupTable. +static FLOAT_POW5_INV_SPLIT: [u64; 32] = [ + 576460752303423489, + 461168601842738791, + 368934881474191033, + 295147905179352826, + 472236648286964522, + 377789318629571618, + 302231454903657294, + 483570327845851670, + 386856262276681336, + 309485009821345069, + 495176015714152110, + 396140812571321688, + 316912650057057351, + 507060240091291761, + 405648192073033409, + 324518553658426727, + 519229685853482763, + 415383748682786211, + 332306998946228969, + 531691198313966350, + 425352958651173080, + 340282366920938464, + 544451787073501542, + 435561429658801234, + 348449143727040987, + 557518629963265579, + 446014903970612463, + 356811923176489971, + 570899077082383953, + 456719261665907162, + 365375409332725730, + 1 << 63, +]; + +static FLOAT_POW5_SPLIT: [u64; 47] = [ + 1152921504606846976, + 1441151880758558720, + 1801439850948198400, + 2251799813685248000, + 1407374883553280000, + 1759218604441600000, + 2199023255552000000, + 1374389534720000000, + 1717986918400000000, + 2147483648000000000, + 1342177280000000000, + 1677721600000000000, + 2097152000000000000, + 1310720000000000000, + 1638400000000000000, + 2048000000000000000, + 1280000000000000000, + 1600000000000000000, + 2000000000000000000, + 1250000000000000000, + 1562500000000000000, + 1953125000000000000, + 1220703125000000000, + 1525878906250000000, + 1907348632812500000, + 1192092895507812500, + 1490116119384765625, + 1862645149230957031, + 1164153218269348144, + 1455191522836685180, + 1818989403545856475, + 2273736754432320594, + 1421085471520200371, + 1776356839400250464, + 2220446049250313080, + 1387778780781445675, + 1734723475976807094, + 2168404344971008868, + 1355252715606880542, + 1694065894508600678, + 2117582368135750847, + 1323488980084844279, + 1654361225106055349, + 2067951531382569187, + 1292469707114105741, + 1615587133892632177, + 2019483917365790221, +]; + +#[cfg_attr(feature = "no-panic", inline)] +fn pow5_factor(mut value: u32) -> u32 { + let mut count = 0u32; + loop { + debug_assert!(value != 0); + let q = value / 5; + let r = value % 5; + if r != 0 { + break; + } + value = q; + count += 1; + } + count +} + +// Returns true if value is divisible by 5^p. +#[cfg_attr(feature = "no-panic", inline)] +fn multiple_of_power_of_5(value: u32, p: u32) -> bool { + pow5_factor(value) >= p +} + +// Returns true if value is divisible by 2^p. +#[cfg_attr(feature = "no-panic", inline)] +fn multiple_of_power_of_2(value: u32, p: u32) -> bool { + // return __builtin_ctz(value) >= p; + (value & ((1u32 << p) - 1)) == 0 +} + +// It seems to be slightly faster to avoid uint128_t here, although the +// generated code for uint128_t looks slightly nicer. +#[cfg_attr(feature = "no-panic", inline)] +fn mul_shift(m: u32, factor: u64, shift: i32) -> u32 { + debug_assert!(shift > 32); + + // The casts here help MSVC to avoid calls to the __allmul library + // function. + let factor_lo = factor as u32; + let factor_hi = (factor >> 32) as u32; + let bits0 = m as u64 * factor_lo as u64; + let bits1 = m as u64 * factor_hi as u64; + + let sum = (bits0 >> 32) + bits1; + let shifted_sum = sum >> (shift - 32); + debug_assert!(shifted_sum <= u32::max_value() as u64); + shifted_sum as u32 +} + +#[cfg_attr(feature = "no-panic", inline)] +fn mul_pow5_inv_div_pow2(m: u32, q: u32, j: i32) -> u32 { + debug_assert!(q < FLOAT_POW5_INV_SPLIT.len() as u32); + unsafe { mul_shift(m, *FLOAT_POW5_INV_SPLIT.get_unchecked(q as usize), j) } +} + +#[cfg_attr(feature = "no-panic", inline)] +fn mul_pow5_div_pow2(m: u32, i: u32, j: i32) -> u32 { + debug_assert!(i < FLOAT_POW5_SPLIT.len() as u32); + unsafe { mul_shift(m, *FLOAT_POW5_SPLIT.get_unchecked(i as usize), j) } +} + +// A floating decimal representing m * 10^e. +pub struct FloatingDecimal32 { + pub mantissa: u32, + // Decimal exponent's range is -45 to 38 + // inclusive, and can fit in i16 if needed. + pub exponent: i32, +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 { + let (e2, m2) = if ieee_exponent == 0 { + ( + // We subtract 2 so that the bounds computation has 2 additional bits. + 1 - FLOAT_BIAS - FLOAT_MANTISSA_BITS as i32 - 2, + ieee_mantissa, + ) + } else { + ( + ieee_exponent as i32 - FLOAT_BIAS - FLOAT_MANTISSA_BITS as i32 - 2, + (1u32 << FLOAT_MANTISSA_BITS) | ieee_mantissa, + ) + }; + let even = (m2 & 1) == 0; + let accept_bounds = even; + + // Step 2: Determine the interval of valid decimal representations. + let mv = 4 * m2; + let mp = 4 * m2 + 2; + // Implicit bool -> int conversion. True is 1, false is 0. + let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32; + let mm = 4 * m2 - 1 - mm_shift; + + // Step 3: Convert to a decimal power base using 64-bit arithmetic. + let mut vr: u32; + let mut vp: u32; + let mut vm: u32; + let e10: i32; + let mut vm_is_trailing_zeros = false; + let mut vr_is_trailing_zeros = false; + let mut last_removed_digit = 0u8; + if e2 >= 0 { + let q = log10_pow2(e2); + e10 = q as i32; + let k = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1; + let i = -e2 + q as i32 + k; + vr = mul_pow5_inv_div_pow2(mv, q, i); + vp = mul_pow5_inv_div_pow2(mp, q, i); + vm = mul_pow5_inv_div_pow2(mm, q, i); + if q != 0 && (vp - 1) / 10 <= vm / 10 { + // We need to know one removed digit even if we are not going to loop below. We could use + // q = X - 1 above, except that would require 33 bits for the result, and we've found that + // 32-bit arithmetic is faster even on 64-bit machines. + let l = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32 - 1) - 1; + last_removed_digit = + (mul_pow5_inv_div_pow2(mv, q - 1, -e2 + q as i32 - 1 + l) % 10) as u8; + } + if q <= 9 { + // The largest power of 5 that fits in 24 bits is 5^10, but q <= 9 seems to be safe as well. + // Only one of mp, mv, and mm can be a multiple of 5, if any. + if mv % 5 == 0 { + vr_is_trailing_zeros = multiple_of_power_of_5(mv, q); + } else if accept_bounds { + vm_is_trailing_zeros = multiple_of_power_of_5(mm, q); + } else { + vp -= multiple_of_power_of_5(mp, q) as u32; + } + } + } else { + let q = log10_pow5(-e2); + e10 = q as i32 + e2; + let i = -e2 - q as i32; + let k = pow5bits(i) - FLOAT_POW5_BITCOUNT; + let mut j = q as i32 - k; + vr = mul_pow5_div_pow2(mv, i as u32, j); + vp = mul_pow5_div_pow2(mp, i as u32, j); + vm = mul_pow5_div_pow2(mm, i as u32, j); + if q != 0 && (vp - 1) / 10 <= vm / 10 { + j = q as i32 - 1 - (pow5bits(i + 1) - FLOAT_POW5_BITCOUNT); + last_removed_digit = (mul_pow5_div_pow2(mv, (i + 1) as u32, j) % 10) as u8; + } + if q <= 1 { + // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. + // mv = 4 * m2, so it always has at least two trailing 0 bits. + vr_is_trailing_zeros = true; + if accept_bounds { + // mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1. + vm_is_trailing_zeros = mm_shift == 1; + } else { + // mp = mv + 2, so it always has at least one trailing 0 bit. + vp -= 1; + } + } else if q < 31 { + // TODO(ulfjack): Use a tighter bound here. + vr_is_trailing_zeros = multiple_of_power_of_2(mv, q - 1); + } + } + + // Step 4: Find the shortest decimal representation in the interval of valid representations. + let mut removed = 0i32; + let output = if vm_is_trailing_zeros || vr_is_trailing_zeros { + // General case, which happens rarely (~4.0%). + while vp / 10 > vm / 10 { + vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0; + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = (vr % 10) as u8; + vr /= 10; + vp /= 10; + vm /= 10; + removed += 1; + } + if vm_is_trailing_zeros { + while vm % 10 == 0 { + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = (vr % 10) as u8; + vr /= 10; + vp /= 10; + vm /= 10; + removed += 1; + } + } + if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 { + // Round even if the exact number is .....50..0. + last_removed_digit = 4; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) + as u32 + } else { + // Specialized for the common case (~96.0%). Percentages below are relative to this. + // Loop iterations below (approximately): + // 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01% + while vp / 10 > vm / 10 { + last_removed_digit = (vr % 10) as u8; + vr /= 10; + vp /= 10; + vm /= 10; + removed += 1; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + (vr == vm || last_removed_digit >= 5) as u32 + }; + let exp = e10 + removed; + + FloatingDecimal32 { + exponent: exp, + mantissa: output, + } +} diff --git a/third_party/rust/ryu/src/lib.rs b/third_party/rust/ryu/src/lib.rs new file mode 100644 index 0000000000..8aecb51e5b --- /dev/null +++ b/third_party/rust/ryu/src/lib.rs @@ -0,0 +1,111 @@ +//! Pure Rust implementation of Ryū, an algorithm to quickly convert floating +//! point numbers to decimal strings. +//! +//! The PLDI'18 paper [*Ryū: fast float-to-string conversion*][paper] by Ulf +//! Adams includes a complete correctness proof of the algorithm. The paper is +//! available under the creative commons CC-BY-SA license. +//! +//! This Rust implementation is a line-by-line port of Ulf Adams' implementation +//! in C, [https://github.com/ulfjack/ryu][upstream]. +//! +//! [paper]: https://dl.acm.org/citation.cfm?id=3192369 +//! [upstream]: https://github.com/ulfjack/ryu +//! +//! # Example +//! +//! ```edition2018 +//! fn main() { +//! let mut buffer = ryu::Buffer::new(); +//! let printed = buffer.format(1.234); +//! assert_eq!(printed, "1.234"); +//! } +//! ``` +//! +//! ## Performance +//! +//! You can run upstream's benchmarks with: +//! +//! ```console +//! $ git clone https://github.com/ulfjack/ryu c-ryu +//! $ cd c-ryu +//! $ bazel run -c opt //ryu/benchmark +//! ``` +//! +//! And the same benchmark against our implementation with: +//! +//! ```console +//! $ git clone https://github.com/dtolnay/ryu rust-ryu +//! $ cd rust-ryu +//! $ cargo run --example upstream_benchmark --release +//! ``` +//! +//! These benchmarks measure the average time to print a 32-bit float and average +//! time to print a 64-bit float, where the inputs are distributed as uniform random +//! bit patterns 32 and 64 bits wide. +//! +//! The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API +//! all perform the same, taking around 21 nanoseconds to format a 32-bit float and +//! 31 nanoseconds to format a 64-bit float. +//! +//! There is also a Rust-specific benchmark comparing this implementation to the +//! standard library which you can run with: +//! +//! ```console +//! $ cargo bench +//! ``` +//! +//! The benchmark shows Ryu approximately 4-10x faster than the standard library +//! across a range of f32 and f64 inputs. Measurements are in nanoseconds per +//! iteration; smaller is better. +//! +//! | type=f32 | 0.0 | 0.1234 | 2.718281828459045 | f32::MAX | +//! |:--------:|:----:|:------:|:-----------------:|:--------:| +//! | RYU | 3ns | 28ns | 23ns | 22ns | +//! | STD | 40ns | 106ns | 128ns | 110ns | +//! +//! | type=f64 | 0.0 | 0.1234 | 2.718281828459045 | f64::MAX | +//! |:--------:|:----:|:------:|:-----------------:|:--------:| +//! | RYU | 3ns | 50ns | 35ns | 32ns | +//! | STD | 39ns | 105ns | 128ns | 202ns | +//! +//! ## Formatting +//! +//! This library tends to produce more human-readable output than the standard +//! library's to\_string, which never uses scientific notation. Here are two +//! examples: +//! +//! - *ryu:* 1.23e40, *std:* 12300000000000000000000000000000000000000 +//! - *ryu:* 1.23e-40, *std:* 0.000000000000000000000000000000000000000123 +//! +//! Both libraries print short decimals such as 0.0000123 without scientific +//! notation. + +#![no_std] +#![doc(html_root_url = "https://docs.rs/ryu/1.0.2")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr( + feature = "cargo-clippy", + allow(cast_lossless, many_single_char_names, unreadable_literal,) +)] + +#[cfg(feature = "no-panic")] +extern crate no_panic; + +mod buffer; +mod common; +mod d2s; +#[cfg(not(feature = "small"))] +mod d2s_full_table; +mod d2s_intrinsics; +#[cfg(feature = "small")] +mod d2s_small_table; +mod digit_table; +mod f2s; +mod pretty; + +pub use buffer::{Buffer, Float}; + +/// Unsafe functions that mirror the API of the C implementation of Ryū. +pub mod raw { + pub use pretty::{format32, format64}; +} diff --git a/third_party/rust/ryu/src/pretty/exponent.rs b/third_party/rust/ryu/src/pretty/exponent.rs new file mode 100644 index 0000000000..f10643f22d --- /dev/null +++ b/third_party/rust/ryu/src/pretty/exponent.rs @@ -0,0 +1,49 @@ +use core::ptr; + +use digit_table::*; + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_exponent3(mut k: isize, mut result: *mut u8) -> usize { + let sign = k < 0; + if sign { + *result = b'-'; + result = result.offset(1); + k = -k; + } + + debug_assert!(k < 1000); + if k >= 100 { + *result = b'0' + (k / 100) as u8; + k %= 100; + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, result.offset(1), 2); + sign as usize + 3 + } else if k >= 10 { + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, result, 2); + sign as usize + 2 + } else { + *result = b'0' + k as u8; + sign as usize + 1 + } +} + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_exponent2(mut k: isize, mut result: *mut u8) -> usize { + let sign = k < 0; + if sign { + *result = b'-'; + result = result.offset(1); + k = -k; + } + + debug_assert!(k < 100); + if k >= 10 { + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, result, 2); + sign as usize + 2 + } else { + *result = b'0' + k as u8; + sign as usize + 1 + } +} diff --git a/third_party/rust/ryu/src/pretty/mantissa.rs b/third_party/rust/ryu/src/pretty/mantissa.rs new file mode 100644 index 0000000000..428023233d --- /dev/null +++ b/third_party/rust/ryu/src/pretty/mantissa.rs @@ -0,0 +1,51 @@ +use core::ptr; + +use digit_table::*; + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_mantissa_long(mut output: u64, mut result: *mut u8) { + if (output >> 32) != 0 { + // One expensive 64-bit division. + let mut output2 = (output - 100_000_000 * (output / 100_000_000)) as u32; + output /= 100_000_000; + + let c = output2 % 10_000; + output2 /= 10_000; + let d = output2 % 10_000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + let d0 = (d % 100) << 1; + let d1 = (d / 100) << 1; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d0 as usize), result.offset(-6), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d1 as usize), result.offset(-8), 2); + result = result.offset(-8); + } + write_mantissa(output as u32, result); +} + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_mantissa(mut output: u32, mut result: *mut u8) { + while output >= 10_000 { + let c = (output - 10_000 * (output / 10_000)) as u32; + output /= 10_000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2); + result = result.offset(-4); + } + if output >= 100 { + let c = ((output % 100) << 1) as u32; + output /= 100; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2); + result = result.offset(-2); + } + if output >= 10 { + let c = (output << 1) as u32; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2); + } else { + *result.offset(-1) = b'0' + output as u8; + } +} diff --git a/third_party/rust/ryu/src/pretty/mod.rs b/third_party/rust/ryu/src/pretty/mod.rs new file mode 100644 index 0000000000..3dead1bf36 --- /dev/null +++ b/third_party/rust/ryu/src/pretty/mod.rs @@ -0,0 +1,228 @@ +mod exponent; +mod mantissa; + +use core::{mem, ptr}; + +use self::exponent::*; +use self::mantissa::*; +use common; +use d2s; +use d2s::*; +use f2s::*; + +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +/// Print f64 to the given buffer and return number of bytes written. +/// +/// At most 24 bytes will be written. +/// +/// ## Special cases +/// +/// This function **does not** check for NaN or infinity. If the input +/// number is not a finite float, the printed representation will be some +/// correctly formatted but unspecified numerical value. +/// +/// Please check [`is_finite`] yourself before calling this function, or +/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. +/// +/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite +/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan +/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite +/// +/// ## Safety +/// +/// The `result` pointer argument must point to sufficiently many writable bytes +/// to hold Ryū's representation of `f`. +/// +/// ## Example +/// +/// ```edition2018 +/// use std::mem::MaybeUninit; +/// +/// let f = 1.234f64; +/// +/// unsafe { +/// let mut buffer: [MaybeUninit<u8>; 24] = MaybeUninit::uninit().assume_init(); +/// let len = ryu::raw::format64(f, buffer.as_mut_ptr() as *mut u8); +/// let slice = std::slice::from_raw_parts(buffer.as_ptr() as *const u8, len); +/// let print = std::str::from_utf8_unchecked(slice); +/// assert_eq!(print, "1.234"); +/// } +/// ``` +#[cfg_attr(must_use_return, must_use)] +#[cfg_attr(feature = "no-panic", no_panic)] +pub unsafe fn format64(f: f64, result: *mut u8) -> usize { + let bits = mem::transmute::<f64, u64>(f); + let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0; + let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1); + let ieee_exponent = + (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1); + + let mut index = 0isize; + if sign { + *result = b'-'; + index += 1; + } + + if ieee_exponent == 0 && ieee_mantissa == 0 { + ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3); + return sign as usize + 3; + } + + let v = d2d(ieee_mantissa, ieee_exponent); + + let length = d2s::decimal_length17(v.mantissa) as isize; + let k = v.exponent as isize; + let kk = length + k; // 10^(kk-1) <= v < 10^kk + debug_assert!(k >= -324); + + if 0 <= k && kk <= 16 { + // 1234e7 -> 12340000000.0 + write_mantissa_long(v.mantissa, result.offset(index + length)); + for i in length..kk { + *result.offset(index + i) = b'0'; + } + *result.offset(index + kk) = b'.'; + *result.offset(index + kk + 1) = b'0'; + index as usize + kk as usize + 2 + } else if 0 < kk && kk <= 16 { + // 1234e-2 -> 12.34 + write_mantissa_long(v.mantissa, result.offset(index + length + 1)); + ptr::copy(result.offset(index + 1), result.offset(index), kk as usize); + *result.offset(index + kk) = b'.'; + index as usize + length as usize + 1 + } else if -5 < kk && kk <= 0 { + // 1234e-6 -> 0.001234 + *result.offset(index) = b'0'; + *result.offset(index + 1) = b'.'; + let offset = 2 - kk; + for i in 2..offset { + *result.offset(index + i) = b'0'; + } + write_mantissa_long(v.mantissa, result.offset(index + length + offset)); + index as usize + length as usize + offset as usize + } else if length == 1 { + // 1e30 + *result.offset(index) = b'0' + v.mantissa as u8; + *result.offset(index + 1) = b'e'; + index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2)) + } else { + // 1234e30 -> 1.234e33 + write_mantissa_long(v.mantissa, result.offset(index + length + 1)); + *result.offset(index) = *result.offset(index + 1); + *result.offset(index + 1) = b'.'; + *result.offset(index + length + 1) = b'e'; + index as usize + + length as usize + + 2 + + write_exponent3(kk - 1, result.offset(index + length + 2)) + } +} + +/// Print f32 to the given buffer and return number of bytes written. +/// +/// At most 16 bytes will be written. +/// +/// ## Special cases +/// +/// This function **does not** check for NaN or infinity. If the input +/// number is not a finite float, the printed representation will be some +/// correctly formatted but unspecified numerical value. +/// +/// Please check [`is_finite`] yourself before calling this function, or +/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. +/// +/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_finite +/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_nan +/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_infinite +/// +/// ## Safety +/// +/// The `result` pointer argument must point to sufficiently many writable bytes +/// to hold Ryū's representation of `f`. +/// +/// ## Example +/// +/// ```edition2018 +/// use std::mem::MaybeUninit; +/// +/// let f = 1.234f32; +/// +/// unsafe { +/// let mut buffer: [MaybeUninit<u8>; 16] = MaybeUninit::uninit().assume_init(); +/// let len = ryu::raw::format32(f, buffer.as_mut_ptr() as *mut u8); +/// let slice = std::slice::from_raw_parts(buffer.as_ptr() as *const u8, len); +/// let print = std::str::from_utf8_unchecked(slice); +/// assert_eq!(print, "1.234"); +/// } +/// ``` +#[cfg_attr(must_use_return, must_use)] +#[cfg_attr(feature = "no-panic", no_panic)] +pub unsafe fn format32(f: f32, result: *mut u8) -> usize { + let bits = mem::transmute::<f32, u32>(f); + let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0; + let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1); + let ieee_exponent = + ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32; + + let mut index = 0isize; + if sign { + *result = b'-'; + index += 1; + } + + if ieee_exponent == 0 && ieee_mantissa == 0 { + ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3); + return sign as usize + 3; + } + + let v = f2d(ieee_mantissa, ieee_exponent); + + let length = common::decimal_length9(v.mantissa) as isize; + let k = v.exponent as isize; + let kk = length + k; // 10^(kk-1) <= v < 10^kk + debug_assert!(k >= -45); + + if 0 <= k && kk <= 13 { + // 1234e7 -> 12340000000.0 + write_mantissa(v.mantissa, result.offset(index + length)); + for i in length..kk { + *result.offset(index + i) = b'0'; + } + *result.offset(index + kk) = b'.'; + *result.offset(index + kk + 1) = b'0'; + index as usize + kk as usize + 2 + } else if 0 < kk && kk <= 13 { + // 1234e-2 -> 12.34 + write_mantissa(v.mantissa, result.offset(index + length + 1)); + ptr::copy(result.offset(index + 1), result.offset(index), kk as usize); + *result.offset(index + kk) = b'.'; + index as usize + length as usize + 1 + } else if -6 < kk && kk <= 0 { + // 1234e-6 -> 0.001234 + *result.offset(index) = b'0'; + *result.offset(index + 1) = b'.'; + let offset = 2 - kk; + for i in 2..offset { + *result.offset(index + i) = b'0'; + } + write_mantissa(v.mantissa, result.offset(index + length + offset)); + index as usize + length as usize + offset as usize + } else if length == 1 { + // 1e30 + *result.offset(index) = b'0' + v.mantissa as u8; + *result.offset(index + 1) = b'e'; + index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2)) + } else { + // 1234e30 -> 1.234e33 + write_mantissa(v.mantissa, result.offset(index + length + 1)); + *result.offset(index) = *result.offset(index + 1); + *result.offset(index + 1) = b'.'; + *result.offset(index + length + 1) = b'e'; + index as usize + + length as usize + + 2 + + write_exponent2(kk - 1, result.offset(index + length + 2)) + } +} diff --git a/third_party/rust/ryu/tests/d2s_table_test.rs b/third_party/rust/ryu/tests/d2s_table_test.rs new file mode 100644 index 0000000000..8f27726db4 --- /dev/null +++ b/third_party/rust/ryu/tests/d2s_table_test.rs @@ -0,0 +1,52 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +#![allow(dead_code)] + +extern crate core; + +#[path = "../src/common.rs"] +mod common; + +#[path = "../src/d2s_full_table.rs"] +mod d2s_full_table; + +#[path = "../src/d2s_intrinsics.rs"] +mod d2s_intrinsics; + +#[path = "../src/d2s_small_table.rs"] +mod d2s_small_table; + +use d2s_full_table::*; +use d2s_small_table::*; + +#[test] +fn test_compute_pow5() { + for (i, entry) in DOUBLE_POW5_SPLIT.iter().enumerate() { + assert_eq!(*entry, unsafe { compute_pow5(i as u32) }, "entry {}", i); + } +} + +#[test] +fn test_compute_inv_pow5() { + for (i, entry) in DOUBLE_POW5_INV_SPLIT.iter().enumerate() { + assert_eq!(*entry, unsafe { compute_inv_pow5(i as u32) }, "entry {}", i); + } +} diff --git a/third_party/rust/ryu/tests/d2s_test.rs b/third_party/rust/ryu/tests/d2s_test.rs new file mode 100644 index 0000000000..c30a305212 --- /dev/null +++ b/third_party/rust/ryu/tests/d2s_test.rs @@ -0,0 +1,321 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +extern crate rand; +extern crate ryu; + +#[macro_use] +mod macros; + +use std::f64; + +fn pretty(f: f64) -> String { + ryu::Buffer::new().format(f).to_owned() +} + +fn ieee_parts_to_double(sign: bool, ieee_exponent: u32, ieee_mantissa: u64) -> f64 { + assert!(ieee_exponent <= 2047); + assert!(ieee_mantissa <= (1u64 << 53) - 1); + f64::from_bits(((sign as u64) << 63) | ((ieee_exponent as u64) << 52) | ieee_mantissa) +} + +#[test] +fn test_ryu() { + check!(0.3); + check!(1234000000000000.0); + check!(1.234e16); + check!(2.71828); + check!(1.1e128); + check!(1.1e-64); + check!(2.718281828459045); + check!(5e-324); + check!(1.7976931348623157e308); +} + +#[test] +fn test_random() { + let mut buffer = ryu::Buffer::new(); + for _ in 0..1000000 { + let f: f64 = rand::random(); + assert_eq!(f, buffer.format_finite(f).parse().unwrap()); + } +} + +#[test] +fn test_non_finite() { + for i in 0u64..1 << 23 { + let f = f64::from_bits((((1 << 11) - 1) << 52) + (i << 29)); + assert!(!f.is_finite(), "f={}", f); + ryu::Buffer::new().format_finite(f); + } +} + +#[test] +fn test_basic() { + check!(0.0); + check!(-0.0); + check!(1.0); + check!(-1.0); + assert_eq!(pretty(f64::NAN), "NaN"); + assert_eq!(pretty(f64::INFINITY), "inf"); + assert_eq!(pretty(f64::NEG_INFINITY), "-inf"); +} + +#[test] +fn test_switch_to_subnormal() { + check!(2.2250738585072014e-308); +} + +#[test] +fn test_min_and_max() { + assert_eq!(f64::from_bits(0x7fefffffffffffff), 1.7976931348623157e308); + check!(1.7976931348623157e308); + assert_eq!(f64::from_bits(1), 5e-324); + check!(5e-324); +} + +#[test] +fn test_lots_of_trailing_zeros() { + check!(2.9802322387695312e-8); +} + +#[test] +fn test_regression() { + check!(-2.109808898695963e16); + check!(4.940656e-318); + check!(1.18575755e-316); + check!(2.989102097996e-312); + check!(9060801153433600.0); + check!(4.708356024711512e18); + check!(9.409340012568248e18); + check!(1.2345678); +} + +#[test] +fn test_looks_like_pow5() { + // These numbers have a mantissa that is a multiple of the largest power of + // 5 that fits, and an exponent that causes the computation for q to result + // in 22, which is a corner case for Ryu. + assert_eq!(f64::from_bits(0x4830F0CF064DD592), 5.764607523034235e39); + check!(5.764607523034235e39); + assert_eq!(f64::from_bits(0x4840F0CF064DD592), 1.152921504606847e40); + check!(1.152921504606847e40); + assert_eq!(f64::from_bits(0x4850F0CF064DD592), 2.305843009213694e40); + check!(2.305843009213694e40); +} + +#[test] +fn test_output_length() { + check!(1.0); // already tested in Basic + check!(1.2); + check!(1.23); + check!(1.234); + check!(1.2345); + check!(1.23456); + check!(1.234567); + check!(1.2345678); // already tested in Regression + check!(1.23456789); + check!(1.234567895); // 1.234567890 would be trimmed + check!(1.2345678901); + check!(1.23456789012); + check!(1.234567890123); + check!(1.2345678901234); + check!(1.23456789012345); + check!(1.234567890123456); + check!(1.2345678901234567); + + // Test 32-bit chunking + check!(4.294967294); // 2^32 - 2 + check!(4.294967295); // 2^32 - 1 + check!(4.294967296); // 2^32 + check!(4.294967297); // 2^32 + 1 + check!(4.294967298); // 2^32 + 2 +} + +// Test min, max shift values in shiftright128 +#[test] +fn test_min_max_shift() { + let max_mantissa = (1u64 << 53) - 1; + + // 32-bit opt-size=0: 49 <= dist <= 50 + // 32-bit opt-size=1: 30 <= dist <= 50 + // 64-bit opt-size=0: 50 <= dist <= 50 + // 64-bit opt-size=1: 30 <= dist <= 50 + assert_eq!(1.7800590868057611E-307, ieee_parts_to_double(false, 4, 0)); + check!(1.7800590868057611e-307); + // 32-bit opt-size=0: 49 <= dist <= 49 + // 32-bit opt-size=1: 28 <= dist <= 49 + // 64-bit opt-size=0: 50 <= dist <= 50 + // 64-bit opt-size=1: 28 <= dist <= 50 + assert_eq!( + 2.8480945388892175E-306, + ieee_parts_to_double(false, 6, max_mantissa) + ); + check!(2.8480945388892175e-306); + // 32-bit opt-size=0: 52 <= dist <= 53 + // 32-bit opt-size=1: 2 <= dist <= 53 + // 64-bit opt-size=0: 53 <= dist <= 53 + // 64-bit opt-size=1: 2 <= dist <= 53 + assert_eq!(2.446494580089078E-296, ieee_parts_to_double(false, 41, 0)); + check!(2.446494580089078e-296); + // 32-bit opt-size=0: 52 <= dist <= 52 + // 32-bit opt-size=1: 2 <= dist <= 52 + // 64-bit opt-size=0: 53 <= dist <= 53 + // 64-bit opt-size=1: 2 <= dist <= 53 + assert_eq!( + 4.8929891601781557E-296, + ieee_parts_to_double(false, 40, max_mantissa) + ); + check!(4.8929891601781557e-296); + + // 32-bit opt-size=0: 57 <= dist <= 58 + // 32-bit opt-size=1: 57 <= dist <= 58 + // 64-bit opt-size=0: 58 <= dist <= 58 + // 64-bit opt-size=1: 58 <= dist <= 58 + assert_eq!(1.8014398509481984E16, ieee_parts_to_double(false, 1077, 0)); + check!(1.8014398509481984e16); + // 32-bit opt-size=0: 57 <= dist <= 57 + // 32-bit opt-size=1: 57 <= dist <= 57 + // 64-bit opt-size=0: 58 <= dist <= 58 + // 64-bit opt-size=1: 58 <= dist <= 58 + assert_eq!( + 3.6028797018963964E16, + ieee_parts_to_double(false, 1076, max_mantissa) + ); + check!(3.6028797018963964e16); + // 32-bit opt-size=0: 51 <= dist <= 52 + // 32-bit opt-size=1: 51 <= dist <= 59 + // 64-bit opt-size=0: 52 <= dist <= 52 + // 64-bit opt-size=1: 52 <= dist <= 59 + assert_eq!(2.900835519859558E-216, ieee_parts_to_double(false, 307, 0)); + check!(2.900835519859558e-216); + // 32-bit opt-size=0: 51 <= dist <= 51 + // 32-bit opt-size=1: 51 <= dist <= 59 + // 64-bit opt-size=0: 52 <= dist <= 52 + // 64-bit opt-size=1: 52 <= dist <= 59 + assert_eq!( + 5.801671039719115E-216, + ieee_parts_to_double(false, 306, max_mantissa) + ); + check!(5.801671039719115e-216); + + // https://github.com/ulfjack/ryu/commit/19e44d16d80236f5de25800f56d82606d1be00b9#commitcomment-30146483 + // 32-bit opt-size=0: 49 <= dist <= 49 + // 32-bit opt-size=1: 44 <= dist <= 49 + // 64-bit opt-size=0: 50 <= dist <= 50 + // 64-bit opt-size=1: 44 <= dist <= 50 + assert_eq!( + 3.196104012172126E-27, + ieee_parts_to_double(false, 934, 0x000FA7161A4D6E0C) + ); + check!(3.196104012172126e-27); +} + +#[test] +fn test_small_integers() { + check!(9007199254740991.0); // 2^53-1 + check!(9007199254740992.0); // 2^53 + + check!(1.0); + check!(12.0); + check!(123.0); + check!(1234.0); + check!(12345.0); + check!(123456.0); + check!(1234567.0); + check!(12345678.0); + check!(123456789.0); + check!(1234567890.0); + check!(1234567895.0); + check!(12345678901.0); + check!(123456789012.0); + check!(1234567890123.0); + check!(12345678901234.0); + check!(123456789012345.0); + check!(1234567890123456.0); + + // 10^i + check!(1.0); + check!(10.0); + check!(100.0); + check!(1000.0); + check!(10000.0); + check!(100000.0); + check!(1000000.0); + check!(10000000.0); + check!(100000000.0); + check!(1000000000.0); + check!(10000000000.0); + check!(100000000000.0); + check!(1000000000000.0); + check!(10000000000000.0); + check!(100000000000000.0); + check!(1000000000000000.0); + + // 10^15 + 10^i + check!(1000000000000001.0); + check!(1000000000000010.0); + check!(1000000000000100.0); + check!(1000000000001000.0); + check!(1000000000010000.0); + check!(1000000000100000.0); + check!(1000000001000000.0); + check!(1000000010000000.0); + check!(1000000100000000.0); + check!(1000001000000000.0); + check!(1000010000000000.0); + check!(1000100000000000.0); + check!(1001000000000000.0); + check!(1010000000000000.0); + check!(1100000000000000.0); + + // Largest power of 2 <= 10^(i+1) + check!(8.0); + check!(64.0); + check!(512.0); + check!(8192.0); + check!(65536.0); + check!(524288.0); + check!(8388608.0); + check!(67108864.0); + check!(536870912.0); + check!(8589934592.0); + check!(68719476736.0); + check!(549755813888.0); + check!(8796093022208.0); + check!(70368744177664.0); + check!(562949953421312.0); + check!(9007199254740992.0); + + // 1000 * (Largest power of 2 <= 10^(i+1)) + check!(8000.0); + check!(64000.0); + check!(512000.0); + check!(8192000.0); + check!(65536000.0); + check!(524288000.0); + check!(8388608000.0); + check!(67108864000.0); + check!(536870912000.0); + check!(8589934592000.0); + check!(68719476736000.0); + check!(549755813888000.0); + check!(8796093022208000.0); +} diff --git a/third_party/rust/ryu/tests/exhaustive.rs b/third_party/rust/ryu/tests/exhaustive.rs new file mode 100644 index 0000000000..5c36969ffc --- /dev/null +++ b/third_party/rust/ryu/tests/exhaustive.rs @@ -0,0 +1,55 @@ +#![cfg(exhaustive)] + +extern crate num_cpus; +extern crate ryu; + +use std::str; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread; + +#[test] +fn test_exhaustive() { + const BATCH_SIZE: u32 = 1_000_000; + let counter = Arc::new(AtomicUsize::new(0)); + let finished = Arc::new(AtomicUsize::new(0)); + + let mut workers = Vec::new(); + for _ in 0..num_cpus::get() { + let counter = counter.clone(); + let finished = finished.clone(); + workers.push(thread::spawn(move || loop { + let batch = counter.fetch_add(1, Ordering::SeqCst) as u32; + if batch > u32::max_value() / BATCH_SIZE { + return; + } + + let min = batch * BATCH_SIZE; + let max = if batch == u32::max_value() / BATCH_SIZE { + u32::max_value() + } else { + min + BATCH_SIZE - 1 + }; + + let mut bytes = [0u8; 24]; + let mut buffer = ryu::Buffer::new(); + for u in min..=max { + let f = f32::from_bits(u); + if !f.is_finite() { + continue; + } + let n = unsafe { ryu::raw::format32(f, &mut bytes[0]) }; + assert_eq!(Ok(Ok(f)), str::from_utf8(&bytes[..n]).map(str::parse)); + assert_eq!(Ok(f), buffer.format_finite(f).parse()); + } + + let increment = (max - min + 1) as usize; + let update = finished.fetch_add(increment, Ordering::SeqCst); + println!("{}", update + increment); + })); + } + + for w in workers { + w.join().unwrap(); + } +} diff --git a/third_party/rust/ryu/tests/f2s_test.rs b/third_party/rust/ryu/tests/f2s_test.rs new file mode 100644 index 0000000000..82968b4a86 --- /dev/null +++ b/third_party/rust/ryu/tests/f2s_test.rs @@ -0,0 +1,173 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +extern crate rand; +extern crate ryu; + +#[macro_use] +mod macros; + +use std::f32; + +fn pretty(f: f32) -> String { + ryu::Buffer::new().format(f).to_owned() +} + +#[test] +fn test_ryu() { + check!(0.3); + check!(1234000000000.0); + check!(1.234e13); + check!(2.71828); + check!(1.1e32); + check!(1.1e-32); + check!(2.7182817); + check!(1e-45); + check!(3.4028235e38); + check!(-0.001234); +} + +#[test] +fn test_random() { + let mut buffer = ryu::Buffer::new(); + for _ in 0..1000000 { + let f: f32 = rand::random(); + assert_eq!(f, buffer.format_finite(f).parse().unwrap()); + } +} + +#[test] +fn test_non_finite() { + for i in 0u32..1 << 23 { + let f = f32::from_bits((((1 << 8) - 1) << 23) + i); + assert!(!f.is_finite(), "f={}", f); + ryu::Buffer::new().format_finite(f); + } +} + +#[test] +fn test_basic() { + check!(0.0); + check!(-0.0); + check!(1.0); + check!(-1.0); + assert_eq!(pretty(f32::NAN), "NaN"); + assert_eq!(pretty(f32::INFINITY), "inf"); + assert_eq!(pretty(f32::NEG_INFINITY), "-inf"); +} + +#[test] +fn test_switch_to_subnormal() { + check!(1.1754944e-38); +} + +#[test] +fn test_min_and_max() { + assert_eq!(f32::from_bits(0x7f7fffff), 3.4028235e38); + check!(3.4028235e38); + assert_eq!(f32::from_bits(1), 1e-45); + check!(1e-45); +} + +// Check that we return the exact boundary if it is the shortest +// representation, but only if the original floating point number is even. +#[test] +fn test_boundary_round_even() { + check!(33554450.0); + check!(9000000000.0); + check!(34366720000.0); +} + +// If the exact value is exactly halfway between two shortest representations, +// then we round to even. It seems like this only makes a difference if the +// last two digits are ...2|5 or ...7|5, and we cut off the 5. +#[test] +fn test_exact_value_round_even() { + check!(305404.12); + check!(8099.0312); +} + +#[test] +fn test_lots_of_trailing_zeros() { + // Pattern for the first test: 00111001100000000000000000000000 + check!(0.00024414062); + check!(0.0024414062); + check!(0.0043945312); + check!(0.0063476562); +} + +#[test] +fn test_regression() { + check!(4.7223665e21); + check!(8388608.0); + check!(16777216.0); + check!(33554436.0); + check!(67131496.0); + check!(1.9310392e-38); + check!(-2.47e-43); + check!(1.993244e-38); + check!(4103.9004); + check!(5339999700.0); + check!(6.0898e-39); + check!(0.0010310042); + check!(2.882326e17); + check!(7.038531e-26); + check!(9.223404e17); + check!(67108870.0); + check!(1e-44); + check!(2.816025e14); + check!(9.223372e18); + check!(1.5846086e29); + check!(1.1811161e19); + check!(5.368709e18); + check!(4.6143166e18); + check!(0.007812537); + check!(1e-45); + check!(1.18697725e20); + check!(1.00014165e-36); + check!(200.0); + check!(33554432.0); +} + +#[test] +fn test_looks_like_pow5() { + // These numbers have a mantissa that is the largest power of 5 that fits, + // and an exponent that causes the computation for q to result in 10, which + // is a corner case for Ryu. + assert_eq!(f32::from_bits(0x5D1502F9), 6.7108864e17); + check!(6.7108864e17); + assert_eq!(f32::from_bits(0x5D9502F9), 1.3421773e18); + check!(1.3421773e18); + assert_eq!(f32::from_bits(0x5E1502F9), 2.6843546e18); + check!(2.6843546e18); +} + +#[test] +fn test_output_length() { + check!(1.0); // already tested in Basic + check!(1.2); + check!(1.23); + check!(1.234); + check!(1.2345); + check!(1.23456); + check!(1.234567); + check!(1.2345678); + check!(1.23456735e-36); +} diff --git a/third_party/rust/ryu/tests/macros/mod.rs b/third_party/rust/ryu/tests/macros/mod.rs new file mode 100644 index 0000000000..de6fb465e8 --- /dev/null +++ b/third_party/rust/ryu/tests/macros/mod.rs @@ -0,0 +1,8 @@ +macro_rules! check { + ($f:tt) => { + assert_eq!(pretty($f), stringify!($f)); + }; + (-$f:tt) => { + assert_eq!(pretty(-$f), concat!("-", stringify!($f))); + }; +} |