├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── examples ├── euclid.rs ├── factorial.rs └── pidigits.rs ├── src ├── int.rs ├── lib.rs ├── ll │ ├── addsub.rs │ ├── asm │ │ ├── addmul_1.S │ │ ├── addsub_n.S │ │ └── mul_1.S │ ├── base.rs │ ├── bit.rs │ ├── div.rs │ ├── gcd.rs │ ├── limb.rs │ ├── limb_ptr.rs │ ├── mod.rs │ ├── mul.rs │ └── pow.rs ├── mem.rs ├── rational.rs ├── raw_vec.rs └── traits.rs └── tests ├── quickcheck.rs └── quickcheck_limbs.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | perf.data 4 | perf.data.old 5 | *.vi 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | cache: cargo 4 | 5 | install: | 6 | echo -e "\033[33;1mDownloading Rust\033[0m" && \ 7 | curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly-$TARGET && \ 8 | export PATH=$HOME/.cargo/bin:$PATH 9 | 10 | before_script: | 11 | pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH 12 | rustc --version 13 | 14 | script: 15 | - | 16 | travis-cargo build -- --features "$FEATURES" && 17 | travis-cargo test -- --lib --features "$FEATURES" && 18 | # need optimisations or else a full quickcheck takes too long 19 | travis-cargo test -- --release --features "$FEATURES full-quickcheck" && 20 | travis-cargo bench -- --features "$FEATURES" && 21 | travis-cargo doc -- --features "$FEATURES" 22 | 23 | after_success: 24 | - if [ -z "$FEATURES" -a "$BITS" = "32" ]; then travis-cargo doc-upload; fi 25 | 26 | matrix: 27 | include: 28 | - env: 29 | - TARGET=i686-unknown-linux-gnu 30 | BITS=32 31 | FEATURES='' 32 | addons: 33 | apt: 34 | packages: 35 | - libc6:i386 36 | - libstdc++6:i386 37 | - zlib1g-dev:i386 38 | - libssl-dev:i386 39 | - pkg-config:i386 40 | - gcc-multilib 41 | - libgmp-dev:i386 42 | - env: 43 | - TARGET=x86_64-unknown-linux-gnu 44 | BITS=64 45 | FEATURES='' 46 | addons: 47 | apt: 48 | packages: 49 | - libgmp-dev 50 | - env: 51 | - TARGET=i686-unknown-linux-gnu 52 | BITS=32 53 | FEATURES='fallbacks' 54 | addons: 55 | apt: 56 | packages: 57 | - libc6:i386 58 | - libstdc++6:i386 59 | - zlib1g-dev:i386 60 | - libssl-dev:i386 61 | - pkg-config:i386 62 | - gcc-multilib 63 | - libgmp-dev:i386 64 | - env: 65 | - TARGET=x86_64-unknown-linux-gnu 66 | BITS=64 67 | FEATURES='fallbacks' 68 | addons: 69 | apt: 70 | packages: 71 | - libgmp-dev 72 | - env: 73 | - TARGET=x86_64-unknown-linux-gnu 74 | BITS=64 75 | FEATURES='asm' 76 | addons: 77 | apt: 78 | packages: 79 | - libgmp-dev 80 | 81 | env: 82 | global: 83 | - TRAVIS_CARGO_NIGHTLY_FEATURE=unstable 84 | - secure: dc4TpJx2YONax6C5967cUmTKH/54pwUtDQu/9+KdjxA75AE1KjibZcg1W5bJhfYaWMPCTT2cwTfvUZP8k2tC0erWQUJv9iWy6MsrDTx88WeHmUlHls4OF64pa0kfSN4+Np4+96WMfFH2nlVGFazXzNeP2Dzwhyh54jW+qEfpICT5PSZm4cuLbhIzMviNu1fwFzQHDlsGnrhhc/rP9riYHIVYF9rCMMAugufKoDYdp4wllowhvVt+2OZlY2i7G0cPr3OZq5DvdQ07JWpGGKBMqSK5dLGTirfBSgTOv28CaCDwKUkTz1JCU3205NjbAnvGFkiym4opjRJpyLBIeRjxGULkodbBsUdg6F5JZTsmyaBaxszzk/l4TFaZ6TaKb2hU1G4EYa1lsPe5NEwOHY2YgGf+eCy/0kA4QpumUktY7844Vn409wJvZ5lmoiWhm6ZZpbu27KnZEBZGdWjfYIUdB3rm07BZcS8CcjYREzO+7rRPNwk3wg6DFFxRCugKMADLBBtndBxqenO12FuFiOkD5kyoufqSioO0quU6kAe5BtU+7+n7+mkzvhq7BowKXadKozNFVyo1rmGnO54z9TLgrwybRmx7pRXKJiYuOxL8T7UUPQUvQE2AYSF9462SdgDmpH+Um7Mojc9jb/qlEqBzHxze4X8Gz+25AcWvbgTVsQU= 85 | 86 | notifications: 87 | email: 88 | recipients: 89 | - micro@fastmail.com 90 | on_success: change 91 | on_failure: change 92 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ramp" 3 | description = "A high-performance multiple-precision arithmetic library" 4 | version = "0.7.0" 5 | authors = ["James Miller ", "Michael Rosenberg "] 6 | build = "build.rs" 7 | license = "Apache-2.0" 8 | readme = "README.md" 9 | keywords = ["bignum","math","number"] 10 | 11 | repository = "https://github.com/Aatch/ramp" 12 | documentation = "https://docs.rs/ramp" 13 | 14 | [lib] 15 | name = "ramp" 16 | path = "src/lib.rs" 17 | 18 | [features] 19 | unstable = [] # To keep travis-cargo happy 20 | fallbacks = [] 21 | asm = [] 22 | 23 | full-quickcheck = [] 24 | 25 | [dependencies] 26 | ieee754 = "0.2" 27 | rand = "0.8" 28 | hamming = "0.1" 29 | num-traits = "0.2" 30 | num-integer = "0.1" 31 | rust-gmp = { version = "0.5", optional = true } 32 | 33 | [build-dependencies] 34 | num-bigint = "0.4" 35 | rustc-cfg = "0.4" 36 | cc = "1.0" 37 | 38 | [dev-dependencies] 39 | num-bigint = "0.4" 40 | quickcheck = "0.6" 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | **This crate is no longer being maintained.** 4 | 5 | Fortunately, there's [lots of alternatives](https://crates.io/keywords/bignum) to `ramp`. Thanks for the good times :`) 6 | 7 | --- 8 | --- 9 | --- 10 | 11 | 12 | # RAMP - Rust Arithmetic in Multiple Precision 13 | 14 | [![Build Status](https://travis-ci.org/Aatch/ramp.svg?branch=master)](https://travis-ci.org/Aatch/ramp) 15 | [![Version](http://meritbadge.herokuapp.com/ramp)](https://crates.io/crates/ramp) 16 | [![Docs](https://docs.rs/ramp/badge.svg)](https://docs.rs/ramp) 17 | 18 | Ramp is a high-performance multiple-precision (aka "BigNum") library for working with numbers 19 | bigger than can normally be handled. Usage is very easy, you can almost use them as regular 20 | numbers. 21 | 22 | ## Example 23 | 24 | ```rust 25 | 26 | extern crate ramp; 27 | use ramp::Int; 28 | 29 | // Calculates n! 30 | fn factorial(n: usize) -> Int { 31 | let mut a = Int::from(1); 32 | 33 | for i in 2..n { 34 | a *= i; 35 | } 36 | 37 | return a * n; 38 | } 39 | ``` 40 | 41 | As you can see, it is very easy to work with these numbers. 42 | 43 | Operator overloads have been provided for by-value, which consumes the operand(s) and by-reference, 44 | which does not. The by-value overloads will attempt to re-use the space for the result (this isn't 45 | always possible). 46 | 47 | Operator overloads have also been provided for `i32` and `usize`, allowing easy (and efficient) 48 | operations when you have smaller numbers. The above example actually uses the `usize` overload, 49 | meaning only one `Int` is ever allocated. 50 | 51 | **NOTE** Due to use of unstable features (notably inline assembly), Ramp can only be compiled with 52 | a nightly build of `rustc`. 53 | 54 | ## Why another library? 55 | 56 | The `num` crate provides some bignum types that can be used, so why use Ramp? Well, Ramp is 57 | specifically focussed on multiple-precision arithmetic, while `num` is a general-purpose numerics 58 | library that happens to provide some multiple-precision arithmetic. 59 | 60 | You should `num` if you aren't able to use unstable Rust features or just want a small amount of 61 | functionality. Ramp should be used when you need high-performance and extra functionality. 62 | 63 | ## Overall Design 64 | 65 | Ramp is split into two main parts: high-level code and low-level code. The high-level code is what 66 | you should be using, however the low-level code is where the real work is done. 67 | 68 | The low-level routines (in `ll`) are predominantly unsafe functions that work with raw pointers, 69 | and some of the routines are implemented using inline assembly to gain access to processor-specific 70 | functionality. 71 | 72 | ### Limbs 73 | 74 | The term "Limb" is used frequently in Ramp. It's a term borrowed from GMP and is a single "digit" 75 | for the base that Ramp works in. Since the base is equal to 2^word_size, these are very large 76 | "digits", hence the use of the word "Limb" instead. 77 | 78 | ## Future Work 79 | 80 | Ramp is currently very rough and incomplete. Broadly, there are three types Ramp aims to provide: 81 | integers, rationals, and floats. Integers (`Int`) are present and mostly complete, Rationals are 82 | present and have a basic implementation. Floats are not yet implemented. 83 | 84 | In the low-level routines, there are a few operations, notably multiplication and division, that 85 | are currently implemented using the simplest working algorithm. While this is sufficient for 86 | relatively small numbers, larger numbers should be using better algorithms. 87 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_must_use)] 2 | 3 | extern crate cc; 4 | extern crate num_bigint; 5 | extern crate rustc_cfg; 6 | 7 | use std::env; 8 | use std::fs::File; 9 | use std::io::Write; 10 | use std::path::Path; 11 | 12 | use num_bigint::BigUint; 13 | 14 | fn main() { 15 | let out_dir = env::var("OUT_DIR").unwrap(); 16 | let dest_path = Path::new(&out_dir).join("bases_table.rs"); 17 | let mut f = File::create(&dest_path).unwrap(); 18 | 19 | gen_bases(&mut f); 20 | 21 | if env::var("CARGO_FEATURE_ASM").is_ok() { 22 | compile_asm(); 23 | } 24 | } 25 | 26 | // Compile the asm implementations of operations. This is currently very dumb 27 | // and should probably be a little smarter in how it does the job. I'll probably 28 | // need to split out the generic impls and handle that too... 29 | fn compile_asm() { 30 | if let Ok(target) = env::var("TARGET") { 31 | if let Ok(host) = env::var("HOST") { 32 | if host != target { 33 | panic!("Cross compiling not currently supported"); 34 | } 35 | 36 | // Currently only supported for 64-bit linux 37 | if (target.contains("x86-64") || target.contains("x86_64")) && target.contains("linux") 38 | { 39 | let asm_srcs = &[ 40 | "src/ll/asm/addsub_n.S", 41 | "src/ll/asm/mul_1.S", 42 | "src/ll/asm/addmul_1.S", 43 | ]; 44 | cc::Build::new().files(asm_srcs).compile("libasm.a"); 45 | 46 | // Use a cfg param so turning the feature on when we don't have 47 | // asm impls available doesn't cause compile errors 48 | println!("cargo:rustc-cfg=asm"); 49 | } 50 | } 51 | } 52 | } 53 | 54 | fn gen_bases(f: &mut File) { 55 | let limb_size = get_target_limb_size(); 56 | 57 | // Base '0' and Base '1' don't make any sense, but having 58 | // entries for them makes the code that uses them simpler. 59 | f.write_all( 60 | b"static BASES : [Base; 257] = [ 61 | /* 0 */ Base { digits_per_limb: 0, big_base: ::ll::limb::Limb(0) }, 62 | /* 1 */ Base { digits_per_limb: 0, big_base: ::ll::limb::Limb(0) },\n", 63 | ); 64 | 65 | // Generate entries up to base 256, which is the largest base 66 | // where a digit still fits in a single byte. 67 | for i in 2..257 { 68 | gen_base(f, limb_size, i); 69 | } 70 | 71 | f.write_all(b"];\n"); 72 | } 73 | 74 | fn gen_base(f: &mut File, limb_size: u64, base: usize) { 75 | let mut digits_per_limb = 1; 76 | let base_as_bigint: BigUint = base.into(); 77 | let mut big_base: BigUint = base_as_bigint.clone(); 78 | // Loop through, multiplying `big_base` by `base` until 79 | // `big_base` is bigger than 2^limb_size 80 | loop { 81 | let base_big_base = big_base.clone() * &base_as_bigint; 82 | // big_base * base can't fit in a single limb anymore 83 | if base_big_base.bits() > limb_size { 84 | // If the overflow is exactly 1, then big_base * base 85 | // is equal to 2^limb_size, not greater than. Add another 86 | // digit before breaking. 87 | if base_big_base == BigUint::from(1usize) << limb_size { 88 | digits_per_limb += 1; 89 | } 90 | break; 91 | } 92 | digits_per_limb += 1; 93 | big_base = base_big_base; 94 | } 95 | 96 | // Powers of two use a different path, so re-use the big_base field to store 97 | // the number of bits required to store a digit in the base. 98 | if base.is_power_of_two() { 99 | big_base = base.trailing_zeros().into(); 100 | } 101 | 102 | writeln!( 103 | f, 104 | " /* {:3} */ Base {{ digits_per_limb: {}, big_base: ::ll::limb::Limb(0x{:x}) }},", 105 | base, digits_per_limb, big_base 106 | ); 107 | } 108 | 109 | fn get_target_limb_size() -> u64 { 110 | let target = env::var_os("TARGET") 111 | .expect("no build target given") 112 | .into_string() 113 | .expect("build target isn't unicode"); 114 | let cfg = rustc_cfg::Cfg::of(&target).expect("couldn't load config of target env"); 115 | cfg.target_pointer_width.parse().unwrap() 116 | } 117 | -------------------------------------------------------------------------------- /examples/euclid.rs: -------------------------------------------------------------------------------- 1 | extern crate ramp; 2 | 3 | use std::cmp::Ordering; 4 | use ramp::Int; 5 | 6 | #[derive(Debug,Copy,Clone,PartialEq,Eq)] 7 | struct GcdResult { 8 | /// Greatest common divisor. 9 | gcd: T, 10 | /// Coefficients such that: gcd(a, b) = c1*a + c2*b 11 | c1: T, c2: T, 12 | } 13 | 14 | /// Calculate greatest common divisor and the corresponding coefficients. 15 | fn extended_gcd(a: Int, b: Int) -> GcdResult { 16 | // Euclid's extended algorithm 17 | let (mut s, mut old_s) = (Int::zero(), Int::one()); 18 | let (mut t, mut old_t) = (Int::one(), Int::zero()); 19 | let (mut r, mut old_r) = (b, a); 20 | 21 | let mut tmp = Int::zero(); 22 | while r != 0 { 23 | let quotient = &old_r / &r; 24 | tmp.clone_from(&r); r = &old_r - "ient * r; old_r.clone_from(&tmp); 25 | tmp.clone_from(&s); s = &old_s - "ient * s; old_s.clone_from(&tmp); 26 | tmp.clone_from(&t); t = &old_t - "ient * t; old_t.clone_from(&tmp); 27 | } 28 | 29 | let _quotients = (t, s); // == (a, b) / gcd 30 | 31 | GcdResult { gcd: old_r, c1: old_s, c2: old_t } 32 | } 33 | 34 | /// Find the standard representation of a (mod n). 35 | fn normalize(a: Int, n: &Int) -> Int { 36 | let a = a % n; 37 | match a.cmp(&Int::zero()) { 38 | Ordering::Less => a + n, 39 | _ => a, 40 | } 41 | } 42 | 43 | /// Calculate the inverse of a (mod n). 44 | fn inverse(a: Int, n: &Int) -> Option { 45 | let GcdResult { gcd, c1: c, c2: _ } = extended_gcd(a, n.clone()); 46 | if gcd == 1 { 47 | Some(normalize(c, n)) 48 | } else { 49 | None 50 | } 51 | } 52 | 53 | /// Calculate base^exp (mod modulus). 54 | fn mpow(mut base: Int, mut exp: u32, modulus: &Int) -> Int { 55 | let mut result = Int::one(); 56 | base = base % modulus; 57 | while exp > 0 { 58 | if exp % 2 == 1 { 59 | result = (result * &base) % modulus; 60 | } 61 | exp = exp >> 1; 62 | base = (base.dsquare()) % modulus; 63 | } 64 | result 65 | } 66 | 67 | fn main() { 68 | let (a, b) = (Int::from(6), Int::from(3)); 69 | let GcdResult { gcd, c1, c2 } = extended_gcd(a.clone(), b.clone()); 70 | println!("gcd({}, {}) = {}*{} + {}*{} = {}", &a, &b, &c1, &a, &c2, &b, &gcd); 71 | println!("7**-1 (mod 10) = {}", inverse(Int::from(7), &Int::from(10)).unwrap()); 72 | println!("7**1000 (mod 13) = {}", mpow(Int::from(7), 1000, &Int::from(13))); 73 | } 74 | -------------------------------------------------------------------------------- /examples/factorial.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | extern crate ramp; 16 | 17 | use ramp::Int; 18 | 19 | fn main() { 20 | println!("5!: {}", factorial(5)); 21 | println!("10!: {}", factorial(10)); 22 | println!("20!: {}", factorial(20)); 23 | println!("100!: {}", factorial(100)); 24 | println!("1000!: {}", factorial(1000)); 25 | println!("20000!: {}", factorial(20000)); 26 | } 27 | 28 | /// Calculates n! 29 | fn factorial(n: usize) -> Int { 30 | let mut a = Int::from(1); 31 | if n == 0 || n == 1 { 32 | return a; 33 | } 34 | 35 | for i in 2..n { 36 | a = a * i; 37 | } 38 | 39 | return a * n; 40 | } 41 | -------------------------------------------------------------------------------- /examples/pidigits.rs: -------------------------------------------------------------------------------- 1 | // A ramp port of TeXitoi's Rust version on 2 | // http://benchmarksgame.alioth.debian.org/ 3 | 4 | extern crate ramp; 5 | use ramp::Int; 6 | use ramp::ll::limb::Limb; 7 | 8 | fn main() { 9 | let n = std::env::args_os().nth(1) 10 | .and_then(|s| s.into_string().ok()) 11 | .and_then(|n| n.parse().ok()) 12 | .unwrap_or(27); 13 | for (i, d) in Context::new().enumerate().take(n) { 14 | print!("{}", d); 15 | if (i + 1) % 10 == 0 { println!("\t:{}", i + 1); } 16 | } 17 | if n % 10 != 0 { 18 | for _ in n % 10 .. 10 { print!(" "); } 19 | println!("\t:{}", n); 20 | } 21 | } 22 | 23 | pub struct Context { 24 | k: Limb, 25 | tmp1: Int, 26 | acc: Int, 27 | den: Int, 28 | num: Int 29 | } 30 | impl Context { 31 | pub fn new() -> Context { 32 | Context { 33 | k: Limb(0), 34 | tmp1: Int::zero(), 35 | acc: Int::zero(), 36 | den: Int::one(), 37 | num: Int::one() 38 | } 39 | } 40 | fn extract_digit(&mut self, nth: Limb) -> Limb { 41 | self.tmp1.clone_from(&self.num); 42 | self.tmp1 *= nth; 43 | self.tmp1 += &self.acc; 44 | self.tmp1 /= &self.den; 45 | 46 | return self.tmp1.to_single_limb(); 47 | } 48 | fn eliminate_digit(&mut self, d: Limb) { 49 | self.acc -= self.den.clone() * d; 50 | self.acc *= 10; 51 | self.num *= 10; 52 | } 53 | fn next_term(&mut self) { 54 | self.k = self.k + 1; 55 | let k2 = self.k * 2 + 1; 56 | self.acc += &self.num + &self.num; 57 | self.acc *= k2; 58 | 59 | self.den *= k2; 60 | self.num *= self.k; 61 | } 62 | } 63 | impl Iterator for Context { 64 | type Item = Limb; 65 | fn next(&mut self) -> Option { 66 | loop { 67 | self.next_term(); 68 | if self.num > self.acc { continue; } 69 | let d = self.extract_digit(Limb(3)); 70 | if d != self.extract_digit(Limb(4)) { continue; } 71 | 72 | self.eliminate_digit(d); 73 | return Some(d); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! # Deprecated 16 | //! 17 | //! **This crate is no longer being maintained.** 18 | //! 19 | //! Fortunately, there's [lots of alternatives](https://crates.io/keywords/bignum) to `ramp`. 20 | //! Thanks for the good times :`) 21 | 22 | #![crate_type = "lib"] 23 | #![crate_name = "ramp"] 24 | #![feature(core_intrinsics, allocator_api)] 25 | #![feature(step_trait, ptr_internals, try_reserve_kind, raw_vec_internals)] 26 | #![cfg_attr(test, feature(test))] 27 | 28 | #[cfg(test)] 29 | extern crate test; 30 | 31 | extern crate alloc; 32 | extern crate core; 33 | extern crate hamming; 34 | extern crate ieee754; 35 | extern crate num_integer; 36 | extern crate num_traits; 37 | extern crate rand; 38 | 39 | pub mod ll; 40 | mod mem; 41 | mod raw_vec; 42 | 43 | pub mod int; 44 | pub mod rational; 45 | pub mod traits; 46 | 47 | // Re-exports 48 | 49 | pub use int::Int; 50 | pub use int::RandomInt; 51 | -------------------------------------------------------------------------------- /src/ll/addsub.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![allow(improper_ctypes)] 16 | 17 | use ll::limb::Limb; 18 | use ll::limb_ptr::{Limbs, LimbsMut}; 19 | use super::{copy_rest, same_or_separate}; 20 | 21 | #[allow(dead_code)] 22 | unsafe fn add_n_generic(mut wp: LimbsMut, mut xp: Limbs, mut yp: Limbs, 23 | mut n: i32) -> Limb { 24 | 25 | let mut carry = Limb(0); 26 | 27 | loop { 28 | let xl = *xp; 29 | let yl = *yp; 30 | 31 | let (sl, c1) = xl.add_overflow(yl); 32 | let (rl, c2) = sl.add_overflow(carry); 33 | 34 | carry = if c1 || c2 { Limb(1) } else { Limb(0) }; 35 | *wp = rl; 36 | 37 | n -= 1; 38 | if n == 0 { break; } 39 | 40 | wp = wp.offset(1); 41 | xp = xp.offset(1); 42 | yp = yp.offset(1); 43 | 44 | } 45 | 46 | carry 47 | } 48 | 49 | /** 50 | * Adds the `n` least signficant limbs of `xp` and `yp`, storing the result in {wp, n}. 51 | * If there was a carry, it is returned. 52 | */ 53 | #[inline] 54 | #[cfg(asm)] 55 | pub unsafe fn add_n(mut wp: LimbsMut, xp: Limbs, yp: Limbs, 56 | n: i32) -> Limb { 57 | #[cfg(all(not(feature="fallbacks"),target_arch="x86_64"))] 58 | extern "C" { fn ramp_add_n(wp: *mut Limb, xp: *const Limb, yp: *const Limb, 59 | n: i32) -> Limb; } 60 | 61 | debug_assert!(n >= 1); 62 | debug_assert!(same_or_separate(wp, n, xp, n)); 63 | debug_assert!(same_or_separate(wp, n, yp, n)); 64 | 65 | return ramp_add_n(&mut *wp, &*xp, &*yp, n); 66 | } 67 | 68 | /** 69 | * Adds the `n` least signficant limbs of `xp` and `yp`, storing the result in {wp, n}. 70 | * If there was a carry, it is returned. 71 | */ 72 | #[cfg(any(feature="fallbacks",not(asm)))] 73 | #[inline] 74 | pub unsafe fn add_n(wp: LimbsMut, xp: Limbs, yp: Limbs, 75 | n: i32) -> Limb { 76 | debug_assert!(n >= 1); 77 | debug_assert!(same_or_separate(wp, n, xp, n)); 78 | debug_assert!(same_or_separate(wp, n, yp, n)); 79 | 80 | add_n_generic(wp, xp, yp, n) 81 | } 82 | 83 | #[allow(dead_code)] 84 | unsafe fn sub_n_generic(mut wp: LimbsMut, mut xp: Limbs, mut yp: Limbs, 85 | mut n: i32) -> Limb { 86 | let mut carry = Limb(0); 87 | 88 | debug_assert!(n >= 1); 89 | debug_assert!(same_or_separate(wp, n, xp, n)); 90 | debug_assert!(same_or_separate(wp, n, yp, n)); 91 | 92 | loop { 93 | let xl = *xp; 94 | let yl = *yp; 95 | 96 | let (sl, c1) = xl.sub_overflow(yl); 97 | let (rl, c2) = sl.sub_overflow(carry); 98 | 99 | carry = if c1 || c2 { Limb(1) } else { Limb(0) }; 100 | *wp = rl; 101 | 102 | n -= 1; 103 | if n == 0 { break; } 104 | 105 | wp = wp.offset(1); 106 | xp = xp.offset(1); 107 | yp = yp.offset(1); 108 | 109 | } 110 | 111 | carry 112 | } 113 | 114 | /** 115 | * Subtracts the `n` least signficant limbs of `yp` from `xp`, storing the result in {wp, n}. 116 | * If there was a borrow from a higher-limb (i.e., the result would be negative), it is returned. 117 | */ 118 | #[cfg(asm)] 119 | #[inline] 120 | pub unsafe fn sub_n(mut wp: LimbsMut, xp: Limbs, yp: Limbs, 121 | n: i32) -> Limb { 122 | extern "C" { 123 | fn ramp_sub_n(wp: *mut Limb, xp: *const Limb, yp: *const Limb, 124 | n: i32) -> Limb; 125 | } 126 | 127 | ramp_sub_n(&mut *wp, &*xp, &*yp, n) 128 | } 129 | 130 | /** 131 | * Subtracts the `n` least signficant limbs of `yp` from `xp`, storing the result in {wp, n}. 132 | * If there was a borrow from a higher-limb (i.e., the result would be negative), it is returned. 133 | */ 134 | #[cfg(not(asm))] 135 | #[inline] 136 | pub unsafe fn sub_n(wp: LimbsMut, xp: Limbs, yp: Limbs, 137 | n: i32) -> Limb { 138 | sub_n_generic(wp, xp, yp, n) 139 | } 140 | 141 | macro_rules! aors { 142 | ($op:ident, $lop:ident, $f:ident) => { 143 | #[inline] 144 | pub unsafe fn $op(wp: LimbsMut, 145 | xp: Limbs, xs: i32, 146 | yp: Limbs, ys: i32) -> Limb { 147 | 148 | debug_assert!(xs >= ys); 149 | debug_assert!(ys >= 0); 150 | 151 | let mut i = ys; 152 | let carry = $f(wp, xp, yp, ys); 153 | if carry == 1 { 154 | loop { 155 | if i >= xs { return Limb(1); } 156 | 157 | let (x, carry) = Limb::$lop(*xp.offset(i as isize), Limb(1)); 158 | *wp.offset(i as isize) = x; 159 | i += 1; 160 | if !carry { 161 | break; 162 | } 163 | } 164 | } 165 | 166 | if wp.as_const() != xp && i < xs { 167 | copy_rest(xp, wp, xs, i); 168 | } 169 | 170 | return Limb(0); 171 | } 172 | } 173 | } 174 | 175 | aors!(add, add_overflow, add_n); 176 | aors!(sub, sub_overflow, sub_n); 177 | 178 | macro_rules! aors_1 { 179 | ($op:ident, $f:ident) => { 180 | #[inline] 181 | pub unsafe fn $op(mut wp: LimbsMut, 182 | xp: Limbs, xs: i32, 183 | y: Limb) -> Limb { 184 | 185 | if xs > 0 { 186 | let (v, mut carry) = Limb::$f(*xp, y); 187 | *wp = v; 188 | let mut i = 1; 189 | while carry { 190 | if i >= xs { return Limb(1); } 191 | 192 | let (v, c) = Limb::$f(*xp.offset(i as isize), Limb(1)); 193 | carry = c; 194 | *wp.offset(i as isize) = v; 195 | i += 1; 196 | } 197 | } 198 | return Limb(0); 199 | } 200 | } 201 | } 202 | 203 | aors_1!(add_1, add_overflow); 204 | aors_1!(sub_1, sub_overflow); 205 | 206 | #[inline(always)] 207 | pub unsafe fn incr(mut ptr: LimbsMut, incr: Limb) { 208 | let (x, mut carry) = (*ptr).add_overflow(incr); 209 | *ptr = x; 210 | 211 | while carry { 212 | ptr = ptr.offset(1); 213 | let (x, c) = (*ptr).add_overflow(Limb(1)); 214 | *ptr = x; 215 | carry = c; 216 | } 217 | } 218 | 219 | #[inline(always)] 220 | pub unsafe fn decr(mut ptr: LimbsMut, decr: Limb) { 221 | let x = *ptr; 222 | *ptr = x - decr; 223 | 224 | if x < decr { 225 | loop { 226 | ptr = ptr.offset(1); 227 | let x = *ptr; 228 | *ptr = x - 1; 229 | if x != 0 { break; } 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/ll/asm/addmul_1.S: -------------------------------------------------------------------------------- 1 | .text 2 | .file "addmul_1.S" 3 | 4 | #define wp %rdi 5 | #define xp %rsi 6 | #define n_param %edx 7 | #define n %r11d 8 | #define v %rcx 9 | 10 | .section .text.ramp_addmul_1,"ax",@progbits 11 | .globl ramp_addmul_1 12 | .align 16, 0x90 13 | .type ramp_addmul_1,@function 14 | ramp_addmul_1: 15 | .cfi_startproc 16 | 17 | #define L(lbl) .LADDMUL_ ## lbl 18 | 19 | mov n_param, n # Move n away from %rdx 20 | 21 | mov (xp), %rax 22 | mul v 23 | add %rax, (wp) 24 | adc $0, %rdx 25 | mov %rdx, %r8 26 | 27 | dec n 28 | jz L(ret) 29 | add $8, wp 30 | add $8, xp 31 | .align 16 32 | L(top): 33 | mov (xp), %rax 34 | mul v 35 | add %r8, %rax 36 | adc $0, %rdx 37 | mov %rdx, %r8 38 | add %rax, (wp) 39 | adc $0, %r8 40 | 41 | add $8, wp 42 | add $8, xp 43 | dec n 44 | jnz L(top) 45 | L(ret): 46 | mov %r8, %rax 47 | ret 48 | L(tmp): 49 | .size ramp_addmul_1, L(tmp) - ramp_addmul_1 50 | .cfi_endproc 51 | 52 | .section .text.ramp_submul_1,"ax",@progbits 53 | .globl ramp_submul_1 54 | .align 16, 0x90 55 | .type ramp_submul_1,@function 56 | ramp_submul_1: 57 | .cfi_startproc 58 | 59 | #undef L 60 | #define L(lbl) .LSUBMUL_ ## lbl 61 | 62 | mov n_param, n # Move n away from %rdx 63 | 64 | mov (xp), %rax 65 | mul v 66 | sub %rax, (wp) 67 | adc $0, %rdx 68 | mov %rdx, %r8 69 | 70 | dec n 71 | jz L(ret) 72 | add $8, wp 73 | add $8, xp 74 | .align 16 75 | L(top): 76 | mov (xp), %rax 77 | mul v 78 | add %r8, %rax 79 | adc $0, %rdx 80 | mov %rdx, %r8 81 | sub %rax, (wp) 82 | adc $0, %r8 83 | 84 | add $8, wp 85 | add $8, xp 86 | dec n 87 | jnz L(top) 88 | L(ret): 89 | mov %r8, %rax 90 | ret 91 | L(tmp): 92 | .size ramp_submul_1, L(tmp) - ramp_submul_1 93 | .cfi_endproc 94 | -------------------------------------------------------------------------------- /src/ll/asm/addsub_n.S: -------------------------------------------------------------------------------- 1 | .text 2 | .file "addsub_n.S" 3 | 4 | #define wp %rdi 5 | #define xp %rsi 6 | #define yp %rdx 7 | #define n %rcx 8 | 9 | .section .text.ramp_add_n,"ax",@progbits 10 | .globl ramp_add_n 11 | .align 16, 0x90 12 | .type ramp_add_n,@function 13 | ramp_add_n: 14 | .cfi_startproc 15 | 16 | #define L(lbl) .LADD_ ## lbl 17 | 18 | mov %ecx, %eax 19 | shr $2, n 20 | and $3, %eax 21 | jrcxz L(lt4) 22 | 23 | mov (xp), %r8 24 | mov 8(xp), %r9 25 | dec n 26 | jmp L(mid) 27 | 28 | L(lt4): 29 | dec %eax 30 | mov (xp), %r8 31 | jnz L(2) 32 | adc (yp), %r8 33 | mov %r8, (wp) 34 | adc %eax, %eax 35 | ret 36 | 37 | L(2): 38 | dec %eax 39 | mov 8(xp), %r9 40 | jnz L(3) 41 | adc (yp), %r8 42 | adc 8(yp), %r9 43 | mov %r8, (wp) 44 | mov %r9, 8(wp) 45 | adc %eax, %eax 46 | ret 47 | 48 | L(3): 49 | mov 16(xp), %r10 50 | adc (yp), %r8 51 | adc 8(yp), %r9 52 | adc 16(yp), %r10 53 | mov %r8, (wp) 54 | mov %r9, 8(wp) 55 | mov %r10, 16(wp) 56 | setc %al 57 | ret 58 | 59 | .align 16 60 | L(top): 61 | adc (yp), %r8 62 | adc 8(yp), %r9 63 | adc 16(yp), %r10 64 | adc 24(yp), %r11 65 | mov %r8, (wp) 66 | lea 32(xp), xp 67 | mov %r9, 8(wp) 68 | mov %r10, 16(wp) 69 | dec n 70 | mov %r11, 24(wp) 71 | lea 32(yp), yp 72 | mov (xp), %r8 73 | mov 8(xp), %r9 74 | lea 32(wp), %rdi 75 | L(mid): 76 | mov 16(xp), %r10 77 | mov 24(xp), %r11 78 | jnz L(top) 79 | 80 | L(end): 81 | lea 32(xp), xp 82 | adc (yp), %r8 83 | adc 8(yp), %r9 84 | adc 16(yp), %r10 85 | adc 24(yp), %r11 86 | lea 32(yp), yp 87 | mov %r8, (wp) 88 | mov %r9, 8(wp) 89 | mov %r10, 16(wp) 90 | mov %r11, 24(wp) 91 | lea 32(wp), wp 92 | 93 | inc %eax 94 | dec %eax 95 | jnz L(lt4) 96 | adc %eax, %eax 97 | ret 98 | L(tmp): 99 | .size ramp_add_n, L(tmp) - ramp_add_n 100 | .cfi_endproc 101 | 102 | .section .text.ramp_sub_n,"ax",@progbits 103 | .globl ramp_sub_n 104 | .align 16, 0x90 105 | .type ramp_sub_n,@function 106 | ramp_sub_n: 107 | .cfi_startproc 108 | 109 | #undef L 110 | #define L(lbl) .LSUB_ ## lbl 111 | 112 | mov %ecx, %eax 113 | shr $2, n 114 | and $3, %eax 115 | jrcxz L(lt4) 116 | 117 | mov (xp), %r8 118 | mov 8(xp), %r9 119 | dec n 120 | jmp L(mid) 121 | 122 | L(lt4): 123 | dec %eax 124 | mov (xp), %r8 125 | jnz L(2) 126 | sbb (yp), %r8 127 | mov %r8, (wp) 128 | adc %eax, %eax 129 | ret 130 | 131 | L(2): 132 | dec %eax 133 | mov 8(xp), %r9 134 | jnz L(3) 135 | sbb (yp), %r8 136 | sbb 8(yp), %r9 137 | mov %r8, (wp) 138 | mov %r9, 8(wp) 139 | adc %eax, %eax 140 | ret 141 | 142 | L(3): 143 | mov 16(xp), %r10 144 | sbb (yp), %r8 145 | sbb 8(yp), %r9 146 | sbb 16(yp), %r10 147 | mov %r8, (wp) 148 | mov %r9, 8(wp) 149 | mov %r10, 16(wp) 150 | setc %al 151 | ret 152 | 153 | .align 16 154 | L(top): 155 | sbb (yp), %r8 156 | sbb 8(yp), %r9 157 | sbb 16(yp), %r10 158 | sbb 24(yp), %r11 159 | mov %r8, (wp) 160 | lea 32(xp), xp 161 | mov %r9, 8(wp) 162 | mov %r10, 16(wp) 163 | dec n 164 | mov %r11, 24(wp) 165 | lea 32(yp), yp 166 | mov (xp), %r8 167 | mov 8(xp), %r9 168 | lea 32(wp), %rdi 169 | L(mid): 170 | mov 16(xp), %r10 171 | mov 24(xp), %r11 172 | jnz L(top) 173 | 174 | L(end): 175 | lea 32(xp), xp 176 | sbb (yp), %r8 177 | sbb 8(yp), %r9 178 | sbb 16(yp), %r10 179 | sbb 24(yp), %r11 180 | lea 32(yp), yp 181 | mov %r8, (wp) 182 | mov %r9, 8(wp) 183 | mov %r10, 16(wp) 184 | mov %r11, 24(wp) 185 | lea 32(wp), wp 186 | 187 | inc %eax 188 | dec %eax 189 | jnz L(lt4) 190 | adc %eax, %eax 191 | ret 192 | L(tmp): 193 | .size ramp_sub_n, L(tmp) - ramp_sub_n 194 | .cfi_endproc 195 | -------------------------------------------------------------------------------- /src/ll/asm/mul_1.S: -------------------------------------------------------------------------------- 1 | .text 2 | .file "mul_1.S" 3 | 4 | #define wp %rdi 5 | #define xp %rsi 6 | #define n_param %edx 7 | #define n %r11d 8 | #define v %rcx 9 | 10 | .section .text.ramp_mul_1,"ax",@progbits 11 | .globl ramp_mul_1 12 | .align 16, 0x90 13 | .type ramp_mul_1,@function 14 | ramp_mul_1: 15 | .cfi_startproc 16 | 17 | #define L(lbl) .LMUL_ ## lbl 18 | 19 | mov n_param, n # Move n away from %rdx 20 | 21 | mov (xp), %rax 22 | mul v 23 | mov %rax, (wp) 24 | 25 | dec n 26 | jz L(ret) 27 | add $8, wp 28 | add $8, xp 29 | mov %rdx, %r8 30 | .align 16 31 | L(top): 32 | mov (xp), %rax 33 | mul v 34 | add %r8, %rax 35 | adc $0, %rdx 36 | mov %rax, (wp) 37 | add $8, wp 38 | add $8, xp 39 | dec n 40 | jz L(ret) 41 | mov %rdx, %r8 42 | jmp L(top) 43 | L(ret): 44 | mov %rdx, %rax 45 | ret 46 | L(tmp): 47 | .size ramp_mul_1, L(tmp) - ramp_mul_1 48 | .cfi_endproc 49 | -------------------------------------------------------------------------------- /src/ll/base.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /*! 16 | * Base conversion utilities 17 | * 18 | * Provides functions for converting an integer to/from a given base. In both `to_base` and 19 | * `from_base` the base-N output or input (respectively) is stored as raw bytes. That means that a 20 | * base-10 input contains bytes each with a value from 0-9. 21 | */ 22 | 23 | use std::intrinsics::assume; 24 | 25 | use ll; 26 | use ll::limb::Limb; 27 | use ll::limb_ptr::{Limbs, LimbsMut}; 28 | 29 | /// Information for converting to/from a given base, B. Stored in a table generated 30 | /// by build.rs 31 | struct Base { 32 | /// Number of digits a limb can hold in a given base. Except if B is a power of 2, 33 | /// in which case it is equal to the number of bits per digit in base B 34 | digits_per_limb: u32, 35 | /// The "big base", essentially the largest B^m that will fit in a limb. 36 | /// Should be the same as B^digits_per_limb 37 | big_base: Limb, 38 | } 39 | // Include BASES table 40 | include!(concat!(env!("OUT_DIR"), "/bases_table.rs")); 41 | 42 | #[inline(always)] 43 | fn div_unnorm(n: Limb, d: Limb) -> (Limb, Limb) { 44 | (n / d, n % d) 45 | } 46 | 47 | #[inline] 48 | /// Returns the number of digits needed to represent `p` in base `base` 49 | /// without sign. If the base is not a power of two, the result is only 50 | /// an estimate. It can equal the the actually needed digits or overestimate 51 | /// by 1. 52 | /// Returns 1 if the number is 0; 53 | pub unsafe fn num_base_digits(p: Limbs, n: i32, base: u32) -> usize { 54 | debug_assert!(base >= 2); 55 | assume(base >= 2); 56 | 57 | if n == 0 { return 1; } 58 | 59 | let cnt = (*p.offset((n - 1) as isize)).leading_zeros() as usize; 60 | let total_bits = (Limb::BITS * (n as usize)) - cnt; 61 | 62 | if base == 2 { 63 | // no need to do anything complicated here at all, so let's go 64 | // as fast as possible (this is a somewhat common case, due to 65 | // `bit_length`) 66 | total_bits 67 | } else if base.is_power_of_two() { 68 | let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize; 69 | if bits_per_digit.is_power_of_two() { 70 | // doing an actual division here is much slower than this 71 | (total_bits + bits_per_digit - 1) >> bits_per_digit.trailing_zeros() 72 | } else { 73 | (total_bits + bits_per_digit - 1) / bits_per_digit 74 | } 75 | } else { 76 | // Not sure if using floating-point arithmetic here is the best idea, 77 | // but it should be a reasonable accurate result, maybe a little high 78 | let total_bits = total_bits as f64; 79 | 80 | let lg2b = (base as f64).log2(); 81 | let digits = total_bits / lg2b; 82 | return digits.ceil() as usize; 83 | } 84 | } 85 | 86 | #[inline] 87 | pub fn base_digits_to_len(num: usize, base: u32) -> usize { 88 | debug_assert!(base >= 2); 89 | 90 | if num == 0 { return 0; } 91 | 92 | let digits_per_limb = BASES[base as usize].digits_per_limb as usize; 93 | 94 | (num / digits_per_limb) + 1 95 | } 96 | 97 | /** 98 | * Converts `nn` limbs at `np` to the given base, storing the output in `out`. `out` is assumed to 99 | * have enough space for the entire digit. The output is stored from most-significant digit to least. 100 | * 101 | * The values in `out` are the raw values of the base. Conversion for output should be done as a second 102 | * step. 103 | */ 104 | pub unsafe fn to_base(base: u32, np: Limbs, nn: i32, mut out_byte: F) { 105 | debug_assert!(nn >= 0); 106 | debug_assert!(base < BASES.len() as u32); 107 | debug_assert!(base >= 2); 108 | assume(base < BASES.len() as u32); 109 | assume(base >= 2); 110 | 111 | if nn <= 0 { 112 | out_byte(0); 113 | return; 114 | } 115 | // Fast path for powers-of-two, since each limb is already in base B^m format 116 | if base.is_power_of_two() { 117 | let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize; 118 | assume(bits_per_digit > 0); 119 | 120 | let mut n1 = *np.offset((nn - 1) as isize); 121 | let cnt = n1.leading_zeros() as usize; 122 | 123 | let mut bits = Limb::BITS * (nn as usize) - cnt; 124 | let cnt = bits % bits_per_digit; 125 | if cnt != 0 { 126 | bits += bits_per_digit - cnt; 127 | } 128 | 129 | let mut bit_pos : isize = (bits - (nn as usize - 1) * Limb::BITS) as isize; 130 | 131 | let mut i = nn - 1; 132 | // Convert each limb by shifting and masking to get the value for each output digit 133 | loop { 134 | bit_pos -= bits_per_digit as isize; 135 | while bit_pos >= 0 { 136 | let b = ((n1 >> (bit_pos as usize)) & ((Limb(1) << bits_per_digit) - 1)).0 as u8; 137 | out_byte(b); 138 | bit_pos -= bits_per_digit as isize; 139 | } 140 | i -= 1; 141 | if i < 0 { break; } 142 | 143 | let n0 = (n1 << ((-bit_pos) as usize)) & ((Limb(1) << bits_per_digit) - 1); 144 | n1 = *np.offset(i as isize); 145 | bit_pos += Limb::BITS as isize; 146 | // We have a potential overlap of bits, so get the value of the digit 147 | // that spans the two limbs. 148 | // The specific situation is (using 8-bit limbs as demonstration): 149 | // 150 | // bbbbbbbb bbbbbbbb 151 | // ^---^ Bits for next digit 152 | let b = (n0 | (n1 >> (bit_pos as usize))).0 as u8; 153 | out_byte(b); 154 | } 155 | return; 156 | } 157 | // TODO: Use divide-and-conquer for large numbers 158 | to_base_impl(0, base, np, nn, out_byte); 159 | } 160 | 161 | unsafe fn to_base_impl(mut len: u32, base: u32, np: Limbs, mut nn: i32, mut out_byte: F) { 162 | debug_assert!(base > 2); 163 | 164 | let buf_len = num_base_digits(np, nn, base); 165 | let mut buf : Vec = vec![0; buf_len]; 166 | let mut r : Vec = vec![Limb(0); (nn + 1) as usize]; 167 | let rp = LimbsMut::new(&mut r[0], 0, r.len() as i32); 168 | 169 | ll::copy_incr(np, rp.offset(1), nn); 170 | 171 | let mut sz = 0; 172 | 173 | let s : *mut u8 = &mut buf[0]; 174 | let mut s = s.offset(buf_len as isize); 175 | 176 | let base = Limb(base as ll::limb::BaseInt); 177 | 178 | macro_rules! base_impl ( 179 | ($base:expr, $s:expr, $rp:expr, $sz:ident, $nn:ident) => ( 180 | { 181 | let digits_per_limb = BASES.get_unchecked($base.0 as usize).digits_per_limb; 182 | let big_base = BASES.get_unchecked($base.0 as usize).big_base; 183 | 184 | // Process limbs from least-significant to most, until there is only one 185 | // limb left 186 | while $nn > 1 { 187 | // Divide rp by the big_base, with a single fractional limb produced. 188 | // The fractional limb is approximately 1/remainder 189 | ll::divrem_1($rp, 1, $rp.offset(1).as_const(), $nn, big_base); 190 | 191 | $nn -= if *$rp.offset($nn as isize) == 0 { 1 } else { 0 }; 192 | let mut frac = *$rp + 1; 193 | // The loop below produces digits from most-significant to least, but 194 | // the containing loop works from least signficant limb up, so move 195 | // the first position for the output for this limb. Since we know 196 | // there is at least one more limb to process after this one, it's 197 | // safe to output all digits that may be produced. 198 | $s = $s.offset(-(digits_per_limb as isize)); 199 | let mut i = digits_per_limb; 200 | loop { 201 | // Multiply the fraction from divrem by the base, the overflow 202 | // amount is the next digit we want 203 | let (digit, f) = frac.mul_hilo($base); 204 | frac = f; 205 | *$s = digit.0 as u8; 206 | $s = $s.offset(1); 207 | 208 | $sz += 1; 209 | 210 | i -= 1; 211 | if i == 0 { break; } 212 | } 213 | 214 | $s = $s.offset(-(digits_per_limb as isize)); 215 | } 216 | 217 | // Last limb, use normal conversion for this one so we 218 | // don't overshoot the number of digits 219 | let mut ul = *$rp.offset(1); 220 | while ul != 0 { 221 | let (q, r) = div_unnorm(ul, base); 222 | $s = $s.offset(-1); 223 | *$s = r.0 as u8; 224 | ul = q; 225 | 226 | $sz += 1; 227 | } 228 | } 229 | ) 230 | ); 231 | 232 | // Specialise on the base-10 conversion routine. The other common base, 16, is handled 233 | // by the power-of-two case in to_base. This allows the compiler to unroll the inner 234 | // loop in the conversion, which is a sigificant speed increase. 235 | if base == 10 { 236 | base_impl!(Limb(10), s, rp, sz, nn); 237 | } else { 238 | base_impl!(base, s, rp, sz, nn); 239 | } 240 | 241 | let mut l = sz; 242 | 243 | // Output any leading zeros we may want 244 | while l < len { 245 | out_byte(0); 246 | len -= 1; 247 | } 248 | 249 | // Copy the temporary buffer into the output string 250 | while l != 0 { 251 | out_byte(*s); 252 | s = s.offset(1); 253 | l -= 1; 254 | } 255 | } 256 | 257 | /** 258 | * Converts the base `base` bytestring {bp, bs}, storing the limbs in `out`. `out` is assumed to 259 | * have enough space to store the result. 260 | */ 261 | pub unsafe fn from_base(mut out: LimbsMut, bp: *const u8, bs: i32, base: u32) -> usize { 262 | debug_assert!(bs > 0); 263 | debug_assert!(base < BASES.len() as u32); 264 | debug_assert!(base >= 2); 265 | assume(base < BASES.len() as u32); 266 | assume(base >= 2); 267 | 268 | if bs <= 0 { 269 | *out = Limb(0); 270 | return 1; 271 | } 272 | 273 | if base.is_power_of_two() { 274 | let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize; 275 | assume(bits_per_digit > 0); 276 | 277 | let mut size = 0; 278 | 279 | let mut b = bp.offset((bs - 1) as isize); 280 | let mut res_digit = Limb(0); 281 | let mut next_bitpos = 0; 282 | while b >= bp { 283 | let digit = Limb((*b) as ll::limb::BaseInt); 284 | 285 | res_digit = res_digit | (digit << next_bitpos); 286 | next_bitpos += bits_per_digit; 287 | if next_bitpos >= Limb::BITS { 288 | next_bitpos -= Limb::BITS; 289 | *out.offset(size as isize) = res_digit; 290 | size += 1; 291 | res_digit = digit >> (bits_per_digit - next_bitpos); 292 | } 293 | 294 | b = b.offset(-1); 295 | } 296 | 297 | if res_digit > 0 { 298 | *out.offset(size as isize) = res_digit; 299 | size += 1; 300 | } 301 | 302 | return size; 303 | } 304 | 305 | // TODO, use a divide-and-conquer algorithm for large inputs 306 | from_base_small(out, bp, bs, base) 307 | } 308 | 309 | unsafe fn from_base_small(mut out: LimbsMut, mut bp: *const u8, bs: i32, base: u32) -> usize { 310 | debug_assert!(base > 2); 311 | assume(base > 2); 312 | 313 | let big_base = BASES.get_unchecked(base as usize).big_base; 314 | let digits_per_limb = BASES.get_unchecked(base as usize).digits_per_limb; 315 | 316 | let mut i = digits_per_limb; 317 | let mut size : usize = 0; 318 | while i < (bs as u32) { 319 | let mut res_digit = Limb((*bp) as ll::limb::BaseInt); 320 | bp = bp.offset(1); 321 | 322 | if base == 10 { 323 | let mut j = digits_per_limb - 1; 324 | while j > 0 { 325 | res_digit = res_digit * 10 + ((*bp) as ll::limb::BaseInt); 326 | bp = bp.offset(1); 327 | j -= 1; 328 | } 329 | } else { 330 | let mut j = digits_per_limb - 1; 331 | while j > 0 { 332 | res_digit = res_digit * (base as ll::limb::BaseInt) + ((*bp) as ll::limb::BaseInt); 333 | bp = bp.offset(1); 334 | j -= 1; 335 | } 336 | } 337 | 338 | if size == 0 { 339 | if res_digit != 0 { 340 | *out = res_digit; 341 | size = 1; 342 | } 343 | } else { 344 | let mut carry = ll::mul_1(out, out.as_const(), size as i32, big_base); 345 | carry = carry + ll::add_1(out, out.as_const(), size as i32, res_digit); 346 | if carry != 0 { 347 | *out.offset(size as isize) = carry; 348 | size += 1; 349 | } 350 | } 351 | 352 | i += digits_per_limb; 353 | } 354 | 355 | let mut big_base = base as ll::limb::BaseInt; 356 | let mut res_digit = Limb((*bp) as ll::limb::BaseInt); 357 | bp = bp.offset(1); 358 | 359 | if base == 10 { 360 | let mut j = (bs as u32) - (i - digits_per_limb) - 1; 361 | while j > 0 { 362 | res_digit = res_digit * 10 + ((*bp) as ll::limb::BaseInt); 363 | big_base *= 10; 364 | bp = bp.offset(1); 365 | j -= 1; 366 | } 367 | } else { 368 | let mut j = (bs as u32) - (i - digits_per_limb) - 1; 369 | while j > 0 { 370 | res_digit = res_digit * (base as ll::limb::BaseInt) + ((*bp) as ll::limb::BaseInt); 371 | bp = bp.offset(1); 372 | big_base *= base as ll::limb::BaseInt; 373 | j -= 1; 374 | } 375 | } 376 | 377 | if size == 0 { 378 | if res_digit != 0 { 379 | *out = res_digit; 380 | size = 1; 381 | } 382 | } else { 383 | let mut carry = ll::mul_1(out, out.as_const(), size as i32, Limb(big_base)); 384 | carry = carry + ll::add_1(out, out.as_const(), size as i32, res_digit); 385 | if carry != 0 { 386 | *out.offset(size as isize) = carry; 387 | size += 1; 388 | } 389 | } 390 | 391 | return size; 392 | } 393 | -------------------------------------------------------------------------------- /src/ll/bit.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use ll::limb::{Limb, BaseInt}; 16 | use ll::{same_or_decr, same_or_incr}; 17 | 18 | use ll::limb_ptr::{Limbs, LimbsMut}; 19 | 20 | /** 21 | * Performs a bit-shift of the limbs in {xp, xs}, left by `cnt` bits storing the result in {rp, 22 | * rs}. The top-most shifted bits are returned. 23 | * 24 | * If `cnt` is greater than or equal to the number of bits in a limb, the result is undefined. 25 | */ 26 | pub unsafe fn shl(mut rp: LimbsMut, mut xp: Limbs, mut xs: i32, cnt: u32) -> Limb { 27 | debug_assert!(xs >= 1); 28 | debug_assert!(cnt >= 1); 29 | debug_assert!(cnt < Limb::BITS as u32); 30 | debug_assert!(same_or_decr(rp, xs, xp, xs)); 31 | 32 | let cnt = cnt as usize; 33 | 34 | rp = rp.offset((xs - 1) as isize); 35 | xp = xp.offset((xs - 1) as isize); 36 | 37 | let inv_cnt = Limb::BITS - cnt; 38 | 39 | let l = *xp; 40 | let ret = l >> inv_cnt; 41 | let mut high_limb = l << cnt; 42 | 43 | xs -= 1; 44 | while xs != 0 { 45 | xp = xp.offset(-1); 46 | let low = *xp; 47 | 48 | *rp = high_limb | (low >> inv_cnt); 49 | high_limb = low << cnt; 50 | 51 | rp = rp.offset(-1); 52 | xs -= 1; 53 | } 54 | 55 | *rp = high_limb; 56 | 57 | return ret; 58 | } 59 | 60 | /** 61 | * Performs a bit-shift of the limbs in {xp, xs}, right by `cnt` bits storing the result in {rp, 62 | * rs}. The bottom-most shifted bits are returned. 63 | * 64 | * If `cnt` is greater than or equal to the number of bits in a limb, the result is undefined. 65 | */ 66 | pub unsafe fn shr(mut rp: LimbsMut, mut xp: Limbs, mut xs: i32, cnt: u32) -> Limb { 67 | debug_assert!(xs >= 1); 68 | debug_assert!(cnt >= 1); 69 | debug_assert!(cnt < Limb::BITS as u32); 70 | debug_assert!(same_or_incr(rp, xs, xp, xs)); 71 | 72 | let cnt = cnt as usize; 73 | 74 | let inv_cnt = Limb::BITS - cnt; 75 | 76 | let h = *xp; 77 | let ret = h << inv_cnt; 78 | let mut low_limb = h >> cnt; 79 | 80 | xp = xp.offset(1); 81 | 82 | xs -= 1; 83 | while xs != 0 { 84 | let high = *xp; 85 | xp = xp.offset(1); 86 | 87 | *rp = low_limb | (high << inv_cnt); 88 | low_limb = high >> cnt; 89 | rp = rp.offset(1); 90 | 91 | xs -= 1; 92 | } 93 | 94 | *rp = low_limb; 95 | 96 | return ret; 97 | } 98 | 99 | // Common function for the operations below, since they're all essentially the same 100 | #[inline(always)] 101 | unsafe fn bitop Limb>(mut wp: LimbsMut, 102 | mut xp: Limbs, mut yp: Limbs, 103 | n: i32, op: F) { 104 | debug_assert!(same_or_incr(wp, n, xp, n)); 105 | debug_assert!(same_or_incr(wp, n, yp, n)); 106 | 107 | let mut i = 0; 108 | while i < n { 109 | *wp = op(*xp, *yp); 110 | wp = wp.offset(1); 111 | xp = xp.offset(1); 112 | yp = yp.offset(1); 113 | i += 1; 114 | } 115 | } 116 | 117 | /** 118 | * Performs a bitwise "and" (`&`) of the n least signficant limbs of `xp` and `yp`, storing the 119 | * result in `wp` 120 | */ 121 | pub unsafe fn and_n(wp: LimbsMut, 122 | xp: Limbs, yp: Limbs, 123 | n: i32) { 124 | bitop(wp, xp, yp, n, |x, y| x & y); 125 | } 126 | 127 | /** 128 | * Performs a bitwise and of the n least signficant limbs of `xp` and `yp`, with the limbs of `yp` 129 | * being first inverted. The result is stored in `wp`. 130 | * 131 | * The operation is x & !y 132 | */ 133 | pub unsafe fn and_not_n(wp: LimbsMut, 134 | xp: Limbs, yp: Limbs, 135 | n: i32) { 136 | bitop(wp, xp, yp, n, |x, y| x & !y); 137 | } 138 | 139 | /** 140 | * Performs a bitwise "nand" of the n least signficant limbs of `xp` and `yp`, storing the 141 | * result in `wp` 142 | * 143 | * The operation is !(x & y) 144 | */ 145 | pub unsafe fn nand_n(wp: LimbsMut, 146 | xp: Limbs, yp: Limbs, 147 | n: i32) { 148 | bitop(wp, xp, yp, n, |x, y| !(x & y)); 149 | } 150 | 151 | /** 152 | * Performs a bitwise "or" (`|`) of the n least signficant limbs of `xp` and `yp`, storing the 153 | * result in `wp` 154 | */ 155 | pub unsafe fn or_n(wp: LimbsMut, 156 | xp: Limbs, yp: Limbs, 157 | n: i32) { 158 | bitop(wp, xp, yp, n, |x, y| x | y); 159 | } 160 | 161 | /** 162 | * Performs a bitwise "or" of the n least signficant limbs of `xp` and `yp`, with the limbs of `yp` 163 | * being first inverted. The result is stored in `wp`. 164 | */ 165 | pub unsafe fn or_not_n(wp: LimbsMut, 166 | xp: Limbs, yp: Limbs, 167 | n: i32) { 168 | bitop(wp, xp, yp, n, |x, y| x | !y); 169 | } 170 | 171 | /** 172 | * Performs a bitwise "nor" of the n least signficant limbs of `xp` and `yp`, storing the 173 | * result in `wp` 174 | * 175 | * The operation is !(x | y) 176 | */ 177 | pub unsafe fn nor_n(wp: LimbsMut, 178 | xp: Limbs, yp: Limbs, 179 | n: i32) { 180 | bitop(wp, xp, yp, n, |x, y| !(x | y)); 181 | } 182 | 183 | /** 184 | * Performs a bitwise "xor" (`^`) of the n least signficant limbs of `xp` and `yp`, storing the 185 | * result in `wp` 186 | */ 187 | pub unsafe fn xor_n(wp: LimbsMut, 188 | xp: Limbs, yp: Limbs, 189 | n: i32) { 190 | bitop(wp, xp, yp, n, |x, y| x ^ y); 191 | } 192 | 193 | /** 194 | * Performs a bitwise inversion ("not") of the n least signficant limbs of `xp`, storing the 195 | * result in `wp` 196 | */ 197 | pub unsafe fn not(mut wp: LimbsMut, mut xp: Limbs, n: i32) { 198 | debug_assert!(same_or_incr(wp, n, xp, n)); 199 | 200 | let mut i = 0; 201 | while i < n { 202 | *wp = !*xp; 203 | wp = wp.offset(1); 204 | xp = xp.offset(1); 205 | i += 1; 206 | } 207 | } 208 | 209 | /** 210 | * Computes the two's complement of the `xs` least significant words 211 | * of `xp`. The result is stored the result in `wp`, and a carry is 212 | * returned, if there is one. 213 | */ 214 | pub unsafe fn twos_complement(mut wp: LimbsMut, mut xp: Limbs, xs: i32) -> Limb { 215 | let mut i = 0; 216 | let mut carry = Limb(1); 217 | 218 | while i < xs { 219 | let flipped = !*xp; 220 | *wp = flipped + carry; 221 | xp = xp.offset(1); 222 | wp = wp.offset(1); 223 | i += 1; 224 | carry = carry & Limb((flipped == !0) as BaseInt); 225 | } 226 | 227 | carry 228 | } 229 | 230 | /** 231 | * Scans for the first 1 bit starting from the least-significant bit the the most, returning 232 | * the bit index. 233 | */ 234 | pub unsafe fn scan_1(mut xp: Limbs, mut xs: i32) -> u32 { 235 | debug_assert!(xs > 0); 236 | let mut cnt = 0u32; 237 | 238 | while *xp == 0 { 239 | cnt += Limb::BITS as u32; 240 | xp = xp.offset(1); 241 | xs -= 1; 242 | if xs == 0 { return cnt; } 243 | } 244 | cnt += (*xp).trailing_zeros() as u32; 245 | 246 | return cnt; 247 | } 248 | 249 | /** 250 | * Scans for the first 0 bit starting from the least-significant bit the the most, returning 251 | * the bit index. 252 | */ 253 | pub unsafe fn scan_0(mut xp: Limbs, mut xs: i32) -> u32 { 254 | debug_assert!(xs > 0); 255 | let mut cnt = 0u32; 256 | 257 | while *xp == !0 { 258 | cnt += Limb::BITS as u32; 259 | xp = xp.offset(1); 260 | xs -= 1; 261 | if xs == 0 { return cnt; } 262 | } 263 | let mut last = (*xp).0; 264 | while last & 1 != 0 { 265 | cnt += 1; 266 | last >>= 1; 267 | } 268 | 269 | return cnt; 270 | } 271 | -------------------------------------------------------------------------------- /src/ll/div.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::cmp::{self, Ordering}; 16 | use std::intrinsics::assume; 17 | 18 | use super::{overlap, same_or_separate}; 19 | use ll; 20 | use ll::limb::{self, Limb}; 21 | use ll::limb_ptr::{Limbs, LimbsMut}; 22 | use mem; 23 | 24 | /** 25 | * Divides the `xs` least-significant limbs at `xp` by `d`, storing the result in {qp, qxn + xs}. 26 | * 27 | * Specifically, the integer part is stored in {qp+qxn, xs} and the fractional part (if any) is 28 | * stored in {qp, qxn}. The remainder is returned. 29 | */ 30 | pub unsafe fn divrem_1(mut qp: LimbsMut, qxn: i32, xp: Limbs, mut xs: i32, d: Limb) -> Limb { 31 | debug_assert!(qxn >= 0); 32 | debug_assert!(xs >= 0); 33 | debug_assert!(d != 0); 34 | debug_assert!(same_or_separate(qp.offset(qxn as isize), xs, xp, xs)); 35 | 36 | assume(qxn >= 0); 37 | assume(xs >= 0); 38 | assume(d != 0); 39 | 40 | let mut n = xs + qxn; 41 | if n == 0 { 42 | return Limb(0); 43 | } 44 | 45 | // FIXME (#49): this is used for bounds checks below, which may be 46 | // unnecessary. 47 | let qp_lo = qp; 48 | qp = qp.offset((n - 1) as isize); 49 | 50 | let mut r = Limb(0); 51 | if d.high_bit_set() { 52 | if xs != 0 { 53 | r = *xp.offset((xs - 1) as isize); 54 | let q = if r >= d { Limb(1) } else { Limb(0) }; 55 | *qp = q; 56 | if qp > qp_lo { 57 | qp = qp.offset(-1); 58 | } 59 | r = r - (d & -q); 60 | xs -= 1; 61 | } 62 | 63 | let dinv = d.invert(); 64 | let mut i = xs - 1; 65 | while i >= 0 { 66 | let n0 = *xp.offset(i as isize); 67 | let (q, rem) = limb::div_preinv(r, n0, d, dinv); 68 | r = rem; 69 | *qp = q; 70 | if qp > qp_lo { 71 | qp = qp.offset(-1); 72 | } 73 | i -= 1; 74 | } 75 | let mut i = qxn - 1; 76 | while i >= 0 { 77 | let (q, rem) = limb::div_preinv(r, Limb(0), d, dinv); 78 | r = rem; 79 | *qp = q; 80 | if qp > qp_lo { 81 | qp = qp.offset(-1); 82 | } 83 | i -= 1; 84 | } 85 | 86 | return r; 87 | } else { 88 | if xs != 0 { 89 | let n1 = *xp.offset((xs - 1) as isize); 90 | if n1 < d { 91 | r = n1; 92 | *qp = Limb(0); 93 | if qp > qp_lo { 94 | qp = qp.offset(-1); 95 | } 96 | n -= 1; 97 | if n == 0 { 98 | return r; 99 | } 100 | xs -= 1; 101 | } 102 | } 103 | 104 | let cnt = d.leading_zeros() as usize; 105 | 106 | let d = d << cnt; 107 | r = r << cnt; 108 | 109 | let dinv = d.invert(); 110 | if xs != 0 { 111 | let mut n1 = *xp.offset((xs - 1) as isize); 112 | r = r | (n1 >> (Limb::BITS - cnt)); 113 | let mut i = xs - 2; 114 | while i >= 0 { 115 | let n0 = *xp.offset(i as isize); 116 | let nshift = (n1 << cnt) | (n0 >> (Limb::BITS - cnt)); 117 | let (q, rem) = limb::div_preinv(r, nshift, d, dinv); 118 | 119 | r = rem; 120 | *qp = q; 121 | 122 | qp = qp.offset(-1); 123 | n1 = n0; 124 | i -= 1; 125 | } 126 | let (q, rem) = limb::div_preinv(r, n1 << cnt, d, dinv); 127 | r = rem; 128 | *qp = q; 129 | if qp > qp_lo { 130 | qp = qp.offset(-1); 131 | } 132 | } 133 | 134 | let mut i = qxn - 1; 135 | while i >= 0 { 136 | let (q, rem) = limb::div_preinv(r, Limb(0), d, dinv); 137 | r = rem; 138 | *qp = q; 139 | 140 | if qp > qp_lo { 141 | qp = qp.offset(-1); 142 | } 143 | i -= 1; 144 | } 145 | 146 | return r >> cnt; 147 | } 148 | } 149 | 150 | pub unsafe fn divrem_2(mut qp: LimbsMut, qxn: i32, mut np: LimbsMut, ns: i32, dp: Limbs) -> Limb { 151 | debug_assert!(ns >= 2); 152 | debug_assert!(qxn >= 0); 153 | debug_assert!((*dp.offset(1)).high_bit_set()); 154 | debug_assert!(!overlap(qp, ns - 2 + qxn, np.as_const(), ns) || qp >= np.offset(2)); 155 | 156 | np = np.offset((ns - 2) as isize); 157 | 158 | let d1 = *dp.offset(1); 159 | let d0 = *dp.offset(0); 160 | let mut r1 = *np.offset(1); 161 | let mut r0 = *np.offset(0); 162 | 163 | let mut most_significant_q_limb = 0; 164 | if r1 >= d1 && (r1 > d1 || r0 >= d0) { 165 | let (r_1, r_0) = ll::limb::sub_2(r1, r0, d1, d0); 166 | r1 = r_1; 167 | r0 = r_0; 168 | most_significant_q_limb = 1; 169 | } 170 | 171 | let dinv = invert_pi(d1, d0); 172 | 173 | qp = qp.offset(qxn as isize); 174 | 175 | let mut i = ns - 2 - 1; 176 | while i >= 0 { 177 | let n0 = *np.offset(-1); 178 | let (q, r_1, r_0) = divrem_3by2(r1, r0, n0, d1, d0, dinv); 179 | np = np.offset(-1); 180 | r1 = r_1; 181 | r0 = r_0; 182 | *qp.offset(i as isize) = q; 183 | 184 | i -= 1; 185 | } 186 | 187 | if qxn != 0 { 188 | qp = qp.offset(-qxn as isize); 189 | let mut i = qxn - 1; 190 | while i >= 0 { 191 | let (q, r_1, r_0) = divrem_3by2(r1, r0, Limb(0), d1, d0, dinv); 192 | r1 = r_1; 193 | r0 = r_0; 194 | 195 | *qp.offset(i as isize) = q; 196 | 197 | i -= 1; 198 | } 199 | } 200 | 201 | *np.offset(1) = r1; 202 | *np = r0; 203 | 204 | return Limb(most_significant_q_limb); 205 | } 206 | 207 | #[inline] 208 | fn invert_pi(d1: Limb, d0: Limb) -> Limb { 209 | let mut v = d1.invert(); 210 | let (mut p, cy) = (d1 * v).add_overflow(d0); 211 | if cy { 212 | v = v - 1; 213 | let mask = if p >= d1 { Limb(!0) } else { Limb(0) }; 214 | p = p - d1; 215 | v = v + mask; 216 | p = p - (mask & d1); 217 | } 218 | 219 | let (t1, t0) = d0.mul_hilo(v); 220 | p = p + t1; 221 | if p < t1 { 222 | v = v - 1; 223 | if p >= d1 && (p > d1 || t0 >= d0) { 224 | v = v - 1; 225 | } 226 | } 227 | 228 | v 229 | } 230 | 231 | #[inline] 232 | fn divrem_3by2(n2: Limb, n1: Limb, n0: Limb, d1: Limb, d0: Limb, dinv: Limb) -> (Limb, Limb, Limb) { 233 | let (q, ql) = n2.mul_hilo(dinv); 234 | let (q, ql) = ll::limb::add_2(q, ql, n2, n1); 235 | 236 | let r1 = n1 - d1 * q; 237 | let (r1, r0) = ll::limb::sub_2(r1, n0, d1, d0); 238 | let (t1, t0) = d0.mul_hilo(q); 239 | let (r1, r0) = ll::limb::sub_2(r1, r0, t1, t0); 240 | 241 | let q = q + 1; 242 | let mask = if r1 >= ql { Limb(!0) } else { Limb(0) }; 243 | 244 | let q = q + mask; 245 | let (r1, r0) = ll::limb::add_2(r1, r0, mask & d1, mask & d0); 246 | 247 | if r1 >= d1 && (r1 > d1 || r0 >= d0) { 248 | let (r1, r0) = ll::limb::sub_2(r1, r0, d1, d0); 249 | (q + 1, r1, r0) 250 | } else { 251 | (q, r1, r0) 252 | } 253 | } 254 | 255 | /** 256 | * Divides {np, ns} by {dp, ds}. If ns <= ds, the quotient is stored in {qp, 1}, otherwise 257 | * the quotient is stored to {qp, (ns - ds) + 1}. The remainder is always stored to {rp, ds}. 258 | */ 259 | pub unsafe fn divrem(mut qp: LimbsMut, mut rp: LimbsMut, np: Limbs, ns: i32, dp: Limbs, ds: i32) { 260 | // Space for at least one limb is always needed, even if 261 | // (logarithmically) the result will be so small that negative 262 | // would work. 263 | let max_result_size = cmp::max((ns - ds) + 1, 1); 264 | debug_assert!(!overlap(qp, max_result_size, np, ns)); 265 | 266 | if ns < ds { 267 | *qp = Limb(0); 268 | ll::copy_incr(np, rp, ns); 269 | return; 270 | } else if ns == ds { 271 | if let Ordering::Less = ll::cmp(np, dp, ns) { 272 | *qp = Limb(0); 273 | ll::copy_incr(np, rp, ns); 274 | return; 275 | } 276 | } 277 | 278 | match ds { 279 | 1 => { 280 | let r = divrem_1(qp, 0, np, ns, *dp); 281 | *rp = r; 282 | } 283 | 2 => { 284 | let mut tmp = mem::TmpAllocator::new(); 285 | let dh = *dp.offset((ds - 1) as isize); 286 | 287 | let cnt = dh.leading_zeros() as usize; 288 | if cnt == 0 { 289 | let np_tmp = tmp.allocate((ns + 1) as usize); 290 | ll::copy_incr(np, np_tmp, ns); 291 | let qhl = divrem_2(qp, 0, np_tmp, ns, dp); 292 | *qp.offset((ns - 2) as isize) = qhl; 293 | *rp = *np_tmp; 294 | *rp.offset(1) = *np_tmp.offset(1); 295 | } else { 296 | let dtmp = [ 297 | *dp << cnt, 298 | (*dp.offset(1) << cnt) | *dp >> (Limb::BITS - cnt), 299 | ]; 300 | let dp_tmp = Limbs::new(&dtmp[0], 0, dtmp.len() as i32); 301 | 302 | let np_tmp = tmp.allocate((ns + 1) as usize); 303 | let c = ll::shl(np_tmp, np, ns, cnt as u32); 304 | *np_tmp.offset(ns as isize) = c; 305 | 306 | let ns_tmp = ns + if c == 0 { 0 } else { 1 }; 307 | 308 | let qhl = divrem_2(qp, 0, np_tmp, ns_tmp, dp_tmp); 309 | if c == 0 { 310 | *qp.offset((ns - 2) as isize) = qhl; 311 | } 312 | 313 | *rp = (*np_tmp >> cnt) | (*np_tmp.offset(1) << (Limb::BITS - cnt)); 314 | *rp.offset(1) = *np_tmp.offset(1) >> cnt; 315 | } 316 | return; 317 | } 318 | _ => { 319 | let mut tmp = mem::TmpAllocator::new(); 320 | 321 | let dh = *dp.offset((ds - 1) as isize); 322 | 323 | let cnt = dh.leading_zeros() as u32; 324 | let dp_tmp; 325 | let np_tmp; 326 | let mut ns_tmp = ns; 327 | 328 | if cnt == 0 { 329 | dp_tmp = dp; 330 | np_tmp = tmp.allocate(ns_tmp as usize); 331 | ll::copy_incr(np, np_tmp, ns); 332 | } else { 333 | ns_tmp += 1; 334 | np_tmp = tmp.allocate(ns_tmp as usize); 335 | 336 | let c = ll::shl(np_tmp, np, ns, cnt); 337 | if c > 0 { 338 | *np_tmp.offset(ns as isize) = c; 339 | } else { 340 | ns_tmp -= 1; 341 | } 342 | 343 | let dtmp = tmp.allocate(ds as usize); 344 | ll::shl(dtmp, dp, ds, cnt); 345 | dp_tmp = dtmp.as_const(); 346 | } 347 | 348 | let dinv = invert_pi( 349 | *dp_tmp.offset((ds - 1) as isize), 350 | *dp_tmp.offset((ds - 2) as isize), 351 | ); 352 | let qh = sb_div(qp, np_tmp, ns_tmp, dp_tmp, ds, dinv); 353 | if qh > 0 { 354 | *qp.offset((ns - ds) as isize) = qh; 355 | } 356 | 357 | if cnt == 0 { 358 | ll::copy_incr(np_tmp.as_const(), rp, ds); 359 | } else { 360 | ll::shr(rp, np_tmp.as_const(), ds, cnt); 361 | } 362 | } 363 | } 364 | } 365 | 366 | /** 367 | * "Schoolbook" division of two unsigned integers, N, D, producing Q = floor(N/D). 368 | * The return value is the highest limb of the quotient, which may be zero. 369 | * Specifically, it divides the `ns` least significant limbs of N by the `ds` least 370 | * significant limbs of `D`, writing ns - ds limbs of quotient to qp. 371 | * 372 | * The limbs stored in `np` are modified and the lowest `ds` limbs contain the remainder 373 | * of the division. 374 | * 375 | * The denominator is assumed to conform to the follow restrictions (where B is the base): 376 | * 377 | * 1. D < N 378 | * 2. Most significant limb of D is >= floor(B/2). 379 | * 380 | * It is also assumed that `ns >= ds`. 381 | */ 382 | unsafe fn sb_div(qp: LimbsMut, np: LimbsMut, ns: i32, dp: Limbs, ds: i32, dinv: Limb) -> Limb { 383 | debug_assert!(ds > 2); 384 | debug_assert!(ns >= ds); 385 | debug_assert!((*dp.offset((ds - 1) as isize)).high_bit_set()); 386 | 387 | let mut np = np.offset(ns as isize); 388 | 389 | // If N < D*B^(m-n-1), then the high limb is zero. If not, then the high limb 390 | // is 1 and we subtract D*B^(m-n-1) from N. 391 | let qh = if let Ordering::Less = ll::cmp(np.offset(-ds as isize).as_const(), dp, ds) { 392 | Limb(0) 393 | } else { 394 | let np = np.offset(-ds as isize); 395 | ll::sub_n(np, np.as_const(), dp, ds); 396 | Limb(1) 397 | }; 398 | 399 | let mut qp = qp.offset((ns - ds) as isize); 400 | 401 | let ds = (ds - 2) as isize; 402 | 403 | let d1 = *dp.offset(ds + 1); 404 | let d0 = *dp.offset(ds + 0); 405 | 406 | np = np.offset(-2); 407 | 408 | let mut n2 = *np.offset(1); 409 | 410 | let mut i = ns - (ds + 2) as i32; 411 | while i > 0 { 412 | np = np.offset(-1); 413 | let n1 = *np.offset(1); 414 | let n0 = *np; 415 | 416 | let q = if n2 == d1 && n1 == d0 { 417 | ll::submul_1(np.offset(-ds), dp, (ds + 2) as i32, Limb(!0)); 418 | n2 = *np.offset(1); 419 | Limb(!0) 420 | } else { 421 | let (q, r1, mut r0) = divrem_3by2(n2, n1, n0, d1, d0, dinv); 422 | let cy = ll::submul_1(np.offset(-ds), dp, ds as i32, q); 423 | 424 | n2 = r1; 425 | 426 | let cy1 = r0 < cy; 427 | r0 = r0 - cy; 428 | let cy = n2 < (cy1 as ll::limb::BaseInt); 429 | if cy1 { 430 | n2 = n2 - 1; 431 | } 432 | *np = r0; 433 | 434 | if cy { 435 | n2 = d1 436 | + n2 437 | + ll::add_n( 438 | np.offset(-ds), 439 | np.offset(-ds).as_const(), 440 | dp, 441 | (ds + 1) as i32, 442 | ); 443 | q - 1 444 | } else { 445 | q 446 | } 447 | }; 448 | 449 | qp = qp.offset(-1); 450 | *qp = q; 451 | 452 | i -= 1; 453 | } 454 | 455 | *np.offset(1) = n2; 456 | 457 | return qh; 458 | } 459 | -------------------------------------------------------------------------------- /src/ll/gcd.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::cmp::Ordering; 16 | 17 | use ll; 18 | use ll::limb_ptr::LimbsMut; 19 | 20 | pub unsafe fn gcd(mut gp: LimbsMut, mut ap: LimbsMut, mut an: i32, mut bp: LimbsMut, mut bn: i32) -> i32 { 21 | assert!(an >= bn); 22 | 23 | let mut gc = 0; 24 | while *ap == 0 && !ll::is_zero(ap.as_const(), an) 25 | && *bp == 0 && !ll::is_zero(bp.as_const(), bn) { 26 | ap = ap.offset(1); 27 | bp = bp.offset(1); 28 | gp = gp.offset(1); 29 | an -= 1; 30 | bn -= 1; 31 | gc += 1; 32 | } 33 | 34 | let a_trailing = (*ap).trailing_zeros() as u32; 35 | let b_trailing = (*bp).trailing_zeros() as u32; 36 | 37 | let trailing = if a_trailing <= b_trailing { 38 | a_trailing 39 | } else { 40 | b_trailing 41 | }; 42 | if trailing > 0 { 43 | ll::shr(ap, ap.as_const(), an, trailing); 44 | ll::shr(bp, bp.as_const(), bn, trailing); 45 | } 46 | 47 | while !ll::is_zero(ap.as_const(), an) { 48 | 49 | while *ap == 0 && !ll::is_zero(ap.as_const(), an) { 50 | ap = ap.offset(1); 51 | an -= 1; 52 | } 53 | 54 | let at = (*ap).trailing_zeros() as u32; 55 | if at > 0 { 56 | ll::shr(ap, ap.as_const(), an, at); 57 | } 58 | 59 | while *bp == 0 && !ll::is_zero(bp.as_const(), bn) { 60 | bp = bp.offset(1); 61 | bn -= 1; 62 | } 63 | 64 | let bt = (*bp).trailing_zeros() as u32; 65 | if bt > 0 { 66 | ll::shr(bp, bp.as_const(), bn, bt); 67 | } 68 | 69 | an = ll::normalize(ap.as_const(), an); 70 | bn = ll::normalize(bp.as_const(), bn); 71 | 72 | let c = if an == bn { 73 | ll::cmp(ap.as_const(), bp.as_const(), an) 74 | } else if an > bn { 75 | Ordering::Greater 76 | } else { 77 | Ordering::Less 78 | }; 79 | 80 | if c == Ordering::Greater || c == Ordering::Equal { 81 | ll::sub(ap, ap.as_const(), an, bp.as_const(), bn); 82 | ll::shr(ap, ap.as_const(), an, 1); 83 | } else { 84 | ll::sub(bp, bp.as_const(), bn, ap.as_const(), an); 85 | ll::shr(bp, bp.as_const(), bn, 1); 86 | } 87 | } 88 | 89 | ll::copy_incr(bp.as_const(), gp, bn); 90 | 91 | if trailing > 0 { 92 | let v = ll::shl(gp, gp.as_const(), bn, trailing); 93 | if v > 0 { 94 | *gp.offset(bn as isize) = v; 95 | } 96 | } 97 | 98 | gc + bn 99 | } 100 | -------------------------------------------------------------------------------- /src/ll/limb.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std; 16 | use std::arch::asm; 17 | use std::cmp::{Ordering, PartialEq, PartialOrd}; 18 | use std::fmt; 19 | use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub}; 20 | 21 | use std::intrinsics::assume; 22 | 23 | use ::std::num::Wrapping; 24 | #[allow(dead_code)] 25 | type Word = Wrapping; 26 | 27 | macro_rules! if_cfg { 28 | ($(#[cfg($cfg:meta)] $it:item)+ fallback: $els:item) => ( 29 | $(#[cfg($cfg)] $it)+ 30 | #[cfg(not(any($($cfg),*)))] $els 31 | ) 32 | } 33 | 34 | #[cfg(target_pointer_width = "32")] 35 | pub type BaseInt = u32; 36 | #[cfg(target_pointer_width = "64")] 37 | pub type BaseInt = u64; 38 | 39 | /** 40 | * Helper newtype for operations. 41 | * 42 | * A "Limb" is a single digit in base 2^word size. 43 | */ 44 | #[derive(Copy, Eq, Ord, Hash)] 45 | pub struct Limb(pub BaseInt); 46 | 47 | impl Clone for Limb { 48 | #[inline(always)] 49 | fn clone(&self) -> Limb { 50 | *self 51 | } 52 | } 53 | 54 | impl Limb { 55 | #[cfg(target_pointer_width = "32")] 56 | pub const BITS: usize = 32; 57 | #[cfg(target_pointer_width = "64")] 58 | pub const BITS: usize = 64; 59 | 60 | pub const B: Limb = Limb(1 << (Limb::BITS / 2)); 61 | 62 | /// Returns the high half of the limb 63 | #[inline(always)] 64 | pub fn high_part(self) -> Limb { 65 | self >> (Limb::BITS / 2) 66 | } 67 | 68 | #[inline(always)] 69 | /// Returns the low half of the limb 70 | pub fn low_part(self) -> Limb { 71 | self & (Limb::B - 1) 72 | } 73 | 74 | /** 75 | * Performs `self + other`, returning the result and whether or not the addition overflowed 76 | */ 77 | #[inline(always)] 78 | pub fn add_overflow(self, other: Limb) -> (Limb, bool) { 79 | let (val, c) = std::intrinsics::add_with_overflow(self.0, other.0); 80 | (Limb(val), c) 81 | } 82 | 83 | /** 84 | * Performs `self - other`, returning the result and whether or not the subtraction overflowed 85 | */ 86 | #[inline(always)] 87 | pub fn sub_overflow(self, other: Limb) -> (Limb, bool) { 88 | let (val, c) = std::intrinsics::sub_with_overflow(self.0, other.0); 89 | (Limb(val), c) 90 | } 91 | 92 | /** 93 | * Performs `self * other` returning the lower half of the product 94 | */ 95 | #[inline(always)] 96 | pub fn mul_lo(self, other: Limb) -> Limb { 97 | Limb(self.0.wrapping_mul(other.0)) 98 | } 99 | 100 | /** 101 | * Performs `self * other` returning the higher half of the product 102 | */ 103 | #[inline(always)] 104 | pub fn mul_hi(self, other: Limb) -> Limb { 105 | mul(self, other).0 106 | } 107 | 108 | /** 109 | * Performs `self * other` returning the two-limb result as (high, low). 110 | */ 111 | #[inline(always)] 112 | pub fn mul_hilo(self, other: Limb) -> (Limb, Limb) { 113 | mul(self, other) 114 | } 115 | 116 | #[inline(always)] 117 | pub fn invert(self) -> Limb { 118 | debug_assert!(self.0 != 0); 119 | div(!self, Limb(!0), self).0 120 | } 121 | 122 | /** 123 | * Returns whether or not the highest bit in the limb is set. 124 | * 125 | * Division algorithms often require the highest limb of the divisor 126 | * to be `d >= BASE/2`. 127 | */ 128 | #[inline(always)] 129 | pub fn high_bit_set(self) -> bool { 130 | (self & Limb(1 << (Limb::BITS - 1))) != 0 131 | } 132 | 133 | /** 134 | * Returns the number of leading zeros in the limb 135 | */ 136 | #[inline(always)] 137 | pub fn leading_zeros(self) -> BaseInt { 138 | self.0.leading_zeros() as BaseInt 139 | } 140 | 141 | /** 142 | * Returns the number of trailing zeros in the limb 143 | */ 144 | #[inline(always)] 145 | pub fn trailing_zeros(self) -> BaseInt { 146 | self.0.trailing_zeros() as BaseInt 147 | } 148 | } 149 | 150 | impl Add for Limb { 151 | type Output = Limb; 152 | 153 | #[inline(always)] 154 | fn add(self, other: Limb) -> Limb { 155 | Limb(self.0.wrapping_add(other.0)) 156 | } 157 | } 158 | 159 | impl Add for Limb { 160 | type Output = Limb; 161 | 162 | #[inline(always)] 163 | fn add(self, other: BaseInt) -> Limb { 164 | Limb(self.0.wrapping_add(other)) 165 | } 166 | } 167 | 168 | impl Add for Limb { 169 | type Output = Limb; 170 | 171 | #[inline(always)] 172 | fn add(self, other: bool) -> Limb { 173 | Limb(self.0.wrapping_add(other as BaseInt)) 174 | } 175 | } 176 | 177 | impl Add for BaseInt { 178 | type Output = Limb; 179 | 180 | #[inline(always)] 181 | fn add(self, other: Limb) -> Limb { 182 | Limb(self.wrapping_add(other.0)) 183 | } 184 | } 185 | 186 | impl Sub for Limb { 187 | type Output = Limb; 188 | 189 | #[inline(always)] 190 | fn sub(self, other: Limb) -> Limb { 191 | Limb(self.0.wrapping_sub(other.0)) 192 | } 193 | } 194 | 195 | impl Sub for Limb { 196 | type Output = Limb; 197 | 198 | #[inline(always)] 199 | fn sub(self, other: BaseInt) -> Limb { 200 | Limb(self.0.wrapping_sub(other)) 201 | } 202 | } 203 | 204 | impl Sub for Limb { 205 | type Output = Limb; 206 | 207 | #[inline(always)] 208 | fn sub(self, other: bool) -> Limb { 209 | Limb(self.0.wrapping_sub(other as BaseInt)) 210 | } 211 | } 212 | 213 | impl Sub for BaseInt { 214 | type Output = Limb; 215 | 216 | #[inline(always)] 217 | fn sub(self, other: Limb) -> Limb { 218 | Limb(self.wrapping_sub(other.0)) 219 | } 220 | } 221 | 222 | impl Mul for Limb { 223 | type Output = Limb; 224 | 225 | #[inline(always)] 226 | fn mul(self, other: Limb) -> Limb { 227 | self.mul_lo(other) 228 | } 229 | } 230 | 231 | impl Mul for Limb { 232 | type Output = Limb; 233 | 234 | #[inline(always)] 235 | fn mul(self, other: BaseInt) -> Limb { 236 | Limb(self.0.wrapping_mul(other)) 237 | } 238 | } 239 | 240 | impl Mul for BaseInt { 241 | type Output = Limb; 242 | 243 | #[inline(always)] 244 | fn mul(self, other: Limb) -> Limb { 245 | Limb(self.wrapping_mul(other.0)) 246 | } 247 | } 248 | 249 | impl Div for Limb { 250 | type Output = Limb; 251 | 252 | #[inline(always)] 253 | fn div(self, other: Limb) -> Limb { 254 | debug_assert!(other.0 != 0); 255 | unsafe { 256 | assume(other.0 != 0); 257 | } 258 | Limb(self.0 / other.0) 259 | } 260 | } 261 | 262 | impl Div for Limb { 263 | type Output = Limb; 264 | 265 | #[inline(always)] 266 | fn div(self, other: BaseInt) -> Limb { 267 | debug_assert!(other != 0); 268 | unsafe { 269 | assume(other != 0); 270 | } 271 | Limb(self.0 / other) 272 | } 273 | } 274 | 275 | impl Rem for Limb { 276 | type Output = Limb; 277 | 278 | #[inline(always)] 279 | fn rem(self, other: Limb) -> Limb { 280 | debug_assert!(other.0 != 0); 281 | unsafe { 282 | assume(other.0 != 0); 283 | } 284 | Limb(self.0 % other.0) 285 | } 286 | } 287 | 288 | impl Rem for Limb { 289 | type Output = Limb; 290 | 291 | #[inline(always)] 292 | fn rem(self, other: BaseInt) -> Limb { 293 | debug_assert!(other != 0); 294 | unsafe { 295 | assume(other != 0); 296 | } 297 | Limb(self.0 % other) 298 | } 299 | } 300 | 301 | impl Neg for Limb { 302 | type Output = Limb; 303 | 304 | #[inline(always)] 305 | fn neg(self) -> Limb { 306 | Limb(0) - self 307 | } 308 | } 309 | 310 | impl Shl for Limb 311 | where 312 | BaseInt: Shl, 313 | { 314 | type Output = Limb; 315 | 316 | #[inline(always)] 317 | fn shl(self, other: I) -> Limb { 318 | Limb(self.0 << other) 319 | } 320 | } 321 | 322 | impl Shr for Limb 323 | where 324 | BaseInt: Shr, 325 | { 326 | type Output = Limb; 327 | 328 | #[inline(always)] 329 | fn shr(self, other: I) -> Limb { 330 | Limb(self.0 >> other) 331 | } 332 | } 333 | 334 | impl Not for Limb { 335 | type Output = Limb; 336 | 337 | #[inline(always)] 338 | fn not(self) -> Limb { 339 | Limb(!self.0) 340 | } 341 | } 342 | 343 | impl BitAnd for Limb { 344 | type Output = Limb; 345 | 346 | #[inline(always)] 347 | fn bitand(self, other: Limb) -> Limb { 348 | Limb(self.0 & other.0) 349 | } 350 | } 351 | 352 | impl BitOr for Limb { 353 | type Output = Limb; 354 | 355 | #[inline(always)] 356 | fn bitor(self, other: Limb) -> Limb { 357 | Limb(self.0 | other.0) 358 | } 359 | } 360 | 361 | impl BitXor for Limb { 362 | type Output = Limb; 363 | 364 | #[inline(always)] 365 | fn bitxor(self, other: Limb) -> Limb { 366 | Limb(self.0 ^ other.0) 367 | } 368 | } 369 | 370 | impl PartialEq for Limb { 371 | #[inline(always)] 372 | fn eq(&self, other: &Limb) -> bool { 373 | self.0 == other.0 374 | } 375 | 376 | #[inline(always)] 377 | fn ne(&self, other: &Limb) -> bool { 378 | self.0 != other.0 379 | } 380 | } 381 | 382 | impl PartialOrd for Limb { 383 | #[inline(always)] 384 | fn partial_cmp(&self, other: &Limb) -> Option { 385 | self.0.partial_cmp(&other.0) 386 | } 387 | 388 | #[inline(always)] 389 | fn lt(&self, other: &Limb) -> bool { 390 | self.0 < other.0 391 | } 392 | 393 | #[inline(always)] 394 | fn le(&self, other: &Limb) -> bool { 395 | self.0 <= other.0 396 | } 397 | 398 | #[inline(always)] 399 | fn gt(&self, other: &Limb) -> bool { 400 | self.0 > other.0 401 | } 402 | 403 | #[inline(always)] 404 | fn ge(&self, other: &Limb) -> bool { 405 | self.0 >= other.0 406 | } 407 | } 408 | 409 | impl PartialEq for Limb { 410 | #[inline(always)] 411 | fn eq(&self, other: &BaseInt) -> bool { 412 | self.0 == *other 413 | } 414 | 415 | #[inline(always)] 416 | fn ne(&self, other: &BaseInt) -> bool { 417 | self.0 != *other 418 | } 419 | } 420 | 421 | impl PartialOrd for Limb { 422 | #[inline(always)] 423 | fn partial_cmp(&self, other: &BaseInt) -> Option { 424 | self.0.partial_cmp(other) 425 | } 426 | 427 | #[inline(always)] 428 | fn lt(&self, other: &BaseInt) -> bool { 429 | self.0 < *other 430 | } 431 | 432 | #[inline(always)] 433 | fn le(&self, other: &BaseInt) -> bool { 434 | self.0 <= *other 435 | } 436 | 437 | #[inline(always)] 438 | fn gt(&self, other: &BaseInt) -> bool { 439 | self.0 > *other 440 | } 441 | 442 | #[inline(always)] 443 | fn ge(&self, other: &BaseInt) -> bool { 444 | self.0 >= *other 445 | } 446 | } 447 | 448 | impl fmt::Debug for Limb { 449 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 450 | fmt::Debug::fmt(&self.0, f) 451 | } 452 | } 453 | 454 | impl fmt::Display for Limb { 455 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 456 | fmt::Debug::fmt(&self.0, f) 457 | } 458 | } 459 | 460 | pub fn mul(u: Limb, v: Limb) -> (Limb, Limb) { 461 | if_cfg! { 462 | #[cfg(all(not(feature="fallbacks"),target_arch="x86_64"))] 463 | #[inline(always)] 464 | fn mul_impl(u: Limb, v: Limb) -> (Limb, Limb) { 465 | let mut high: Limb = Limb(0); 466 | let mut low: Limb = Limb(0); 467 | unsafe { 468 | asm!( 469 | "mul {v}", // multiply u by v and store in high:low 470 | v = in(reg) v.0, 471 | inout("rax") u.0 => low.0, 472 | out("rdx") high.0 473 | ); 474 | } 475 | 476 | (high, low) 477 | } 478 | 479 | #[cfg(all(not(feature="fallbacks"),target_arch="x86"))] 480 | #[inline(always)] 481 | fn mul_impl(u: Limb, v: Limb) -> (Limb, Limb) { 482 | let mut high: Limb = Limb(0); 483 | let mut low: Limb = Limb(0); 484 | unsafe { 485 | asm!( 486 | "mul {v}", // multiply u by v and store in high:low 487 | v = in(reg) v.0, 488 | inout("eax") u.0 => low.0, 489 | out("edx") high.0 490 | ); 491 | } 492 | 493 | (high, low) 494 | } 495 | 496 | #[cfg(all( not(feature="fallbacks"), 497 | not(target_arch="x86"), 498 | target_pointer_width="32", 499 | ))] 500 | #[inline(always)] 501 | fn mul_impl(u: Limb, v: Limb) -> (Limb, Limb) { 502 | let u = u.0 as u64; 503 | let v = v.0 as u64; 504 | let p = u*v; 505 | (Limb((p>>32) as u32), Limb(p as u32)) 506 | } 507 | 508 | fallback: 509 | #[inline(always)] 510 | fn mul_impl(u: Limb, v: Limb) -> (Limb, Limb) { 511 | fn mul_2_usize_to_2_usize(u:Word, v: Word) -> (Word,Word) { 512 | // see http://www.hackersdelight.org/hdcodetxt/muldwu.c.txt 513 | const BITS:usize = Limb::BITS / 2; 514 | const LO_MASK:Word = Wrapping((1usize << BITS) - 1); 515 | 516 | let u0 = u >> BITS; 517 | let u1 = u & LO_MASK; 518 | let v0 = v >> BITS; 519 | let v1 = v & LO_MASK; 520 | 521 | let t = u1 * v1; 522 | let w3 = t & LO_MASK; 523 | let k = t >> BITS; 524 | 525 | let t = u0*v1 + k; 526 | let w2 = t & LO_MASK; 527 | let w1 = t >> BITS; 528 | 529 | let t = u1 * v0 + w2; 530 | let k = t >> BITS; 531 | 532 | (u0*v0+w1+k, (t< (Limb, Limb) { 551 | if_cfg! { 552 | #[cfg(all(not(feature="fallbacks"), any(target_arch="x86_64", target_arch="x86")))] 553 | #[inline(always)] 554 | fn add_2_impl(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 555 | let mut high: Limb = Limb(0); 556 | let mut low: Limb = Limb(0); 557 | unsafe { 558 | asm!( 559 | "add {0}, {bl}", // adds bl to al and stores in low 560 | "adc {1}, {bh}", // adds bh to ah with carry and stores in high 561 | inout(reg) al.0 => low.0, 562 | inout(reg) ah.0 => high.0, 563 | bl = in(reg) bl.0, 564 | bh = in(reg) bh.0, 565 | ); 566 | } 567 | 568 | (high, low) 569 | } 570 | 571 | #[cfg(all( not(feature="fallbacks"), 572 | not(target_arch="x86"), 573 | target_pointer_width="32", 574 | ))] 575 | #[inline(always)] 576 | fn add_2_impl(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 577 | let a = ((ah.0 as u64) << 32) | al.0 as u64; 578 | let b = ((bh.0 as u64) << 32) | bl.0 as u64; 579 | let s = a.overflowing_add(b).0; 580 | (Limb((s>>32) as u32), Limb(s as u32)) 581 | } 582 | 583 | fallback: 584 | #[inline(always)] 585 | fn add_2_impl(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 586 | let (low, carry) = al.add_overflow(bl); 587 | let high = ah + bh + carry; 588 | 589 | (high, low) 590 | } 591 | } 592 | return add_2_impl(ah, al, bh, bl); 593 | } 594 | 595 | /** 596 | * Performs the two-word subtraction (ah, al) - (bh, bl), ignoring any borrow. 597 | */ 598 | #[inline(always)] 599 | pub fn sub_2(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 600 | if_cfg! { 601 | #[cfg(all(not(feature="fallbacks"), any(target_arch="x86_64", target_arch="x86")))] 602 | #[inline(always)] 603 | fn sub_2_impl(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 604 | let mut high: Limb = Limb(0); 605 | let mut low: Limb = Limb(0); 606 | unsafe { 607 | asm!( 608 | "sub {0}, {bl}", // subtracts bl from al and stores in low 609 | "sbb {1}, {bh}", // subtracts bh from ah with carry and stores in high 610 | inout(reg) al.0 => low.0, 611 | inout(reg) ah.0 => high.0, 612 | bl = in(reg) bl.0, 613 | bh = in(reg) bh.0 614 | ); 615 | } 616 | 617 | (high, low) 618 | } 619 | 620 | #[cfg(all( not(feature="fallbacks"), 621 | not(target_arch="x86"), 622 | target_pointer_width="32", 623 | ))] 624 | #[inline(always)] 625 | fn sub_2_impl(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 626 | let a = ((ah.0 as u64) << 32) | al.0 as u64; 627 | let b = ((bh.0 as u64) << 32) | bl.0 as u64; 628 | let s = a.overflowing_sub(b).0; 629 | (Limb((s>>32) as u32), Limb(s as u32)) 630 | } 631 | 632 | fallback: 633 | #[inline(always)] 634 | fn sub_2_impl(ah: Limb, al: Limb, bh: Limb, bl: Limb) -> (Limb, Limb) { 635 | let (low, carry) = al.sub_overflow(bl); 636 | let high = ah - bh - carry; 637 | 638 | (high, low) 639 | } 640 | } 641 | return sub_2_impl(ah, al, bh, bl); 642 | } 643 | 644 | /** 645 | * Divides the two-limb numerator `(nh, nl)` by `d`, returning a single-limb 646 | * quotient, Q, and remainder, R, as (Q, R). 647 | * 648 | * In order to ensure a single-limb result, the following conditions are required: 649 | * 650 | * - `nh` < `d` 651 | * - `d` >= BASE/2 652 | */ 653 | #[inline(always)] 654 | pub fn div(nh: Limb, nl: Limb, d: Limb) -> (Limb, Limb) { 655 | if_cfg! { 656 | #[cfg(all(not(feature="fallbacks"),target_arch="x86_64"))] 657 | #[inline(always)] 658 | fn div_impl(nh: Limb, nl: Limb, d: Limb) -> (Limb, Limb) { 659 | let mut q: Limb = Limb(0); 660 | let mut r: Limb = Limb(0); 661 | unsafe { 662 | asm!( 663 | "div {d}", // divide nh:nl by d and store the quotient in q and remainder in r 664 | d = in(reg) d.0, 665 | inout("rax") nl.0 => q.0, 666 | inout("rdx") nh.0 => r.0 667 | ); 668 | } 669 | (q, r) 670 | } 671 | 672 | #[cfg(all(not(feature="fallbacks"),target_arch="x86"))] 673 | #[inline(always)] 674 | fn div_impl(nh: Limb, nl: Limb, d: Limb) -> (Limb, Limb) { 675 | let mut q: Limb = Limb(0); 676 | let mut r: Limb = Limb(0); 677 | unsafe { 678 | asm!( 679 | "div {d}", // divide nh:nl by d and store the quotient in q and remainder in r 680 | d = in(reg) d.0, 681 | inout("eax") nl.0 => q.0, 682 | inout("edx") nh.0 => r.0 683 | ); 684 | } 685 | (q, r) 686 | } 687 | 688 | #[cfg(all( not(feature="fallbacks"), 689 | not(target_arch="x86"), 690 | target_pointer_width="32", 691 | ))] 692 | #[inline(always)] 693 | fn div_impl(nh: Limb, nl: Limb, d: Limb) -> (Limb, Limb) { 694 | let n = (nh.0 as u64) << 32 | nl.0 as u64; 695 | let d = d.0 as u64; 696 | (Limb((n/d) as u32), Limb((n%d) as u32)) 697 | } 698 | 699 | fallback: 700 | #[inline(always)] 701 | fn div_impl(nh: Limb, nl: Limb, d: Limb) -> (Limb, Limb) { 702 | fn div_2_usize_by_usize(u1:Word, u0: Word, v: Word) -> (Word,Word) { 703 | // See http://www.hackersdelight.org/hdcodetxt/divlu.c.txt (last one) 704 | // s == 0 in our case, d normalization is already done 705 | const BITS:usize = Limb::BITS / 2; 706 | const ONE:Word = Wrapping(1usize); 707 | const B:Word = Wrapping(1usize << BITS); 708 | const LO_MASK:Word = Wrapping((1usize << BITS) - 1); 709 | 710 | let vn1 = v >> BITS; 711 | let vn0 = v & LO_MASK; 712 | 713 | let un32 = u1; 714 | let un10 = u0; 715 | 716 | let un1 = un10 >> BITS; 717 | let un0 = un10 & LO_MASK; 718 | 719 | let mut q1 = un32 / vn1; 720 | let mut rhat = un32 - q1*vn1; 721 | 722 | while q1 >= B || q1*vn0 > B*rhat + un1 { 723 | q1 -= ONE; 724 | rhat += vn1; 725 | if rhat >= B { 726 | break; 727 | } 728 | } 729 | 730 | let un21 = un32*B +un1 - q1*v; 731 | 732 | let mut q0 = un21 / vn1; 733 | let mut rhat = un21 - q0*vn1; 734 | while q0 >= B || q0*vn0 > B*rhat + un0 { 735 | q0 -= ONE; 736 | rhat += vn1; 737 | if rhat >= B { 738 | break; 739 | } 740 | } 741 | (q1*B + q0, un21*B + un0 - q0*v) 742 | } 743 | 744 | let (q,r) = div_2_usize_by_usize( 745 | Wrapping(nh.0 as usize), 746 | Wrapping(nl.0 as usize), 747 | Wrapping(d.0 as usize)); 748 | 749 | (Limb(q.0 as BaseInt), Limb(r.0 as BaseInt)) 750 | } 751 | } 752 | 753 | debug_assert!(d.high_bit_set()); 754 | debug_assert!(nh < d); 755 | unsafe { 756 | assume(nh < d); 757 | assume(d.high_bit_set()); 758 | } 759 | 760 | return div_impl(nh, nl, d); 761 | } 762 | 763 | /** 764 | * Divides `(nh, nl)` by `d` using the inverted limb `dinv`. Returns the quotient, Q, and 765 | * remainder, R, as (Q, R); 766 | */ 767 | #[inline(always)] 768 | pub fn div_preinv(nh: Limb, nl: Limb, d: Limb, dinv: Limb) -> (Limb, Limb) { 769 | let (qh, ql) = dinv.mul_hilo(nh); 770 | let (mut qh, ql) = add_2(qh, ql, nh + 1, nl); 771 | 772 | let mut r = nl - qh * d; 773 | if r > ql { 774 | qh = qh - 1; 775 | r = r + d; 776 | } 777 | if r >= d { 778 | qh = qh + 1; 779 | r = r - d; 780 | } 781 | 782 | (qh, r) 783 | } 784 | 785 | #[test] 786 | fn test_bug_div_1() { 787 | let (q, r) = div( 788 | Limb(0), 789 | Limb(10), 790 | Limb((usize::max_value() / 2 + 1) as BaseInt), 791 | ); 792 | assert_eq!((q.0, r.0), (0, 10)); 793 | } 794 | 795 | #[cfg(target_pointer_width = "64")] 796 | #[test] 797 | fn test_bug_mul_1() { 798 | let (h, l) = mul(Limb(18446744073709551615), Limb(7868907223611932671)); 799 | assert_eq!((h.0, l.0), (7868907223611932670, 10577836850097618945)); 800 | } 801 | 802 | #[test] 803 | fn test_add_2() { 804 | let (h, l) = add_2(Limb(4), Limb(2), Limb(3), Limb(1)); 805 | assert_eq!((h.0, l.0), (7, 3)); 806 | } 807 | 808 | #[test] 809 | fn test_sub_2() { 810 | let (h, l) = sub_2(Limb(4), Limb(2), Limb(3), Limb(1)); 811 | assert_eq!((h.0, l.0), (1, 1)); 812 | } 813 | 814 | #[test] 815 | fn test_div() { 816 | let (q, r) = div( 817 | Limb(2), 818 | Limb(0), 819 | Limb((usize::max_value() / 2 + 1) as BaseInt), 820 | ); 821 | assert_eq!((q.0, r.0), (4, 0)); 822 | } 823 | -------------------------------------------------------------------------------- /src/ll/limb_ptr.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use ll::limb::Limb; 16 | 17 | use std::{fmt, ops}; 18 | #[cfg(debug_assertions)] 19 | use std::mem; 20 | use std::cmp::Ordering; 21 | 22 | 23 | /// A version of `*const Limb` that is bounds-checked when debug assertions are on 24 | #[derive(Copy, Clone, Debug)] 25 | pub struct Limbs { 26 | ptr: *const Limb, 27 | bounds: Bounds, 28 | } 29 | 30 | /// A version of `*mut Limb` that is bounds-checked when debug assertions are on 31 | #[derive(Copy, Clone)] 32 | pub struct LimbsMut { 33 | ptr: *mut Limb, 34 | bounds: Bounds, 35 | } 36 | 37 | macro_rules! api { 38 | ($ty: ident, $ptr: ty) => { 39 | impl $ty { 40 | /// Create a new instance, pointing at `base` and valid 41 | /// from `base.offset(start)` to `base.offset(end)`. 42 | pub unsafe fn new(base: $ptr, start: i32, end: i32) -> $ty { 43 | $ty { 44 | ptr: base, 45 | bounds: Bounds::new(base as usize, start, end) 46 | } 47 | } 48 | 49 | /// Move `self` to point to the `x`th Limbs from the 50 | /// current location. 51 | #[inline] 52 | pub unsafe fn offset(self, x: isize) -> $ty { 53 | debug_assert!(self.bounds.offset_valid(self.ptr as usize, x), 54 | "invalid offset of {:?} by {}, which should be in {:?}", self.ptr, x, self.bounds); 55 | $ty { 56 | ptr: self.ptr.offset(x), 57 | bounds: self.bounds, 58 | } 59 | } 60 | } 61 | 62 | impl PartialEq for $ty { 63 | fn eq(&self, other: &$ty) -> bool { 64 | self.ptr == other.ptr 65 | } 66 | } 67 | impl PartialOrd for $ty { 68 | fn partial_cmp(&self, other: &$ty) -> Option { 69 | self.ptr.partial_cmp(&other.ptr) 70 | } 71 | } 72 | impl Eq for $ty {} 73 | impl Ord for $ty { 74 | fn cmp(&self, other: &$ty) -> Ordering { 75 | self.ptr.cmp(&other.ptr) 76 | } 77 | } 78 | 79 | impl ops::Deref for $ty { 80 | type Target = Limb; 81 | fn deref(&self) -> &Limb { 82 | debug_assert!(self.bounds.can_deref(self.ptr as usize), 83 | "invalid deref of {:?}, which should be in {:?}", self.ptr, self.bounds); 84 | unsafe { &*self.ptr } 85 | } 86 | } 87 | } 88 | } 89 | 90 | api!(Limbs, *const Limb); 91 | api!(LimbsMut, *mut Limb); 92 | impl LimbsMut { 93 | /// View the `LimbsMut` as a `Limbs` (an explicit `*const 94 | /// Limb` -> `*mut Limb` conversion) 95 | pub fn as_const(self) -> Limbs { 96 | Limbs { 97 | ptr: self.ptr, 98 | bounds: self.bounds, 99 | } 100 | } 101 | } 102 | impl ops::DerefMut for LimbsMut { 103 | fn deref_mut(&mut self) -> &mut Limb { 104 | debug_assert!(self.bounds.can_deref(self.ptr as usize), 105 | "invalid mut deref of {:?}, which should be in {:?}", self.ptr, self.bounds); 106 | unsafe { &mut *self.ptr } 107 | } 108 | } 109 | 110 | // This is where the magic is at: the bounds are only stored/checked 111 | // in debug mode; release mode just powers ahead without any overhead. 112 | 113 | #[derive(Copy, Clone)] 114 | #[cfg(debug_assertions)] 115 | struct Bounds { 116 | lo: usize, 117 | hi: usize, 118 | } 119 | #[derive(Copy, Clone)] 120 | #[cfg(not(debug_assertions))] 121 | struct Bounds; 122 | 123 | #[cfg(debug_assertions)] 124 | impl Bounds { 125 | fn new(ptr: usize, start: i32, end: i32) -> Bounds { 126 | assert!(start <= end); 127 | Bounds { 128 | lo: ptr + start as usize * mem::size_of::(), 129 | hi: ptr + end as usize * mem::size_of::(), 130 | } 131 | } 132 | fn can_deref(self, ptr: usize) -> bool { 133 | // a deref can't deref when we're at the limit 134 | self.lo <= ptr && ptr < self.hi 135 | } 136 | fn offset_valid(self, ptr: usize, offset: isize) -> bool { 137 | let bytes = offset * mem::size_of::() as isize; 138 | let new = ptr.wrapping_add(bytes as usize); 139 | // an offset can point to the limit (i.e. one byte past the end) 140 | self.lo <= new && new <= self.hi 141 | } 142 | } 143 | #[cfg(not(debug_assertions))] 144 | impl Bounds { 145 | fn new(_ptr: usize, _start: i32, _end: i32) -> Bounds { Bounds } 146 | #[inline] 147 | fn can_deref(self, _ptr: usize) -> bool { true } 148 | #[inline] 149 | fn offset_valid(self, _ptr: usize, _offset: isize) -> bool { true } 150 | } 151 | impl fmt::Debug for Bounds { 152 | #[cfg(debug_assertions)] 153 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 154 | write!(f, "Bounds {{ lo: 0x{:x}, hi: 0x{:x} }}", self.lo, self.hi) 155 | } 156 | #[cfg(not(debug_assertions))] 157 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 158 | write!(f, "Bounds {{ }}") 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/ll/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! This module provides the low-level operations for working with arbitrary precision numbers. 16 | //! 17 | //! ## Overview 18 | //! 19 | //! This module forms the core of the library. As such, the functions are required to be highly 20 | //! performant, even small inefficiencies can cause a large impact given how frequently some of 21 | //! these functions are called. `addmul` for example is one of the most frequently called functions 22 | //! in the library, so an efficiencies there will be multiplied out to almost the entire library. 23 | //! 24 | //! There are no real restrictions on the functions that can implemented in here. Exposed functions 25 | //! should be generally useful to high-level code, but otherwise any operation that can be more 26 | //! efficiently implemented here and then exposed by a higher-level API is a candidate. 27 | //! 28 | //! The functions in this module assume that all inputs are valid, though some checking is performed 29 | //! in debug builds. 30 | //! 31 | //! ## Limbs 32 | //! 33 | //! A `Limb` is a single "digit" in an arbitrary-precision integer. To explain, consider the 34 | //! standard base we work in, base-10. Base-10 uses represents numbers as a sequence of the digits 35 | //! 0-9. The number 251 is 2 x 10^2 + 5 x 10^1 + 1 x 10^0. Similarly base-16 (hexadecimal) uses 36 | //! sixteen digits and a base of 16 to represent numbers. 37 | //! 38 | //! A `Limb` is one word, with N bits (32 on a 32-bit platform, 64 on a 64-bit platform), so it can 39 | //! represent 2^N unique values. It can therefore form the basis of a base-2^N number system. The 40 | //! word "Limb" is used by GMP to distinguish it from a regular numerical digit, and there is no 41 | //! obvious reason to use different terminology. 42 | //! 43 | //! `Limb` itself implements a number of useful methods. The basic mathematical operators are 44 | //! implemented to provide wrapping behaviour by default. The most basic operations are also 45 | //! implemented on `Limb`, notably multiplication with a two-word output and division of a two-word 46 | //! numerator by a one-word denominator. The implementations of these operations are done with 47 | //! inline assembly on x86 platforms with a Rust implementation as fallback. 48 | //! 49 | //! ## Integer representation 50 | //! 51 | //! Integers are passed around as pointers to a series of `Limb`s. The limbs are stored 52 | //! least-significant first. If required, a size parameter is also provided, but otherwise is 53 | //! omitted when it can be inferred from other sources of information. This is the case with the 54 | //! output pointers used to store the result, they are assumed to have enough memory store the 55 | //! result as the maximum output size is bounded by the size of the inputs. 56 | //! 57 | //! The integers are not required to be "normalized" in most cases. That is, they may have 58 | //! zero-value limbs in the highest positions. Functions should aim to avoid requiring normalized 59 | //! integers but otherwise explicitly document said requirement. 60 | //! 61 | //! ## Memory allocation 62 | //! 63 | //! No function will allocate memory for a return value. However, it is sometimes required to 64 | //! allocate "scratch space" for storing intermediate values. This scratch space is always temporary 65 | //! and freed before the function returns. Functions that need to make heavy use of scratch space 66 | //! while also being recursive, are split so that scratch space can be re-used. 67 | //! 68 | //! ## Argument Conventions 69 | //! 70 | //! There are no hard-and-fast rules for the argument conventions in this module. There are however 71 | //! some general conventions: 72 | //! 73 | //! * Output/Result pointer goes first (if applicable). 74 | //! * Pointer and matching size are kept close together in the argument list. 75 | //! * Sizes come after the matching pointers. For example, `add_n` takes two pointers and a length, 76 | //! the length applies to both pointers and so comes after both of them. 77 | 78 | use std::cmp::Ordering; 79 | use std::intrinsics::abort; 80 | 81 | mod addsub; 82 | mod bit; 83 | mod div; 84 | mod gcd; 85 | mod mul; 86 | 87 | pub mod base; 88 | pub mod limb; 89 | pub mod limb_ptr; 90 | pub mod pow; 91 | use self::limb::Limb; 92 | 93 | use ll::limb_ptr::{Limbs, LimbsMut}; 94 | 95 | pub use self::addsub::{add, add_1, add_n, decr, incr, sub, sub_1, sub_n}; 96 | pub use self::bit::{ 97 | and_n, and_not_n, nand_n, nor_n, not, or_n, or_not_n, scan_0, scan_1, shl, shr, 98 | twos_complement, xor_n, 99 | }; 100 | pub use self::div::{divrem, divrem_1, divrem_2}; 101 | pub use self::gcd::gcd; 102 | pub use self::mul::{addmul_1, mul, mul_1, sqr, submul_1}; 103 | 104 | #[inline(always)] 105 | pub unsafe fn overlap(xp: LimbsMut, xs: i32, yp: Limbs, ys: i32) -> bool { 106 | xp.offset(xs as isize).as_const() > yp && yp.offset(ys as isize) > xp.as_const() 107 | } 108 | 109 | #[inline(always)] 110 | pub unsafe fn same_or_separate(xp: LimbsMut, xs: i32, yp: Limbs, ys: i32) -> bool { 111 | xp.as_const() == yp || !overlap(xp, xs, yp, ys) 112 | } 113 | 114 | #[inline(always)] 115 | pub unsafe fn same_or_incr(xp: LimbsMut, xs: i32, yp: Limbs, ys: i32) -> bool { 116 | xp.as_const() <= yp || !overlap(xp, xs, yp, ys) 117 | } 118 | 119 | #[inline(always)] 120 | pub unsafe fn same_or_decr(xp: LimbsMut, xs: i32, yp: Limbs, ys: i32) -> bool { 121 | xp.as_const() >= yp || !overlap(xp, xs, yp, ys) 122 | } 123 | 124 | /** 125 | * Copies the `n` limbs from `src` to `dst` in an incremental fashion. 126 | */ 127 | #[inline] 128 | pub unsafe fn copy_incr(src: Limbs, dst: LimbsMut, n: i32) { 129 | debug_assert!(same_or_incr(dst, n, src, n)); 130 | 131 | let mut i = 0; 132 | while i < n { 133 | *dst.offset(i as isize) = *src.offset(i as isize); 134 | i += 1; 135 | } 136 | } 137 | 138 | /** 139 | * Copies the `n` limbs from `src` to `dst` in a decremental fashion. 140 | */ 141 | #[inline] 142 | pub unsafe fn copy_decr(src: Limbs, dst: LimbsMut, mut n: i32) { 143 | debug_assert!(same_or_decr(dst, n, src, n)); 144 | 145 | n -= 1; 146 | while n >= 0 { 147 | *dst.offset(n as isize) = *src.offset(n as isize); 148 | n -= 1; 149 | } 150 | } 151 | 152 | /** 153 | * Copies the `n - start` limbs from `src + start` to `dst + start` 154 | */ 155 | #[inline] 156 | pub unsafe fn copy_rest(src: Limbs, dst: LimbsMut, n: i32, start: i32) { 157 | copy_incr( 158 | src.offset(start as isize), 159 | dst.offset(start as isize), 160 | n - start, 161 | ); 162 | } 163 | 164 | #[inline] 165 | /** 166 | * Returns the size of the integer pointed to by `p` such that the most 167 | * significant limb is non-zero. 168 | */ 169 | pub unsafe fn normalize(p: Limbs, mut n: i32) -> i32 { 170 | debug_assert!(n >= 0); 171 | while n > 0 && *p.offset((n - 1) as isize) == 0 { 172 | n -= 1; 173 | } 174 | 175 | return n; 176 | } 177 | 178 | /** 179 | * Called when a divide by zero occurs. 180 | * 181 | * If debug assertions are enabled, a message is printed and the 182 | * stack unwinds. Otherwise it will simply abort the process. 183 | */ 184 | #[cold] 185 | #[inline(never)] 186 | pub fn divide_by_zero() -> ! { 187 | if cfg!(debug_assertions) { 188 | panic!("divide by zero") 189 | } else { 190 | abort(); 191 | } 192 | } 193 | 194 | /** 195 | * Checks that all `nn` limbs in `np` are zero 196 | */ 197 | pub unsafe fn is_zero(mut np: Limbs, mut nn: i32) -> bool { 198 | while nn > 0 { 199 | if *np != 0 { 200 | return false; 201 | } 202 | np = np.offset(1); 203 | nn -= 1; 204 | } 205 | return true; 206 | } 207 | 208 | pub unsafe fn zero(mut np: LimbsMut, mut nn: i32) { 209 | while nn > 0 { 210 | *np = Limb(0); 211 | np = np.offset(1); 212 | nn -= 1; 213 | } 214 | } 215 | 216 | /** 217 | * Compares the `n` least-significant limbs of `xp` and `yp`, returning whether 218 | * {xp, n} is less than, equal to or greater than {yp, n} 219 | */ 220 | pub unsafe fn cmp(xp: Limbs, yp: Limbs, n: i32) -> Ordering { 221 | let mut i = n - 1; 222 | while i >= 0 { 223 | let x = *xp.offset(i as isize); 224 | let y = *yp.offset(i as isize); 225 | if x != y { 226 | return if x > y { 227 | Ordering::Greater 228 | } else { 229 | Ordering::Less 230 | }; 231 | } 232 | i -= 1; 233 | } 234 | 235 | Ordering::Equal 236 | } 237 | 238 | #[doc(hidden)] 239 | #[allow(unused_must_use)] 240 | #[cold] 241 | #[inline(never)] 242 | pub unsafe fn dump(lbl: &str, mut p: Limbs, mut n: i32) { 243 | use std::io::{self, Write}; 244 | let stdout = io::stdout(); 245 | let mut stdout = stdout.lock(); 246 | 247 | stdout.write_all(lbl.as_bytes()); 248 | write!(stdout, ": ({})", n); 249 | stdout.write_all(b"[\n"); 250 | let mut i = 0; 251 | while n > 0 { 252 | write!(stdout, "0x{:0>2X}", (*p).0); 253 | p = p.offset(1); 254 | n -= 1; 255 | if n != 0 { 256 | stdout.write_all(b", "); 257 | } 258 | i += 1; 259 | if (i % 8) == 0 { 260 | stdout.write_all(b"\n"); 261 | } 262 | } 263 | 264 | stdout.write_all(b"]\n"); 265 | stdout.flush(); 266 | } 267 | 268 | #[cfg(test)] 269 | mod test { 270 | use super::*; 271 | use ll::limb::Limb; 272 | use ll::limb_ptr::{Limbs, LimbsMut}; 273 | 274 | macro_rules! make_limbs { 275 | (const $nm:ident, $($d:expr),*) => ( 276 | { 277 | $nm = [$(Limb($d)),*]; 278 | let len = $nm.len() as i32; 279 | let ptr = unsafe {Limbs::new($nm.as_ptr(), 0, len)}; 280 | (ptr, len) 281 | } 282 | ); 283 | (out $nm:ident, $len:expr) => ( 284 | { 285 | $nm = [Limb(0);$len]; 286 | unsafe {LimbsMut::new($nm.as_mut_ptr(), 0, $len as i32)} 287 | } 288 | ); 289 | } 290 | 291 | #[test] 292 | fn test_add() { 293 | let a; 294 | let b; 295 | let mut c; 296 | 297 | let (ap, asz) = make_limbs!(const a, 1); 298 | let (bp, bsz) = make_limbs!(const b, 2); 299 | let cp = make_limbs!(out c, 1); 300 | 301 | unsafe { 302 | assert_eq!(add(cp, ap, asz, bp, bsz), 0); 303 | } 304 | 305 | assert_eq!(c[0], 3); 306 | 307 | let a; 308 | let b; 309 | let mut c; 310 | 311 | let (ap, asz) = make_limbs!(const a, !0); 312 | let (bp, bsz) = make_limbs!(const b, 5); 313 | let cp = make_limbs!(out c, 1); 314 | 315 | unsafe { 316 | assert_eq!(add(cp, ap, asz, bp, bsz), 1); 317 | } 318 | assert_eq!(c[0], 4); 319 | 320 | let a; 321 | let b; 322 | let mut c; 323 | 324 | let (ap, asz) = make_limbs!(const a, !0, 0); 325 | let (bp, bsz) = make_limbs!(const b, 5); 326 | let cp = make_limbs!(out c, 2); 327 | 328 | unsafe { 329 | assert_eq!(add(cp, ap, asz, bp, bsz), 0); 330 | } 331 | assert_eq!(c, [4, 1]); 332 | 333 | let a; 334 | let b; 335 | let mut c; 336 | 337 | let (ap, asz) = make_limbs!(const a, !0, !9); 338 | let (bp, bsz) = make_limbs!(const b, 5, 10); 339 | let cp = make_limbs!(out c, 2); 340 | 341 | unsafe { 342 | assert_eq!(add(cp, ap, asz, bp, bsz), 1); 343 | } 344 | assert_eq!(c, [4, 1]); 345 | } 346 | 347 | #[test] 348 | fn test_add_self() { 349 | let a; 350 | let mut b; 351 | 352 | let (ap, asz) = make_limbs!(const a, !0, !9); 353 | let bp = make_limbs!(out b, 2); 354 | let bsz = 2; 355 | b[0] = Limb(5); 356 | b[1] = Limb(10); 357 | 358 | unsafe { 359 | assert_eq!(add(bp, ap, asz, bp.as_const(), bsz), 1); 360 | } 361 | assert_eq!(b, [4, 1]); 362 | } 363 | 364 | #[test] 365 | fn test_sub() { 366 | let a; 367 | let b; 368 | let mut c; 369 | 370 | let (ap, asz) = make_limbs!(const a, 2); 371 | let (bp, bsz) = make_limbs!(const b, 1); 372 | let cp = make_limbs!(out c, 1); 373 | 374 | unsafe { 375 | assert_eq!(sub(cp, ap, asz, bp, bsz), 0); 376 | } 377 | 378 | assert_eq!(c[0], 1); 379 | 380 | let a; 381 | let b; 382 | let mut c; 383 | 384 | let (ap, asz) = make_limbs!(const a, 0, 2); 385 | let (bp, bsz) = make_limbs!(const b, 1); 386 | let cp = make_limbs!(out c, 2); 387 | 388 | unsafe { 389 | assert_eq!(sub(cp, ap, asz, bp, bsz), 0); 390 | } 391 | 392 | assert_eq!(c, [!0, 1]); 393 | 394 | let a; 395 | let b; 396 | let mut c; 397 | let (ap, asz) = make_limbs!(const a, 0, 2); 398 | let (bp, bsz) = make_limbs!(const b, 2, 1); 399 | let cp = make_limbs!(out c, 2); 400 | 401 | unsafe { 402 | assert_eq!(sub(cp, ap, asz, bp, bsz), 0); 403 | } 404 | 405 | assert_eq!(c, [!1, 0]); 406 | } 407 | 408 | #[test] 409 | fn test_sub_self() { 410 | let a; 411 | let mut b; 412 | 413 | let (ap, asz) = make_limbs!(const a, 0, 2); 414 | let bp = make_limbs!(out b, 2); 415 | let bsz = 2; 416 | b[0] = Limb(2); 417 | b[1] = Limb(1); 418 | 419 | unsafe { 420 | assert_eq!(sub(bp, ap, asz, bp.as_const(), bsz), 0); 421 | } 422 | assert_eq!(b, [!1, 0]); 423 | } 424 | 425 | #[test] 426 | fn test_mul_hilo() { 427 | let r = Limb(10).mul_hilo(Limb(20)); 428 | assert_eq!((Limb(0), Limb(200)), r); 429 | 430 | let r = Limb(!1).mul_hilo(Limb(2)); 431 | assert_eq!((Limb(1), Limb(!3)), r); 432 | 433 | let r = Limb(2).mul_hilo(Limb(!1)); 434 | assert_eq!((Limb(1), Limb(!3)), r); 435 | 436 | let r = Limb(!0).mul_hilo(Limb(!0)); 437 | assert_eq!((Limb(!1), Limb(1)), r); 438 | } 439 | 440 | #[test] 441 | fn test_mul_1() { 442 | let a; 443 | let mut b; 444 | let (ap, asz) = make_limbs!(const a, 10); 445 | let bp = make_limbs!(out b, 1); 446 | 447 | unsafe { 448 | assert_eq!(mul_1(bp, ap, asz, Limb(20)), 0); 449 | } 450 | 451 | assert_eq!(b, [200]); 452 | 453 | let a; 454 | let mut b; 455 | let (ap, asz) = make_limbs!(const a, !1); 456 | let bp = make_limbs!(out b, 1); 457 | 458 | unsafe { 459 | assert_eq!(mul_1(bp, ap, asz, Limb(2)), 1); 460 | } 461 | 462 | assert_eq!(b, [!3]); 463 | 464 | let a; 465 | let mut b; 466 | let (ap, asz) = make_limbs!(const a, 10, 10); 467 | let bp = make_limbs!(out b, 2); 468 | 469 | unsafe { 470 | assert_eq!(mul_1(bp, ap, asz, Limb(2)), 0); 471 | } 472 | 473 | assert_eq!(b, [20, 20]); 474 | } 475 | 476 | #[test] 477 | fn test_mul() { 478 | let a; 479 | let b; 480 | let mut c; 481 | 482 | let (ap, asz) = make_limbs!(const a, 2); 483 | let (bp, bsz) = make_limbs!(const b, 2); 484 | let cp = make_limbs!(out c, 2); 485 | 486 | unsafe { 487 | mul(cp, ap, asz, bp, bsz); 488 | } 489 | 490 | assert_eq!(c, [4, 0]); 491 | 492 | let a; 493 | let b; 494 | let mut c; 495 | 496 | let (ap, asz) = make_limbs!(const a, !1); 497 | let (bp, bsz) = make_limbs!(const b, 2); 498 | let cp = make_limbs!(out c, 2); 499 | 500 | unsafe { 501 | mul(cp, ap, asz, bp, bsz); 502 | } 503 | 504 | assert_eq!(c, [!3, 1]); 505 | 506 | let a; 507 | let b; 508 | let mut c; 509 | 510 | let (ap, asz) = make_limbs!(const a, !1, 1); 511 | let (bp, bsz) = make_limbs!(const b, 4); 512 | let cp = make_limbs!(out c, 3); 513 | 514 | unsafe { 515 | mul(cp, ap, asz, bp, bsz); 516 | } 517 | 518 | assert_eq!(c, [!7, 7, 0]); 519 | 520 | let a; 521 | let b; 522 | let mut c; 523 | let (ap, asz) = make_limbs!(const a, !1, 1); 524 | let (bp, bsz) = make_limbs!(const b, 0, 1); 525 | let cp = make_limbs!(out c, 4); 526 | 527 | unsafe { 528 | mul(cp, ap, asz, bp, bsz); 529 | } 530 | 531 | assert_eq!(c, [0, !1, 1, 0]); 532 | } 533 | 534 | #[test] 535 | fn test_mul_large() { 536 | // Warning, dragons lie ahead, mostly to avoid writing out 150-limb numbers 537 | 538 | let a; 539 | let b; 540 | let mut c; 541 | // Abuse the fact that fixed-size arrays and tuples are laid out sequentially in memory 542 | let expected: [Limb; 73] = unsafe { 543 | ::std::mem::transmute(( 544 | Limb(1), 545 | [Limb(0); 29], 546 | [Limb(!0); 13], 547 | Limb(!1), 548 | [Limb(!0); 29], 549 | )) 550 | }; 551 | 552 | // (B^43 - 1) 553 | a = [Limb(!0); 43]; 554 | // (B^30 - 1) 555 | b = [Limb(!0); 30]; 556 | 557 | c = [Limb(0); 73]; 558 | 559 | unsafe { 560 | let ap = Limbs::new(&a[0], 0, a.len() as i32); 561 | let bp = Limbs::new(&b[0], 0, b.len() as i32); 562 | let cp = LimbsMut::new(&mut c[0], 0, c.len() as i32); 563 | 564 | mul(cp, ap, 43, bp, 30); 565 | } 566 | 567 | let ep: &[Limb] = &expected; 568 | let cp: &[Limb] = &c; 569 | assert_eq!(cp, ep); 570 | 571 | let a; 572 | let b; 573 | let mut c; 574 | // Abuse the fact that fixed-size arrays and tuples are laid out sequentially in memory 575 | let expected: [Limb; 150] = unsafe { 576 | ::std::mem::transmute(( 577 | Limb(1), 578 | [Limb(0); 25], 579 | [Limb(!0); 98], 580 | Limb(!1), 581 | [Limb(!0); 25], 582 | )) 583 | }; 584 | 585 | // (B^124 - 1) 586 | a = [Limb(!0); 124]; 587 | // (B^25 - 1) 588 | b = [Limb(!0); 26]; 589 | 590 | c = [Limb(0); 150]; 591 | 592 | unsafe { 593 | let ap = Limbs::new(&a[0], 0, a.len() as i32); 594 | let bp = Limbs::new(&b[0], 0, b.len() as i32); 595 | let cp = LimbsMut::new(&mut c[0], 0, c.len() as i32); 596 | 597 | mul(cp, ap, 124, bp, 26); 598 | } 599 | 600 | let ep: &[Limb] = &expected; 601 | let cp: &[Limb] = &c; 602 | assert_eq!(cp, ep); 603 | } 604 | 605 | #[test] 606 | fn test_divrem_1() { 607 | let a; 608 | let mut b; 609 | 610 | let (ap, asz) = make_limbs!(const a, 2); 611 | let bp = make_limbs!(out b, 1); 612 | 613 | unsafe { 614 | assert_eq!(divrem_1(bp, 0, ap, asz, Limb(2)), 0); 615 | } 616 | 617 | assert_eq!(b, [1]); 618 | 619 | let a; 620 | let mut b; 621 | 622 | let (ap, asz) = make_limbs!(const a, 7); 623 | let bp = make_limbs!(out b, 1); 624 | 625 | unsafe { 626 | assert_eq!(divrem_1(bp, 0, ap, asz, Limb(1)), 0); 627 | } 628 | 629 | assert_eq!(b, [7]); 630 | 631 | let a; 632 | let mut b; 633 | 634 | let (ap, asz) = make_limbs!(const a, 7); 635 | let bp = make_limbs!(out b, 1); 636 | 637 | unsafe { 638 | assert_eq!(divrem_1(bp, 0, ap, asz, Limb(2)), 1); 639 | } 640 | 641 | assert_eq!(b, [3]); 642 | 643 | let a; 644 | let mut b; 645 | 646 | let (ap, asz) = make_limbs!(const a, 0, 1); 647 | let bp = make_limbs!(out b, 2); 648 | 649 | unsafe { 650 | assert_eq!(divrem_1(bp, 0, ap, asz, Limb(4)), 0); 651 | } 652 | 653 | assert_eq!(b, [1 << (Limb::BITS - 2), 0 as limb::BaseInt]); 654 | 655 | let a; 656 | let mut b; 657 | 658 | let (ap, asz) = make_limbs!(const a, 5); 659 | let bp = make_limbs!(out b, 2); 660 | 661 | unsafe { 662 | assert_eq!(divrem_1(bp, 1, ap, asz, Limb(2)), 0); 663 | } 664 | 665 | assert_eq!(b, [1 << (Limb::BITS - 1), 2 as limb::BaseInt]); 666 | } 667 | 668 | #[test] 669 | fn test_divrem() { 670 | let a; 671 | let b; 672 | let mut q; 673 | let mut r; 674 | 675 | let (ap, asz) = make_limbs!(const a, 4, 3, 4); 676 | let (bp, bsz) = make_limbs!(const b, 1, !0); 677 | let qp = make_limbs!(out q, 2); 678 | let rp = make_limbs!(out r, 2); 679 | 680 | unsafe { 681 | divrem(qp, rp, ap, asz, bp, bsz); 682 | } 683 | 684 | assert_eq!(q, [4, 0]); 685 | assert_eq!(r, [0, 7]); 686 | 687 | let a; 688 | let b; 689 | let mut q; 690 | let mut r; 691 | 692 | let (ap, asz) = make_limbs!(const a, 0, 4, 3, 4, 2); 693 | let (bp, bsz) = make_limbs!(const b, 0, !1); 694 | let qp = make_limbs!(out q, 4); 695 | let rp = make_limbs!(out r, 2); 696 | 697 | unsafe { 698 | divrem(qp, rp, ap, asz, bp, bsz); 699 | } 700 | 701 | assert_eq!(q, [19, 8, 2, 0]); 702 | assert_eq!(r, [0, 42]); 703 | 704 | let a; 705 | let b; 706 | let mut q; 707 | let mut r; 708 | 709 | let (ap, asz) = make_limbs!(const a, 8, 1, 3, 4, 1); 710 | let (bp, bsz) = make_limbs!(const b, 0, 1); 711 | let qp = make_limbs!(out q, 4); 712 | let rp = make_limbs!(out r, 2); 713 | 714 | unsafe { 715 | divrem(qp, rp, ap, asz, bp, bsz); 716 | } 717 | 718 | assert_eq!(q, [1, 3, 4, 1]); 719 | assert_eq!(r, [8, 0]); 720 | 721 | { 722 | let a; 723 | let b; 724 | let mut q; 725 | let mut r; 726 | 727 | // (B^4 - 1)(B^8 - 1) 728 | let (ap, asz) = make_limbs!(const a, 1, 0, 0, 0, !0, !0, !0, !0, !1, !0, !0, !0); 729 | // (B^4 - 1) 730 | let (bp, bsz) = make_limbs!(const b, !0, !0, !0, !0); 731 | let qp = make_limbs!(out q, 9); 732 | let rp = make_limbs!(out r, 4); 733 | 734 | unsafe { 735 | divrem(qp, rp, ap, asz, bp, bsz); 736 | } 737 | 738 | // q = (B^8 - 1) 739 | assert_eq!(q, [!0, !0, !0, !0, !0, !0, !0, !0, 0]); 740 | assert_eq!(r, [0, 0, 0, 0]); 741 | } 742 | } 743 | 744 | #[test] 745 | fn test_bitscan() { 746 | let a; 747 | 748 | let (ap, asz) = make_limbs!(const a, 256); 749 | 750 | let pos = unsafe { scan_1(ap, asz) }; 751 | 752 | assert_eq!(pos, 8); 753 | 754 | let a; 755 | let (ap, asz) = make_limbs!(const a, 0, 256); 756 | 757 | let pos = unsafe { scan_1(ap, asz) }; 758 | 759 | assert_eq!(pos, Limb::BITS as u32 + 8); 760 | 761 | let a; 762 | let (ap, asz) = make_limbs!(const a, !256); 763 | 764 | let pos = unsafe { scan_0(ap, asz) }; 765 | 766 | assert_eq!(pos, 8); 767 | 768 | let a; 769 | let (ap, asz) = make_limbs!(const a, !0, !256); 770 | 771 | let pos = unsafe { scan_0(ap, asz) }; 772 | 773 | assert_eq!(pos, Limb::BITS as u32 + 8); 774 | } 775 | } 776 | -------------------------------------------------------------------------------- /src/ll/mul.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![allow(improper_ctypes)] 16 | 17 | use std::cmp::Ordering; 18 | 19 | use ll; 20 | use ll::limb::Limb; 21 | use super::{overlap, same_or_separate, same_or_incr}; 22 | use mem; 23 | 24 | use ll::limb_ptr::{Limbs, LimbsMut}; 25 | 26 | const TOOM22_THRESHOLD : i32 = 20; 27 | 28 | #[allow(dead_code)] 29 | unsafe fn mul_1_generic(mut wp: LimbsMut, mut xp: Limbs, mut n: i32, vl: Limb) -> Limb { 30 | let mut cl = Limb(0); 31 | loop { 32 | let xl = *xp; 33 | let (hpl, lpl) = xl.mul_hilo(vl); 34 | let (lpl, carry) = lpl.add_overflow(cl); 35 | cl = hpl + carry; 36 | 37 | *wp = lpl; 38 | 39 | n -= 1; 40 | if n == 0 { break; } 41 | 42 | wp = wp.offset(1); 43 | xp = xp.offset(1); 44 | } 45 | 46 | return cl; 47 | } 48 | 49 | /** 50 | * Multiplies the `n` least-significant limbs of `xp` by `vl` storing the `n` least-significant 51 | * limbs of the product in `{wp, n}`. 52 | * 53 | * Returns the highest limb of the product 54 | */ 55 | #[cfg(not(asm))] 56 | #[inline] 57 | pub unsafe fn mul_1(wp: LimbsMut, xp: Limbs, n: i32, vl: Limb) -> Limb { 58 | debug_assert!(n > 0); 59 | debug_assert!(same_or_incr(wp, n, xp, n)); 60 | 61 | mul_1_generic(wp, xp, n, vl) 62 | } 63 | 64 | /** 65 | * Multiplies the `n` least-significant limbs of `xp` by `vl` storing the `n` least-significant 66 | * limbs of the product in `{wp, n}`. 67 | * 68 | * Returns the highest limb of the product 69 | */ 70 | #[cfg(asm)] 71 | #[inline] 72 | pub unsafe fn mul_1(mut wp: LimbsMut, xp: Limbs, n: i32, vl: Limb) -> Limb { 73 | debug_assert!(n > 0); 74 | debug_assert!(same_or_incr(wp, n, xp, n)); 75 | extern "C" { 76 | fn ramp_mul_1(wp: *mut Limb, xp: *const Limb, n: i32, vl: Limb) -> Limb; 77 | } 78 | 79 | ramp_mul_1(&mut *wp, &*xp, n, vl) 80 | } 81 | 82 | #[allow(dead_code)] 83 | unsafe fn addmul_1_generic(mut wp: LimbsMut, mut xp: Limbs, mut n: i32, vl: Limb) -> Limb { 84 | debug_assert!(n > 0); 85 | debug_assert!(same_or_separate(wp, n, xp, n)); 86 | 87 | let mut cl = Limb(0); 88 | loop { 89 | let xl = *xp; 90 | let (hpl, lpl) = xl.mul_hilo(vl); 91 | let (lpl, carry) = lpl.add_overflow(cl); 92 | cl = hpl + carry; 93 | 94 | let (lpl, carry) = (*wp).add_overflow(lpl); 95 | cl = cl + carry; 96 | 97 | *wp = lpl; 98 | 99 | n -= 1; 100 | if n == 0 { break; } 101 | 102 | wp = wp.offset(1); 103 | xp = xp.offset(1); 104 | } 105 | 106 | return cl; 107 | } 108 | 109 | /** 110 | * Multiplies the `n` least-signficiant digits of `xp` by `vl` and adds them to the `n` 111 | * least-significant digits of `wp`. Returns the highest limb of the result. 112 | */ 113 | #[cfg(not(asm))] 114 | #[inline] 115 | pub unsafe fn addmul_1(wp: LimbsMut, xp: Limbs, n: i32, vl: Limb) -> Limb { 116 | addmul_1_generic(wp, xp, n, vl) 117 | } 118 | 119 | /** 120 | * Multiplies the `n` least-signficiant digits of `xp` by `vl` and adds them to the `n` 121 | * least-significant digits of `wp`. Returns the highest limb of the result. 122 | */ 123 | #[cfg(asm)] 124 | #[inline] 125 | pub unsafe fn addmul_1(mut wp: LimbsMut, xp: Limbs, n: i32, vl: Limb) -> Limb { 126 | extern "C" { 127 | fn ramp_addmul_1(wp: *mut Limb, xp: *const Limb, n: i32, vl: Limb) -> Limb; 128 | } 129 | 130 | ramp_addmul_1(&mut *wp, &*xp, n, vl) 131 | } 132 | 133 | #[allow(dead_code)] 134 | unsafe fn submul_1_generic(mut wp: LimbsMut, mut xp: Limbs, mut n: i32, vl: Limb) -> Limb { 135 | debug_assert!(n > 0); 136 | debug_assert!(same_or_separate(wp, n, xp, n)); 137 | 138 | let mut cl = Limb(0); 139 | loop { 140 | let xl = *xp; 141 | let (hpl, lpl) = xl.mul_hilo(vl); 142 | let (lpl, carry) = lpl.add_overflow(cl); 143 | cl = hpl + carry; 144 | 145 | let (lpl, carry) = (*wp).sub_overflow(lpl); 146 | cl = cl + carry; 147 | 148 | *wp = lpl; 149 | 150 | n -= 1; 151 | if n == 0 { break; } 152 | 153 | wp = wp.offset(1); 154 | xp = xp.offset(1); 155 | } 156 | 157 | return cl; 158 | } 159 | 160 | /** 161 | * Multiplies the `n` least-signficiant digits of `xp` by `vl` and subtracts them from the `n` 162 | * least-significant digits of `wp`. Returns the highest limb of the result, adjust for borrow. 163 | */ 164 | #[cfg(not(asm))] 165 | #[inline] 166 | pub unsafe fn submul_1(wp: LimbsMut, xp: Limbs, n: i32, vl: Limb) -> Limb { 167 | submul_1_generic(wp, xp, n, vl) 168 | } 169 | 170 | /** 171 | * Multiplies the `n` least-signficiant digits of `xp` by `vl` and subtracts them from the `n` 172 | * least-significant digits of `wp`. Returns the highest limb of the result, adjust for borrow. 173 | */ 174 | #[cfg(asm)] 175 | #[inline] 176 | pub unsafe fn submul_1(mut wp: LimbsMut, xp: Limbs, n: i32, vl: Limb) -> Limb { 177 | extern "C" { 178 | fn ramp_submul_1(wp: *mut Limb, xp: *const Limb, n: i32, vl: Limb) -> Limb; 179 | } 180 | 181 | ramp_submul_1(&mut *wp, &*xp, n, vl) 182 | } 183 | 184 | /** 185 | * Multiplies `{xp, xs}` by `{yp, ys}`, storing the result to `{wp, xs + ys}`. 186 | * 187 | * `{wp, xs + ys}` must be disjoint from both inputs. 188 | */ 189 | pub unsafe fn mul(wp: LimbsMut, xp: Limbs, xs: i32, yp: Limbs, ys: i32) { 190 | debug_assert!(xs >= ys); 191 | debug_assert!(ys > 0); 192 | debug_assert!(!overlap(wp, xs + ys, xp, xs)); 193 | debug_assert!(!overlap(wp, xs + ys, yp, ys)); 194 | 195 | // TODO: Pick between algorithms based on input sizes 196 | if ys <= TOOM22_THRESHOLD { 197 | mul_basecase(wp, xp, xs, yp, ys); 198 | } else { 199 | let mut tmp = mem::TmpAllocator::new(); 200 | let scratch = tmp.allocate((xs * 2) as usize); 201 | 202 | // Can't use xs >= (ys * 2) because if xs is odd, some other invariants 203 | // in toom22 don't hold 204 | if (xs * 2) >= (ys * 3) { 205 | mul_unbalanced(wp, xp, xs, yp, ys, scratch); 206 | } else { 207 | mul_toom22(wp, xp, xs, yp, ys, scratch); 208 | } 209 | } 210 | } 211 | 212 | unsafe fn mul_basecase(mut wp: LimbsMut, xp: Limbs, xs: i32, mut yp: Limbs, mut ys: i32) { 213 | 214 | *wp.offset(xs as isize) = ll::mul_1(wp, xp, xs, *yp); 215 | wp = wp.offset(1); 216 | yp = yp.offset(1); 217 | ys -= 1; 218 | 219 | while ys > 0 { 220 | *wp.offset(xs as isize) = ll::addmul_1(wp, xp, xs, *yp); 221 | 222 | wp = wp.offset(1); 223 | yp = yp.offset(1); 224 | ys -= 1; 225 | } 226 | } 227 | 228 | // Helper fn 229 | #[inline(always)] 230 | unsafe fn mul_rec(wp: LimbsMut, 231 | xp: Limbs, xs: i32, 232 | yp: Limbs, ys: i32, 233 | scratch: LimbsMut) { 234 | if ys < TOOM22_THRESHOLD { 235 | mul_basecase(wp, xp, xs, yp, ys); 236 | } else if (xs * 2) >= (ys*3) { 237 | mul_unbalanced(wp, xp, xs, yp, ys, scratch); 238 | } else { 239 | mul_toom22(wp, xp, xs, yp, ys, scratch); 240 | } 241 | } 242 | 243 | unsafe fn mul_toom22(wp: LimbsMut, 244 | xp: Limbs, xs: i32, 245 | yp: Limbs, ys: i32, 246 | scratch: LimbsMut) { 247 | // Split x into x1, x0 where x = x1*(B^n) + x0 248 | // Split y into y1, y0 where y = y1*(B^n) + y0 249 | // 250 | // Which means the following holds: 251 | // 252 | // x*y = (B^2n + B^n)*z2 - (B^n)*z1 + (B^n + 1)*z0 253 | // = (B^2n)*z2 + (B^n)*(z2 + z0 - z1) + z0 254 | // 255 | // Where: 256 | // z0 = x0*y0 257 | // z1 = (x1-x0)*(y1-y0) 258 | // z2 = x1*y1 259 | // 260 | // z1 is split further into: 261 | // 262 | // zx1 = x1-x0 263 | // zy1 = y1-y0 264 | // 265 | // So z1 = zx1*zy1 266 | 267 | debug_assert!(xs >= ys && xs < ys*2, 268 | "assertion failed: `xs >= ys && xs < ys*2` xs: {}, ys: {}", xs, ys); 269 | 270 | let xh = xs >> 1; // Number of high limbs in x 271 | let nl = xs - xh; // Number of low limbs 272 | let yh = ys - nl; // Number of high limbs in y 273 | 274 | debug_assert!(0 < xh && xh <= nl); 275 | debug_assert!(0 < yh && yh <= xh, 276 | "assertion failed: 0 < yh && yh <= xh, xs: {}, ys: {}, xh: {}, yh: {}", 277 | xs, ys, xh, yh); 278 | 279 | let x0 = xp; // nl limbs 280 | let y0 = yp; // nl limbs 281 | 282 | let x1 = xp.offset(nl as isize); // xh limbs 283 | let y1 = yp.offset(nl as isize); // yh limbs 284 | 285 | let zx1 = wp; // nl limbs 286 | let zy1 = wp.offset(nl as isize); // nl limbs 287 | let mut z1_neg = false; // Keep track of whether the real z1 is negative 288 | 289 | // Calculate zx1 290 | if nl == xh { 291 | if ll::cmp(x0, x1, nl) == Ordering::Less { 292 | ll::sub_n(zx1, x1, x0, nl); 293 | z1_neg = true; 294 | } else { 295 | ll::sub_n(zx1, x0, x1, nl); 296 | } 297 | } else { // nl > xh 298 | if ll::is_zero(x0.offset(xh as isize), nl-xh) && ll::cmp(x0, x1, xh) == Ordering::Less { 299 | ll::sub_n(zx1, x1, x0, xh); 300 | ll::zero(zx1.offset(xh as isize), nl-xh); // Zero the extra limbs 301 | z1_neg = true; 302 | } else { 303 | ll::sub(zx1, x0, nl, x1, xh); 304 | } 305 | } 306 | 307 | // Calculate zy1 308 | if nl == yh { 309 | if ll::cmp(y0, y1, nl) == Ordering::Less { 310 | ll::sub_n(zy1, y1, y0, nl); 311 | z1_neg = !z1_neg; 312 | } else { 313 | ll::sub_n(zy1, y0, y1, nl); 314 | } 315 | } else { // nl > yh 316 | if ll::is_zero(y0.offset(yh as isize), nl-yh) && ll::cmp(y0, y1, yh) == Ordering::Less { 317 | ll::sub_n(zy1, y1, y0, yh); 318 | ll::zero(zy1.offset(yh as isize), nl-yh); // Zero the extra limbs 319 | z1_neg = !z1_neg; 320 | } else { 321 | ll::sub(zy1, y0, nl, y1, yh); 322 | } 323 | } 324 | 325 | let z0 = wp; 326 | let z1 = scratch; 327 | let z2 = wp.offset((nl * 2) as isize); 328 | let scratch_out = scratch.offset((nl * 2) as isize); 329 | 330 | // Calculate z1 - 2*nl limbs 331 | mul_rec(z1, zx1.as_const(), nl, zy1.as_const(), nl, scratch_out); 332 | 333 | // Calculate z0 - 2*nl limbs 334 | mul_rec(z0, x0, nl, y0, nl, scratch_out); 335 | 336 | // Calculate z2 - xh+yh limbs 337 | mul_rec(z2, x1, xh, y1, yh, scratch_out); 338 | 339 | // Now {wp, 2*nl} = z0 and {wp + 2*nl, xh+yh} = z2 340 | 341 | // {wp + nl, 2*nl} += z0 + z2 - z1 342 | // += {wp, 2*nl} 343 | // + {wp + 2*nl, xh+yh} 344 | // - z1 345 | // 346 | // So with {wp, xs+ys}: 347 | // 348 | // 0 nl 2*nl xs+ys 349 | // +--------+--------+--------+---+ 350 | // | z0 | z2 | 351 | // +--------+--------+--------+---+ 352 | // + | z0 | 353 | // +--------+---+----+ 354 | // + | z2 | 355 | // +------------+ 356 | // 357 | // {wp + nl, nl} = HIGH(z0) + LOW(z0) + LOW(z2) 358 | // {wp + 2*nl, nl} = HIGH(z0) + HIGH(z2) + LOW(z2) + carry 359 | 360 | // LOW(z2) = HIGH(z0) + LOW(z2) 361 | let cy = ll::add_n(wp.offset((2*nl) as isize), 362 | z2.as_const(), z0.offset(nl as isize).as_const(), 363 | nl); 364 | 365 | // LOW(z0) + LOW(z2) 366 | let cy2 = cy + ll::add_n(wp.offset(nl as isize), 367 | z0.as_const(), z2.as_const(), 368 | nl); 369 | 370 | // LOW(z2) + HIGH(z2) 371 | let mut cy = cy + ll::add(wp.offset((2*nl) as isize), 372 | z2.as_const(), nl, 373 | z2.offset(nl as isize).as_const(), yh+xh-nl); 374 | 375 | // Add or subtract `z1` depending on the sign of the real result 376 | // (we calculate such that it's always positive, easier this way) 377 | if z1_neg { 378 | cy = cy + ll::add_n(wp.offset(nl as isize), 379 | wp.offset(nl as isize).as_const(), z1.as_const(), 380 | 2*nl); 381 | } else { 382 | cy = cy - ll::sub_n(wp.offset(nl as isize), 383 | wp.offset(nl as isize).as_const(), z1.as_const(), 384 | 2*nl); 385 | } 386 | 387 | // Apply the carries, has to be done last. 388 | ll::incr(wp.offset((nl * 2) as isize), cy2); 389 | ll::incr(wp.offset((nl * 3) as isize), cy); 390 | } 391 | 392 | /** 393 | * Handles multiplication when xs is much bigger than ys. 394 | * 395 | * Works basically the same way `mul_1` does, except with `ys` limbs 396 | * instead of a single limb. 397 | */ 398 | unsafe fn mul_unbalanced(mut wp: LimbsMut, 399 | mut xp: Limbs, mut xs: i32, 400 | yp: Limbs, ys: i32, 401 | scratch: LimbsMut) { 402 | debug_assert!(xs > ys); 403 | 404 | mul_toom22(wp, xp, ys, yp, ys, scratch); 405 | 406 | xs -= ys; 407 | xp = xp.offset(ys as isize); 408 | wp = wp.offset(ys as isize); 409 | 410 | // Temporary storage for the output of the multiplication 411 | // in the loop, the loop only needs ys*2 limbs, but the last 412 | // multiplication needs slightly more than that, but no more 413 | // than ys*3 414 | let mut tmp = mem::TmpAllocator::new(); 415 | let w_tmp = tmp.allocate((ys * 3) as usize); 416 | 417 | while xs >= (ys * 2) { 418 | mul_toom22(w_tmp, xp, ys, yp, ys, scratch); 419 | xs -= ys; 420 | xp = xp.offset(ys as isize); 421 | let cy = ll::add_n(wp, wp.as_const(), w_tmp.as_const(), ys); 422 | ll::copy_incr(w_tmp.offset(ys as isize).as_const(), 423 | wp.offset(ys as isize), 424 | ys); 425 | ll::incr(wp.offset(ys as isize), cy); 426 | 427 | wp = wp.offset(ys as isize); 428 | } 429 | 430 | if xs >= ys { 431 | mul_rec(w_tmp, xp, xs, yp, ys, scratch); 432 | } else { 433 | mul_rec(w_tmp, yp, ys, xp, xs, scratch); 434 | } 435 | 436 | let cy = ll::add_n(wp, wp.as_const(), w_tmp.as_const(), ys); 437 | ll::copy_incr(w_tmp.offset(ys as isize).as_const(), 438 | wp.offset(ys as isize), 439 | xs); 440 | ll::incr(wp.offset(ys as isize), cy); 441 | } 442 | 443 | /** 444 | * Squares the number in `{xp, xs}` storing the result in `{wp, xs*2}`. 445 | * This is slightly more efficient than regular multiplication with both 446 | * inputs the same. 447 | * 448 | * `{wp, xs*2}` must not overlap with `{xp, xs}` 449 | */ 450 | pub unsafe fn sqr(wp: LimbsMut, xp: Limbs, xs: i32) { 451 | debug_assert!(xs > 0); 452 | debug_assert!(!overlap(wp, 2*xs, xp, xs)); 453 | 454 | if xs <= TOOM22_THRESHOLD { 455 | mul_basecase(wp, xp, xs, xp, xs); 456 | } else { 457 | let mut tmp = mem::TmpAllocator::new(); 458 | let scratch = tmp.allocate((xs * 2) as usize); 459 | 460 | sqr_toom2(wp, xp, xs, scratch); 461 | } 462 | } 463 | 464 | #[inline(always)] 465 | unsafe fn sqr_rec(wp: LimbsMut, xp: Limbs, xs: i32, scratch: LimbsMut) { 466 | if xs < TOOM22_THRESHOLD { 467 | mul_basecase(wp, xp, xs, xp, xs); 468 | } else { 469 | sqr_toom2(wp, xp, xs, scratch); 470 | } 471 | } 472 | 473 | unsafe fn sqr_toom2(wp: LimbsMut, xp: Limbs, xs: i32, scratch: LimbsMut) { 474 | // This is very similar to regular mul_toom22, however it is slightly more efficient 475 | // as it can take advantage of the coefficents being the same. 476 | // 477 | // Splitting x into x1, x0 to get x = x1*(B^n) + x0 means we get 478 | // 479 | // x*x = (B^2n)*z2 + 2*(B^n)*z1 + z0 480 | // 481 | // Where: 482 | // z0 = x0*x0 483 | // z1 = x0*x1 484 | // z2 = x1*x1 485 | 486 | let xh = xs >> 1; 487 | let xl = xs - xh; 488 | 489 | let x0 = xp; 490 | let x1 = xp.offset(xl as isize); 491 | 492 | let z0 = wp; 493 | let z1 = scratch; 494 | let z2 = wp.offset((xl * 2) as isize); 495 | let scratch_out = scratch.offset((xl * 2) as isize); 496 | 497 | // Calculate z1 498 | mul_rec(z1, x0, xl, x1, xh, scratch_out); 499 | // Calculate z0 500 | sqr_rec(z0, x0, xl, scratch_out); 501 | // Calculate z2 502 | sqr_rec(z2, x1, xh, scratch_out); 503 | 504 | // Calculate 2*z1 505 | let mut cy = ll::add_n(z1, z1.as_const(), z1.as_const(), xs); 506 | 507 | // wp now contains the result of (B^2n)*z2 + z0 508 | 509 | cy = cy + ll::add_n(wp.offset(xl as isize), wp.offset(xl as isize).as_const(), z1.as_const(), xs); 510 | 511 | ll::incr(wp.offset((xl + xs) as isize), cy); 512 | } 513 | -------------------------------------------------------------------------------- /src/ll/pow.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use ll; 16 | use ll::limb::Limb; 17 | use mem; 18 | 19 | use ll::limb_ptr::{Limbs, LimbsMut}; 20 | 21 | /** 22 | * Takes `{ap, an}` to the power of `exp` and stores the result to `wp`. `wp` is 23 | * assumed to have enough space to store the result (which can be calculated using 24 | * `num_pow_limbs` 25 | * 26 | * `{wp, an*exp}` must be disjoint from `{ap, an}`. 27 | * `{ap, an}` must not be zero. 28 | * `exp` must be greater than 2 29 | */ 30 | pub unsafe fn pow(mut wp: LimbsMut, mut ap: Limbs, mut an: i32, mut exp: u32) { 31 | debug_assert!(exp > 2); 32 | debug_assert!(!ll::is_zero(ap, an)); 33 | 34 | let mut wn = num_pow_limbs(ap, an, exp); 35 | debug_assert!(!ll::overlap(wp, wn, ap, an)); 36 | 37 | let mut tmp = mem::TmpAllocator::new(); 38 | 39 | ll::zero(wp, wn); 40 | 41 | // (m * 2**K)**exp == m**exp * 2**(K*exp) 42 | while *ap == 0 { 43 | ap = ap.offset(1); 44 | an -= 1; 45 | wp = wp.offset(exp as isize); 46 | wn -= exp as i32; 47 | } 48 | let trailing = (*ap).trailing_zeros() as u32; 49 | 50 | let sz = wn as usize; 51 | 52 | // An extra limb of scratch space is needed because the length 53 | // estimation is precise: if you're doing something like x**7, the 54 | // final multiplication is ``x**3 * x**4`. These could have 55 | // lengths, like, say, 30 and 40 limbs, so the multiplication can 56 | // take at most 30 + 40 + 1 limbs, and the multiplication 57 | // algorithm will write to all of them, possibly putting a zero in 58 | // the very highest limb... however, the x**7 length estimator may 59 | // work out that the final result actually fits into only 70 60 | // limbs, so if we don't account for this mismatch we risk memory 61 | // corruption. 62 | // 63 | // (Examples of such x are 2**(k L), where k > 0 is an integer and 64 | // L is the number of bits in a limb.) 65 | let (bp, scratch) = tmp.allocate_2(sz, sz + 1); 66 | let mut bn = an; 67 | 68 | if trailing > 0 { 69 | ll::shr(bp, ap, an, trailing); 70 | } else { 71 | ll::copy_incr(ap, bp, an); 72 | } 73 | 74 | // Calculate the amount we'll need to shift by at the end, 75 | // we need to adjust wp here because the shift functions only 76 | // work with shifts of < Limb::BITS 77 | let mut shift = trailing * exp; 78 | while shift >= Limb::BITS as u32 { 79 | shift -= Limb::BITS as u32; 80 | wp = wp.offset(1); 81 | } 82 | 83 | *wp = Limb(1); 84 | let mut wn = 1; 85 | 86 | loop { 87 | if (exp & 1) == 1 { 88 | if wn > bn { 89 | ll::mul(scratch, wp.as_const(), wn, bp.as_const(), bn); 90 | } else { 91 | ll::mul(scratch, bp.as_const(), bn, wp.as_const(), wn); 92 | } 93 | wn = ll::normalize(scratch.as_const(), wn + bn); 94 | ll::copy_incr(scratch.as_const(), wp, wn); 95 | } 96 | 97 | exp >>= 1; 98 | 99 | // Do this check before the base multiplication so we don't 100 | // end up needing more space than necessary 101 | if exp == 0 { 102 | break; 103 | } 104 | 105 | ll::sqr(scratch, bp.as_const(), bn); 106 | bn = ll::normalize(scratch.as_const(), bn + bn); 107 | 108 | ll::copy_incr(scratch.as_const(), bp, bn); 109 | 110 | } 111 | 112 | if shift > 0 { 113 | let v = ll::shl(wp, wp.as_const(), wn, shift); 114 | if v > 0 { 115 | *wp.offset(wn as isize) = v; 116 | } 117 | } 118 | } 119 | 120 | /// Calculates the number of limbs required to store the result of taking 121 | /// `{xp, xn}` to the power of `exp` 122 | pub unsafe fn num_pow_limbs(xp: Limbs, xn: i32, exp: u32) -> i32 { 123 | // This is a better approximation of log_b(x^e) than simply using the 124 | // the number of digits, n. 125 | // Instead it uses the most significant digit, a, to calculate 126 | // e*log_b(a*b^(n-1)), which is e*(log_b(a) + n - 1) 127 | let n = xn - 1; 128 | let high_limb = *xp.offset(n as isize); 129 | 130 | // Calculate log_2(a), this is because floor(log_b(a)) will always be 131 | // 0 132 | let lg2 = Limb::BITS as u32 - high_limb.leading_zeros() as u32; 133 | 134 | // Get e*log_2(a) 135 | let lg2e = exp as i32 * lg2 as i32; 136 | 137 | // Now convert it to log_b using the formula 138 | // log_a(x) = log_b(x) / log_b(a) 139 | let elog_b = lg2e / Limb::BITS as i32; 140 | 141 | // Add a final 1 to account for the error in the estimate 142 | elog_b + (exp as i32 * n) + 1 143 | } 144 | -------------------------------------------------------------------------------- /src/mem.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Memory management functions. The base functions align to a pointer-width, so they shouldn't 16 | //! be used for anything that requires an alignment greater than that. 17 | 18 | use std::alloc; 19 | use std::intrinsics::abort; 20 | use std::io::{self, Write}; 21 | use std::mem; 22 | use std::ptr; 23 | 24 | use ll::limb::Limb; 25 | use ll::limb_ptr::LimbsMut; 26 | 27 | /// Returns a Layout with the given size and pointer-width (i.e., usize) alignment. Panics if 28 | /// unable to create the Layout. 29 | unsafe fn get_usize_align_layout(size: usize) -> alloc::Layout { 30 | let alignment = mem::align_of::(); 31 | 32 | match alloc::Layout::from_size_align(size, alignment) { 33 | Ok(l) => l, 34 | Err(layout_err) => { 35 | let _ = writeln!( 36 | io::stderr(), 37 | "Failed to construct mem layout (size={}, alignment={}): {}", 38 | size, 39 | alignment, 40 | layout_err 41 | ); 42 | abort(); 43 | } 44 | } 45 | } 46 | 47 | pub unsafe fn allocate_bytes(size: usize) -> *mut u8 { 48 | let layout = get_usize_align_layout(size); 49 | let ret = alloc::alloc_zeroed(layout.clone()); 50 | if ret.is_null() { 51 | writeln!( 52 | io::stderr(), 53 | "Failed to allocate memory (layout={:?})", 54 | layout, 55 | ) 56 | .unwrap(); 57 | abort(); 58 | }; 59 | 60 | ptr::write_bytes(ret, 0, size); 61 | ret 62 | } 63 | 64 | pub unsafe fn deallocate_bytes(ptr: ptr::NonNull, size: usize) { 65 | let layout = get_usize_align_layout(size); 66 | alloc::dealloc(ptr.as_ptr(), layout); 67 | } 68 | 69 | /// Allocate for temporary storage. Ensures that the allocations are 70 | /// freed when the structure drops 71 | pub struct TmpAllocator { 72 | mark: *mut Marker, 73 | } 74 | 75 | struct Marker { 76 | next: *mut Marker, 77 | size: usize, 78 | } 79 | 80 | impl TmpAllocator { 81 | pub fn new() -> TmpAllocator { 82 | TmpAllocator { 83 | mark: ptr::null_mut(), 84 | } 85 | } 86 | 87 | pub unsafe fn allocate_bytes(&mut self, size: usize) -> *mut u8 { 88 | let size = size + mem::size_of::(); 89 | let ptr = allocate_bytes(size); 90 | 91 | let mark = ptr as *mut Marker; 92 | (*mark).size = size; 93 | (*mark).next = self.mark; 94 | 95 | self.mark = mark; 96 | 97 | ptr.offset(mem::size_of::() as isize) 98 | } 99 | 100 | /// Allocate space for n limbs 101 | pub unsafe fn allocate(&mut self, n: usize) -> LimbsMut { 102 | let ptr = self.allocate_bytes(n * mem::size_of::()) as *mut Limb; 103 | LimbsMut::new(ptr, 0, n as i32) 104 | } 105 | 106 | /// Allocates space for n1+n2 limbs and returns a pair of pointers. 107 | pub unsafe fn allocate_2(&mut self, n1: usize, n2: usize) -> (LimbsMut, LimbsMut) { 108 | let mut x = self.allocate(n1 + n2); 109 | let mut y = x.offset(n1 as isize); 110 | ( 111 | LimbsMut::new(&mut *x, 0, n1 as i32), 112 | LimbsMut::new(&mut *y, 0, n2 as i32), 113 | ) 114 | } 115 | } 116 | 117 | impl Drop for TmpAllocator { 118 | fn drop(&mut self) { 119 | unsafe { 120 | let mut next; 121 | let mut mark = self.mark; 122 | // Iterate the list until we hit a null ptr 123 | while let Some(checked_mark) = ptr::NonNull::new(mark) { 124 | next = checked_mark.as_ref().next; 125 | let size = checked_mark.as_ref().size; 126 | deallocate_bytes(checked_mark.cast(), size); 127 | mark = next; 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/raw_vec.rs: -------------------------------------------------------------------------------- 1 | // This file is modified from 2 | // https://raw.githubusercontent.com/rust-lang/rust/c212fc4aa7719613e5254e9051ea03a93558fef4/library/alloc/src/raw_vec.rs 3 | 4 | use core::alloc::LayoutError; 5 | use core::intrinsics; 6 | use core::mem; 7 | use core::ops::Drop; 8 | use core::ptr::{NonNull, Unique}; 9 | 10 | use alloc::alloc::handle_alloc_error; 11 | use alloc::alloc::{Allocator, Global, Layout}; 12 | use alloc::collections::TryReserveError; 13 | use alloc::collections::TryReserveErrorKind::*; 14 | 15 | /// A low-level utility for more ergonomically allocating, reallocating, and deallocating 16 | /// a buffer of memory on the heap without having to worry about all the corner cases 17 | /// involved. This type is excellent for building your own data structures like Vec and VecDeque. 18 | /// In particular: 19 | /// 20 | /// * Produces `Unique::dangling()` on zero-sized types. 21 | /// * Produces `Unique::dangling()` on zero-length allocations. 22 | /// * Avoids freeing `Unique::dangling()`. 23 | /// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). 24 | /// * Guards against 32-bit systems allocating more than isize::MAX bytes. 25 | /// * Guards against overflowing your length. 26 | /// * Calls `handle_alloc_error` for fallible allocations. 27 | /// * Contains a `ptr::Unique` and thus endows the user with all related benefits. 28 | /// * Uses the excess returned from the allocator to use the largest available capacity. 29 | /// 30 | /// This type does not in anyway inspect the memory that it manages. When dropped it *will* 31 | /// free its memory, but it *won't* try to drop its contents. It is up to the user of `RawVec` 32 | /// to handle the actual things *stored* inside of a `RawVec`. 33 | /// 34 | /// Note that the excess of a zero-sized types is always infinite, so `capacity()` always returns 35 | /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a 36 | /// `Box<[T]>`, since `capacity()` won't yield the length. 37 | #[allow(missing_debug_implementations)] 38 | pub(crate) struct RawVec { 39 | ptr: Unique, 40 | cap: usize, 41 | alloc: A, 42 | } 43 | 44 | impl RawVec { 45 | /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. 46 | /// 47 | /// # Safety 48 | /// 49 | /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given 50 | /// `capacity`. 51 | /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit 52 | /// systems). ZST vectors may have a capacity up to `usize::MAX`. 53 | /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is 54 | /// guaranteed. 55 | #[inline] 56 | pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self { 57 | Self { 58 | ptr: Unique::new_unchecked(ptr), 59 | cap: capacity, 60 | alloc, 61 | } 62 | } 63 | 64 | /// Gets a raw pointer to the start of the allocation. Note that this is 65 | /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must 66 | /// be careful. 67 | #[inline] 68 | pub fn ptr(&self) -> *mut T { 69 | self.ptr.as_ptr() 70 | } 71 | 72 | /// Gets the capacity of the allocation. 73 | /// 74 | /// This will always be `usize::MAX` if `T` is zero-sized. 75 | #[inline(always)] 76 | pub fn capacity(&self) -> usize { 77 | if mem::size_of::() == 0 { 78 | usize::MAX 79 | } else { 80 | self.cap 81 | } 82 | } 83 | 84 | fn current_memory(&self) -> Option<(NonNull, Layout)> { 85 | if mem::size_of::() == 0 || self.cap == 0 { 86 | None 87 | } else { 88 | // We have an allocated chunk of memory, so we can bypass runtime 89 | // checks to get our current layout. 90 | unsafe { 91 | let layout = Layout::array::(self.cap).unwrap_unchecked(); 92 | Some((self.ptr.cast().into(), layout)) 93 | } 94 | } 95 | } 96 | 97 | /// Ensures that the buffer contains at least enough space to hold `len + 98 | /// additional` elements. If it doesn't already, will reallocate the 99 | /// minimum possible amount of memory necessary. Generally this will be 100 | /// exactly the amount of memory necessary, but in principle the allocator 101 | /// is free to give back more than we asked for. 102 | /// 103 | /// If `len` exceeds `self.capacity()`, this may fail to actually allocate 104 | /// the requested space. This is not really unsafe, but the unsafe code 105 | /// *you* write that relies on the behavior of this function may break. 106 | /// 107 | /// # Panics 108 | /// 109 | /// Panics if the new capacity exceeds `isize::MAX` bytes. 110 | /// 111 | /// # Aborts 112 | /// 113 | /// Aborts on OOM. 114 | pub fn reserve_exact(&mut self, len: usize, additional: usize) { 115 | handle_reserve(self.try_reserve_exact(len, additional)); 116 | } 117 | 118 | /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. 119 | pub fn try_reserve_exact( 120 | &mut self, 121 | len: usize, 122 | additional: usize, 123 | ) -> Result<(), TryReserveError> { 124 | if self.needs_to_grow(len, additional) { 125 | self.grow_exact(len, additional) 126 | } else { 127 | Ok(()) 128 | } 129 | } 130 | 131 | /// Shrinks the buffer down to the specified capacity. If the given amount 132 | /// is 0, actually completely deallocates. 133 | /// 134 | /// # Panics 135 | /// 136 | /// Panics if the given amount is *larger* than the current capacity. 137 | /// 138 | /// # Aborts 139 | /// 140 | /// Aborts on OOM. 141 | pub fn shrink_to_fit(&mut self, cap: usize) { 142 | handle_reserve(self.shrink(cap)); 143 | } 144 | } 145 | 146 | impl RawVec { 147 | /// Returns if the buffer needs to grow to fulfill the needed extra capacity. 148 | /// Mainly used to make inlining reserve-calls possible without inlining `grow`. 149 | fn needs_to_grow(&self, len: usize, additional: usize) -> bool { 150 | additional > self.capacity().wrapping_sub(len) 151 | } 152 | 153 | fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { 154 | // Allocators currently return a `NonNull<[u8]>` whose length matches 155 | // the size requested. If that ever changes, the capacity here should 156 | // change to `ptr.len() / mem::size_of::()`. 157 | self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }; 158 | self.cap = cap; 159 | } 160 | 161 | // The constraints on this method are much the same as those on 162 | // `grow_amortized`, but this method is usually instantiated less often so 163 | // it's less critical. 164 | fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { 165 | if mem::size_of::() == 0 { 166 | // Since we return a capacity of `usize::MAX` when the type size is 167 | // 0, getting to here necessarily means the `RawVec` is overfull. 168 | return Err(CapacityOverflow.into()); 169 | } 170 | 171 | let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; 172 | let new_layout = Layout::array::(cap); 173 | 174 | // `finish_grow` is non-generic over `T`. 175 | let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; 176 | self.set_ptr_and_cap(ptr, cap); 177 | Ok(()) 178 | } 179 | 180 | fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { 181 | assert!( 182 | cap <= self.capacity(), 183 | "Tried to shrink to a larger capacity" 184 | ); 185 | 186 | let (ptr, layout) = if let Some(mem) = self.current_memory() { 187 | mem 188 | } else { 189 | return Ok(()); 190 | }; 191 | 192 | let ptr = unsafe { 193 | // `Layout::array` cannot overflow here because it would have 194 | // overflowed earlier when capacity was larger. 195 | let new_layout = Layout::array::(cap).unwrap_unchecked(); 196 | self.alloc 197 | .shrink(ptr, layout, new_layout) 198 | .map_err(|_| AllocError { 199 | layout: new_layout, 200 | non_exhaustive: (), 201 | })? 202 | }; 203 | self.set_ptr_and_cap(ptr, cap); 204 | Ok(()) 205 | } 206 | } 207 | 208 | // This function is outside `RawVec` to minimize compile times. See the comment 209 | // above `RawVec::grow_amortized` for details. (The `A` parameter isn't 210 | // significant, because the number of different `A` types seen in practice is 211 | // much smaller than the number of `T` types.) 212 | #[inline(never)] 213 | fn finish_grow( 214 | new_layout: Result, 215 | current_memory: Option<(NonNull, Layout)>, 216 | alloc: &mut A, 217 | ) -> Result, TryReserveError> 218 | where 219 | A: Allocator, 220 | { 221 | // Check for the error here to minimize the size of `RawVec::grow_*`. 222 | let new_layout = new_layout.map_err(|_| CapacityOverflow)?; 223 | 224 | alloc_guard(new_layout.size())?; 225 | 226 | let memory = if let Some((ptr, old_layout)) = current_memory { 227 | debug_assert_eq!(old_layout.align(), new_layout.align()); 228 | unsafe { 229 | // The allocator checks for alignment equality 230 | intrinsics::assume(old_layout.align() == new_layout.align()); 231 | alloc.grow(ptr, old_layout, new_layout) 232 | } 233 | } else { 234 | alloc.allocate(new_layout) 235 | }; 236 | 237 | memory.map_err(|_| { 238 | AllocError { 239 | layout: new_layout, 240 | non_exhaustive: (), 241 | } 242 | .into() 243 | }) 244 | } 245 | 246 | impl Drop for RawVec { 247 | /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. 248 | fn drop(&mut self) { 249 | if let Some((ptr, layout)) = self.current_memory() { 250 | unsafe { self.alloc.deallocate(ptr, layout) } 251 | } 252 | } 253 | } 254 | 255 | // Central function for reserve error handling. 256 | #[inline] 257 | fn handle_reserve(result: Result<(), TryReserveError>) { 258 | match result.map_err(|e| e.kind()) { 259 | Err(CapacityOverflow) => capacity_overflow(), 260 | Err(AllocError { layout, .. }) => handle_alloc_error(layout), 261 | Ok(()) => { /* yay */ } 262 | } 263 | } 264 | 265 | // We need to guarantee the following: 266 | // * We don't ever allocate `> isize::MAX` byte-size objects. 267 | // * We don't overflow `usize::MAX` and actually allocate too little. 268 | // 269 | // On 64-bit we just need to check for overflow since trying to allocate 270 | // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add 271 | // an extra guard for this in case we're running on a platform which can use 272 | // all 4GB in user-space, e.g., PAE or x32. 273 | 274 | #[inline] 275 | fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { 276 | if usize::BITS < 64 && alloc_size > isize::MAX as usize { 277 | Err(CapacityOverflow.into()) 278 | } else { 279 | Ok(()) 280 | } 281 | } 282 | 283 | // One central function responsible for reporting capacity overflows. This'll 284 | // ensure that the code generation related to these panics is minimal as there's 285 | // only one location which panics rather than a bunch throughout the module. 286 | fn capacity_overflow() -> ! { 287 | panic!("capacity overflow"); 288 | } 289 | -------------------------------------------------------------------------------- /src/traits.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ramp Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! This module holds various traits. 16 | 17 | /// A trait for types which can compute division and remainder in one step. 18 | pub trait DivRem { 19 | // Default to (Self, RHS) when associated type defaults are more stable. 20 | type Output; 21 | 22 | fn divrem(self, rhs: RHS) -> Self::Output; 23 | } 24 | 25 | /// We re-export num_integer::Integer for convenience. 26 | pub use num_integer::Integer; 27 | -------------------------------------------------------------------------------- /tests/quickcheck.rs: -------------------------------------------------------------------------------- 1 | use std::{convert::TryInto, fmt::Write}; 2 | 3 | #[cfg(feature = "rust-gmp")] 4 | extern crate gmp; 5 | #[cfg(not(feature = "rust-gmp"))] 6 | extern crate num_bigint; 7 | #[cfg(not(feature = "rust-gmp"))] 8 | extern crate num_integer; 9 | #[cfg(not(feature = "rust-gmp"))] 10 | extern crate num_traits; 11 | 12 | #[macro_use] 13 | extern crate quickcheck; 14 | 15 | extern crate ramp; 16 | 17 | #[cfg(feature = "rust-gmp")] 18 | pub use gmp::mpz::Mpz as RefImpl; 19 | #[cfg(feature = "rust-gmp")] 20 | pub use gmp::mpz::Mpz as RefImplU; 21 | #[cfg(not(feature = "rust-gmp"))] 22 | pub use num_bigint::BigInt as RefImpl; 23 | #[cfg(not(feature = "rust-gmp"))] 24 | pub use num_bigint::BigUint as RefImplU; 25 | 26 | #[cfg(not(feature = "rust-gmp"))] 27 | use num_traits::sign::Signed; 28 | 29 | use ramp::traits::DivRem; 30 | use ramp::Int; 31 | 32 | use quickcheck::{Arbitrary, Gen, TestResult}; 33 | 34 | #[cfg(feature = "full-quickcheck")] 35 | const RANGE_MULT: usize = 200; 36 | #[cfg(not(feature = "full-quickcheck"))] 37 | const RANGE_MULT: usize = 20; 38 | 39 | #[cfg(feature = "rust-gmp")] 40 | fn ref_from_hex(a: &str) -> RefImpl { 41 | RefImpl::from_str_radix(a, 16).unwrap() 42 | } 43 | #[cfg(not(feature = "rust-gmp"))] 44 | fn ref_from_hex(a: &str) -> RefImpl { 45 | RefImpl::parse_bytes(a.as_bytes(), 16).unwrap() 46 | } 47 | 48 | // a hex string representing some integer, to be randomly generated by 49 | // quickcheck. 50 | #[derive(Debug, Clone, PartialEq, Eq)] 51 | struct BigIntStr(String); 52 | 53 | impl BigIntStr { 54 | // Parse the string into a ramp::Int and a GMP mpz. 55 | fn parse(&self) -> (Int, RefImpl) { 56 | self.into() 57 | } 58 | 59 | fn parse_u(&self) -> (Int, RefImplU) { 60 | self.into() 61 | } 62 | } 63 | 64 | impl<'a> From<&'a BigIntStr> for (Int, RefImpl) { 65 | fn from(s: &'a BigIntStr) -> (Int, RefImpl) { 66 | (Int::from_str_radix(&s.0, 16).unwrap(), ref_from_hex(&s.0)) 67 | } 68 | } 69 | 70 | #[cfg(not(feature = "rust-gmp"))] 71 | impl<'a> From<&'a BigIntStr> for (Int, RefImplU) { 72 | fn from(s: &'a BigIntStr) -> (Int, RefImplU) { 73 | ( 74 | Int::from_str_radix(&s.0, 16).unwrap().abs(), 75 | ref_from_hex(&s.0).abs().to_biguint().unwrap(), 76 | ) 77 | } 78 | } 79 | 80 | impl Arbitrary for BigIntStr { 81 | fn arbitrary(g: &mut G) -> BigIntStr { 82 | if g.gen::() < 0.005 { 83 | // 0.5% chance of generating zero means 63% chance of a 84 | // zero appearing at least once when running a function 85 | // taking two BigIntStrs 100 times, and 39% chance for a 86 | // function taking one. 87 | return BigIntStr("0".to_owned()); 88 | } 89 | 90 | let raw_size = g.size(); 91 | 92 | let size = std::cmp::max(g.gen_range(raw_size / RANGE_MULT, raw_size * RANGE_MULT), 1); 93 | 94 | // negative numbers are rarer 95 | let neg = g.gen::() % 4 == 0; 96 | let mut string = String::with_capacity(neg as usize + size); 97 | 98 | if neg { 99 | string.push_str("-") 100 | } 101 | // shouldn't start with zero 102 | let mut first = 0; 103 | while first == 0 { 104 | first = g.gen::() % 16; 105 | } 106 | write!(&mut string, "{:x}", first).unwrap(); 107 | 108 | let mut sticky = None; 109 | for _ in 0..(size - 1) { 110 | // Each nibble only has a "small" chance (4/20 == 20%) of 111 | // going into sticky mode, but a much higher chance of 112 | // staying in it ((16*19)/(16*20) == 95%). This means we 113 | // get long sequences of 0x0 or 0xF nibbles but still have 114 | // some evenly distributed ones scattered around. 115 | // 116 | // This is trying to imitate gmp's`mpz_rrandomb`, which, 117 | // apparently, seem to uncover more edge cases than truly 118 | // uniform bits. 119 | let limit = if sticky.is_none() { 16 + 4 } else { 16 * 20 }; 120 | let raw_digit = g.gen_range(0, limit); 121 | 122 | let digit = if raw_digit < 16 { 123 | sticky = None; 124 | raw_digit 125 | } else if let Some(d) = sticky { 126 | d 127 | } else { 128 | let d = if raw_digit % 2 == 0 { 0xF } else { 0x0 }; 129 | sticky = Some(d); 130 | d 131 | }; 132 | 133 | write!(&mut string, "{:x}", digit).unwrap(); 134 | } 135 | BigIntStr(string) 136 | } 137 | 138 | fn shrink(&self) -> Box> { 139 | // shrink the "number" by just truncating the string from the 140 | // end. 141 | let mut string = self.clone(); 142 | let iter = (0..) 143 | .map(move |_| { 144 | // small numbers strink slowly. 145 | let rate = match string.0.len() { 146 | 0 => 0, 147 | 1..=10 => 1, 148 | 11..=100 => 5, 149 | 101..=1000 => 25, 150 | _ => 125, 151 | }; 152 | for _ in 0..rate { 153 | string.0.pop(); 154 | } 155 | string.clone() 156 | }) 157 | .take_while(|s| s.0 != "" && s.0 != "-"); 158 | Box::new(iter) 159 | } 160 | } 161 | 162 | macro_rules! eq { 163 | ($($r: expr, $g: expr);*) => { 164 | ::quickcheck::TestResult::from_bool(eq_bool!($($r, $g);*)) 165 | } 166 | } 167 | 168 | // compare a Ramp int and a GMP int via their string representations. 169 | macro_rules! eq_bool { 170 | ($($r: expr, $g: expr);*) => { 171 | $($r.to_str_radix(16, false) == $g.to_str_radix(16))&&* 172 | } 173 | } 174 | 175 | quickcheck! { 176 | // hex parsing/printing is a fundamental assumption of these tests, so 177 | // let's just double check it works 178 | fn to_str_hex_roundtrip(a: BigIntStr) -> TestResult { 179 | let (ar, _) = a.parse(); 180 | let t = ar.to_str_radix(16, false); 181 | TestResult::from_bool(t == a.0) 182 | } 183 | 184 | // methods 185 | fn abs(a: BigIntStr) -> TestResult { 186 | let (ar, ag) = a.parse(); 187 | eq!(ar.abs(), ag.abs()) 188 | } 189 | 190 | fn abs_cmp(a: BigIntStr, b: BigIntStr) -> TestResult { 191 | let (ar, _) = a.parse(); 192 | let (br, _) = b.parse(); 193 | 194 | let c1 = ar.abs_cmp(&-&ar) == std::cmp::Ordering::Equal; 195 | let c2 = br.abs_cmp(&-&br) == std::cmp::Ordering::Equal; 196 | let c3 = ar.abs_cmp(&br) == ar.abs().cmp(&br.abs()); 197 | 198 | TestResult::from_bool(c1 && c2 && c3) 199 | } 200 | 201 | fn divmod(a: BigIntStr, b: BigIntStr) -> TestResult { 202 | let (ar, ag) = a.parse(); 203 | let (br, bg) = b.parse(); 204 | if br == 0 { return TestResult::discard() } 205 | 206 | let (qr, rr) = ar.divmod(&br); 207 | let qg = &ag / &bg; 208 | let rg = ag % bg; 209 | 210 | eq!(qr, qg; 211 | rr, rg) 212 | } 213 | } 214 | 215 | #[cfg(feature = "rust-gmp")] 216 | quickcheck! { 217 | fn pow(a: BigIntStr, b: u32) -> TestResult { 218 | if b > (RANGE_MULT as u32)/10 { 219 | return TestResult::discard(); 220 | } 221 | let (ar, ag) = a.parse(); 222 | 223 | eq!(ar.pow(b as usize), ag.pow(b)) 224 | } 225 | 226 | fn square(a: BigIntStr) -> TestResult { 227 | let (ar, ag) = a.parse(); 228 | eq!(ar.square(), ag.pow(2)) 229 | } 230 | 231 | fn dsquare(a: BigIntStr) -> TestResult { 232 | let (ar, ag) = a.parse(); 233 | eq!(ar.dsquare(), ag.pow(2)) 234 | } 235 | 236 | fn sqrt_rem(a: BigIntStr) -> TestResult { 237 | let (ar, ag) = a.parse(); 238 | if ar < 0 { 239 | return TestResult::discard(); 240 | } 241 | 242 | let (s_r, rem_r) = ar.sqrt_rem().unwrap(); 243 | let s_g = ag.sqrt(); 244 | let rem_g = ag - &s_g * &s_g; 245 | 246 | eq!(s_r, s_g; 247 | rem_r, rem_g) 248 | } 249 | } 250 | 251 | quickcheck! { 252 | fn negate(a: BigIntStr) -> TestResult { 253 | let (mut ar, ag) = a.parse(); 254 | ar.negate(); 255 | eq!(ar, -ag) 256 | } 257 | } 258 | 259 | #[cfg(feature = "rust-gmp")] 260 | fn tstbit(ag: &RefImpl, i: usize) -> bool { 261 | ag.tstbit(i) 262 | } 263 | 264 | #[cfg(not(feature = "rust-gmp"))] 265 | fn tstbit(ag: &RefImplU, i: usize) -> bool { 266 | use num_bigint::BigUint; 267 | use num_traits::One; 268 | (ag >> i) & BigUint::one() == BigUint::one() 269 | } 270 | 271 | quickcheck! { 272 | fn is_even(a: BigIntStr) -> TestResult { 273 | let (ar, ag) = a.parse_u(); 274 | 275 | TestResult::from_bool(ar.is_even() == !tstbit(&ag,0)) 276 | } 277 | 278 | fn trailing_zeros(a: BigIntStr) -> TestResult { 279 | let (ar, ag) = a.parse_u(); 280 | 281 | let bit = if ar == 0 { 282 | 0 283 | } else { 284 | (0..).position(|idx| tstbit(&ag, idx)).unwrap() 285 | }; 286 | TestResult::from_bool(ar.trailing_zeros() as usize == bit) 287 | } 288 | } 289 | 290 | #[cfg(feature = "rust-gmp")] 291 | quickcheck! { 292 | fn count_ones(a: BigIntStr) -> TestResult { 293 | let (ar, ag) = a.parse(); 294 | 295 | TestResult::from_bool(ar.count_ones() == ag.popcount()) 296 | } 297 | } 298 | 299 | #[cfg(not(feature = "rust-gmp"))] 300 | quickcheck! { 301 | fn count_ones(a: BigIntStr) -> TestResult { 302 | let (ar, ag) = a.parse_u(); 303 | 304 | let ones = (0..ag.bits()).filter(|&idx| tstbit(&ag, idx.try_into().unwrap())).count(); 305 | 306 | TestResult::from_bool(ar.count_ones() == ones) 307 | } 308 | } 309 | 310 | #[cfg(feature = "rust-gmp")] 311 | quickcheck! { 312 | fn bit_length(a: BigIntStr) -> TestResult { 313 | let (ar, ag) = a.parse(); 314 | 315 | TestResult::from_bool(ar.bit_length() == ag.bit_length() as u32) 316 | } 317 | } 318 | 319 | #[cfg(not(feature = "rust-gmp"))] 320 | quickcheck! { 321 | fn bit_length(a: BigIntStr) -> TestResult { 322 | let (ar, ag) = a.parse(); 323 | 324 | TestResult::from_bool(ar.bit_length() == std::cmp::max(1, ag.bits() as u32)) 325 | } 326 | } 327 | 328 | quickcheck! { 329 | fn bit(a: BigIntStr, bit: u16) -> TestResult { 330 | let (ar, ag) = a.parse_u(); 331 | 332 | TestResult::from_bool(ar.bit(bit as u32) == tstbit(&ag, bit as usize)) 333 | } 334 | } 335 | 336 | #[cfg(feature = "rust-gmp")] 337 | quickcheck! { 338 | fn set_bit(a: BigIntStr, bit: u16, b: bool) -> TestResult { 339 | let (mut ar, mut ag) = a.parse(); 340 | 341 | ar.set_bit(bit as u32, b); 342 | if b { 343 | ag.setbit(bit as usize); 344 | } else { 345 | ag.clrbit(bit as usize); 346 | } 347 | 348 | let c1 = eq_bool!(ar, ag); 349 | let c2 = ar.bit(bit as u32) == b; 350 | TestResult::from_bool(c1 && c2) 351 | } 352 | } 353 | 354 | fn order_asc(a: T, b: T) -> (T, T) { 355 | if a < b { 356 | (a, b) 357 | } else { 358 | (b, a) 359 | } 360 | } 361 | 362 | quickcheck! { 363 | fn divrem(a: BigIntStr, b: BigIntStr, c: BigIntStr) -> TestResult { 364 | let (ar, ag) = a.parse(); 365 | let (br, bg) = b.parse(); 366 | let (cr, cg) = c.parse(); 367 | if ar <= 0 || br <= 0 || cr <= 0 || br == cr { 368 | return TestResult::discard() 369 | } 370 | let (br, cr) = order_asc(br, cr); 371 | let (bg, cg) = order_asc(bg, cg); 372 | let dr = (&ar * &cr) + &br; 373 | let dg = (&ag * &cg) + &bg; 374 | let (er, fr) = (&dr).divrem(&cr); 375 | let (eg, fg) = (&dg / &cg, &dg % &cg); 376 | 377 | let c1 = br == fr; 378 | let c2 = ar == er; 379 | let c3 = eq_bool!(er, eg; 380 | fr, fg); 381 | 382 | TestResult::from_bool(c1 && c2 && c3) 383 | } 384 | } 385 | 386 | fn ref_via_hex(x: T) -> RefImpl { 387 | ref_from_hex(format!("{:x}", x).as_str()) 388 | } 389 | 390 | quickcheck! { 391 | fn divrem_usize(a: BigIntStr, b: usize, c: usize) -> TestResult { 392 | let (ar, ag) = a.parse(); 393 | if ar <= 0 || b <= 0 || c <= 0 || b == c { 394 | return TestResult::discard() 395 | } 396 | let (b, c) = order_asc(b, c); 397 | let bg = ref_via_hex(b); 398 | let cg = ref_via_hex(c); 399 | let dr = (&ar * c) + b; 400 | let dg = (&ag * &cg) + &bg; 401 | let (er, fr) = dr.divrem(c); 402 | let frg = ref_via_hex(fr); 403 | let (eg, fg) = (&dg / &cg, &dg % &cg); 404 | 405 | let c1 = b == fr; 406 | let c2 = ar == er; 407 | let c3 = frg == fg; 408 | let c4 = eq_bool!(er, eg); 409 | TestResult::from_bool(c1 && c2 && c3 && c4) 410 | } 411 | } 412 | 413 | // operators 414 | 415 | macro_rules! expr { 416 | ($e: expr) => { 417 | $e 418 | }; 419 | } 420 | 421 | macro_rules! test_binop { 422 | ($($name: ident: $op: tt, $assign: tt, $allow_zero: expr, $typ:ty;)*) => { 423 | mod binop { 424 | $(mod $name { 425 | #![allow(unused_imports)] 426 | use ::BigIntStr; 427 | use quickcheck::TestResult; 428 | use ramp::ll::limb::{Limb, BaseInt}; 429 | use ::{ RefImpl, RefImplU }; 430 | 431 | quickcheck! { 432 | fn int_int(a: BigIntStr, b: BigIntStr) -> TestResult { 433 | let (ar, ag):(_, $typ) = (&a).into(); 434 | let (br, bg):(_, $typ) = (&b).into(); 435 | if !$allow_zero && br == 0 { return TestResult::discard() } 436 | 437 | eq!(ar $op br, ag $op bg) 438 | } 439 | 440 | fn intref_int(a: BigIntStr, b: BigIntStr) -> TestResult { 441 | let (ar, ag):(_, $typ) = (&a).into(); 442 | let (br, bg):(_, $typ) = (&b).into(); 443 | if !$allow_zero && br == 0 { return TestResult::discard() } 444 | 445 | eq!(&ar $op br, ag $op bg) 446 | } 447 | 448 | fn int_intref(a: BigIntStr, b: BigIntStr) -> TestResult { 449 | let (ar, ag):(_, $typ) = (&a).into(); 450 | let (br, bg):(_, $typ) = (&b).into(); 451 | if !$allow_zero && br == 0 { return TestResult::discard() } 452 | 453 | eq!(ar $op &br, ag $op bg) 454 | } 455 | 456 | fn intref_intref(a: BigIntStr, b: BigIntStr) -> TestResult { 457 | let (ar, ag):(_, $typ) = (&a).into(); 458 | let (br, bg):(_, $typ) = (&b).into(); 459 | if !$allow_zero && br == 0 { return TestResult::discard() } 460 | 461 | eq!(&ar $op &br, ag $op bg) 462 | } 463 | 464 | fn int_limb(a: BigIntStr, b: BaseInt) -> TestResult { 465 | if !$allow_zero && b == 0 { 466 | return TestResult::discard() 467 | } 468 | let (ar, ag):(_, $typ) = (&a).into(); 469 | let bg:$typ = (b as u64).into(); 470 | 471 | eq!(ar $op Limb(b), ag $op bg) 472 | } 473 | 474 | fn int_baseint(a: BigIntStr, b: BaseInt) -> TestResult { 475 | if !$allow_zero && b == 0 { 476 | return TestResult::discard() 477 | } 478 | let (ar, ag):(_, $typ) = (&a).into(); 479 | let bg:$typ = (b as u64).into(); 480 | 481 | eq!(ar $op b, ag $op bg) 482 | } 483 | 484 | fn int_usize(a: BigIntStr, b: usize) -> TestResult { 485 | if !$allow_zero && b == 0 { 486 | return TestResult::discard() 487 | } 488 | let (ar, ag):(_, $typ) = (&a).into(); 489 | let bg:$typ = (b as u64).into(); 490 | 491 | eq!(ar $op b, ag $op bg) 492 | } 493 | 494 | fn baseint_int(a: BaseInt, b: BigIntStr) -> TestResult { 495 | let ag:$typ = (a as u64).into(); 496 | let (br, bg):(_, $typ) = (&b).into(); 497 | if !$allow_zero && br == 0 { return TestResult::discard() } 498 | 499 | eq!(a $op br, ag $op bg) 500 | } 501 | 502 | fn usize_int(a: usize, b: BigIntStr) -> TestResult { 503 | let ag:$typ = (a as u64).into(); 504 | let (br, bg):(_, $typ) = (&b).into(); 505 | if !$allow_zero && br == 0 { return TestResult::discard() } 506 | 507 | eq!(a $op br, ag $op bg) 508 | } 509 | 510 | fn assign_int(a: BigIntStr, b: BigIntStr) -> TestResult { 511 | let (mut ar, ag):(_, $typ) = (&a).into(); 512 | let (br, bg):(_, $typ) = (&b).into(); 513 | if !$allow_zero && br == 0 { return TestResult::discard() } 514 | 515 | expr!(ar $assign br); 516 | eq!(ar, ag $op bg) 517 | } 518 | 519 | fn assign_intref(a: BigIntStr, b: BigIntStr) -> TestResult { 520 | let (mut ar, ag):(_, $typ) = (&a).into(); 521 | let (br, bg):(_, $typ) = (&b).into(); 522 | if !$allow_zero && br == 0 { return TestResult::discard() } 523 | 524 | expr!(ar $assign &br); 525 | eq!(ar, ag $op bg) 526 | } 527 | 528 | fn assign_limb(a: BigIntStr, b: BaseInt) -> TestResult { 529 | if !$allow_zero && b == 0 { 530 | return TestResult::discard() 531 | } 532 | let (mut ar, ag):(_, $typ) = (&a).into(); 533 | let bg:$typ = (b as u64).into(); 534 | 535 | expr!(ar $assign Limb(b)); 536 | eq!(ar, ag $op bg) 537 | } 538 | 539 | fn assign_baseint(a: BigIntStr, b: BaseInt) -> TestResult { 540 | if !$allow_zero && b == 0 { 541 | return TestResult::discard() 542 | } 543 | let (mut ar, ag):(_, $typ) = (&a).into(); 544 | let bg:$typ = (b as u64).into(); 545 | 546 | expr!(ar $assign b); 547 | eq!(ar, ag $op bg) 548 | } 549 | 550 | fn assign_usize(a: BigIntStr, b: usize) -> TestResult { 551 | if !$allow_zero && b == 0 { 552 | return TestResult::discard() 553 | } 554 | let (mut ar, ag):(_, $typ) = (&a).into(); 555 | let bg:$typ = (b as u64).into(); 556 | 557 | expr!(ar $assign b); 558 | eq!(ar, ag $op bg) 559 | } 560 | } 561 | })* 562 | } 563 | } 564 | } 565 | 566 | test_binop! { 567 | add: +, +=, true, RefImpl; 568 | sub: -, -=, true, RefImpl; 569 | mul: *, *=, true, RefImpl; 570 | div: /, /=, false, RefImpl; 571 | rem: %, %=, false, RefImpl; 572 | bitand: &, &=, true, RefImplU; 573 | bitor: |, |=, true, RefImplU; 574 | bitxor: ^, ^=, true, RefImplU; 575 | } 576 | 577 | macro_rules! test_binop_signed { 578 | ($($name: ident: $op: tt, $assign: tt, $allow_zero: expr, $typ:ty;)*) => { 579 | mod binop_signed { 580 | $(mod $name { 581 | #![allow(unused_imports)] 582 | use ::BigIntStr; 583 | use quickcheck::TestResult; 584 | use ramp::ll::limb::{Limb, BaseInt}; 585 | use ::{ RefImpl, RefImplU }; 586 | 587 | quickcheck! { 588 | fn i32_int(a: i32, b: BigIntStr) -> TestResult { 589 | let ag:$typ = (a as i64).into(); 590 | let (br, bg):(_, $typ) = (&b).into(); 591 | if !$allow_zero && br == 0 { return TestResult::discard() } 592 | 593 | eq!(a $op br, ag $op bg) 594 | } 595 | 596 | fn int_i32(a: BigIntStr, b: i32) -> TestResult { 597 | if !$allow_zero && b == 0 { 598 | return TestResult::discard() 599 | } 600 | let (ar, ag):(_, $typ) = (&a).into(); 601 | let bg:$typ = (b as i64).into(); 602 | 603 | eq!(ar $op b, ag $op bg) 604 | } 605 | 606 | fn assign_i32(a: BigIntStr, b: i32) -> TestResult { 607 | if !$allow_zero && b == 0 { 608 | return TestResult::discard() 609 | } 610 | let (mut ar, ag):(_, $typ) = (&a).into(); 611 | let bg:$typ = b.into(); 612 | 613 | expr!(ar $assign b); 614 | eq!(ar, ag $op bg) 615 | } 616 | } 617 | 618 | })* 619 | } 620 | } 621 | } 622 | 623 | test_binop_signed! { 624 | add: +, +=, true, RefImpl; 625 | sub: -, -=, true, RefImpl; 626 | mul: *, *=, true, RefImpl; 627 | div: /, /=, false, RefImpl; 628 | rem: %, %=, false, RefImpl; 629 | } 630 | 631 | mod neg { 632 | use ::BigIntStr; 633 | use quickcheck::TestResult; 634 | 635 | quickcheck! { 636 | fn int(a: BigIntStr) -> TestResult { 637 | let (ar, ag) = a.parse(); 638 | eq!(-ar, -ag) 639 | } 640 | 641 | fn intref(a: BigIntStr) -> TestResult { 642 | let (ar, ag) = a.parse(); 643 | eq!(-&ar, -ag) 644 | } 645 | } 646 | } 647 | 648 | macro_rules! test_shiftop { 649 | ($($name: ident: $op: tt, $assign: tt;)*) => { 650 | $(mod $name { 651 | use ::BigIntStr; 652 | use quickcheck::TestResult; 653 | 654 | quickcheck! { 655 | fn int(a: BigIntStr, b: u16) -> TestResult { 656 | let (ar, ag) = a.parse(); 657 | let b = b as usize; 658 | 659 | eq!(ar $op b, ag $op b) 660 | } 661 | 662 | fn intref(a: BigIntStr, b: u16) -> TestResult { 663 | let (ar, ag) = a.parse(); 664 | let b = b as usize; 665 | 666 | eq!(&ar $op b, ag $op b) 667 | } 668 | 669 | fn assign(a: BigIntStr, b: u16) -> TestResult { 670 | let (mut ar, ag) = a.parse(); 671 | let b = b as usize; 672 | 673 | expr!(ar $assign b); 674 | eq!(ar, ag $op b) 675 | } 676 | } 677 | })* 678 | } 679 | } 680 | 681 | test_shiftop! { 682 | shl: <<, <<=; 683 | // FIXME(#27): currently >> doesn't match primitives/GMP for negative values 684 | // shr: >>, >>=; 685 | } 686 | 687 | macro_rules! test_cmpop { 688 | ($($method: ident;)*) => { 689 | mod cmp { 690 | mod cmp { 691 | // special, because Ord doesn't work with primitives 692 | use ::BigIntStr; 693 | use quickcheck::TestResult; 694 | 695 | quickcheck! { 696 | fn int_int(a: BigIntStr, b: BigIntStr) -> TestResult { 697 | let (ar, ag) = a.parse(); 698 | let (br, bg) = b.parse(); 699 | 700 | let c1 = ar.cmp(&ar) == ag.cmp(&ag); 701 | let c2 = br.cmp(&br) == bg.cmp(&bg); 702 | let c3 = ar.cmp(&br) == ag.cmp(&bg); 703 | TestResult::from_bool(c1 && c2 && c3) 704 | } 705 | } 706 | } 707 | 708 | $(mod $method { 709 | use ::BigIntStr; 710 | use ramp::ll::limb::{Limb, BaseInt}; 711 | use ::RefImpl; 712 | 713 | use quickcheck::TestResult; 714 | 715 | quickcheck! { 716 | fn int_int(a: BigIntStr, b: BigIntStr) -> TestResult { 717 | let (ar, ag) = a.parse(); 718 | let (br, bg) = b.parse(); 719 | 720 | let c1 = ar.$method(&ar) == ag.$method(&ag); 721 | let c2 = br.$method(&br) == bg.$method(&bg); 722 | let c3 = ar.$method(&br) == ag.$method(&bg); 723 | TestResult::from_bool(c1 && c2 && c3) 724 | } 725 | 726 | fn int_limb(a: BigIntStr, b: BaseInt) -> TestResult { 727 | let (ar, ag) = a.parse(); 728 | let bg = RefImpl::from(b); 729 | 730 | TestResult::from_bool(ar.$method(&Limb(b)) == ag.$method(&bg)) 731 | } 732 | 733 | fn int_i32(a: BigIntStr, b: i32) -> TestResult { 734 | let (ar, ag) = a.parse(); 735 | let bg = RefImpl::from(b); 736 | 737 | TestResult::from_bool(ar.$method(&b) == ag.$method(&bg)) 738 | } 739 | 740 | fn int_usize(a: BigIntStr, b: usize) -> TestResult { 741 | let (ar, ag) = a.parse(); 742 | let bg = RefImpl::from(b as u64); 743 | 744 | TestResult::from_bool(ar.$method(&b) == ag.$method(&bg)) 745 | } 746 | 747 | fn int_u64(a: BigIntStr, b: u64) -> TestResult { 748 | let (ar, ag) = a.parse(); 749 | let bg = RefImpl::from(b); 750 | 751 | TestResult::from_bool(ar.$method(&b) == ag.$method(&bg)) 752 | } 753 | 754 | fn int_i64(a: BigIntStr, b: i64) -> TestResult { 755 | let (ar, ag) = a.parse(); 756 | let bg = RefImpl::from(b); 757 | 758 | TestResult::from_bool(ar.$method(&b) == ag.$method(&bg)) 759 | } 760 | 761 | fn limb_int(a: BaseInt, b: BigIntStr) -> TestResult { 762 | let ag = RefImpl::from(a); 763 | let (br, bg) = b.parse(); 764 | 765 | TestResult::from_bool(Limb(a).$method(&br) == ag.$method(&bg)) 766 | } 767 | 768 | fn i32_int(a: i32, b: BigIntStr) -> TestResult { 769 | let ag = RefImpl::from(a); 770 | let (br, bg) = b.parse(); 771 | 772 | TestResult::from_bool(a.$method(&br) == ag.$method(&bg)) 773 | } 774 | 775 | fn usize_int(a: usize, b: BigIntStr) -> TestResult { 776 | let ag = RefImpl::from(a as u64); 777 | let (br, bg) = b.parse(); 778 | 779 | TestResult::from_bool(a.$method(&br) == ag.$method(&bg)) 780 | } 781 | 782 | fn u64_int(a: u64, b: BigIntStr) -> TestResult { 783 | let ag = RefImpl::from(a); 784 | let (br, bg) = b.parse(); 785 | 786 | TestResult::from_bool(a.$method(&br) == ag.$method(&bg)) 787 | } 788 | 789 | fn i64_int(a: i64, b: BigIntStr) -> TestResult { 790 | let ag = RefImpl::from(a); 791 | let (br, bg) = b.parse(); 792 | 793 | TestResult::from_bool(a.$method(&br) == ag.$method(&bg)) 794 | } 795 | } 796 | })* 797 | } 798 | } 799 | } 800 | 801 | test_cmpop! { 802 | eq; 803 | ne; 804 | partial_cmp; 805 | // cmp; // in macro 806 | lt; 807 | le; 808 | gt; 809 | ge; 810 | } 811 | 812 | // conversions 813 | 814 | macro_rules! test_from { 815 | ($($prim: ident;)*) => { 816 | mod from { 817 | use ramp::Int; 818 | use quickcheck::TestResult; 819 | 820 | $(quickcheck! { 821 | fn $prim(x: $prim) -> TestResult { 822 | let a = Int::from(x); 823 | 824 | let c1 = a.to_string() == x.to_string(); 825 | let c2 = $prim::from(&a) == x; 826 | TestResult::from_bool(c1 && c2) 827 | } 828 | })* 829 | } 830 | } 831 | } 832 | 833 | test_from! { 834 | i8; i16; i32; i64; isize; 835 | u8; u16; u32; u64; usize; 836 | } 837 | 838 | quickcheck! { 839 | // stringification 840 | fn to_str_radix(a: BigIntStr, b: u8) -> TestResult { 841 | // fold, to avoid discarding too many times, but without a bias 842 | let b = b % 64; 843 | if b < 2 || b > 36 { return TestResult::discard() } 844 | let (ar, ag) = a.parse(); 845 | 846 | TestResult::from_bool(ar.to_str_radix(b, false) == ag.to_str_radix(b.into())) 847 | } 848 | 849 | // decimal is the most common non-trivial (non-power-of-two) base, so 850 | // lets devote some extra attention there. 851 | fn to_str_decimal(a: BigIntStr) -> TestResult { 852 | let (ar, ag) = a.parse(); 853 | 854 | let c1 = ar.to_str_radix(10, false) == ag.to_str_radix(10); 855 | let c2 = ar.to_string() == ag.to_string(); 856 | 857 | TestResult::from_bool(c1 && c2) 858 | } 859 | 860 | fn write_radix(a: BigIntStr, b: u8) -> TestResult { 861 | // fold, to avoid discarding too many times, but without a bias 862 | let b = b % 64; 863 | if b < 2 || b > 36 { return TestResult::discard() } 864 | let (ar, ag) = a.parse(); 865 | 866 | let mut v = Vec::new(); 867 | ar.write_radix(&mut v, b, false).unwrap(); 868 | TestResult::from_bool(v == ag.to_str_radix(b.into()).into_bytes()) 869 | } 870 | 871 | fn from_str_radix(a: BigIntStr, b: u8) -> TestResult { 872 | // fold, to avoid discarding too many times, but without a bias 873 | let b = b % 64; 874 | if b < 2 || b > 36 { return TestResult::discard() } 875 | 876 | let (ar, ag) = a.parse(); 877 | 878 | let s = ag.to_str_radix(b.into()); 879 | 880 | let sr = Int::from_str_radix(&s, b); 881 | TestResult::from_bool(sr.ok() == Some(ar)) 882 | } 883 | 884 | // focus efforts, as per to_str_decimal 885 | fn from_str_decimal(a: BigIntStr) -> TestResult { 886 | let (ar, ag) = a.parse(); 887 | 888 | let s = ag.to_str_radix(10); 889 | 890 | let sr = Int::from_str_radix(&s, 10).unwrap(); 891 | let c1 = sr == ar; 892 | 893 | let sr2 = s.parse::().unwrap(); 894 | let c2 = sr2 == ar; 895 | 896 | TestResult::from_bool(c1 && c2) 897 | } 898 | } 899 | 900 | mod format { 901 | use ::BigIntStr; 902 | use quickcheck::TestResult; 903 | 904 | quickcheck! { 905 | fn display(a: BigIntStr) -> TestResult { 906 | let (ar, ag) = a.parse(); 907 | 908 | TestResult::from_bool(format!("{}", ar) == ag.to_str_radix(10)) 909 | } 910 | 911 | fn debug(a: BigIntStr) -> TestResult { 912 | let (ar, ag) = a.parse(); 913 | 914 | TestResult::from_bool(format!("{:?}", ar) == ag.to_str_radix(10)) 915 | } 916 | 917 | fn binary(a: BigIntStr) -> TestResult { 918 | let (ar, ag) = a.parse(); 919 | 920 | TestResult::from_bool(format!("{:b}", ar) == ag.to_str_radix(2)) 921 | } 922 | 923 | fn octal(a: BigIntStr) -> TestResult { 924 | let (ar, ag) = a.parse(); 925 | 926 | TestResult::from_bool(format!("{:o}", ar) == ag.to_str_radix(8)) 927 | } 928 | 929 | fn lowerhex(a: BigIntStr) -> TestResult { 930 | let (ar, ag) = a.parse(); 931 | 932 | TestResult::from_bool(format!("{:x}", ar) == ag.to_str_radix(16)) 933 | } 934 | 935 | fn upperhex(a: BigIntStr) -> TestResult { 936 | let (ar, ag) = a.parse(); 937 | 938 | TestResult::from_bool(format!("{:X}", ar) == ag.to_str_radix(16).to_uppercase()) 939 | } 940 | } 941 | } 942 | -------------------------------------------------------------------------------- /tests/quickcheck_limbs.rs: -------------------------------------------------------------------------------- 1 | extern crate quickcheck; 2 | extern crate ramp; 3 | extern crate num_bigint; 4 | 5 | use quickcheck::TestResult; 6 | use ramp::ll::limb; 7 | use ramp::ll::limb::Limb; 8 | use num_bigint::BigUint; 9 | 10 | #[cfg(feature = "full-quickcheck")] 11 | const QUICKCHECK_THOROUGNESS: u64 = 100; 12 | #[cfg(not(feature = "full-quickcheck"))] 13 | const QUICKCHECK_THOROUGNESS: u64 = 1; 14 | 15 | // Copy of quickcheck macro, but with custom tests and max_tests values 16 | macro_rules! quickcheck { 17 | (@as_items $($i:item)*) => ($($i)*); 18 | { 19 | $( 20 | fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { 21 | $($code:tt)* 22 | } 23 | )* 24 | } => ( 25 | quickcheck! { 26 | @as_items 27 | $( 28 | #[test] 29 | fn $fn_name() { 30 | fn prop($($arg_name: $arg_ty),*) -> $ret { 31 | $($code)* 32 | } 33 | quickcheck::QuickCheck::new() 34 | .tests(QUICKCHECK_THOROUGNESS*10_000) 35 | .max_tests(QUICKCHECK_THOROUGNESS*100_000) 36 | .quickcheck(prop as fn($($arg_ty),*) -> $ret); 37 | } 38 | )* 39 | } 40 | ) 41 | } 42 | 43 | macro_rules! B { () => { BigUint::from(usize::max_value()) + BigUint::from(1usize) } } 44 | macro_rules! l { ($e:expr) => { Limb($e as limb::BaseInt) } } 45 | macro_rules! b { ($e:expr) => { BigUint::from($e as usize) }; 46 | ($h:expr,$l:expr) => { b!($h) * B!() + b!($l) } 47 | } 48 | 49 | quickcheck!{ 50 | fn check_add(ha:usize, la:usize, hb:usize, lb:usize) -> TestResult { 51 | let a = b!(ha,la); 52 | let b = b!(hb,lb); 53 | let num_sum = (a+b)%(B!()*B!()); 54 | 55 | let (hw,lw) = limb::add_2(l!(ha), l!(la), l!(hb), l!(lb)); 56 | let ramp_sum = b!(hw.0, lw.0); 57 | 58 | TestResult::from_bool(num_sum == ramp_sum) 59 | } 60 | 61 | fn check_sub(ha: usize, la: usize, hb: usize, lb: usize) -> TestResult { 62 | let a = b!(ha,la); 63 | let b = b!(hb,lb); 64 | if a < b { 65 | return TestResult::discard(); 66 | } 67 | let num_diff = (a - b) % (B!()*B!()); 68 | 69 | let (hw, lw) = limb::sub_2(l!(ha), l!(la), l!(hb), l!(lb)); 70 | let ramp_diff = b!(hw.0, lw.0); 71 | 72 | TestResult::from_bool(num_diff == ramp_diff) 73 | } 74 | 75 | fn check_mul(a: usize, b: usize) -> TestResult { 76 | let num_prod = b!(a) * b!(b); 77 | 78 | let (hw, lw) = limb::mul(l!(a), l!(b)); 79 | let ramp_prod = b!(hw.0, lw.0); 80 | 81 | TestResult::from_bool(ramp_prod == num_prod) 82 | } 83 | 84 | fn check_div(hn: usize, ln: usize, d: usize) -> TestResult { 85 | let d = (1 + usize::max_value() / 2).saturating_add(d / 2); 86 | if hn >= d { 87 | return TestResult::discard(); 88 | } 89 | 90 | let num_n = b!(hn,ln); 91 | let num_q = &num_n / b!(d); 92 | let num_r = &num_n % b!(d); 93 | 94 | let (ramp_q, ramp_r) = limb::div(l!(hn), l!(ln), l!(d)); 95 | 96 | TestResult::from_bool(num_q == b!(ramp_q.0) && num_r == b!(ramp_r.0)) 97 | } 98 | } 99 | --------------------------------------------------------------------------------