├── .github └── workflows │ ├── ci.yaml │ ├── master.yaml │ └── pr.yaml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── RELEASES.md ├── benches ├── average.rs ├── gcd.rs └── roots.rs ├── ci ├── rustup.sh └── test_full.sh ├── src ├── average.rs ├── lib.rs └── roots.rs └── tests ├── average.rs └── roots.rs /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: merge_group 3 | 4 | jobs: 5 | 6 | test: 7 | name: Test 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | rust: [ 12 | 1.31.0, # MSRV 13 | 1.51.0, 14 | 1.60.0, 15 | stable, 16 | beta, 17 | nightly, 18 | ] 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: actions/cache@v4 22 | if: startsWith(matrix.rust, '1') 23 | with: 24 | path: ~/.cargo/registry/index 25 | key: cargo-${{ matrix.rust }}-git-index 26 | - uses: dtolnay/rust-toolchain@master 27 | with: 28 | toolchain: ${{ matrix.rust }} 29 | - run: ./ci/test_full.sh 30 | 31 | # try a target that doesn't have std at all 32 | no_std: 33 | name: No Std 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v4 37 | - uses: dtolnay/rust-toolchain@stable 38 | with: 39 | target: thumbv6m-none-eabi 40 | - run: cargo build --target thumbv6m-none-eabi --no-default-features 41 | 42 | fmt: 43 | name: Format 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v4 47 | - uses: dtolnay/rust-toolchain@1.62.0 48 | with: 49 | components: rustfmt 50 | - run: cargo fmt --all --check 51 | 52 | # One job that "summarizes" the success state of this pipeline. This can then be added to branch 53 | # protection, rather than having to add each job separately. 54 | success: 55 | name: Success 56 | runs-on: ubuntu-latest 57 | needs: [test, no_std, fmt] 58 | # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency 59 | # failed" as success. So we have to do some contortions to ensure the job fails if any of its 60 | # dependencies fails. 61 | if: always() # make sure this is never "skipped" 62 | steps: 63 | # Manually check the status of all dependencies. `if: failure()` does not work. 64 | - name: check if any dependency failed 65 | run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' 66 | -------------------------------------------------------------------------------- /.github/workflows/master.yaml: -------------------------------------------------------------------------------- 1 | name: master 2 | on: 3 | push: 4 | branches: 5 | - master 6 | schedule: 7 | - cron: '0 0 * * 0' # 00:00 Sunday 8 | 9 | jobs: 10 | 11 | test: 12 | name: Test 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | rust: [1.31.0, stable] 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/cache@v4 20 | if: startsWith(matrix.rust, '1') 21 | with: 22 | path: ~/.cargo/registry/index 23 | key: cargo-${{ matrix.rust }}-git-index 24 | - uses: dtolnay/rust-toolchain@master 25 | with: 26 | toolchain: ${{ matrix.rust }} 27 | - run: ./ci/test_full.sh 28 | -------------------------------------------------------------------------------- /.github/workflows/pr.yaml: -------------------------------------------------------------------------------- 1 | name: PR 2 | on: 3 | pull_request: 4 | 5 | jobs: 6 | 7 | test: 8 | name: Test 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | rust: [1.31.0, stable] 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/cache@v4 16 | if: startsWith(matrix.rust, '1') 17 | with: 18 | path: ~/.cargo/registry/index 19 | key: cargo-${{ matrix.rust }}-git-index 20 | - uses: dtolnay/rust-toolchain@master 21 | with: 22 | toolchain: ${{ matrix.rust }} 23 | - run: ./ci/test_full.sh 24 | 25 | fmt: 26 | name: Format 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v4 30 | - uses: dtolnay/rust-toolchain@1.62.0 31 | with: 32 | components: rustfmt 33 | - run: cargo fmt --all --check 34 | 35 | # One job that "summarizes" the success state of this pipeline. This can then be added to branch 36 | # protection, rather than having to add each job separately. 37 | success: 38 | name: Success 39 | runs-on: ubuntu-latest 40 | needs: [test, fmt] 41 | # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency 42 | # failed" as success. So we have to do some contortions to ensure the job fails if any of its 43 | # dependencies fails. 44 | if: always() # make sure this is never "skipped" 45 | steps: 46 | # Manually check the status of all dependencies. `if: failure()` does not work. 47 | - name: check if any dependency failed 48 | run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["The Rust Project Developers"] 3 | description = "Integer traits and functions" 4 | documentation = "https://docs.rs/num-integer" 5 | homepage = "https://github.com/rust-num/num-integer" 6 | keywords = ["mathematics", "numerics"] 7 | categories = ["algorithms", "science", "no-std"] 8 | license = "MIT OR Apache-2.0" 9 | repository = "https://github.com/rust-num/num-integer" 10 | name = "num-integer" 11 | version = "0.1.46" 12 | readme = "README.md" 13 | exclude = ["/ci/*", "/.github/*"] 14 | edition = "2018" 15 | rust-version = "1.31" 16 | 17 | [package.metadata.docs.rs] 18 | features = ["std"] 19 | 20 | [dependencies.num-traits] 21 | version = "0.2.11" 22 | default-features = false 23 | features = ["i128"] 24 | 25 | [features] 26 | default = ["std"] 27 | std = ["num-traits/std"] 28 | 29 | # vestigial features, now always in effect 30 | i128 = [] 31 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # num-integer 2 | 3 | [![crate](https://img.shields.io/crates/v/num-integer.svg)](https://crates.io/crates/num-integer) 4 | [![documentation](https://docs.rs/num-integer/badge.svg)](https://docs.rs/num-integer) 5 | [![minimum rustc 1.31](https://img.shields.io/badge/rustc-1.31+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html) 6 | [![build status](https://github.com/rust-num/num-integer/workflows/master/badge.svg)](https://github.com/rust-num/num-integer/actions) 7 | 8 | `Integer` trait and functions for Rust. 9 | 10 | ## Usage 11 | 12 | Add this to your `Cargo.toml`: 13 | 14 | ```toml 15 | [dependencies] 16 | num-integer = "0.1" 17 | ``` 18 | 19 | ## Features 20 | 21 | This crate can be used without the standard library (`#![no_std]`) by disabling 22 | the default `std` feature. Use this in `Cargo.toml`: 23 | 24 | ```toml 25 | [dependencies.num-integer] 26 | version = "0.1.36" 27 | default-features = false 28 | ``` 29 | 30 | There is no functional difference with and without `std` at this time, but 31 | there may be in the future. 32 | 33 | ## Releases 34 | 35 | Release notes are available in [RELEASES.md](RELEASES.md). 36 | 37 | ## Compatibility 38 | 39 | The `num-integer` crate is tested for rustc 1.31 and greater. 40 | 41 | ## License 42 | 43 | Licensed under either of 44 | 45 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 46 | * [MIT license](http://opensource.org/licenses/MIT) 47 | 48 | at your option. 49 | 50 | ### Contribution 51 | 52 | Unless you explicitly state otherwise, any contribution intentionally submitted 53 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 54 | dual licensed as above, without any additional terms or conditions. 55 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # Release 0.1.46 (2024-02-07) 2 | 3 | - [Upgrade to 2018 edition, **MSRV 1.31**][51] 4 | - [The `Integer::divides` method is now properly deprecated][42], 5 | rather than just documented so. 6 | - [The new `Integer::dec` and `inc` methods change the value by one.][53] 7 | 8 | **Contributors**: @aobatact, @cuviper, @hkBst, @MiguelX413 9 | 10 | [42]: https://github.com/rust-num/num-integer/pull/42 11 | [51]: https://github.com/rust-num/num-integer/pull/51 12 | [53]: https://github.com/rust-num/num-integer/pull/53 13 | 14 | # Release 0.1.45 (2022-04-29) 15 | 16 | - [`Integer::next_multiple_of` and `prev_multiple_of` no longer overflow -1][45]. 17 | - [`Integer::is_multiple_of` now handles a 0 argument without panicking][47] 18 | for primitive integers. 19 | - [`ExtendedGcd` no longer has any private fields][46], making it possible for 20 | external implementations to customize `Integer::extended_gcd`. 21 | 22 | **Contributors**: @ciphergoth, @cuviper, @tspiteri, @WizardOfMenlo 23 | 24 | [45]: https://github.com/rust-num/num-integer/pull/45 25 | [46]: https://github.com/rust-num/num-integer/pull/46 26 | [47]: https://github.com/rust-num/num-integer/pull/47 27 | 28 | # Release 0.1.44 (2020-10-29) 29 | 30 | - [The "i128" feature now bypasses compiler probing][35]. The build script 31 | used to probe anyway and panic if requested support wasn't found, but 32 | sometimes this ran into bad corner cases with `autocfg`. 33 | 34 | **Contributors**: @cuviper 35 | 36 | [35]: https://github.com/rust-num/num-integer/pull/35 37 | 38 | # Release 0.1.43 (2020-06-11) 39 | 40 | - [The new `Average` trait][31] computes fast integer averages, rounded up or 41 | down, without any risk of overflow. 42 | 43 | **Contributors**: @althonos, @cuviper 44 | 45 | [31]: https://github.com/rust-num/num-integer/pull/31 46 | 47 | # Release 0.1.42 (2020-01-09) 48 | 49 | - [Updated the `autocfg` build dependency to 1.0][29]. 50 | 51 | **Contributors**: @cuviper, @dingelish 52 | 53 | [29]: https://github.com/rust-num/num-integer/pull/29 54 | 55 | # Release 0.1.41 (2019-05-21) 56 | 57 | - [Fixed feature detection on `no_std` targets][25]. 58 | 59 | **Contributors**: @cuviper 60 | 61 | [25]: https://github.com/rust-num/num-integer/pull/25 62 | 63 | # Release 0.1.40 (2019-05-20) 64 | 65 | - [Optimized primitive `gcd` by avoiding memory swaps][11]. 66 | - [Fixed `lcm(0, 0)` to return `0`, rather than panicking][18]. 67 | - [Added `Integer::div_ceil`, `next_multiple_of`, and `prev_multiple_of`][16]. 68 | - [Added `Integer::gcd_lcm`, `extended_gcd`, and `extended_gcd_lcm`][19]. 69 | 70 | **Contributors**: @cuviper, @ignatenkobrain, @smarnach, @strake 71 | 72 | [11]: https://github.com/rust-num/num-integer/pull/11 73 | [16]: https://github.com/rust-num/num-integer/pull/16 74 | [18]: https://github.com/rust-num/num-integer/pull/18 75 | [19]: https://github.com/rust-num/num-integer/pull/19 76 | 77 | # Release 0.1.39 (2018-06-20) 78 | 79 | - [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9], 80 | calculating an `Integer`'s principal roots rounded toward zero. 81 | 82 | **Contributors**: @cuviper 83 | 84 | [9]: https://github.com/rust-num/num-integer/pull/9 85 | 86 | # Release 0.1.38 (2018-05-11) 87 | 88 | - [Support for 128-bit integers is now automatically detected and enabled.][8] 89 | Setting the `i128` crate feature now causes the build script to panic if such 90 | support is not detected. 91 | 92 | **Contributors**: @cuviper 93 | 94 | [8]: https://github.com/rust-num/num-integer/pull/8 95 | 96 | # Release 0.1.37 (2018-05-10) 97 | 98 | - [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust 99 | 1.26, enabled by the new `i128` crate feature. 100 | 101 | **Contributors**: @cuviper 102 | 103 | [7]: https://github.com/rust-num/num-integer/pull/7 104 | 105 | # Release 0.1.36 (2018-02-06) 106 | 107 | - [num-integer now has its own source repository][num-356] at [rust-num/num-integer][home]. 108 | - [Corrected the argument order documented in `Integer::is_multiple_of`][1] 109 | - [There is now a `std` feature][5], enabled by default, along with the implication 110 | that building *without* this feature makes this a `#[no_std]` crate. 111 | - There is no difference in the API at this time. 112 | 113 | **Contributors**: @cuviper, @jaystrictor 114 | 115 | [home]: https://github.com/rust-num/num-integer 116 | [num-356]: https://github.com/rust-num/num/pull/356 117 | [1]: https://github.com/rust-num/num-integer/pull/1 118 | [5]: https://github.com/rust-num/num-integer/pull/5 119 | 120 | 121 | # Prior releases 122 | 123 | No prior release notes were kept. Thanks all the same to the many 124 | contributors that have made this crate what it is! 125 | 126 | -------------------------------------------------------------------------------- /benches/average.rs: -------------------------------------------------------------------------------- 1 | //! Benchmark sqrt and cbrt 2 | 3 | #![feature(test)] 4 | 5 | extern crate test; 6 | 7 | use num_integer::Integer; 8 | use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul}; 9 | use std::cmp::{max, min}; 10 | use std::fmt::Debug; 11 | use test::{black_box, Bencher}; 12 | 13 | // --- Utilities for RNG ---------------------------------------------------- 14 | 15 | trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} 16 | 17 | impl BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} 18 | 19 | // Simple PRNG so we don't have to worry about rand compatibility 20 | fn lcg(x: T) -> T 21 | where 22 | u32: AsPrimitive, 23 | T: BenchInteger, 24 | { 25 | // LCG parameters from Numerical Recipes 26 | // (but we're applying it to arbitrary sizes) 27 | const LCG_A: u32 = 1664525; 28 | const LCG_C: u32 = 1013904223; 29 | x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_()) 30 | } 31 | 32 | // --- Alt. Implementations ------------------------------------------------- 33 | 34 | trait NaiveAverage { 35 | fn naive_average_ceil(&self, other: &Self) -> Self; 36 | fn naive_average_floor(&self, other: &Self) -> Self; 37 | } 38 | 39 | trait UncheckedAverage { 40 | fn unchecked_average_ceil(&self, other: &Self) -> Self; 41 | fn unchecked_average_floor(&self, other: &Self) -> Self; 42 | } 43 | 44 | trait ModuloAverage { 45 | fn modulo_average_ceil(&self, other: &Self) -> Self; 46 | fn modulo_average_floor(&self, other: &Self) -> Self; 47 | } 48 | 49 | macro_rules! naive_average { 50 | ($T:ident) => { 51 | impl super::NaiveAverage for $T { 52 | fn naive_average_floor(&self, other: &$T) -> $T { 53 | match self.checked_add(*other) { 54 | Some(z) => Integer::div_floor(&z, &2), 55 | None => { 56 | if self > other { 57 | let diff = self - other; 58 | other + Integer::div_floor(&diff, &2) 59 | } else { 60 | let diff = other - self; 61 | self + Integer::div_floor(&diff, &2) 62 | } 63 | } 64 | } 65 | } 66 | fn naive_average_ceil(&self, other: &$T) -> $T { 67 | match self.checked_add(*other) { 68 | Some(z) => Integer::div_ceil(&z, &2), 69 | None => { 70 | if self > other { 71 | let diff = self - other; 72 | self - Integer::div_floor(&diff, &2) 73 | } else { 74 | let diff = other - self; 75 | other - Integer::div_floor(&diff, &2) 76 | } 77 | } 78 | } 79 | } 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unchecked_average { 85 | ($T:ident) => { 86 | impl super::UncheckedAverage for $T { 87 | fn unchecked_average_floor(&self, other: &$T) -> $T { 88 | self.wrapping_add(*other) / 2 89 | } 90 | fn unchecked_average_ceil(&self, other: &$T) -> $T { 91 | (self.wrapping_add(*other) / 2).wrapping_add(1) 92 | } 93 | } 94 | }; 95 | } 96 | 97 | macro_rules! modulo_average { 98 | ($T:ident) => { 99 | impl super::ModuloAverage for $T { 100 | fn modulo_average_ceil(&self, other: &$T) -> $T { 101 | let (q1, r1) = self.div_mod_floor(&2); 102 | let (q2, r2) = other.div_mod_floor(&2); 103 | q1 + q2 + (r1 | r2) 104 | } 105 | fn modulo_average_floor(&self, other: &$T) -> $T { 106 | let (q1, r1) = self.div_mod_floor(&2); 107 | let (q2, r2) = other.div_mod_floor(&2); 108 | q1 + q2 + (r1 * r2) 109 | } 110 | } 111 | }; 112 | } 113 | 114 | // --- Bench functions ------------------------------------------------------ 115 | 116 | fn bench_unchecked(b: &mut Bencher, v: &[(T, T)], f: F) 117 | where 118 | T: Integer + Debug + Copy, 119 | F: Fn(&T, &T) -> T, 120 | { 121 | b.iter(|| { 122 | for (x, y) in v { 123 | black_box(f(x, y)); 124 | } 125 | }); 126 | } 127 | 128 | fn bench_ceil(b: &mut Bencher, v: &[(T, T)], f: F) 129 | where 130 | T: Integer + Debug + Copy, 131 | F: Fn(&T, &T) -> T, 132 | { 133 | for &(i, j) in v { 134 | let rt = f(&i, &j); 135 | let (a, b) = (min(i, j), max(i, j)); 136 | // if both number are the same sign, check rt is in the middle 137 | if (a < T::zero()) == (b < T::zero()) { 138 | if (b - a).is_even() { 139 | assert_eq!(rt - a, b - rt); 140 | } else { 141 | assert_eq!(rt - a, b - rt + T::one()); 142 | } 143 | // if both number have a different sign, 144 | } else if (a + b).is_even() { 145 | assert_eq!(rt, (a + b) / (T::one() + T::one())) 146 | } else { 147 | assert_eq!(rt, (a + b + T::one()) / (T::one() + T::one())) 148 | } 149 | } 150 | bench_unchecked(b, v, f); 151 | } 152 | 153 | fn bench_floor(b: &mut Bencher, v: &[(T, T)], f: F) 154 | where 155 | T: Integer + Debug + Copy, 156 | F: Fn(&T, &T) -> T, 157 | { 158 | for &(i, j) in v { 159 | let rt = f(&i, &j); 160 | let (a, b) = (min(i, j), max(i, j)); 161 | // if both number are the same sign, check rt is in the middle 162 | if (a < T::zero()) == (b < T::zero()) { 163 | if (b - a).is_even() { 164 | assert_eq!(rt - a, b - rt); 165 | } else { 166 | assert_eq!(rt - a + T::one(), b - rt); 167 | } 168 | // if both number have a different sign, 169 | } else if (a + b).is_even() { 170 | assert_eq!(rt, (a + b) / (T::one() + T::one())) 171 | } else { 172 | assert_eq!(rt, (a + b - T::one()) / (T::one() + T::one())) 173 | } 174 | } 175 | bench_unchecked(b, v, f); 176 | } 177 | 178 | // --- Bench implementation ------------------------------------------------- 179 | 180 | macro_rules! bench_average { 181 | ($($T:ident),*) => {$( 182 | mod $T { 183 | use test::Bencher; 184 | use num_integer::{Average, Integer}; 185 | use super::{UncheckedAverage, NaiveAverage, ModuloAverage}; 186 | use super::{bench_ceil, bench_floor, bench_unchecked}; 187 | 188 | naive_average!($T); 189 | unchecked_average!($T); 190 | modulo_average!($T); 191 | 192 | const SIZE: $T = 30; 193 | 194 | fn overflowing() -> Vec<($T, $T)> { 195 | (($T::max_value()-SIZE)..$T::max_value()) 196 | .flat_map(|x| -> Vec<_> { 197 | (($T::max_value()-100)..($T::max_value()-100+SIZE)) 198 | .map(|y| (x, y)) 199 | .collect() 200 | }) 201 | .collect() 202 | } 203 | 204 | fn small() -> Vec<($T, $T)> { 205 | (0..SIZE) 206 | .flat_map(|x| -> Vec<_> {(0..SIZE).map(|y| (x, y)).collect()}) 207 | .collect() 208 | } 209 | 210 | fn rand() -> Vec<($T, $T)> { 211 | small() 212 | .into_iter() 213 | .map(|(x, y)| (super::lcg(x), super::lcg(y))) 214 | .collect() 215 | } 216 | 217 | mod ceil { 218 | 219 | use super::*; 220 | 221 | mod small { 222 | 223 | use super::*; 224 | 225 | #[bench] 226 | fn optimized(b: &mut Bencher) { 227 | let v = small(); 228 | bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y)); 229 | } 230 | 231 | #[bench] 232 | fn naive(b: &mut Bencher) { 233 | let v = small(); 234 | bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y)); 235 | } 236 | 237 | #[bench] 238 | fn unchecked(b: &mut Bencher) { 239 | let v = small(); 240 | bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y)); 241 | } 242 | 243 | #[bench] 244 | fn modulo(b: &mut Bencher) { 245 | let v = small(); 246 | bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y)); 247 | } 248 | } 249 | 250 | mod overflowing { 251 | 252 | use super::*; 253 | 254 | #[bench] 255 | fn optimized(b: &mut Bencher) { 256 | let v = overflowing(); 257 | bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y)); 258 | } 259 | 260 | #[bench] 261 | fn naive(b: &mut Bencher) { 262 | let v = overflowing(); 263 | bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y)); 264 | } 265 | 266 | #[bench] 267 | fn unchecked(b: &mut Bencher) { 268 | let v = overflowing(); 269 | bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y)); 270 | } 271 | 272 | #[bench] 273 | fn modulo(b: &mut Bencher) { 274 | let v = overflowing(); 275 | bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y)); 276 | } 277 | } 278 | 279 | mod rand { 280 | 281 | use super::*; 282 | 283 | #[bench] 284 | fn optimized(b: &mut Bencher) { 285 | let v = rand(); 286 | bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y)); 287 | } 288 | 289 | #[bench] 290 | fn naive(b: &mut Bencher) { 291 | let v = rand(); 292 | bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y)); 293 | } 294 | 295 | #[bench] 296 | fn unchecked(b: &mut Bencher) { 297 | let v = rand(); 298 | bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y)); 299 | } 300 | 301 | #[bench] 302 | fn modulo(b: &mut Bencher) { 303 | let v = rand(); 304 | bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y)); 305 | } 306 | } 307 | 308 | } 309 | 310 | mod floor { 311 | 312 | use super::*; 313 | 314 | mod small { 315 | 316 | use super::*; 317 | 318 | #[bench] 319 | fn optimized(b: &mut Bencher) { 320 | let v = small(); 321 | bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y)); 322 | } 323 | 324 | #[bench] 325 | fn naive(b: &mut Bencher) { 326 | let v = small(); 327 | bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y)); 328 | } 329 | 330 | #[bench] 331 | fn unchecked(b: &mut Bencher) { 332 | let v = small(); 333 | bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y)); 334 | } 335 | 336 | #[bench] 337 | fn modulo(b: &mut Bencher) { 338 | let v = small(); 339 | bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y)); 340 | } 341 | } 342 | 343 | mod overflowing { 344 | 345 | use super::*; 346 | 347 | #[bench] 348 | fn optimized(b: &mut Bencher) { 349 | let v = overflowing(); 350 | bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y)); 351 | } 352 | 353 | #[bench] 354 | fn naive(b: &mut Bencher) { 355 | let v = overflowing(); 356 | bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y)); 357 | } 358 | 359 | #[bench] 360 | fn unchecked(b: &mut Bencher) { 361 | let v = overflowing(); 362 | bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y)); 363 | } 364 | 365 | #[bench] 366 | fn modulo(b: &mut Bencher) { 367 | let v = overflowing(); 368 | bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y)); 369 | } 370 | } 371 | 372 | mod rand { 373 | 374 | use super::*; 375 | 376 | #[bench] 377 | fn optimized(b: &mut Bencher) { 378 | let v = rand(); 379 | bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y)); 380 | } 381 | 382 | #[bench] 383 | fn naive(b: &mut Bencher) { 384 | let v = rand(); 385 | bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y)); 386 | } 387 | 388 | #[bench] 389 | fn unchecked(b: &mut Bencher) { 390 | let v = rand(); 391 | bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y)); 392 | } 393 | 394 | #[bench] 395 | fn modulo(b: &mut Bencher) { 396 | let v = rand(); 397 | bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y)); 398 | } 399 | } 400 | 401 | } 402 | 403 | } 404 | )*} 405 | } 406 | 407 | bench_average!(i8, i16, i32, i64, i128, isize); 408 | bench_average!(u8, u16, u32, u64, u128, usize); 409 | -------------------------------------------------------------------------------- /benches/gcd.rs: -------------------------------------------------------------------------------- 1 | //! Benchmark comparing the current GCD implemtation against an older one. 2 | 3 | #![feature(test)] 4 | 5 | extern crate test; 6 | 7 | use num_integer::Integer; 8 | use num_traits::{AsPrimitive, Bounded, Signed}; 9 | use test::{black_box, Bencher}; 10 | 11 | trait GcdOld: Integer { 12 | fn gcd_old(&self, other: &Self) -> Self; 13 | } 14 | 15 | macro_rules! impl_gcd_old_for_isize { 16 | ($T:ty) => { 17 | impl GcdOld for $T { 18 | /// Calculates the Greatest Common Divisor (GCD) of the number and 19 | /// `other`. The result is always positive. 20 | #[inline] 21 | fn gcd_old(&self, other: &Self) -> Self { 22 | // Use Stein's algorithm 23 | let mut m = *self; 24 | let mut n = *other; 25 | if m == 0 || n == 0 { 26 | return (m | n).abs(); 27 | } 28 | 29 | // find common factors of 2 30 | let shift = (m | n).trailing_zeros(); 31 | 32 | // The algorithm needs positive numbers, but the minimum value 33 | // can't be represented as a positive one. 34 | // It's also a power of two, so the gcd can be 35 | // calculated by bitshifting in that case 36 | 37 | // Assuming two's complement, the number created by the shift 38 | // is positive for all numbers except gcd = abs(min value) 39 | // The call to .abs() causes a panic in debug mode 40 | if m == Self::min_value() || n == Self::min_value() { 41 | return (1 << shift).abs(); 42 | } 43 | 44 | // guaranteed to be positive now, rest like unsigned algorithm 45 | m = m.abs(); 46 | n = n.abs(); 47 | 48 | // divide n and m by 2 until odd 49 | // m inside loop 50 | n >>= n.trailing_zeros(); 51 | 52 | while m != 0 { 53 | m >>= m.trailing_zeros(); 54 | if n > m { 55 | std::mem::swap(&mut n, &mut m) 56 | } 57 | m -= n; 58 | } 59 | 60 | n << shift 61 | } 62 | } 63 | }; 64 | } 65 | 66 | impl_gcd_old_for_isize!(i8); 67 | impl_gcd_old_for_isize!(i16); 68 | impl_gcd_old_for_isize!(i32); 69 | impl_gcd_old_for_isize!(i64); 70 | impl_gcd_old_for_isize!(isize); 71 | impl_gcd_old_for_isize!(i128); 72 | 73 | macro_rules! impl_gcd_old_for_usize { 74 | ($T:ty) => { 75 | impl GcdOld for $T { 76 | /// Calculates the Greatest Common Divisor (GCD) of the number and 77 | /// `other`. The result is always positive. 78 | #[inline] 79 | fn gcd_old(&self, other: &Self) -> Self { 80 | // Use Stein's algorithm 81 | let mut m = *self; 82 | let mut n = *other; 83 | if m == 0 || n == 0 { 84 | return m | n; 85 | } 86 | 87 | // find common factors of 2 88 | let shift = (m | n).trailing_zeros(); 89 | 90 | // divide n and m by 2 until odd 91 | // m inside loop 92 | n >>= n.trailing_zeros(); 93 | 94 | while m != 0 { 95 | m >>= m.trailing_zeros(); 96 | if n > m { 97 | std::mem::swap(&mut n, &mut m) 98 | } 99 | m -= n; 100 | } 101 | 102 | n << shift 103 | } 104 | } 105 | }; 106 | } 107 | 108 | impl_gcd_old_for_usize!(u8); 109 | impl_gcd_old_for_usize!(u16); 110 | impl_gcd_old_for_usize!(u32); 111 | impl_gcd_old_for_usize!(u64); 112 | impl_gcd_old_for_usize!(usize); 113 | impl_gcd_old_for_usize!(u128); 114 | 115 | /// Return an iterator that yields all Fibonacci numbers fitting into a u128. 116 | fn fibonacci() -> impl Iterator { 117 | (0..185).scan((0, 1), |&mut (ref mut a, ref mut b), _| { 118 | let tmp = *a; 119 | *a = *b; 120 | *b += tmp; 121 | Some(*b) 122 | }) 123 | } 124 | 125 | fn run_bench(b: &mut Bencher, gcd: fn(&T, &T) -> T) 126 | where 127 | T: AsPrimitive, 128 | u128: AsPrimitive, 129 | { 130 | let max_value: u128 = T::max_value().as_(); 131 | let pairs: Vec<(T, T)> = fibonacci() 132 | .collect::>() 133 | .windows(2) 134 | .filter(|&pair| pair[0] <= max_value && pair[1] <= max_value) 135 | .map(|pair| (pair[0].as_(), pair[1].as_())) 136 | .collect(); 137 | b.iter(|| { 138 | for &(ref m, ref n) in &pairs { 139 | black_box(gcd(m, n)); 140 | } 141 | }); 142 | } 143 | 144 | macro_rules! bench_gcd { 145 | ($T:ident) => { 146 | mod $T { 147 | use crate::{run_bench, GcdOld}; 148 | use num_integer::Integer; 149 | use test::Bencher; 150 | 151 | #[bench] 152 | fn bench_gcd(b: &mut Bencher) { 153 | run_bench(b, $T::gcd); 154 | } 155 | 156 | #[bench] 157 | fn bench_gcd_old(b: &mut Bencher) { 158 | run_bench(b, $T::gcd_old); 159 | } 160 | } 161 | }; 162 | } 163 | 164 | bench_gcd!(u8); 165 | bench_gcd!(u16); 166 | bench_gcd!(u32); 167 | bench_gcd!(u64); 168 | bench_gcd!(u128); 169 | 170 | bench_gcd!(i8); 171 | bench_gcd!(i16); 172 | bench_gcd!(i32); 173 | bench_gcd!(i64); 174 | bench_gcd!(i128); 175 | -------------------------------------------------------------------------------- /benches/roots.rs: -------------------------------------------------------------------------------- 1 | //! Benchmark sqrt and cbrt 2 | 3 | #![feature(test)] 4 | 5 | extern crate test; 6 | 7 | use num_integer::Integer; 8 | use num_traits::checked_pow; 9 | use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul}; 10 | use test::{black_box, Bencher}; 11 | 12 | trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} 13 | 14 | impl BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} 15 | 16 | fn bench(b: &mut Bencher, v: &[T], f: F, n: u32) 17 | where 18 | T: BenchInteger, 19 | F: Fn(&T) -> T, 20 | { 21 | // Pre-validate the results... 22 | for i in v { 23 | let rt = f(i); 24 | if *i >= T::zero() { 25 | let rt1 = rt + T::one(); 26 | assert!(rt.pow(n) <= *i); 27 | if let Some(x) = checked_pow(rt1, n as usize) { 28 | assert!(*i < x); 29 | } 30 | } else { 31 | let rt1 = rt - T::one(); 32 | assert!(rt < T::zero()); 33 | assert!(*i <= rt.pow(n)); 34 | if let Some(x) = checked_pow(rt1, n as usize) { 35 | assert!(x < *i); 36 | } 37 | }; 38 | } 39 | 40 | // Now just run as fast as we can! 41 | b.iter(|| { 42 | for i in v { 43 | black_box(f(i)); 44 | } 45 | }); 46 | } 47 | 48 | // Simple PRNG so we don't have to worry about rand compatibility 49 | fn lcg(x: T) -> T 50 | where 51 | u32: AsPrimitive, 52 | T: BenchInteger, 53 | { 54 | // LCG parameters from Numerical Recipes 55 | // (but we're applying it to arbitrary sizes) 56 | const LCG_A: u32 = 1664525; 57 | const LCG_C: u32 = 1013904223; 58 | x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_()) 59 | } 60 | 61 | fn bench_rand(b: &mut Bencher, f: F, n: u32) 62 | where 63 | u32: AsPrimitive, 64 | T: BenchInteger, 65 | F: Fn(&T) -> T, 66 | { 67 | let mut x: T = 3u32.as_(); 68 | let v: Vec = (0..1000) 69 | .map(|_| { 70 | x = lcg(x); 71 | x 72 | }) 73 | .collect(); 74 | bench(b, &v, f, n); 75 | } 76 | 77 | fn bench_rand_pos(b: &mut Bencher, f: F, n: u32) 78 | where 79 | u32: AsPrimitive, 80 | T: BenchInteger, 81 | F: Fn(&T) -> T, 82 | { 83 | let mut x: T = 3u32.as_(); 84 | let v: Vec = (0..1000) 85 | .map(|_| { 86 | x = lcg(x); 87 | while x < T::zero() { 88 | x = lcg(x); 89 | } 90 | x 91 | }) 92 | .collect(); 93 | bench(b, &v, f, n); 94 | } 95 | 96 | fn bench_small(b: &mut Bencher, f: F, n: u32) 97 | where 98 | u32: AsPrimitive, 99 | T: BenchInteger, 100 | F: Fn(&T) -> T, 101 | { 102 | let v: Vec = (0..1000).map(|i| i.as_()).collect(); 103 | bench(b, &v, f, n); 104 | } 105 | 106 | fn bench_small_pos(b: &mut Bencher, f: F, n: u32) 107 | where 108 | u32: AsPrimitive, 109 | T: BenchInteger, 110 | F: Fn(&T) -> T, 111 | { 112 | let v: Vec = (0..1000) 113 | .map(|i| i.as_().mod_floor(&T::max_value())) 114 | .collect(); 115 | bench(b, &v, f, n); 116 | } 117 | 118 | macro_rules! bench_roots { 119 | ($($T:ident),*) => {$( 120 | mod $T { 121 | use test::Bencher; 122 | use num_integer::Roots; 123 | 124 | #[bench] 125 | fn sqrt_rand(b: &mut Bencher) { 126 | crate::bench_rand_pos(b, $T::sqrt, 2); 127 | } 128 | 129 | #[bench] 130 | fn sqrt_small(b: &mut Bencher) { 131 | crate::bench_small_pos(b, $T::sqrt, 2); 132 | } 133 | 134 | #[bench] 135 | fn cbrt_rand(b: &mut Bencher) { 136 | crate::bench_rand(b, $T::cbrt, 3); 137 | } 138 | 139 | #[bench] 140 | fn cbrt_small(b: &mut Bencher) { 141 | crate::bench_small(b, $T::cbrt, 3); 142 | } 143 | 144 | #[bench] 145 | fn fourth_root_rand(b: &mut Bencher) { 146 | crate::bench_rand_pos(b, |x: &$T| x.nth_root(4), 4); 147 | } 148 | 149 | #[bench] 150 | fn fourth_root_small(b: &mut Bencher) { 151 | crate::bench_small_pos(b, |x: &$T| x.nth_root(4), 4); 152 | } 153 | 154 | #[bench] 155 | fn fifth_root_rand(b: &mut Bencher) { 156 | crate::bench_rand(b, |x: &$T| x.nth_root(5), 5); 157 | } 158 | 159 | #[bench] 160 | fn fifth_root_small(b: &mut Bencher) { 161 | crate::bench_small(b, |x: &$T| x.nth_root(5), 5); 162 | } 163 | } 164 | )*} 165 | } 166 | 167 | bench_roots!(i8, i16, i32, i64, i128); 168 | bench_roots!(u8, u16, u32, u64, u128); 169 | -------------------------------------------------------------------------------- /ci/rustup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Use rustup to locally run the same suite of tests as .github/workflows/ 3 | # (You should first install/update all of the versions below.) 4 | 5 | set -ex 6 | 7 | ci=$(dirname $0) 8 | for version in 1.31.0 1.51.0 1.60.0 stable beta nightly; do 9 | rustup run "$version" "$ci/test_full.sh" 10 | done 11 | -------------------------------------------------------------------------------- /ci/test_full.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | CRATE=num-integer 6 | MSRV=1.31 7 | 8 | get_rust_version() { 9 | local array=($(rustc --version)); 10 | echo "${array[1]}"; 11 | return 0; 12 | } 13 | RUST_VERSION=$(get_rust_version) 14 | 15 | check_version() { 16 | IFS=. read -ra rust <<< "$RUST_VERSION" 17 | IFS=. read -ra want <<< "$1" 18 | [[ "${rust[0]}" -gt "${want[0]}" || 19 | ( "${rust[0]}" -eq "${want[0]}" && 20 | "${rust[1]}" -ge "${want[1]}" ) 21 | ]] 22 | } 23 | 24 | echo "Testing $CRATE on rustc $RUST_VERSION" 25 | if ! check_version $MSRV ; then 26 | echo "The minimum for $CRATE is rustc $MSRV" 27 | exit 1 28 | fi 29 | 30 | FEATURES=() 31 | echo "Testing supported features: ${FEATURES[*]}" 32 | 33 | cargo generate-lockfile 34 | 35 | # num-traits 0.2.19 started using dep: features, which requires 1.60 and is 36 | # otherwise ignored down to 1.51, but we need a manual downgrade before that. 37 | check_version 1.51 || cargo update -p num-traits --precise 0.2.18 38 | 39 | set -x 40 | 41 | # test the default 42 | cargo build 43 | cargo test 44 | 45 | # test `no_std` 46 | cargo build --no-default-features 47 | cargo test --no-default-features 48 | 49 | # test each isolated feature, with and without std 50 | for feature in ${FEATURES[*]}; do 51 | cargo build --no-default-features --features="std $feature" 52 | cargo test --no-default-features --features="std $feature" 53 | 54 | cargo build --no-default-features --features="$feature" 55 | cargo test --no-default-features --features="$feature" 56 | done 57 | 58 | # test all supported features, with and without std 59 | cargo build --features="std ${FEATURES[*]}" 60 | cargo test --features="std ${FEATURES[*]}" 61 | 62 | cargo build --features="${FEATURES[*]}" 63 | cargo test --features="${FEATURES[*]}" 64 | 65 | if rustc --version | grep -q nightly; then 66 | cargo test --all-features --benches 67 | fi 68 | -------------------------------------------------------------------------------- /src/average.rs: -------------------------------------------------------------------------------- 1 | use crate::Integer; 2 | use core::ops::{BitAnd, BitOr, BitXor, Shr}; 3 | 4 | /// Provides methods to compute the average of two integers, without overflows. 5 | pub trait Average: Integer { 6 | /// Returns the ceiling value of the average of `self` and `other`. 7 | /// -- `⌈(self + other)/2⌉` 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use num_integer::Average; 13 | /// 14 | /// assert_eq!(( 3).average_ceil(&10), 7); 15 | /// assert_eq!((-2).average_ceil(&-5), -3); 16 | /// assert_eq!(( 4).average_ceil(& 4), 4); 17 | /// 18 | /// assert_eq!(u8::max_value().average_ceil(&2), 129); 19 | /// assert_eq!(i8::min_value().average_ceil(&-1), -64); 20 | /// assert_eq!(i8::min_value().average_ceil(&i8::max_value()), 0); 21 | /// ``` 22 | /// 23 | fn average_ceil(&self, other: &Self) -> Self; 24 | 25 | /// Returns the floor value of the average of `self` and `other`. 26 | /// -- `⌊(self + other)/2⌋` 27 | /// 28 | /// # Examples 29 | /// 30 | /// ``` 31 | /// use num_integer::Average; 32 | /// 33 | /// assert_eq!(( 3).average_floor(&10), 6); 34 | /// assert_eq!((-2).average_floor(&-5), -4); 35 | /// assert_eq!(( 4).average_floor(& 4), 4); 36 | /// 37 | /// assert_eq!(u8::max_value().average_floor(&2), 128); 38 | /// assert_eq!(i8::min_value().average_floor(&-1), -65); 39 | /// assert_eq!(i8::min_value().average_floor(&i8::max_value()), -1); 40 | /// ``` 41 | /// 42 | fn average_floor(&self, other: &Self) -> Self; 43 | } 44 | 45 | impl Average for I 46 | where 47 | I: Integer + Shr, 48 | for<'a, 'b> &'a I: 49 | BitAnd<&'b I, Output = I> + BitOr<&'b I, Output = I> + BitXor<&'b I, Output = I>, 50 | { 51 | // The Henry Gordon Dietz implementation as shown in the Hacker's Delight, 52 | // see http://aggregate.org/MAGIC/#Average%20of%20Integers 53 | 54 | /// Returns the floor value of the average of `self` and `other`. 55 | #[inline] 56 | fn average_floor(&self, other: &I) -> I { 57 | (self & other) + ((self ^ other) >> 1) 58 | } 59 | 60 | /// Returns the ceil value of the average of `self` and `other`. 61 | #[inline] 62 | fn average_ceil(&self, other: &I) -> I { 63 | (self | other) - ((self ^ other) >> 1) 64 | } 65 | } 66 | 67 | /// Returns the floor value of the average of `x` and `y` -- 68 | /// see [Average::average_floor](trait.Average.html#tymethod.average_floor). 69 | #[inline] 70 | pub fn average_floor(x: T, y: T) -> T { 71 | x.average_floor(&y) 72 | } 73 | /// Returns the ceiling value of the average of `x` and `y` -- 74 | /// see [Average::average_ceil](trait.Average.html#tymethod.average_ceil). 75 | #[inline] 76 | pub fn average_ceil(x: T, y: T) -> T { 77 | x.average_ceil(&y) 78 | } 79 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Integer trait and functions. 12 | //! 13 | //! ## Compatibility 14 | //! 15 | //! The `num-integer` crate is tested for rustc 1.31 and greater. 16 | 17 | #![doc(html_root_url = "https://docs.rs/num-integer/0.1")] 18 | #![no_std] 19 | 20 | use core::mem; 21 | use core::ops::Add; 22 | 23 | use num_traits::{Num, Signed, Zero}; 24 | 25 | mod roots; 26 | pub use crate::roots::Roots; 27 | pub use crate::roots::{cbrt, nth_root, sqrt}; 28 | 29 | mod average; 30 | pub use crate::average::Average; 31 | pub use crate::average::{average_ceil, average_floor}; 32 | 33 | pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { 34 | /// Floored integer division. 35 | /// 36 | /// # Examples 37 | /// 38 | /// ~~~ 39 | /// # use num_integer::Integer; 40 | /// assert!(( 8).div_floor(& 3) == 2); 41 | /// assert!(( 8).div_floor(&-3) == -3); 42 | /// assert!((-8).div_floor(& 3) == -3); 43 | /// assert!((-8).div_floor(&-3) == 2); 44 | /// 45 | /// assert!(( 1).div_floor(& 2) == 0); 46 | /// assert!(( 1).div_floor(&-2) == -1); 47 | /// assert!((-1).div_floor(& 2) == -1); 48 | /// assert!((-1).div_floor(&-2) == 0); 49 | /// ~~~ 50 | fn div_floor(&self, other: &Self) -> Self; 51 | 52 | /// Floored integer modulo, satisfying: 53 | /// 54 | /// ~~~ 55 | /// # use num_integer::Integer; 56 | /// # let n = 1; let d = 1; 57 | /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) 58 | /// ~~~ 59 | /// 60 | /// # Examples 61 | /// 62 | /// ~~~ 63 | /// # use num_integer::Integer; 64 | /// assert!(( 8).mod_floor(& 3) == 2); 65 | /// assert!(( 8).mod_floor(&-3) == -1); 66 | /// assert!((-8).mod_floor(& 3) == 1); 67 | /// assert!((-8).mod_floor(&-3) == -2); 68 | /// 69 | /// assert!(( 1).mod_floor(& 2) == 1); 70 | /// assert!(( 1).mod_floor(&-2) == -1); 71 | /// assert!((-1).mod_floor(& 2) == 1); 72 | /// assert!((-1).mod_floor(&-2) == -1); 73 | /// ~~~ 74 | fn mod_floor(&self, other: &Self) -> Self; 75 | 76 | /// Ceiled integer division. 77 | /// 78 | /// # Examples 79 | /// 80 | /// ~~~ 81 | /// # use num_integer::Integer; 82 | /// assert_eq!(( 8).div_ceil( &3), 3); 83 | /// assert_eq!(( 8).div_ceil(&-3), -2); 84 | /// assert_eq!((-8).div_ceil( &3), -2); 85 | /// assert_eq!((-8).div_ceil(&-3), 3); 86 | /// 87 | /// assert_eq!(( 1).div_ceil( &2), 1); 88 | /// assert_eq!(( 1).div_ceil(&-2), 0); 89 | /// assert_eq!((-1).div_ceil( &2), 0); 90 | /// assert_eq!((-1).div_ceil(&-2), 1); 91 | /// ~~~ 92 | fn div_ceil(&self, other: &Self) -> Self { 93 | let (q, r) = self.div_mod_floor(other); 94 | if r.is_zero() { 95 | q 96 | } else { 97 | q + Self::one() 98 | } 99 | } 100 | 101 | /// Greatest Common Divisor (GCD). 102 | /// 103 | /// # Examples 104 | /// 105 | /// ~~~ 106 | /// # use num_integer::Integer; 107 | /// assert_eq!(6.gcd(&8), 2); 108 | /// assert_eq!(7.gcd(&3), 1); 109 | /// ~~~ 110 | fn gcd(&self, other: &Self) -> Self; 111 | 112 | /// Lowest Common Multiple (LCM). 113 | /// 114 | /// # Examples 115 | /// 116 | /// ~~~ 117 | /// # use num_integer::Integer; 118 | /// assert_eq!(7.lcm(&3), 21); 119 | /// assert_eq!(2.lcm(&4), 4); 120 | /// assert_eq!(0.lcm(&0), 0); 121 | /// ~~~ 122 | fn lcm(&self, other: &Self) -> Self; 123 | 124 | /// Greatest Common Divisor (GCD) and 125 | /// Lowest Common Multiple (LCM) together. 126 | /// 127 | /// Potentially more efficient than calling `gcd` and `lcm` 128 | /// individually for identical inputs. 129 | /// 130 | /// # Examples 131 | /// 132 | /// ~~~ 133 | /// # use num_integer::Integer; 134 | /// assert_eq!(10.gcd_lcm(&4), (2, 20)); 135 | /// assert_eq!(8.gcd_lcm(&9), (1, 72)); 136 | /// ~~~ 137 | #[inline] 138 | fn gcd_lcm(&self, other: &Self) -> (Self, Self) { 139 | (self.gcd(other), self.lcm(other)) 140 | } 141 | 142 | /// Greatest common divisor and Bézout coefficients. 143 | /// 144 | /// # Examples 145 | /// 146 | /// ~~~ 147 | /// # fn main() { 148 | /// # use num_integer::{ExtendedGcd, Integer}; 149 | /// # use num_traits::NumAssign; 150 | /// fn check(a: A, b: A) -> bool { 151 | /// let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); 152 | /// gcd == x * a + y * b 153 | /// } 154 | /// assert!(check(10isize, 4isize)); 155 | /// assert!(check(8isize, 9isize)); 156 | /// # } 157 | /// ~~~ 158 | #[inline] 159 | fn extended_gcd(&self, other: &Self) -> ExtendedGcd 160 | where 161 | Self: Clone, 162 | { 163 | let mut s = (Self::zero(), Self::one()); 164 | let mut t = (Self::one(), Self::zero()); 165 | let mut r = (other.clone(), self.clone()); 166 | 167 | while !r.0.is_zero() { 168 | let q = r.1.clone() / r.0.clone(); 169 | let f = |mut r: (Self, Self)| { 170 | mem::swap(&mut r.0, &mut r.1); 171 | r.0 = r.0 - q.clone() * r.1.clone(); 172 | r 173 | }; 174 | r = f(r); 175 | s = f(s); 176 | t = f(t); 177 | } 178 | 179 | if r.1 >= Self::zero() { 180 | ExtendedGcd { 181 | gcd: r.1, 182 | x: s.1, 183 | y: t.1, 184 | } 185 | } else { 186 | ExtendedGcd { 187 | gcd: Self::zero() - r.1, 188 | x: Self::zero() - s.1, 189 | y: Self::zero() - t.1, 190 | } 191 | } 192 | } 193 | 194 | /// Greatest common divisor, least common multiple, and Bézout coefficients. 195 | #[inline] 196 | fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) 197 | where 198 | Self: Clone + Signed, 199 | { 200 | (self.extended_gcd(other), self.lcm(other)) 201 | } 202 | 203 | /// Deprecated, use `is_multiple_of` instead. 204 | #[deprecated(note = "Please use is_multiple_of instead")] 205 | #[inline] 206 | fn divides(&self, other: &Self) -> bool { 207 | self.is_multiple_of(other) 208 | } 209 | 210 | /// Returns `true` if `self` is a multiple of `other`. 211 | /// 212 | /// # Examples 213 | /// 214 | /// ~~~ 215 | /// # use num_integer::Integer; 216 | /// assert_eq!(9.is_multiple_of(&3), true); 217 | /// assert_eq!(3.is_multiple_of(&9), false); 218 | /// ~~~ 219 | fn is_multiple_of(&self, other: &Self) -> bool; 220 | 221 | /// Returns `true` if the number is even. 222 | /// 223 | /// # Examples 224 | /// 225 | /// ~~~ 226 | /// # use num_integer::Integer; 227 | /// assert_eq!(3.is_even(), false); 228 | /// assert_eq!(4.is_even(), true); 229 | /// ~~~ 230 | fn is_even(&self) -> bool; 231 | 232 | /// Returns `true` if the number is odd. 233 | /// 234 | /// # Examples 235 | /// 236 | /// ~~~ 237 | /// # use num_integer::Integer; 238 | /// assert_eq!(3.is_odd(), true); 239 | /// assert_eq!(4.is_odd(), false); 240 | /// ~~~ 241 | fn is_odd(&self) -> bool; 242 | 243 | /// Simultaneous truncated integer division and modulus. 244 | /// Returns `(quotient, remainder)`. 245 | /// 246 | /// # Examples 247 | /// 248 | /// ~~~ 249 | /// # use num_integer::Integer; 250 | /// assert_eq!(( 8).div_rem( &3), ( 2, 2)); 251 | /// assert_eq!(( 8).div_rem(&-3), (-2, 2)); 252 | /// assert_eq!((-8).div_rem( &3), (-2, -2)); 253 | /// assert_eq!((-8).div_rem(&-3), ( 2, -2)); 254 | /// 255 | /// assert_eq!(( 1).div_rem( &2), ( 0, 1)); 256 | /// assert_eq!(( 1).div_rem(&-2), ( 0, 1)); 257 | /// assert_eq!((-1).div_rem( &2), ( 0, -1)); 258 | /// assert_eq!((-1).div_rem(&-2), ( 0, -1)); 259 | /// ~~~ 260 | fn div_rem(&self, other: &Self) -> (Self, Self); 261 | 262 | /// Simultaneous floored integer division and modulus. 263 | /// Returns `(quotient, remainder)`. 264 | /// 265 | /// # Examples 266 | /// 267 | /// ~~~ 268 | /// # use num_integer::Integer; 269 | /// assert_eq!(( 8).div_mod_floor( &3), ( 2, 2)); 270 | /// assert_eq!(( 8).div_mod_floor(&-3), (-3, -1)); 271 | /// assert_eq!((-8).div_mod_floor( &3), (-3, 1)); 272 | /// assert_eq!((-8).div_mod_floor(&-3), ( 2, -2)); 273 | /// 274 | /// assert_eq!(( 1).div_mod_floor( &2), ( 0, 1)); 275 | /// assert_eq!(( 1).div_mod_floor(&-2), (-1, -1)); 276 | /// assert_eq!((-1).div_mod_floor( &2), (-1, 1)); 277 | /// assert_eq!((-1).div_mod_floor(&-2), ( 0, -1)); 278 | /// ~~~ 279 | fn div_mod_floor(&self, other: &Self) -> (Self, Self) { 280 | (self.div_floor(other), self.mod_floor(other)) 281 | } 282 | 283 | /// Rounds up to nearest multiple of argument. 284 | /// 285 | /// # Notes 286 | /// 287 | /// For signed types, `a.next_multiple_of(b) = a.prev_multiple_of(b.neg())`. 288 | /// 289 | /// # Examples 290 | /// 291 | /// ~~~ 292 | /// # use num_integer::Integer; 293 | /// assert_eq!(( 16).next_multiple_of(& 8), 16); 294 | /// assert_eq!(( 23).next_multiple_of(& 8), 24); 295 | /// assert_eq!(( 16).next_multiple_of(&-8), 16); 296 | /// assert_eq!(( 23).next_multiple_of(&-8), 16); 297 | /// assert_eq!((-16).next_multiple_of(& 8), -16); 298 | /// assert_eq!((-23).next_multiple_of(& 8), -16); 299 | /// assert_eq!((-16).next_multiple_of(&-8), -16); 300 | /// assert_eq!((-23).next_multiple_of(&-8), -24); 301 | /// ~~~ 302 | #[inline] 303 | fn next_multiple_of(&self, other: &Self) -> Self 304 | where 305 | Self: Clone, 306 | { 307 | let m = self.mod_floor(other); 308 | self.clone() 309 | + if m.is_zero() { 310 | Self::zero() 311 | } else { 312 | other.clone() - m 313 | } 314 | } 315 | 316 | /// Rounds down to nearest multiple of argument. 317 | /// 318 | /// # Notes 319 | /// 320 | /// For signed types, `a.prev_multiple_of(b) = a.next_multiple_of(b.neg())`. 321 | /// 322 | /// # Examples 323 | /// 324 | /// ~~~ 325 | /// # use num_integer::Integer; 326 | /// assert_eq!(( 16).prev_multiple_of(& 8), 16); 327 | /// assert_eq!(( 23).prev_multiple_of(& 8), 16); 328 | /// assert_eq!(( 16).prev_multiple_of(&-8), 16); 329 | /// assert_eq!(( 23).prev_multiple_of(&-8), 24); 330 | /// assert_eq!((-16).prev_multiple_of(& 8), -16); 331 | /// assert_eq!((-23).prev_multiple_of(& 8), -24); 332 | /// assert_eq!((-16).prev_multiple_of(&-8), -16); 333 | /// assert_eq!((-23).prev_multiple_of(&-8), -16); 334 | /// ~~~ 335 | #[inline] 336 | fn prev_multiple_of(&self, other: &Self) -> Self 337 | where 338 | Self: Clone, 339 | { 340 | self.clone() - self.mod_floor(other) 341 | } 342 | 343 | /// Decrements self by one. 344 | /// 345 | /// # Examples 346 | /// 347 | /// ~~~ 348 | /// # use num_integer::Integer; 349 | /// let mut x: i32 = 43; 350 | /// x.dec(); 351 | /// assert_eq!(x, 42); 352 | /// ~~~ 353 | fn dec(&mut self) 354 | where 355 | Self: Clone, 356 | { 357 | *self = self.clone() - Self::one() 358 | } 359 | 360 | /// Increments self by one. 361 | /// 362 | /// # Examples 363 | /// 364 | /// ~~~ 365 | /// # use num_integer::Integer; 366 | /// let mut x: i32 = 41; 367 | /// x.inc(); 368 | /// assert_eq!(x, 42); 369 | /// ~~~ 370 | fn inc(&mut self) 371 | where 372 | Self: Clone, 373 | { 374 | *self = self.clone() + Self::one() 375 | } 376 | } 377 | 378 | /// Greatest common divisor and Bézout coefficients 379 | /// 380 | /// ```no_build 381 | /// let e = isize::extended_gcd(a, b); 382 | /// assert_eq!(e.gcd, e.x*a + e.y*b); 383 | /// ``` 384 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 385 | pub struct ExtendedGcd { 386 | pub gcd: A, 387 | pub x: A, 388 | pub y: A, 389 | } 390 | 391 | /// Simultaneous integer division and modulus 392 | #[inline] 393 | pub fn div_rem(x: T, y: T) -> (T, T) { 394 | x.div_rem(&y) 395 | } 396 | /// Floored integer division 397 | #[inline] 398 | pub fn div_floor(x: T, y: T) -> T { 399 | x.div_floor(&y) 400 | } 401 | /// Floored integer modulus 402 | #[inline] 403 | pub fn mod_floor(x: T, y: T) -> T { 404 | x.mod_floor(&y) 405 | } 406 | /// Simultaneous floored integer division and modulus 407 | #[inline] 408 | pub fn div_mod_floor(x: T, y: T) -> (T, T) { 409 | x.div_mod_floor(&y) 410 | } 411 | /// Ceiled integer division 412 | #[inline] 413 | pub fn div_ceil(x: T, y: T) -> T { 414 | x.div_ceil(&y) 415 | } 416 | 417 | /// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The 418 | /// result is always non-negative. 419 | #[inline(always)] 420 | pub fn gcd(x: T, y: T) -> T { 421 | x.gcd(&y) 422 | } 423 | /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. 424 | #[inline(always)] 425 | pub fn lcm(x: T, y: T) -> T { 426 | x.lcm(&y) 427 | } 428 | 429 | /// Calculates the Greatest Common Divisor (GCD) and 430 | /// Lowest Common Multiple (LCM) of the number and `other`. 431 | #[inline(always)] 432 | pub fn gcd_lcm(x: T, y: T) -> (T, T) { 433 | x.gcd_lcm(&y) 434 | } 435 | 436 | macro_rules! impl_integer_for_isize { 437 | ($T:ty, $test_mod:ident) => { 438 | impl Integer for $T { 439 | /// Floored integer division 440 | #[inline] 441 | fn div_floor(&self, other: &Self) -> Self { 442 | // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, 443 | // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) 444 | let (d, r) = self.div_rem(other); 445 | if (r > 0 && *other < 0) || (r < 0 && *other > 0) { 446 | d - 1 447 | } else { 448 | d 449 | } 450 | } 451 | 452 | /// Floored integer modulo 453 | #[inline] 454 | fn mod_floor(&self, other: &Self) -> Self { 455 | // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, 456 | // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) 457 | let r = *self % *other; 458 | if (r > 0 && *other < 0) || (r < 0 && *other > 0) { 459 | r + *other 460 | } else { 461 | r 462 | } 463 | } 464 | 465 | /// Calculates `div_floor` and `mod_floor` simultaneously 466 | #[inline] 467 | fn div_mod_floor(&self, other: &Self) -> (Self, Self) { 468 | // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, 469 | // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) 470 | let (d, r) = self.div_rem(other); 471 | if (r > 0 && *other < 0) || (r < 0 && *other > 0) { 472 | (d - 1, r + *other) 473 | } else { 474 | (d, r) 475 | } 476 | } 477 | 478 | #[inline] 479 | fn div_ceil(&self, other: &Self) -> Self { 480 | let (d, r) = self.div_rem(other); 481 | if (r > 0 && *other > 0) || (r < 0 && *other < 0) { 482 | d + 1 483 | } else { 484 | d 485 | } 486 | } 487 | 488 | /// Calculates the Greatest Common Divisor (GCD) of the number and 489 | /// `other`. The result is always non-negative. 490 | #[inline] 491 | fn gcd(&self, other: &Self) -> Self { 492 | // Use Stein's algorithm 493 | let mut m = *self; 494 | let mut n = *other; 495 | if m == 0 || n == 0 { 496 | return (m | n).abs(); 497 | } 498 | 499 | // find common factors of 2 500 | let shift = (m | n).trailing_zeros(); 501 | 502 | // The algorithm needs positive numbers, but the minimum value 503 | // can't be represented as a positive one. 504 | // It's also a power of two, so the gcd can be 505 | // calculated by bitshifting in that case 506 | 507 | // Assuming two's complement, the number created by the shift 508 | // is positive for all numbers except gcd = abs(min value) 509 | // The call to .abs() causes a panic in debug mode 510 | if m == Self::min_value() || n == Self::min_value() { 511 | return (1 << shift).abs(); 512 | } 513 | 514 | // guaranteed to be positive now, rest like unsigned algorithm 515 | m = m.abs(); 516 | n = n.abs(); 517 | 518 | // divide n and m by 2 until odd 519 | m >>= m.trailing_zeros(); 520 | n >>= n.trailing_zeros(); 521 | 522 | while m != n { 523 | if m > n { 524 | m -= n; 525 | m >>= m.trailing_zeros(); 526 | } else { 527 | n -= m; 528 | n >>= n.trailing_zeros(); 529 | } 530 | } 531 | m << shift 532 | } 533 | 534 | #[inline] 535 | fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) { 536 | let egcd = self.extended_gcd(other); 537 | // should not have to recalculate abs 538 | let lcm = if egcd.gcd.is_zero() { 539 | Self::zero() 540 | } else { 541 | (*self * (*other / egcd.gcd)).abs() 542 | }; 543 | (egcd, lcm) 544 | } 545 | 546 | /// Calculates the Lowest Common Multiple (LCM) of the number and 547 | /// `other`. 548 | #[inline] 549 | fn lcm(&self, other: &Self) -> Self { 550 | self.gcd_lcm(other).1 551 | } 552 | 553 | /// Calculates the Greatest Common Divisor (GCD) and 554 | /// Lowest Common Multiple (LCM) of the number and `other`. 555 | #[inline] 556 | fn gcd_lcm(&self, other: &Self) -> (Self, Self) { 557 | if self.is_zero() && other.is_zero() { 558 | return (Self::zero(), Self::zero()); 559 | } 560 | let gcd = self.gcd(other); 561 | // should not have to recalculate abs 562 | let lcm = (*self * (*other / gcd)).abs(); 563 | (gcd, lcm) 564 | } 565 | 566 | /// Returns `true` if the number is a multiple of `other`. 567 | #[inline] 568 | fn is_multiple_of(&self, other: &Self) -> bool { 569 | if other.is_zero() { 570 | return self.is_zero(); 571 | } 572 | *self % *other == 0 573 | } 574 | 575 | /// Returns `true` if the number is divisible by `2` 576 | #[inline] 577 | fn is_even(&self) -> bool { 578 | (*self) & 1 == 0 579 | } 580 | 581 | /// Returns `true` if the number is not divisible by `2` 582 | #[inline] 583 | fn is_odd(&self) -> bool { 584 | !self.is_even() 585 | } 586 | 587 | /// Simultaneous truncated integer division and modulus. 588 | #[inline] 589 | fn div_rem(&self, other: &Self) -> (Self, Self) { 590 | (*self / *other, *self % *other) 591 | } 592 | 593 | /// Rounds up to nearest multiple of argument. 594 | #[inline] 595 | fn next_multiple_of(&self, other: &Self) -> Self { 596 | // Avoid the overflow of `MIN % -1` 597 | if *other == -1 { 598 | return *self; 599 | } 600 | 601 | let m = Integer::mod_floor(self, other); 602 | *self + if m == 0 { 0 } else { other - m } 603 | } 604 | 605 | /// Rounds down to nearest multiple of argument. 606 | #[inline] 607 | fn prev_multiple_of(&self, other: &Self) -> Self { 608 | // Avoid the overflow of `MIN % -1` 609 | if *other == -1 { 610 | return *self; 611 | } 612 | 613 | *self - Integer::mod_floor(self, other) 614 | } 615 | } 616 | 617 | #[cfg(test)] 618 | mod $test_mod { 619 | use crate::Integer; 620 | use core::mem; 621 | 622 | /// Checks that the division rule holds for: 623 | /// 624 | /// - `n`: numerator (dividend) 625 | /// - `d`: denominator (divisor) 626 | /// - `qr`: quotient and remainder 627 | #[cfg(test)] 628 | fn test_division_rule((n, d): ($T, $T), (q, r): ($T, $T)) { 629 | assert_eq!(d * q + r, n); 630 | } 631 | 632 | #[test] 633 | fn test_div_rem() { 634 | fn test_nd_dr(nd: ($T, $T), qr: ($T, $T)) { 635 | let (n, d) = nd; 636 | let separate_div_rem = (n / d, n % d); 637 | let combined_div_rem = n.div_rem(&d); 638 | 639 | test_division_rule(nd, qr); 640 | 641 | assert_eq!(separate_div_rem, qr); 642 | assert_eq!(combined_div_rem, qr); 643 | } 644 | 645 | test_nd_dr((8, 3), (2, 2)); 646 | test_nd_dr((8, -3), (-2, 2)); 647 | test_nd_dr((-8, 3), (-2, -2)); 648 | test_nd_dr((-8, -3), (2, -2)); 649 | 650 | test_nd_dr((1, 2), (0, 1)); 651 | test_nd_dr((1, -2), (0, 1)); 652 | test_nd_dr((-1, 2), (0, -1)); 653 | test_nd_dr((-1, -2), (0, -1)); 654 | } 655 | 656 | #[test] 657 | fn test_div_mod_floor() { 658 | fn test_nd_dm(nd: ($T, $T), dm: ($T, $T)) { 659 | let (n, d) = nd; 660 | let separate_div_mod_floor = 661 | (Integer::div_floor(&n, &d), Integer::mod_floor(&n, &d)); 662 | let combined_div_mod_floor = Integer::div_mod_floor(&n, &d); 663 | 664 | test_division_rule(nd, dm); 665 | 666 | assert_eq!(separate_div_mod_floor, dm); 667 | assert_eq!(combined_div_mod_floor, dm); 668 | } 669 | 670 | test_nd_dm((8, 3), (2, 2)); 671 | test_nd_dm((8, -3), (-3, -1)); 672 | test_nd_dm((-8, 3), (-3, 1)); 673 | test_nd_dm((-8, -3), (2, -2)); 674 | 675 | test_nd_dm((1, 2), (0, 1)); 676 | test_nd_dm((1, -2), (-1, -1)); 677 | test_nd_dm((-1, 2), (-1, 1)); 678 | test_nd_dm((-1, -2), (0, -1)); 679 | } 680 | 681 | #[test] 682 | fn test_gcd() { 683 | assert_eq!((10 as $T).gcd(&2), 2 as $T); 684 | assert_eq!((10 as $T).gcd(&3), 1 as $T); 685 | assert_eq!((0 as $T).gcd(&3), 3 as $T); 686 | assert_eq!((3 as $T).gcd(&3), 3 as $T); 687 | assert_eq!((56 as $T).gcd(&42), 14 as $T); 688 | assert_eq!((3 as $T).gcd(&-3), 3 as $T); 689 | assert_eq!((-6 as $T).gcd(&3), 3 as $T); 690 | assert_eq!((-4 as $T).gcd(&-2), 2 as $T); 691 | } 692 | 693 | #[test] 694 | fn test_gcd_cmp_with_euclidean() { 695 | fn euclidean_gcd(mut m: $T, mut n: $T) -> $T { 696 | while m != 0 { 697 | mem::swap(&mut m, &mut n); 698 | m %= n; 699 | } 700 | 701 | n.abs() 702 | } 703 | 704 | // gcd(-128, b) = 128 is not representable as positive value 705 | // for i8 706 | for i in -127..=127 { 707 | for j in -127..=127 { 708 | assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); 709 | } 710 | } 711 | } 712 | 713 | #[test] 714 | fn test_gcd_min_val() { 715 | let min = <$T>::min_value(); 716 | let max = <$T>::max_value(); 717 | let max_pow2 = max / 2 + 1; 718 | assert_eq!(min.gcd(&max), 1 as $T); 719 | assert_eq!(max.gcd(&min), 1 as $T); 720 | assert_eq!(min.gcd(&max_pow2), max_pow2); 721 | assert_eq!(max_pow2.gcd(&min), max_pow2); 722 | assert_eq!(min.gcd(&42), 2 as $T); 723 | assert_eq!((42 as $T).gcd(&min), 2 as $T); 724 | } 725 | 726 | #[test] 727 | #[should_panic] 728 | fn test_gcd_min_val_min_val() { 729 | let min = <$T>::min_value(); 730 | assert!(min.gcd(&min) >= 0); 731 | } 732 | 733 | #[test] 734 | #[should_panic] 735 | fn test_gcd_min_val_0() { 736 | let min = <$T>::min_value(); 737 | assert!(min.gcd(&0) >= 0); 738 | } 739 | 740 | #[test] 741 | #[should_panic] 742 | fn test_gcd_0_min_val() { 743 | let min = <$T>::min_value(); 744 | assert!((0 as $T).gcd(&min) >= 0); 745 | } 746 | 747 | #[test] 748 | fn test_lcm() { 749 | assert_eq!((1 as $T).lcm(&0), 0 as $T); 750 | assert_eq!((0 as $T).lcm(&1), 0 as $T); 751 | assert_eq!((1 as $T).lcm(&1), 1 as $T); 752 | assert_eq!((-1 as $T).lcm(&1), 1 as $T); 753 | assert_eq!((1 as $T).lcm(&-1), 1 as $T); 754 | assert_eq!((-1 as $T).lcm(&-1), 1 as $T); 755 | assert_eq!((8 as $T).lcm(&9), 72 as $T); 756 | assert_eq!((11 as $T).lcm(&5), 55 as $T); 757 | } 758 | 759 | #[test] 760 | fn test_gcd_lcm() { 761 | use core::iter::once; 762 | for i in once(0) 763 | .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) 764 | .chain(once(-128)) 765 | { 766 | for j in once(0) 767 | .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) 768 | .chain(once(-128)) 769 | { 770 | assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); 771 | } 772 | } 773 | } 774 | 775 | #[test] 776 | fn test_extended_gcd_lcm() { 777 | use crate::ExtendedGcd; 778 | use core::fmt::Debug; 779 | use num_traits::NumAssign; 780 | 781 | fn check(a: A, b: A) { 782 | let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); 783 | assert_eq!(gcd, x * a + y * b); 784 | } 785 | 786 | use core::iter::once; 787 | for i in once(0) 788 | .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) 789 | .chain(once(-128)) 790 | { 791 | for j in once(0) 792 | .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) 793 | .chain(once(-128)) 794 | { 795 | check(i, j); 796 | let (ExtendedGcd { gcd, .. }, lcm) = i.extended_gcd_lcm(&j); 797 | assert_eq!((gcd, lcm), (i.gcd(&j), i.lcm(&j))); 798 | } 799 | } 800 | } 801 | 802 | #[test] 803 | fn test_even() { 804 | assert_eq!((-4 as $T).is_even(), true); 805 | assert_eq!((-3 as $T).is_even(), false); 806 | assert_eq!((-2 as $T).is_even(), true); 807 | assert_eq!((-1 as $T).is_even(), false); 808 | assert_eq!((0 as $T).is_even(), true); 809 | assert_eq!((1 as $T).is_even(), false); 810 | assert_eq!((2 as $T).is_even(), true); 811 | assert_eq!((3 as $T).is_even(), false); 812 | assert_eq!((4 as $T).is_even(), true); 813 | } 814 | 815 | #[test] 816 | fn test_odd() { 817 | assert_eq!((-4 as $T).is_odd(), false); 818 | assert_eq!((-3 as $T).is_odd(), true); 819 | assert_eq!((-2 as $T).is_odd(), false); 820 | assert_eq!((-1 as $T).is_odd(), true); 821 | assert_eq!((0 as $T).is_odd(), false); 822 | assert_eq!((1 as $T).is_odd(), true); 823 | assert_eq!((2 as $T).is_odd(), false); 824 | assert_eq!((3 as $T).is_odd(), true); 825 | assert_eq!((4 as $T).is_odd(), false); 826 | } 827 | 828 | #[test] 829 | fn test_multiple_of_one_limits() { 830 | for x in &[<$T>::min_value(), <$T>::max_value()] { 831 | for one in &[1, -1] { 832 | assert_eq!(Integer::next_multiple_of(x, one), *x); 833 | assert_eq!(Integer::prev_multiple_of(x, one), *x); 834 | } 835 | } 836 | } 837 | } 838 | }; 839 | } 840 | 841 | impl_integer_for_isize!(i8, test_integer_i8); 842 | impl_integer_for_isize!(i16, test_integer_i16); 843 | impl_integer_for_isize!(i32, test_integer_i32); 844 | impl_integer_for_isize!(i64, test_integer_i64); 845 | impl_integer_for_isize!(i128, test_integer_i128); 846 | impl_integer_for_isize!(isize, test_integer_isize); 847 | 848 | macro_rules! impl_integer_for_usize { 849 | ($T:ty, $test_mod:ident) => { 850 | impl Integer for $T { 851 | /// Unsigned integer division. Returns the same result as `div` (`/`). 852 | #[inline] 853 | fn div_floor(&self, other: &Self) -> Self { 854 | *self / *other 855 | } 856 | 857 | /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). 858 | #[inline] 859 | fn mod_floor(&self, other: &Self) -> Self { 860 | *self % *other 861 | } 862 | 863 | #[inline] 864 | fn div_ceil(&self, other: &Self) -> Self { 865 | *self / *other + (0 != *self % *other) as Self 866 | } 867 | 868 | /// Calculates the Greatest Common Divisor (GCD) of the number and `other` 869 | #[inline] 870 | fn gcd(&self, other: &Self) -> Self { 871 | // Use Stein's algorithm 872 | let mut m = *self; 873 | let mut n = *other; 874 | if m == 0 || n == 0 { 875 | return m | n; 876 | } 877 | 878 | // find common factors of 2 879 | let shift = (m | n).trailing_zeros(); 880 | 881 | // divide n and m by 2 until odd 882 | m >>= m.trailing_zeros(); 883 | n >>= n.trailing_zeros(); 884 | 885 | while m != n { 886 | if m > n { 887 | m -= n; 888 | m >>= m.trailing_zeros(); 889 | } else { 890 | n -= m; 891 | n >>= n.trailing_zeros(); 892 | } 893 | } 894 | m << shift 895 | } 896 | 897 | #[inline] 898 | fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) { 899 | let egcd = self.extended_gcd(other); 900 | // should not have to recalculate abs 901 | let lcm = if egcd.gcd.is_zero() { 902 | Self::zero() 903 | } else { 904 | *self * (*other / egcd.gcd) 905 | }; 906 | (egcd, lcm) 907 | } 908 | 909 | /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. 910 | #[inline] 911 | fn lcm(&self, other: &Self) -> Self { 912 | self.gcd_lcm(other).1 913 | } 914 | 915 | /// Calculates the Greatest Common Divisor (GCD) and 916 | /// Lowest Common Multiple (LCM) of the number and `other`. 917 | #[inline] 918 | fn gcd_lcm(&self, other: &Self) -> (Self, Self) { 919 | if self.is_zero() && other.is_zero() { 920 | return (Self::zero(), Self::zero()); 921 | } 922 | let gcd = self.gcd(other); 923 | let lcm = *self * (*other / gcd); 924 | (gcd, lcm) 925 | } 926 | 927 | /// Returns `true` if the number is a multiple of `other`. 928 | #[inline] 929 | fn is_multiple_of(&self, other: &Self) -> bool { 930 | if other.is_zero() { 931 | return self.is_zero(); 932 | } 933 | *self % *other == 0 934 | } 935 | 936 | /// Returns `true` if the number is divisible by `2`. 937 | #[inline] 938 | fn is_even(&self) -> bool { 939 | *self % 2 == 0 940 | } 941 | 942 | /// Returns `true` if the number is not divisible by `2`. 943 | #[inline] 944 | fn is_odd(&self) -> bool { 945 | !self.is_even() 946 | } 947 | 948 | /// Simultaneous truncated integer division and modulus. 949 | #[inline] 950 | fn div_rem(&self, other: &Self) -> (Self, Self) { 951 | (*self / *other, *self % *other) 952 | } 953 | } 954 | 955 | #[cfg(test)] 956 | mod $test_mod { 957 | use crate::Integer; 958 | use core::mem; 959 | 960 | #[test] 961 | fn test_div_mod_floor() { 962 | assert_eq!(<$T as Integer>::div_floor(&10, &3), 3 as $T); 963 | assert_eq!(<$T as Integer>::mod_floor(&10, &3), 1 as $T); 964 | assert_eq!(<$T as Integer>::div_mod_floor(&10, &3), (3 as $T, 1 as $T)); 965 | assert_eq!(<$T as Integer>::div_floor(&5, &5), 1 as $T); 966 | assert_eq!(<$T as Integer>::mod_floor(&5, &5), 0 as $T); 967 | assert_eq!(<$T as Integer>::div_mod_floor(&5, &5), (1 as $T, 0 as $T)); 968 | assert_eq!(<$T as Integer>::div_floor(&3, &7), 0 as $T); 969 | assert_eq!(<$T as Integer>::div_floor(&3, &7), 0 as $T); 970 | assert_eq!(<$T as Integer>::mod_floor(&3, &7), 3 as $T); 971 | assert_eq!(<$T as Integer>::div_mod_floor(&3, &7), (0 as $T, 3 as $T)); 972 | } 973 | 974 | #[test] 975 | fn test_gcd() { 976 | assert_eq!((10 as $T).gcd(&2), 2 as $T); 977 | assert_eq!((10 as $T).gcd(&3), 1 as $T); 978 | assert_eq!((0 as $T).gcd(&3), 3 as $T); 979 | assert_eq!((3 as $T).gcd(&3), 3 as $T); 980 | assert_eq!((56 as $T).gcd(&42), 14 as $T); 981 | } 982 | 983 | #[test] 984 | fn test_gcd_cmp_with_euclidean() { 985 | fn euclidean_gcd(mut m: $T, mut n: $T) -> $T { 986 | while m != 0 { 987 | mem::swap(&mut m, &mut n); 988 | m %= n; 989 | } 990 | n 991 | } 992 | 993 | for i in 0..=255 { 994 | for j in 0..=255 { 995 | assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); 996 | } 997 | } 998 | } 999 | 1000 | #[test] 1001 | fn test_lcm() { 1002 | assert_eq!((1 as $T).lcm(&0), 0 as $T); 1003 | assert_eq!((0 as $T).lcm(&1), 0 as $T); 1004 | assert_eq!((1 as $T).lcm(&1), 1 as $T); 1005 | assert_eq!((8 as $T).lcm(&9), 72 as $T); 1006 | assert_eq!((11 as $T).lcm(&5), 55 as $T); 1007 | assert_eq!((15 as $T).lcm(&17), 255 as $T); 1008 | } 1009 | 1010 | #[test] 1011 | fn test_gcd_lcm() { 1012 | for i in (0..).take(256) { 1013 | for j in (0..).take(256) { 1014 | assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); 1015 | } 1016 | } 1017 | } 1018 | 1019 | #[test] 1020 | fn test_is_multiple_of() { 1021 | assert!(<$T as Integer>::is_multiple_of(&(0 as $T), &(0 as $T))); 1022 | assert!(<$T as Integer>::is_multiple_of(&(6 as $T), &(6 as $T))); 1023 | assert!(<$T as Integer>::is_multiple_of(&(6 as $T), &(3 as $T))); 1024 | assert!(<$T as Integer>::is_multiple_of(&(6 as $T), &(1 as $T))); 1025 | 1026 | assert!(!<$T as Integer>::is_multiple_of(&(42 as $T), &(5 as $T))); 1027 | assert!(!<$T as Integer>::is_multiple_of(&(5 as $T), &(3 as $T))); 1028 | assert!(!<$T as Integer>::is_multiple_of(&(42 as $T), &(0 as $T))); 1029 | } 1030 | 1031 | #[test] 1032 | fn test_even() { 1033 | assert_eq!((0 as $T).is_even(), true); 1034 | assert_eq!((1 as $T).is_even(), false); 1035 | assert_eq!((2 as $T).is_even(), true); 1036 | assert_eq!((3 as $T).is_even(), false); 1037 | assert_eq!((4 as $T).is_even(), true); 1038 | } 1039 | 1040 | #[test] 1041 | fn test_odd() { 1042 | assert_eq!((0 as $T).is_odd(), false); 1043 | assert_eq!((1 as $T).is_odd(), true); 1044 | assert_eq!((2 as $T).is_odd(), false); 1045 | assert_eq!((3 as $T).is_odd(), true); 1046 | assert_eq!((4 as $T).is_odd(), false); 1047 | } 1048 | } 1049 | }; 1050 | } 1051 | 1052 | impl_integer_for_usize!(u8, test_integer_u8); 1053 | impl_integer_for_usize!(u16, test_integer_u16); 1054 | impl_integer_for_usize!(u32, test_integer_u32); 1055 | impl_integer_for_usize!(u64, test_integer_u64); 1056 | impl_integer_for_usize!(u128, test_integer_u128); 1057 | impl_integer_for_usize!(usize, test_integer_usize); 1058 | 1059 | /// An iterator over binomial coefficients. 1060 | pub struct IterBinomial { 1061 | a: T, 1062 | n: T, 1063 | k: T, 1064 | } 1065 | 1066 | impl IterBinomial 1067 | where 1068 | T: Integer, 1069 | { 1070 | /// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n. 1071 | /// 1072 | /// Note that this might overflow, depending on `T`. For the primitive 1073 | /// integer types, the following n are the largest ones for which there will 1074 | /// be no overflow: 1075 | /// 1076 | /// type | n 1077 | /// -----|--- 1078 | /// u8 | 10 1079 | /// i8 | 9 1080 | /// u16 | 18 1081 | /// i16 | 17 1082 | /// u32 | 34 1083 | /// i32 | 33 1084 | /// u64 | 67 1085 | /// i64 | 66 1086 | /// 1087 | /// For larger n, `T` should be a bigint type. 1088 | pub fn new(n: T) -> IterBinomial { 1089 | IterBinomial { 1090 | k: T::zero(), 1091 | a: T::one(), 1092 | n, 1093 | } 1094 | } 1095 | } 1096 | 1097 | impl Iterator for IterBinomial 1098 | where 1099 | T: Integer + Clone, 1100 | { 1101 | type Item = T; 1102 | 1103 | fn next(&mut self) -> Option { 1104 | if self.k > self.n { 1105 | return None; 1106 | } 1107 | self.a = if !self.k.is_zero() { 1108 | multiply_and_divide( 1109 | self.a.clone(), 1110 | self.n.clone() - self.k.clone() + T::one(), 1111 | self.k.clone(), 1112 | ) 1113 | } else { 1114 | T::one() 1115 | }; 1116 | self.k = self.k.clone() + T::one(); 1117 | Some(self.a.clone()) 1118 | } 1119 | } 1120 | 1121 | /// Calculate r * a / b, avoiding overflows and fractions. 1122 | /// 1123 | /// Assumes that b divides r * a evenly. 1124 | fn multiply_and_divide(r: T, a: T, b: T) -> T { 1125 | // See http://blog.plover.com/math/choose-2.html for the idea. 1126 | let g = gcd(r.clone(), b.clone()); 1127 | r / g.clone() * (a / (b / g)) 1128 | } 1129 | 1130 | /// Calculate the binomial coefficient. 1131 | /// 1132 | /// Note that this might overflow, depending on `T`. For the primitive integer 1133 | /// types, the following n are the largest ones possible such that there will 1134 | /// be no overflow for any k: 1135 | /// 1136 | /// type | n 1137 | /// -----|--- 1138 | /// u8 | 10 1139 | /// i8 | 9 1140 | /// u16 | 18 1141 | /// i16 | 17 1142 | /// u32 | 34 1143 | /// i32 | 33 1144 | /// u64 | 67 1145 | /// i64 | 66 1146 | /// 1147 | /// For larger n, consider using a bigint type for `T`. 1148 | pub fn binomial(mut n: T, k: T) -> T { 1149 | // See http://blog.plover.com/math/choose.html for the idea. 1150 | if k > n { 1151 | return T::zero(); 1152 | } 1153 | if k > n.clone() - k.clone() { 1154 | return binomial(n.clone(), n - k); 1155 | } 1156 | let mut r = T::one(); 1157 | let mut d = T::one(); 1158 | loop { 1159 | if d > k { 1160 | break; 1161 | } 1162 | r = multiply_and_divide(r, n.clone(), d.clone()); 1163 | n = n - T::one(); 1164 | d = d + T::one(); 1165 | } 1166 | r 1167 | } 1168 | 1169 | /// Calculate the multinomial coefficient. 1170 | pub fn multinomial(k: &[T]) -> T 1171 | where 1172 | for<'a> T: Add<&'a T, Output = T>, 1173 | { 1174 | let mut r = T::one(); 1175 | let mut p = T::zero(); 1176 | for i in k { 1177 | p = p + i; 1178 | r = r * binomial(p.clone(), i.clone()); 1179 | } 1180 | r 1181 | } 1182 | 1183 | #[test] 1184 | fn test_lcm_overflow() { 1185 | macro_rules! check { 1186 | ($t:ty, $x:expr, $y:expr, $r:expr) => {{ 1187 | let x: $t = $x; 1188 | let y: $t = $y; 1189 | let o = x.checked_mul(y); 1190 | assert!( 1191 | o.is_none(), 1192 | "sanity checking that {} input {} * {} overflows", 1193 | stringify!($t), 1194 | x, 1195 | y 1196 | ); 1197 | assert_eq!(x.lcm(&y), $r); 1198 | assert_eq!(y.lcm(&x), $r); 1199 | }}; 1200 | } 1201 | 1202 | // Original bug (Issue #166) 1203 | check!(i64, 46656000000000000, 600, 46656000000000000); 1204 | 1205 | check!(i8, 0x40, 0x04, 0x40); 1206 | check!(u8, 0x80, 0x02, 0x80); 1207 | check!(i16, 0x40_00, 0x04, 0x40_00); 1208 | check!(u16, 0x80_00, 0x02, 0x80_00); 1209 | check!(i32, 0x4000_0000, 0x04, 0x4000_0000); 1210 | check!(u32, 0x8000_0000, 0x02, 0x8000_0000); 1211 | check!(i64, 0x4000_0000_0000_0000, 0x04, 0x4000_0000_0000_0000); 1212 | check!(u64, 0x8000_0000_0000_0000, 0x02, 0x8000_0000_0000_0000); 1213 | } 1214 | 1215 | #[test] 1216 | fn test_iter_binomial() { 1217 | macro_rules! check_simple { 1218 | ($t:ty) => {{ 1219 | let n: $t = 3; 1220 | let expected = [1, 3, 3, 1]; 1221 | for (b, &e) in IterBinomial::new(n).zip(&expected) { 1222 | assert_eq!(b, e); 1223 | } 1224 | }}; 1225 | } 1226 | 1227 | check_simple!(u8); 1228 | check_simple!(i8); 1229 | check_simple!(u16); 1230 | check_simple!(i16); 1231 | check_simple!(u32); 1232 | check_simple!(i32); 1233 | check_simple!(u64); 1234 | check_simple!(i64); 1235 | 1236 | macro_rules! check_binomial { 1237 | ($t:ty, $n:expr) => {{ 1238 | let n: $t = $n; 1239 | let mut k: $t = 0; 1240 | for b in IterBinomial::new(n) { 1241 | assert_eq!(b, binomial(n, k)); 1242 | k += 1; 1243 | } 1244 | }}; 1245 | } 1246 | 1247 | // Check the largest n for which there is no overflow. 1248 | check_binomial!(u8, 10); 1249 | check_binomial!(i8, 9); 1250 | check_binomial!(u16, 18); 1251 | check_binomial!(i16, 17); 1252 | check_binomial!(u32, 34); 1253 | check_binomial!(i32, 33); 1254 | check_binomial!(u64, 67); 1255 | check_binomial!(i64, 66); 1256 | } 1257 | 1258 | #[test] 1259 | fn test_binomial() { 1260 | macro_rules! check { 1261 | ($t:ty, $x:expr, $y:expr, $r:expr) => {{ 1262 | let x: $t = $x; 1263 | let y: $t = $y; 1264 | let expected: $t = $r; 1265 | assert_eq!(binomial(x, y), expected); 1266 | if y <= x { 1267 | assert_eq!(binomial(x, x - y), expected); 1268 | } 1269 | }}; 1270 | } 1271 | check!(u8, 9, 4, 126); 1272 | check!(u8, 0, 0, 1); 1273 | check!(u8, 2, 3, 0); 1274 | 1275 | check!(i8, 9, 4, 126); 1276 | check!(i8, 0, 0, 1); 1277 | check!(i8, 2, 3, 0); 1278 | 1279 | check!(u16, 100, 2, 4950); 1280 | check!(u16, 14, 4, 1001); 1281 | check!(u16, 0, 0, 1); 1282 | check!(u16, 2, 3, 0); 1283 | 1284 | check!(i16, 100, 2, 4950); 1285 | check!(i16, 14, 4, 1001); 1286 | check!(i16, 0, 0, 1); 1287 | check!(i16, 2, 3, 0); 1288 | 1289 | check!(u32, 100, 2, 4950); 1290 | check!(u32, 35, 11, 417225900); 1291 | check!(u32, 14, 4, 1001); 1292 | check!(u32, 0, 0, 1); 1293 | check!(u32, 2, 3, 0); 1294 | 1295 | check!(i32, 100, 2, 4950); 1296 | check!(i32, 35, 11, 417225900); 1297 | check!(i32, 14, 4, 1001); 1298 | check!(i32, 0, 0, 1); 1299 | check!(i32, 2, 3, 0); 1300 | 1301 | check!(u64, 100, 2, 4950); 1302 | check!(u64, 35, 11, 417225900); 1303 | check!(u64, 14, 4, 1001); 1304 | check!(u64, 0, 0, 1); 1305 | check!(u64, 2, 3, 0); 1306 | 1307 | check!(i64, 100, 2, 4950); 1308 | check!(i64, 35, 11, 417225900); 1309 | check!(i64, 14, 4, 1001); 1310 | check!(i64, 0, 0, 1); 1311 | check!(i64, 2, 3, 0); 1312 | } 1313 | 1314 | #[test] 1315 | fn test_multinomial() { 1316 | macro_rules! check_binomial { 1317 | ($t:ty, $k:expr) => {{ 1318 | let n: $t = $k.iter().fold(0, |acc, &x| acc + x); 1319 | let k: &[$t] = $k; 1320 | assert_eq!(k.len(), 2); 1321 | assert_eq!(multinomial(k), binomial(n, k[0])); 1322 | }}; 1323 | } 1324 | 1325 | check_binomial!(u8, &[4, 5]); 1326 | 1327 | check_binomial!(i8, &[4, 5]); 1328 | 1329 | check_binomial!(u16, &[2, 98]); 1330 | check_binomial!(u16, &[4, 10]); 1331 | 1332 | check_binomial!(i16, &[2, 98]); 1333 | check_binomial!(i16, &[4, 10]); 1334 | 1335 | check_binomial!(u32, &[2, 98]); 1336 | check_binomial!(u32, &[11, 24]); 1337 | check_binomial!(u32, &[4, 10]); 1338 | 1339 | check_binomial!(i32, &[2, 98]); 1340 | check_binomial!(i32, &[11, 24]); 1341 | check_binomial!(i32, &[4, 10]); 1342 | 1343 | check_binomial!(u64, &[2, 98]); 1344 | check_binomial!(u64, &[11, 24]); 1345 | check_binomial!(u64, &[4, 10]); 1346 | 1347 | check_binomial!(i64, &[2, 98]); 1348 | check_binomial!(i64, &[11, 24]); 1349 | check_binomial!(i64, &[4, 10]); 1350 | 1351 | macro_rules! check_multinomial { 1352 | ($t:ty, $k:expr, $r:expr) => {{ 1353 | let k: &[$t] = $k; 1354 | let expected: $t = $r; 1355 | assert_eq!(multinomial(k), expected); 1356 | }}; 1357 | } 1358 | 1359 | check_multinomial!(u8, &[2, 1, 2], 30); 1360 | check_multinomial!(u8, &[2, 3, 0], 10); 1361 | 1362 | check_multinomial!(i8, &[2, 1, 2], 30); 1363 | check_multinomial!(i8, &[2, 3, 0], 10); 1364 | 1365 | check_multinomial!(u16, &[2, 1, 2], 30); 1366 | check_multinomial!(u16, &[2, 3, 0], 10); 1367 | 1368 | check_multinomial!(i16, &[2, 1, 2], 30); 1369 | check_multinomial!(i16, &[2, 3, 0], 10); 1370 | 1371 | check_multinomial!(u32, &[2, 1, 2], 30); 1372 | check_multinomial!(u32, &[2, 3, 0], 10); 1373 | 1374 | check_multinomial!(i32, &[2, 1, 2], 30); 1375 | check_multinomial!(i32, &[2, 3, 0], 10); 1376 | 1377 | check_multinomial!(u64, &[2, 1, 2], 30); 1378 | check_multinomial!(u64, &[2, 3, 0], 10); 1379 | 1380 | check_multinomial!(i64, &[2, 1, 2], 30); 1381 | check_multinomial!(i64, &[2, 3, 0], 10); 1382 | 1383 | check_multinomial!(u64, &[], 1); 1384 | check_multinomial!(u64, &[0], 1); 1385 | check_multinomial!(u64, &[12345], 1); 1386 | } 1387 | -------------------------------------------------------------------------------- /src/roots.rs: -------------------------------------------------------------------------------- 1 | use crate::Integer; 2 | use core::mem; 3 | use num_traits::{checked_pow, PrimInt}; 4 | 5 | /// Provides methods to compute an integer's square root, cube root, 6 | /// and arbitrary `n`th root. 7 | pub trait Roots: Integer { 8 | /// Returns the truncated principal `n`th root of an integer 9 | /// -- `if x >= 0 { ⌊ⁿ√x⌋ } else { ⌈ⁿ√x⌉ }` 10 | /// 11 | /// This is solving for `r` in `rⁿ = x`, rounding toward zero. 12 | /// If `x` is positive, the result will satisfy `rⁿ ≤ x < (r+1)ⁿ`. 13 | /// If `x` is negative and `n` is odd, then `(r-1)ⁿ < x ≤ rⁿ`. 14 | /// 15 | /// # Panics 16 | /// 17 | /// Panics if `n` is zero: 18 | /// 19 | /// ```should_panic 20 | /// # use num_integer::Roots; 21 | /// println!("can't compute ⁰√x : {}", 123.nth_root(0)); 22 | /// ``` 23 | /// 24 | /// or if `n` is even and `self` is negative: 25 | /// 26 | /// ```should_panic 27 | /// # use num_integer::Roots; 28 | /// println!("no imaginary numbers... {}", (-1).nth_root(10)); 29 | /// ``` 30 | /// 31 | /// # Examples 32 | /// 33 | /// ``` 34 | /// use num_integer::Roots; 35 | /// 36 | /// let x: i32 = 12345; 37 | /// assert_eq!(x.nth_root(1), x); 38 | /// assert_eq!(x.nth_root(2), x.sqrt()); 39 | /// assert_eq!(x.nth_root(3), x.cbrt()); 40 | /// assert_eq!(x.nth_root(4), 10); 41 | /// assert_eq!(x.nth_root(13), 2); 42 | /// assert_eq!(x.nth_root(14), 1); 43 | /// assert_eq!(x.nth_root(std::u32::MAX), 1); 44 | /// 45 | /// assert_eq!(std::i32::MAX.nth_root(30), 2); 46 | /// assert_eq!(std::i32::MAX.nth_root(31), 1); 47 | /// assert_eq!(std::i32::MIN.nth_root(31), -2); 48 | /// assert_eq!((std::i32::MIN + 1).nth_root(31), -1); 49 | /// 50 | /// assert_eq!(std::u32::MAX.nth_root(31), 2); 51 | /// assert_eq!(std::u32::MAX.nth_root(32), 1); 52 | /// ``` 53 | fn nth_root(&self, n: u32) -> Self; 54 | 55 | /// Returns the truncated principal square root of an integer -- `⌊√x⌋` 56 | /// 57 | /// This is solving for `r` in `r² = x`, rounding toward zero. 58 | /// The result will satisfy `r² ≤ x < (r+1)²`. 59 | /// 60 | /// # Panics 61 | /// 62 | /// Panics if `self` is less than zero: 63 | /// 64 | /// ```should_panic 65 | /// # use num_integer::Roots; 66 | /// println!("no imaginary numbers... {}", (-1).sqrt()); 67 | /// ``` 68 | /// 69 | /// # Examples 70 | /// 71 | /// ``` 72 | /// use num_integer::Roots; 73 | /// 74 | /// let x: i32 = 12345; 75 | /// assert_eq!((x * x).sqrt(), x); 76 | /// assert_eq!((x * x + 1).sqrt(), x); 77 | /// assert_eq!((x * x - 1).sqrt(), x - 1); 78 | /// ``` 79 | #[inline] 80 | fn sqrt(&self) -> Self { 81 | self.nth_root(2) 82 | } 83 | 84 | /// Returns the truncated principal cube root of an integer -- 85 | /// `if x >= 0 { ⌊∛x⌋ } else { ⌈∛x⌉ }` 86 | /// 87 | /// This is solving for `r` in `r³ = x`, rounding toward zero. 88 | /// If `x` is positive, the result will satisfy `r³ ≤ x < (r+1)³`. 89 | /// If `x` is negative, then `(r-1)³ < x ≤ r³`. 90 | /// 91 | /// # Examples 92 | /// 93 | /// ``` 94 | /// use num_integer::Roots; 95 | /// 96 | /// let x: i32 = 1234; 97 | /// assert_eq!((x * x * x).cbrt(), x); 98 | /// assert_eq!((x * x * x + 1).cbrt(), x); 99 | /// assert_eq!((x * x * x - 1).cbrt(), x - 1); 100 | /// 101 | /// assert_eq!((-(x * x * x)).cbrt(), -x); 102 | /// assert_eq!((-(x * x * x + 1)).cbrt(), -x); 103 | /// assert_eq!((-(x * x * x - 1)).cbrt(), -(x - 1)); 104 | /// ``` 105 | #[inline] 106 | fn cbrt(&self) -> Self { 107 | self.nth_root(3) 108 | } 109 | } 110 | 111 | /// Returns the truncated principal square root of an integer -- 112 | /// see [Roots::sqrt](trait.Roots.html#method.sqrt). 113 | #[inline] 114 | pub fn sqrt(x: T) -> T { 115 | x.sqrt() 116 | } 117 | 118 | /// Returns the truncated principal cube root of an integer -- 119 | /// see [Roots::cbrt](trait.Roots.html#method.cbrt). 120 | #[inline] 121 | pub fn cbrt(x: T) -> T { 122 | x.cbrt() 123 | } 124 | 125 | /// Returns the truncated principal `n`th root of an integer -- 126 | /// see [Roots::nth_root](trait.Roots.html#tymethod.nth_root). 127 | #[inline] 128 | pub fn nth_root(x: T, n: u32) -> T { 129 | x.nth_root(n) 130 | } 131 | 132 | macro_rules! signed_roots { 133 | ($T:ty, $U:ty) => { 134 | impl Roots for $T { 135 | #[inline] 136 | fn nth_root(&self, n: u32) -> Self { 137 | if *self >= 0 { 138 | (*self as $U).nth_root(n) as Self 139 | } else { 140 | assert!(n.is_odd(), "even roots of a negative are imaginary"); 141 | -((self.wrapping_neg() as $U).nth_root(n) as Self) 142 | } 143 | } 144 | 145 | #[inline] 146 | fn sqrt(&self) -> Self { 147 | assert!(*self >= 0, "the square root of a negative is imaginary"); 148 | (*self as $U).sqrt() as Self 149 | } 150 | 151 | #[inline] 152 | fn cbrt(&self) -> Self { 153 | if *self >= 0 { 154 | (*self as $U).cbrt() as Self 155 | } else { 156 | -((self.wrapping_neg() as $U).cbrt() as Self) 157 | } 158 | } 159 | } 160 | }; 161 | } 162 | 163 | signed_roots!(i8, u8); 164 | signed_roots!(i16, u16); 165 | signed_roots!(i32, u32); 166 | signed_roots!(i64, u64); 167 | signed_roots!(i128, u128); 168 | signed_roots!(isize, usize); 169 | 170 | #[inline] 171 | fn fixpoint(mut x: T, f: F) -> T 172 | where 173 | T: Integer + Copy, 174 | F: Fn(T) -> T, 175 | { 176 | let mut xn = f(x); 177 | while x < xn { 178 | x = xn; 179 | xn = f(x); 180 | } 181 | while x > xn { 182 | x = xn; 183 | xn = f(x); 184 | } 185 | x 186 | } 187 | 188 | #[inline] 189 | fn bits() -> u32 { 190 | 8 * mem::size_of::() as u32 191 | } 192 | 193 | #[inline] 194 | fn log2(x: T) -> u32 { 195 | debug_assert!(x > T::zero()); 196 | bits::() - 1 - x.leading_zeros() 197 | } 198 | 199 | macro_rules! unsigned_roots { 200 | ($T:ident) => { 201 | impl Roots for $T { 202 | #[inline] 203 | fn nth_root(&self, n: u32) -> Self { 204 | fn go(a: $T, n: u32) -> $T { 205 | // Specialize small roots 206 | match n { 207 | 0 => panic!("can't find a root of degree 0!"), 208 | 1 => return a, 209 | 2 => return a.sqrt(), 210 | 3 => return a.cbrt(), 211 | _ => (), 212 | } 213 | 214 | // The root of values less than 2ⁿ can only be 0 or 1. 215 | if bits::<$T>() <= n || a < (1 << n) { 216 | return (a > 0) as $T; 217 | } 218 | 219 | if bits::<$T>() > 64 { 220 | // 128-bit division is slow, so do a bitwise `nth_root` until it's small enough. 221 | return if a <= core::u64::MAX as $T { 222 | (a as u64).nth_root(n) as $T 223 | } else { 224 | let lo = (a >> n).nth_root(n) << 1; 225 | let hi = lo + 1; 226 | // 128-bit `checked_mul` also involves division, but we can't always 227 | // compute `hiⁿ` without risking overflow. Try to avoid it though... 228 | if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() { 229 | match checked_pow(hi, n as usize) { 230 | Some(x) if x <= a => hi, 231 | _ => lo, 232 | } 233 | } else { 234 | if hi.pow(n) <= a { 235 | hi 236 | } else { 237 | lo 238 | } 239 | } 240 | }; 241 | } 242 | 243 | #[cfg(feature = "std")] 244 | #[inline] 245 | fn guess(x: $T, n: u32) -> $T { 246 | // for smaller inputs, `f64` doesn't justify its cost. 247 | if bits::<$T>() <= 32 || x <= core::u32::MAX as $T { 248 | 1 << ((log2(x) + n - 1) / n) 249 | } else { 250 | ((x as f64).ln() / f64::from(n)).exp() as $T 251 | } 252 | } 253 | 254 | #[cfg(not(feature = "std"))] 255 | #[inline] 256 | fn guess(x: $T, n: u32) -> $T { 257 | 1 << ((log2(x) + n - 1) / n) 258 | } 259 | 260 | // https://en.wikipedia.org/wiki/Nth_root_algorithm 261 | let n1 = n - 1; 262 | let next = |x: $T| { 263 | let y = match checked_pow(x, n1 as usize) { 264 | Some(ax) => a / ax, 265 | None => 0, 266 | }; 267 | (y + x * n1 as $T) / n as $T 268 | }; 269 | fixpoint(guess(a, n), next) 270 | } 271 | go(*self, n) 272 | } 273 | 274 | #[inline] 275 | fn sqrt(&self) -> Self { 276 | fn go(a: $T) -> $T { 277 | if bits::<$T>() > 64 { 278 | // 128-bit division is slow, so do a bitwise `sqrt` until it's small enough. 279 | return if a <= core::u64::MAX as $T { 280 | (a as u64).sqrt() as $T 281 | } else { 282 | let lo = (a >> 2u32).sqrt() << 1; 283 | let hi = lo + 1; 284 | if hi * hi <= a { 285 | hi 286 | } else { 287 | lo 288 | } 289 | }; 290 | } 291 | 292 | if a < 4 { 293 | return (a > 0) as $T; 294 | } 295 | 296 | #[cfg(feature = "std")] 297 | #[inline] 298 | fn guess(x: $T) -> $T { 299 | (x as f64).sqrt() as $T 300 | } 301 | 302 | #[cfg(not(feature = "std"))] 303 | #[inline] 304 | fn guess(x: $T) -> $T { 305 | 1 << ((log2(x) + 1) / 2) 306 | } 307 | 308 | // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method 309 | let next = |x: $T| (a / x + x) >> 1; 310 | fixpoint(guess(a), next) 311 | } 312 | go(*self) 313 | } 314 | 315 | #[inline] 316 | fn cbrt(&self) -> Self { 317 | fn go(a: $T) -> $T { 318 | if bits::<$T>() > 64 { 319 | // 128-bit division is slow, so do a bitwise `cbrt` until it's small enough. 320 | return if a <= core::u64::MAX as $T { 321 | (a as u64).cbrt() as $T 322 | } else { 323 | let lo = (a >> 3u32).cbrt() << 1; 324 | let hi = lo + 1; 325 | if hi * hi * hi <= a { 326 | hi 327 | } else { 328 | lo 329 | } 330 | }; 331 | } 332 | 333 | if bits::<$T>() <= 32 { 334 | // Implementation based on Hacker's Delight `icbrt2` 335 | let mut x = a; 336 | let mut y2 = 0; 337 | let mut y = 0; 338 | let smax = bits::<$T>() / 3; 339 | for s in (0..smax + 1).rev() { 340 | let s = s * 3; 341 | y2 *= 4; 342 | y *= 2; 343 | let b = 3 * (y2 + y) + 1; 344 | if x >> s >= b { 345 | x -= b << s; 346 | y2 += 2 * y + 1; 347 | y += 1; 348 | } 349 | } 350 | return y; 351 | } 352 | 353 | if a < 8 { 354 | return (a > 0) as $T; 355 | } 356 | if a <= core::u32::MAX as $T { 357 | return (a as u32).cbrt() as $T; 358 | } 359 | 360 | #[cfg(feature = "std")] 361 | #[inline] 362 | fn guess(x: $T) -> $T { 363 | (x as f64).cbrt() as $T 364 | } 365 | 366 | #[cfg(not(feature = "std"))] 367 | #[inline] 368 | fn guess(x: $T) -> $T { 369 | 1 << ((log2(x) + 2) / 3) 370 | } 371 | 372 | // https://en.wikipedia.org/wiki/Cube_root#Numerical_methods 373 | let next = |x: $T| (a / (x * x) + x * 2) / 3; 374 | fixpoint(guess(a), next) 375 | } 376 | go(*self) 377 | } 378 | } 379 | }; 380 | } 381 | 382 | unsigned_roots!(u8); 383 | unsigned_roots!(u16); 384 | unsigned_roots!(u32); 385 | unsigned_roots!(u64); 386 | unsigned_roots!(u128); 387 | unsigned_roots!(usize); 388 | -------------------------------------------------------------------------------- /tests/average.rs: -------------------------------------------------------------------------------- 1 | macro_rules! test_average { 2 | ($I:ident, $U:ident) => { 3 | mod $I { 4 | mod ceil { 5 | use num_integer::Average; 6 | 7 | #[test] 8 | fn same_sign() { 9 | assert_eq!((14 as $I).average_ceil(&16), 15 as $I); 10 | assert_eq!((14 as $I).average_ceil(&17), 16 as $I); 11 | 12 | let max = std::$I::MAX; 13 | assert_eq!((max - 3).average_ceil(&(max - 1)), max - 2); 14 | assert_eq!((max - 3).average_ceil(&(max - 2)), max - 2); 15 | } 16 | 17 | #[test] 18 | fn different_sign() { 19 | assert_eq!((14 as $I).average_ceil(&-4), 5 as $I); 20 | assert_eq!((14 as $I).average_ceil(&-5), 5 as $I); 21 | 22 | let min = std::$I::MIN; 23 | let max = std::$I::MAX; 24 | assert_eq!(min.average_ceil(&max), 0 as $I); 25 | } 26 | } 27 | 28 | mod floor { 29 | use num_integer::Average; 30 | 31 | #[test] 32 | fn same_sign() { 33 | assert_eq!((14 as $I).average_floor(&16), 15 as $I); 34 | assert_eq!((14 as $I).average_floor(&17), 15 as $I); 35 | 36 | let max = std::$I::MAX; 37 | assert_eq!((max - 3).average_floor(&(max - 1)), max - 2); 38 | assert_eq!((max - 3).average_floor(&(max - 2)), max - 3); 39 | } 40 | 41 | #[test] 42 | fn different_sign() { 43 | assert_eq!((14 as $I).average_floor(&-4), 5 as $I); 44 | assert_eq!((14 as $I).average_floor(&-5), 4 as $I); 45 | 46 | let min = std::$I::MIN; 47 | let max = std::$I::MAX; 48 | assert_eq!(min.average_floor(&max), -1 as $I); 49 | } 50 | } 51 | } 52 | 53 | mod $U { 54 | mod ceil { 55 | use num_integer::Average; 56 | 57 | #[test] 58 | fn bounded() { 59 | assert_eq!((14 as $U).average_ceil(&16), 15 as $U); 60 | assert_eq!((14 as $U).average_ceil(&17), 16 as $U); 61 | } 62 | 63 | #[test] 64 | fn overflow() { 65 | let max = std::$U::MAX; 66 | assert_eq!((max - 3).average_ceil(&(max - 1)), max - 2); 67 | assert_eq!((max - 3).average_ceil(&(max - 2)), max - 2); 68 | } 69 | } 70 | 71 | mod floor { 72 | use num_integer::Average; 73 | 74 | #[test] 75 | fn bounded() { 76 | assert_eq!((14 as $U).average_floor(&16), 15 as $U); 77 | assert_eq!((14 as $U).average_floor(&17), 15 as $U); 78 | } 79 | 80 | #[test] 81 | fn overflow() { 82 | let max = std::$U::MAX; 83 | assert_eq!((max - 3).average_floor(&(max - 1)), max - 2); 84 | assert_eq!((max - 3).average_floor(&(max - 2)), max - 3); 85 | } 86 | } 87 | } 88 | }; 89 | } 90 | 91 | test_average!(i8, u8); 92 | test_average!(i16, u16); 93 | test_average!(i32, u32); 94 | test_average!(i64, u64); 95 | test_average!(i128, u128); 96 | test_average!(isize, usize); 97 | -------------------------------------------------------------------------------- /tests/roots.rs: -------------------------------------------------------------------------------- 1 | use num_integer::Roots; 2 | use num_traits::checked_pow; 3 | use num_traits::{AsPrimitive, PrimInt, Signed}; 4 | use std::f64::MANTISSA_DIGITS; 5 | use std::fmt::Debug; 6 | use std::mem; 7 | 8 | trait TestInteger: Roots + PrimInt + Debug + AsPrimitive + 'static {} 9 | 10 | impl TestInteger for T where T: Roots + PrimInt + Debug + AsPrimitive + 'static {} 11 | 12 | /// Check that each root is correct 13 | /// 14 | /// If `x` is positive, check `rⁿ ≤ x < (r+1)ⁿ`. 15 | /// If `x` is negative, check `(r-1)ⁿ < x ≤ rⁿ`. 16 | fn check(v: &[T], n: u32) 17 | where 18 | T: TestInteger, 19 | { 20 | for i in v { 21 | let rt = i.nth_root(n); 22 | // println!("nth_root({:?}, {}) = {:?}", i, n, rt); 23 | if n == 2 { 24 | assert_eq!(rt, i.sqrt()); 25 | } else if n == 3 { 26 | assert_eq!(rt, i.cbrt()); 27 | } 28 | if *i >= T::zero() { 29 | let rt1 = rt + T::one(); 30 | assert!(rt.pow(n) <= *i); 31 | if let Some(x) = checked_pow(rt1, n as usize) { 32 | assert!(*i < x); 33 | } 34 | } else { 35 | let rt1 = rt - T::one(); 36 | assert!(rt < T::zero()); 37 | assert!(*i <= rt.pow(n)); 38 | if let Some(x) = checked_pow(rt1, n as usize) { 39 | assert!(x < *i); 40 | } 41 | }; 42 | } 43 | } 44 | 45 | /// Get the maximum value that will round down as `f64` (if any), 46 | /// and its successor that will round up. 47 | /// 48 | /// Important because the `std` implementations cast to `f64` to 49 | /// get a close approximation of the roots. 50 | fn mantissa_max() -> Option<(T, T)> 51 | where 52 | T: TestInteger, 53 | { 54 | let bits = if T::min_value().is_zero() { 55 | 8 * mem::size_of::() 56 | } else { 57 | 8 * mem::size_of::() - 1 58 | }; 59 | if bits > MANTISSA_DIGITS as usize { 60 | let rounding_bit = T::one() << (bits - MANTISSA_DIGITS as usize - 1); 61 | let x = T::max_value() - rounding_bit; 62 | 63 | let x1 = x + T::one(); 64 | let x2 = x1 + T::one(); 65 | assert!(x.as_() < x1.as_()); 66 | assert_eq!(x1.as_(), x2.as_()); 67 | 68 | Some((x, x1)) 69 | } else { 70 | None 71 | } 72 | } 73 | 74 | fn extend(v: &mut Vec, start: T, end: T) 75 | where 76 | T: TestInteger, 77 | { 78 | let mut i = start; 79 | while i < end { 80 | v.push(i); 81 | i = i + T::one(); 82 | } 83 | v.push(i); 84 | } 85 | 86 | fn extend_shl(v: &mut Vec, start: T, end: T, mask: T) 87 | where 88 | T: TestInteger, 89 | { 90 | let mut i = start; 91 | while i != end { 92 | v.push(i); 93 | i = (i << 1) & mask; 94 | } 95 | } 96 | 97 | fn extend_shr(v: &mut Vec, start: T, end: T) 98 | where 99 | T: TestInteger, 100 | { 101 | let mut i = start; 102 | while i != end { 103 | v.push(i); 104 | i = i >> 1; 105 | } 106 | } 107 | 108 | fn pos() -> Vec 109 | where 110 | T: TestInteger, 111 | i8: AsPrimitive, 112 | { 113 | let mut v: Vec = vec![]; 114 | if mem::size_of::() == 1 { 115 | extend(&mut v, T::zero(), T::max_value()); 116 | } else { 117 | extend(&mut v, T::zero(), i8::max_value().as_()); 118 | extend( 119 | &mut v, 120 | T::max_value() - i8::max_value().as_(), 121 | T::max_value(), 122 | ); 123 | if let Some((i, j)) = mantissa_max::() { 124 | v.push(i); 125 | v.push(j); 126 | } 127 | extend_shl(&mut v, T::max_value(), T::zero(), !T::min_value()); 128 | extend_shr(&mut v, T::max_value(), T::zero()); 129 | } 130 | v 131 | } 132 | 133 | fn neg() -> Vec 134 | where 135 | T: TestInteger + Signed, 136 | i8: AsPrimitive, 137 | { 138 | let mut v: Vec = vec![]; 139 | if mem::size_of::() <= 1 { 140 | extend(&mut v, T::min_value(), T::zero()); 141 | } else { 142 | extend(&mut v, i8::min_value().as_(), T::zero()); 143 | extend( 144 | &mut v, 145 | T::min_value(), 146 | T::min_value() - i8::min_value().as_(), 147 | ); 148 | if let Some((i, j)) = mantissa_max::() { 149 | v.push(-i); 150 | v.push(-j); 151 | } 152 | extend_shl(&mut v, -T::one(), T::min_value(), !T::zero()); 153 | extend_shr(&mut v, T::min_value(), -T::one()); 154 | } 155 | v 156 | } 157 | 158 | macro_rules! test_roots { 159 | ($I:ident, $U:ident) => { 160 | mod $I { 161 | use crate::check; 162 | use crate::neg; 163 | use crate::pos; 164 | use num_integer::Roots; 165 | use std::mem; 166 | 167 | #[test] 168 | #[should_panic] 169 | fn zeroth_root() { 170 | (123 as $I).nth_root(0); 171 | } 172 | 173 | #[test] 174 | fn sqrt() { 175 | check(&pos::<$I>(), 2); 176 | } 177 | 178 | #[test] 179 | #[should_panic] 180 | fn sqrt_neg() { 181 | (-123 as $I).sqrt(); 182 | } 183 | 184 | #[test] 185 | fn cbrt() { 186 | check(&pos::<$I>(), 3); 187 | } 188 | 189 | #[test] 190 | fn cbrt_neg() { 191 | check(&neg::<$I>(), 3); 192 | } 193 | 194 | #[test] 195 | fn nth_root() { 196 | let bits = 8 * mem::size_of::<$I>() as u32 - 1; 197 | let pos = pos::<$I>(); 198 | for n in 4..bits { 199 | check(&pos, n); 200 | } 201 | } 202 | 203 | #[test] 204 | fn nth_root_neg() { 205 | let bits = 8 * mem::size_of::<$I>() as u32 - 1; 206 | let neg = neg::<$I>(); 207 | for n in 2..bits / 2 { 208 | check(&neg, 2 * n + 1); 209 | } 210 | } 211 | 212 | #[test] 213 | fn bit_size() { 214 | let bits = 8 * mem::size_of::<$I>() as u32 - 1; 215 | assert_eq!($I::max_value().nth_root(bits - 1), 2); 216 | assert_eq!($I::max_value().nth_root(bits), 1); 217 | assert_eq!($I::min_value().nth_root(bits), -2); 218 | assert_eq!(($I::min_value() + 1).nth_root(bits), -1); 219 | } 220 | } 221 | 222 | mod $U { 223 | use crate::check; 224 | use crate::pos; 225 | use num_integer::Roots; 226 | use std::mem; 227 | 228 | #[test] 229 | #[should_panic] 230 | fn zeroth_root() { 231 | (123 as $U).nth_root(0); 232 | } 233 | 234 | #[test] 235 | fn sqrt() { 236 | check(&pos::<$U>(), 2); 237 | } 238 | 239 | #[test] 240 | fn cbrt() { 241 | check(&pos::<$U>(), 3); 242 | } 243 | 244 | #[test] 245 | fn nth_root() { 246 | let bits = 8 * mem::size_of::<$I>() as u32 - 1; 247 | let pos = pos::<$I>(); 248 | for n in 4..bits { 249 | check(&pos, n); 250 | } 251 | } 252 | 253 | #[test] 254 | fn bit_size() { 255 | let bits = 8 * mem::size_of::<$U>() as u32; 256 | assert_eq!($U::max_value().nth_root(bits - 1), 2); 257 | assert_eq!($U::max_value().nth_root(bits), 1); 258 | } 259 | } 260 | }; 261 | } 262 | 263 | test_roots!(i8, u8); 264 | test_roots!(i16, u16); 265 | test_roots!(i32, u32); 266 | test_roots!(i64, u64); 267 | test_roots!(i128, u128); 268 | test_roots!(isize, usize); 269 | --------------------------------------------------------------------------------