├── .github └── workflows │ ├── cargo-msrv.yml │ ├── codecov-report.yml │ ├── publish-dry-run.yml │ ├── publish.yml │ └── test.yml ├── .gitignore ├── .vscode └── settings.json ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── TODO.md ├── bench ├── .gitignore ├── Cargo.toml ├── benches │ ├── float.rs │ ├── uint.rs │ └── unzip.rs └── open-report.sh ├── changes ├── prior-bugs.md ├── v0.11.0 ├── v0.12.0 ├── v0.12.1 ├── v0.13.0 ├── v0.5.0 ├── v0.6.0 ├── v0.7.0 ├── v0.8.0 └── v0.9.0 ├── codecov.yml ├── licenses ├── LICENSE-num-bigint └── LICENSE-rand ├── lit-parser ├── Cargo.toml └── src │ ├── lib.rs │ └── main.rs ├── scripts ├── quickcheck_test.sh ├── quickcheck_test_name.sh └── run_all_tests.sh └── src ├── .DS_Store ├── bint ├── bigint_helpers.rs ├── cast.rs ├── checked.rs ├── cmp.rs ├── const_trait_fillers.rs ├── consts.rs ├── convert.rs ├── endian.rs ├── fmt.rs ├── mod.rs ├── numtraits.rs ├── ops.rs ├── overflowing.rs ├── radix.rs ├── saturating.rs ├── strict.rs ├── unchecked.rs └── wrapping.rs ├── buint ├── bigint_helpers.rs ├── cast.rs ├── checked.rs ├── cmp.rs ├── const_trait_fillers.rs ├── consts.rs ├── convert.rs ├── div.rs ├── endian.rs ├── fmt.rs ├── mask.rs ├── mod.rs ├── mul.rs ├── numtraits.rs ├── ops.rs ├── overflowing.rs ├── radix.rs ├── saturating.rs ├── strict.rs ├── unchecked.rs └── wrapping.rs ├── cast ├── float │ ├── float_from_uint.rs │ ├── mod.rs │ └── uint_from_float.rs └── mod.rs ├── digit.rs ├── doc ├── bigint_helpers.rs ├── checked.rs ├── classify.rs ├── cmp.rs ├── const_trait_fillers.rs ├── consts.rs ├── endian.rs ├── math.rs ├── mod.rs ├── overflowing.rs ├── radix.rs ├── rounding.rs ├── saturating.rs ├── strict.rs ├── unchecked.rs └── wrapping.rs ├── errors ├── macros.rs ├── mod.rs ├── parseint.rs └── tryfrom.rs ├── float ├── cast.rs ├── classify.rs ├── cmp.rs ├── const_trait_fillers.rs ├── consts.rs ├── convert.rs ├── endian.rs ├── math │ ├── mod.rs │ ├── recip.rs │ ├── remquof.rs │ └── sqrt.rs ├── mod.rs ├── numtraits.rs ├── ops │ ├── add.rs │ ├── div.rs │ ├── mod.rs │ ├── mul.rs │ ├── rem.rs │ └── sub.rs ├── parse.rs ├── random.rs ├── rounding copy.rs ├── rounding.rs └── to_str.rs ├── helpers.rs ├── int ├── bigint_helpers.rs ├── cast.rs ├── checked.rs ├── cmp.rs ├── endian.rs ├── fmt.rs ├── mod.rs ├── numtraits.rs ├── ops.rs ├── radix.rs ├── strict.rs └── unchecked.rs ├── lib.rs ├── nightly.rs ├── prelude.rs ├── random.rs ├── test ├── convert.rs ├── macros.rs ├── mod.rs └── types.rs └── types.rs /.github/workflows/cargo-msrv.yml: -------------------------------------------------------------------------------- 1 | name: Verify MSRV 2 | 3 | on: 4 | push: 5 | branches: "**" 6 | pull_request: 7 | branches: "**" 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | cargo-msrv: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Install Rust 18 | run: rustup update nightly 19 | - name: Set nightly as default 20 | run: rustup default nightly 21 | - name: Install cargo-binstall 22 | uses: taiki-e/install-action@cargo-binstall 23 | - name: Install cargo-msrv 24 | run: cargo binstall cargo-msrv --no-confirm 25 | - name: verify MSRV 26 | run: cargo msrv verify -------------------------------------------------------------------------------- /.github/workflows/codecov-report.yml: -------------------------------------------------------------------------------- 1 | name: codecov report 2 | 3 | on: 4 | push: 5 | branches: "**" 6 | 7 | env: 8 | CARGO_TERM_COLOR: always 9 | 10 | jobs: 11 | codecov: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Install Rust 16 | run: rustup update nightly 17 | - name: Set nightly as default 18 | run: rustup default nightly 19 | - name: Install cargo-llvm-cov 20 | uses: taiki-e/install-action@cargo-llvm-cov 21 | - name: Generate code coverage 22 | run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info 23 | - name: Upload coverage to Codecov 24 | uses: codecov/codecov-action@v3 25 | with: 26 | token: ${{ secrets.CODECOV_TOKEN }} 27 | files: lcov.info 28 | fail_ci_if_error: true 29 | -------------------------------------------------------------------------------- /.github/workflows/publish-dry-run.yml: -------------------------------------------------------------------------------- 1 | name: Publish dry run 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish_dry_run: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: publish dry run 14 | run: cargo publish --dry-run 15 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to crates.io 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | #test: 10 | # uses: ./.github/workflows/test.yml 11 | publish: 12 | #needs: test 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: publish 17 | run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - master # master is a protected branch so tests will be run when we create a PR 7 | pull_request: 8 | branches-ignore: 9 | - master # master is a protected branch so tests will be run when we create a PR 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | build_stable: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Install latest stable Rust 20 | run: rustup install stable 21 | - name: Check crate builds on stable 22 | # NOTE: consider using https://github.com/frewsxcv/cargo-all-features, because all features != their arbitrary combinations 23 | run: cargo build --features serde,numtraits,rand,arbitrary,borsh && cargo build 24 | test_nightly: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Install latest nightly Rust 29 | run: rustup install nightly 30 | - name: Set nightly as default 31 | run: rustup default nightly 32 | - name: Build 33 | run: cargo build --all-features --verbose 34 | - name: Run tests 35 | run: sh scripts/run_all_tests.sh 36 | - name: Run doc tests 37 | run: cargo test --all-features --doc && cargo test --doc 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | 4 | .DS_Store 5 | 6 | /bench/target 7 | /bench/criterion 8 | 9 | lit-parser/target 10 | lit-parser/bench/target 11 | lit-parser/bench/criterion -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.rustfmt.extraArgs": [ 3 | "+nightly" 4 | ], 5 | "rust-analyzer.cargo.features": "all", 6 | "rust-analyzer.linkedProjects": [ 7 | "./Cargo.toml", 8 | "./bench/Cargo.toml", 9 | "./lit-parser/Cargo.toml" 10 | ] 11 | } -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 Isaac Holt 2 | 3 | This project uses some code modified from third party sources, under the MIT license: 4 | - rand: Copyright 2018 Developers of the Rand project; Copyright 2013-2017 The Rust Project Developers; Copyright 2018-2020 Developers of the Rand project; Copyright 2017 The Rust Project Developers. A copy of the original license for this can be found at /licenses/LICENSE-rand. 5 | - num-bigint: Copyright (c) 2014 The Rust Project Developers. A copy of the original license for this can found at /licenses/LICENSE-num-bigint. -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bnum" 3 | version = "0.13.0" 4 | authors = ["isaac-holt "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | description = "Arbitrary, fixed size numeric types that extend the functionality of primitive numeric types." 8 | homepage = "https://github.com/isaacholt100/bnum" 9 | documentation = "https://docs.rs/bnum/latest/bnum" 10 | repository = "https://github.com/isaacholt100/bnum" 11 | readme = "README.md" 12 | keywords = ["uint", "int", "bignum", "maths", "arbitrary"] 13 | categories = ["algorithms", "mathematics", "cryptography", "no-std"] 14 | rust-version = "1.65" 15 | 16 | exclude = ["src/float/*", "src/tests", "TODO.txt", "lit-parser/*"] # TODO: make sure to include these when they are ready 17 | 18 | [features] 19 | default = [] 20 | nightly = [] 21 | serde = ["dep:serde", "serde-big-array"] 22 | numtraits = ["num-integer", "num-traits"] 23 | 24 | [dependencies] 25 | num-integer = { version = "0.1", optional = true, default-features = false } 26 | num-traits = { version = "0.2.19", optional = true, default-features = false } 27 | serde = { version = "1.0", features = ["derive"], optional = true, default-features = false } 28 | serde-big-array = { version = "0.5", optional = true, default-features = false } 29 | rand = { version = "0.8", features = ["min_const_gen"], optional = true, default-features = false } 30 | arbitrary = { version = "1.3", features = ["derive"], optional = true } 31 | zeroize = { version = "1.6", optional = true, default-features = false } 32 | quickcheck = { version = "1.0", optional = true, default-features = false } 33 | # proptest = { version = "1.2", optional = true, default-features = false } 34 | valuable = { version = "0.1", optional = true, features = ["derive"], default-features = false } 35 | # lit-parser = { path = "./lit-parser/", optional = true } 36 | borsh = { version = "^1.5", optional = true, default-features = false, features = ["unstable__schema"] } 37 | 38 | [dev-dependencies] 39 | quickcheck = "1.0" 40 | paste = "1.0" 41 | rand = { version = "0.8", features = ["min_const_gen", "small_rng", "std_rng"], default-features = false } # ideally, this would be an optional feature, but since it is used by quickcheck anyway, it does not matter too much 42 | 43 | [profile.release] 44 | lto = true # enable link-time optimisation for faster runtime, but slower compile time 45 | opt-level = 3 # maximum optimisation level for faster runtime, but slower compile time 46 | 47 | [package.metadata.docs.rs] 48 | all-features = true 49 | 50 | [lints.rust] 51 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test_int_bits, values("16", "32", "64", "128"))'] } -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Isaac Holt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## Floats 2 | 3 | - FromStr trait: REMEMBER: the num_traits crate has a general from_str_radix method for floats, could use if stuck 4 | - Display, debug, upper exp, lower exp traits 5 | - Transcendental functions: 6 | - exp 7 | - exp2 8 | - exp_m1 9 | - ln 10 | - ln_1p 11 | - log 12 | - log2 13 | - log10 14 | - cbrt 15 | - hypot 16 | - sin 17 | - cos 18 | - tan 19 | - asin 20 | - acos 21 | - atan 22 | - atan2 23 | - sin_cos 24 | - sinh 25 | - cosh 26 | - tanh 27 | - asinh 28 | - acosh 29 | - atanh 30 | - to_degrees 31 | - to_radians 32 | - powf 33 | - gamma 34 | - ln_gamma 35 | - Other functions: 36 | - mul_add 37 | - midpoint 38 | - recip 39 | - Optimised division algorithm depending on size of mantissa 40 | - Optimised multiplication algorithm depending on size of mantissa 41 | - Constants: 42 | - DIGITS. For this, we can divide MB by f64::LOG2_10 and take floor (roughly speaking). 43 | - MIN_10_EXP. For this, we can divide MIN_EXP by f64::LOG2_10, and take floor (roughly speaking) 44 | - MAX_10_EXP. For this, we can divide MAX_EXP by f64::LOG2_10, and take floor (roughly speaking) 45 | - Maths constants: 46 | - E 47 | - FRAC_1_PI 48 | - FRAC_1_SQRT_2 49 | - FRAC_2_PI 50 | - FRAC_PI_2 51 | - FRAC_PI_3 52 | - FRAC_PI_4 53 | - FRAC_PI_6 54 | - FRAC_PI_8 55 | - LN_2 56 | - LN_10 57 | - LOG2_10 58 | - LOG2_E 59 | - LOG10_2 60 | - LOG10_E 61 | - PI 62 | - SQRT_2 63 | - TAU 64 | - FloatToInt trait 65 | - From/TryFrom trait for ints, other floats 66 | - Float type aliases from IEEE standard: f16, f32, f64, f80, f128. (Include f32 and f64 as allows const methods which aren't available on the primitives) 67 | - Rand: 68 | - gen_range stuff 69 | - num_traits::{Bounded, Float, FloatConst, FloatCore, AsPrimitive, FromPrimitive, ToPrimitive, FromBytes, ToBytes, Inv, MulAdd, MulAddAssign, Pow, Signed, Euclid, Num} 70 | - Division algorithm which doesn't need where clause 71 | 72 | ## Ints 73 | 74 | - big idea: could only use u8 digits, but for calculations (would need to do this as BUintD8 is noticeably slower than BUint), use u64s or u128s, e.g. when iterating, iterate in batches of 8, use u64::from_ne_bytes/u64::from_le_bytes - this is a transmute so should be very small overhead (this might sacrifice some code readability) 75 | - unsigned_signed_diff methods 76 | - isqrt methods 77 | - unbounded shr, shl methods 78 | - Use new Rust const capabilities to write more idiomatic code (e.g. we don't need the option_expect! macro anymore). Note though that maybe we should wait a bit to keep the MSRV not too recent 79 | - Faster mulitplication algorithm for larger integers 80 | - Faster division algorithms for larger integers 81 | - Update serde to use decimal string instead of struct debug - but CHECK that all serde options serialise primitive ints as decimal strings 82 | - FromBytes and ToBytes num_traits traits - only when can implement without "unconstrained generic constant" error 83 | - do we need the from_be_slice and from_le_slice methods? (think we can just call from_radix_{b, l}e with radix 256) 84 | - create more efficient implementation of ilog10 (see e.g. Hacker's Delight book) 85 | 86 | Other stuff: 87 | - Think about removing BTryFrom and just implementing TryFrom (no From for now), then can use CastFrom/As trait for Result-less conversions 88 | - Replace bitors, bitands, shifts, masks etc. with more efficient implementations (e.g. using set_bit, flip_bit, one-less-than-power-of-two methods, methods for efficiently generating masks/getting certain range of bits of integer) 89 | - Consider putting floats and signed integers behind optional features (which are enabled by default) 90 | - Add 16 bit and 32 bit width types to the test widths, so test u16, u32, f16, f32 as well (just make the digit sizes that are too wide not do anything for those tests) 91 | - Consider removing implementation of AsPrimitive for primitive ints 92 | - Consider removing Add and Div impls 93 | - Rewrite README 94 | - consider removing parse_str_radix method, not really necessary now Option::expect and unwrap are const 95 | - consider raising issue in num_traits crate about PrimInt dependency on NumCast 96 | - consider using Rust's ParseIntError and TryFromIntError instead of own types, would have to do this by deliberating doing a calculation resulting in error (e.g. u8::from_str_radix(" ", 10)). this might be not be very good practice though, and would have to do for ParseFloatError eventually as well, which could be trickier to do this way 97 | - consider splitting off allow-based methods into gated "alloc" feature 98 | - work out and add assertions about sizes of e.g. int widths (should be <= u32::MAX), and float mantissa and exponent widths, etc. 99 | - include list of difference with primitives in README, e.g. overflow_checks not detected yet, serde implementation different, memory layout different (always little endian - although maybe this could be changed? probably not a good idea though) 100 | - test using stable, only use nightly when need to test be_bytes methods 101 | - check you're happy with the layout of the random crate-level module -------------------------------------------------------------------------------- /bench/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | 4 | .DS_Store -------------------------------------------------------------------------------- /bench/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bnum_benchmarks" 3 | version = "0.1.0" 4 | authors = ["isaac-holt "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dev-dependencies] 9 | criterion = { version = "0.5" } 10 | bnum = { path = "../", features = ["rand"] } 11 | num-traits = "0.2" 12 | uint = "0.9" 13 | rand = { version = "0.8", features = ["std", "std_rng"] } 14 | paste = "1.0" 15 | 16 | [[bench]] 17 | name = "float" 18 | # path = "benches/float/mod.rs" 19 | harness = false 20 | 21 | [[bench]] 22 | name = "uint" 23 | harness = false 24 | 25 | [profile.release] 26 | lto = true # enable link-time optimisation for faster runtime, but slower compile time 27 | opt-level = 3 # maximum optimisation level for faster runtime, but slower compile time -------------------------------------------------------------------------------- /bench/benches/float.rs: -------------------------------------------------------------------------------- 1 | use bnum::cast::CastFrom; 2 | use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; 3 | use rand::prelude::*; 4 | 5 | mod unzip; 6 | 7 | const SAMPLE_SIZE: usize = 10000; 8 | 9 | // use bnum::Float; 10 | 11 | // type F256 = Float<32, 236>; 12 | // type F128 = Float<32, 236>; 13 | // type F64 = Float<8, 48>; 14 | // type F32 = Float<4, 23>; 15 | 16 | type U256 = bnum::BUintD8<32>; 17 | type U1024 = bnum::BUintD8<{17 * 8}>; 18 | type U1024D64 = bnum::BUint<17>; 19 | 20 | 21 | // fn bench_fibs(c: &mut Criterion) { 22 | // let mut group = c.benchmark_group("round"); 23 | // let mut rng = rand::rngs::StdRng::seed_from_u64(0); 24 | // let inputs = (0..SAMPLE_SIZE) 25 | // .map(|_| rng.gen::<(u64, u64)>()) 26 | // .map(|(a, b)| ( 27 | // (f64::from_bits(a >> 1), f64::from_bits(b >> 1)), 28 | // (F64::from_bits((a >> 1).into()), F64::from_bits((b >> 1).into())) 29 | // )); 30 | // let (prim_inputs, big_inputs) = unzip::unzip2(inputs); 31 | 32 | // // group.bench_with_input(BenchmarkId::new("Recursive", "new"), &big_inputs, |b, inputs| b.iter(|| { 33 | // // for a in inputs.iter().cloned() { 34 | // // let _ = black_box(a).floor(); 35 | // // } 36 | // // })); 37 | // group.bench_with_input(BenchmarkId::new("Iterative", "old"), &big_inputs, |b, inputs| b.iter(|| { 38 | // inputs.iter().cloned().for_each(|(a, b)| { 39 | // let _ = black_box(a) + black_box(b); 40 | // }) 41 | // })); 42 | // group.bench_with_input(BenchmarkId::new("Iterative", "prim"), &prim_inputs, |b, inputs| b.iter(|| { 43 | // inputs.iter().cloned().for_each(|(a, b)| { 44 | // let _ = black_box(a) + black_box(b); 45 | // }) 46 | // })); 47 | // group.finish(); 48 | // } 49 | 50 | 51 | fn bench_add(c: &mut Criterion) { 52 | let mut group = c.benchmark_group("round"); 53 | let mut rng = rand::rngs::StdRng::seed_from_u64(0); 54 | let big_inputs = (0..SAMPLE_SIZE) 55 | .map(|_| rng.gen::<(U1024, U1024)>()) 56 | .map(|(a, b)| ((a, b), (U1024D64::cast_from(a), U1024D64::cast_from(b)))); 57 | // .map(|(a, b)| ( 58 | // (F64::from_bits((a >> 1)), F64::from_bits((b >> 1))) 59 | // )); 60 | let (inputs1, inputs2) = unzip::unzip2(big_inputs); 61 | 62 | // group.bench_with_input(BenchmarkId::new("Recursive", "new"), &big_inputs, |b, inputs| b.iter(|| { 63 | // for a in inputs.iter().cloned() { 64 | // let _ = black_box(a).floor(); 65 | // } 66 | // })); 67 | group.bench_with_input(BenchmarkId::new("Iterative", "d8"), &inputs1, |b, inputs| b.iter(|| { 68 | inputs.iter().cloned().for_each(|(a, b)| { 69 | let _ = black_box(!a); 70 | }) 71 | })); 72 | group.bench_with_input(BenchmarkId::new("Iterative", "d64"), &inputs2, |b, inputs| b.iter(|| { 73 | inputs.iter().cloned().for_each(|(a, b)| { 74 | let _ = black_box(!a); 75 | }) 76 | })); 77 | group.finish(); 78 | } 79 | 80 | criterion_group!(benches, bench_add); 81 | criterion_main!(benches); -------------------------------------------------------------------------------- /bench/benches/unzip.rs: -------------------------------------------------------------------------------- 1 | macro_rules! unzip { 2 | (fn $name: ident <$($Gen: ident), *>) => { 3 | paste::paste! { 4 | pub fn $name<$($Gen), *, I>(i: I) -> ($(Vec<$Gen>), *) 5 | where I: Iterator 6 | { 7 | let ($(mut []), *) = match i.size_hint().1 { 8 | Some(size) => ($(Vec::<$Gen>::with_capacity(size)), *), 9 | None => ($(Vec::<$Gen>::new()), *), 10 | }; 11 | i.for_each(|($([<$Gen:lower>]), *)| { 12 | $( 13 | [].push([<$Gen:lower>]); 14 | )* 15 | }); 16 | ($([]), *) 17 | } 18 | } 19 | }; 20 | } 21 | 22 | // unzip!(fn unzip3); 23 | unzip!(fn unzip2); -------------------------------------------------------------------------------- /bench/open-report.sh: -------------------------------------------------------------------------------- 1 | open target/criterion/$1/report/index.html -------------------------------------------------------------------------------- /changes/prior-bugs.md: -------------------------------------------------------------------------------- 1 | - `<= v0.1.0`: incorrect implementation of `from_be`, `to_be` on all integers. 2 | - `<= v0.8.0`: incorrect implementation of `unchecked_shl`, `unchecked_shr` for `BUint` with `64` bit digits. 3 | - `<= v0.8.0`: incorrect implementation of `Add<$Digit>` for all `BUint`s (where `$Digit` is the underlying digit type). 4 | - `<= v0.8.0`: `lcm` incorrectly panics when `self` is zero. 5 | - `v0.7.0 - v0.9.1`: the implementations of `shr, shl, wrapping_{shr, shl}, overflowing_{shr, shl}, checked_{shr, shl}, rotate_left, rotate_right, from_be_slice, from_le_slice` methods and any methods that involved left-shift or right-shift operations, contained undefined behaviour (this was due to a premature stabilisation of a feature in the Rust compiler - see and ). Note that all tests for these methods were still passing for each relevant version, so it is very likely that the code was still working correctly. However, as of the time of writing, the code that they relied on will soon be rejected by the compiler. They have now been replaced with safe implementations which are just as fast. 6 | - `<= v0.12.1`: `to_str_radix`, `to_radix_be`, `to_radix_le` did not panic on invalid radices but should have done. -------------------------------------------------------------------------------- /changes/v0.11.0: -------------------------------------------------------------------------------- 1 | - Make integer ilog methods panic for invalid inputs in release mode as well as debug mode. 2 | - Match ilog panic message with that of Rust's primitives. -------------------------------------------------------------------------------- /changes/v0.12.0: -------------------------------------------------------------------------------- 1 | - Add optional borsh support 2 | - Add `digits_mut` and `set_bit` method to unsigned integers. 3 | - `As` and `CastFrom` traits no longer const, as const trait support removed from latest nightly. 4 | - `cast_signed` method for unsigned integers. 5 | - `cast_unsigned` method for signed integers. 6 | - `midpoint` method for integers. 7 | - `carrying_add` and `borrowing_sub` methods for signed integers. 8 | - strict methods added. 9 | - added `(bnum) ` prefix to error messages that were lacking it. -------------------------------------------------------------------------------- /changes/v0.12.1: -------------------------------------------------------------------------------- 1 | - fix midpoint method 2 | - fix posoverflow being returned instead of invaliddigit for parsing ints 3 | - change debug implementation of parseinterror 4 | - fix num-integer lcm implementation for signed ints -------------------------------------------------------------------------------- /changes/v0.13.0: -------------------------------------------------------------------------------- 1 | Add ConstZero and ConstOne (from num_traits) for ints 2 | Add OverflowingAdd and OverflowingSub 3 | Make to_str_radix, to_radix_{b,l}_e panic on invalid radix 4 | Add unbounded_{shl, shr} methods 5 | Make it possible to test on stable 6 | Use branchless algorithm for set_bit on unsigned ints 7 | Add as_bits, as_bits_mut to signed ints -------------------------------------------------------------------------------- /changes/v0.5.0: -------------------------------------------------------------------------------- 1 | Breaking: 2 | num_traits and num_integer traits no longer const implementation (requires traits to be marked as const_trait which hasn't been done in these crates) -------------------------------------------------------------------------------- /changes/v0.6.0: -------------------------------------------------------------------------------- 1 | Non-breaking: 2 | * the following methods are now const: {BUint, BInt}::from_str_radix, {BUint, BInt}::parse_bytes, BInt::overflowing_mul, BInt::overflowing_neg, BInt::overflowing_abs, BInt::overflowing_pow, BInt::wrapping_neg, BInt::wrapping_abs, BInt::checked_mul, BInt::checked_neg, BInt::checked_abs, BInt::checked_pow, BInt::saturating_mul, BInt::saturating_neg, BInt::saturating_abs, BInt::saturating_pow, BInt::unsigned_abs, BInt::pow, BInt::abs, BInt::abs_diff 3 | * the following methods are now const when the nightly feature is enabled: {BUint, BInt}::from_radix_be, {BUint, BInt}::from_radix_le -------------------------------------------------------------------------------- /changes/v0.7.0: -------------------------------------------------------------------------------- 1 | Removal of `const` impls of standard library traits, addition of equivalent methods defined on the integer types themselves. 2 | Following methods are now `const`: `abs_diff`, `BUint::{overflowing_neg, wrapping_neg}`, `wrapping_{shr, shl}`, `overflowing_{shr, shl}`, `checked_{shr, shl}`, `rotate_left`, `rotate_right`, `from_be_slice`, `from_le_slice`. 3 | Implementation of `Arbitrary`. -------------------------------------------------------------------------------- /changes/v0.8.0: -------------------------------------------------------------------------------- 1 | - Added casting between integers of different digit sizes 2 | - Fixed incorrect implementation of some formatting traits 3 | - The following methods are now `const` on stable for signed and unsigned integers: `checked_div`, `checked_div_euclid`, `checked_rem`, `checked_rem_euclid`, `checked_next_multiple_of`, `checked_ilog10`, `checked_ilog`, `div`, `rem`, `overflowing_div`, `overflowing_div_euclid`, `overflowing_rem`, `overflowing_rem_euclid`, `saturating_div`, `wrapping_div`, `wrapping_div_euclid`, `wrapping_rem`, `wrapping_rem_euclid`, `div_euclid`, `rem_euclid`, `ilog10`, `ilog`, `next_multiple_of`, `div_floor`, `div_ceil` -------------------------------------------------------------------------------- /changes/v0.9.0: -------------------------------------------------------------------------------- 1 | - Add optional zeroize support 2 | - Add optional quickcheck support 3 | - Add optional valuable support 4 | - Make integers #[repr(transparent)]. 5 | - Make Slice struct #[repr(transparent)]. 6 | - Performance enhancement for `shr` methods 7 | - Make wrapping_rem panic message same as for primitives 8 | - Breaking: make unchecked_shl, unchecked_shr take u32 as shift argument, not Self. 9 | - Fixed incorrect implementation of unchecked_shl, unchecked_shr for 64 bit digit integers. 10 | - Fixed incorrect implementation of Add<$Digit> for all BUints 11 | - Fixed lcm implementation to not panic if self is zero 12 | - Changed to #[derive(PartialEq, Eq)] to allow pattern matching on const values. 13 | - Added trait `BTryFrom` for fallible conversions between bnum integers (`TryFrom` can't be used due to the automatic implementation of `TryFrom for T`). 14 | - Don't require `std_rng` and `small_rng` features of rand crate except when testing. -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | threshold: 2% # needed because due to property based testing, coverage isn't exactly the same each time 6 | patch: 7 | default: 8 | threshold: 2% # needed because due to property based testing, coverage isn't exactly the same each time -------------------------------------------------------------------------------- /licenses/LICENSE-num-bigint: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE-rand: -------------------------------------------------------------------------------- 1 | Copyright 2018 Developers of the Rand project 2 | Copyright (c) 2014 The Rust Project Developers 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /lit-parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lit-parser" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | syn = { version = "^1.0", features = ["full"] } 11 | quote = "^1.0" -------------------------------------------------------------------------------- /lit-parser/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | use proc_macro::{TokenStream, TokenTree}; 4 | use syn::{parse_macro_input, LitInt}; 5 | use quote::quote; 6 | use core::str::FromStr; 7 | //use bint::BUint; 8 | 9 | fn get_bitwidth_signed(suffix: &str) -> Result<(usize, bool), ()> { 10 | let first = suffix.as_bytes().get(0); 11 | match first { 12 | Some(b'u' | b'i') => { 13 | let bit_width = usize::from_str(&suffix[1..]).map_err(|_e| ())?; 14 | Ok((bit_width, first == Some(&b'u'))) 15 | }, 16 | _ => Err(()), 17 | } 18 | } 19 | 20 | #[proc_macro] 21 | pub fn n(input: TokenStream) -> TokenStream { 22 | println!("{}", input.to_string()); 23 | let literal = parse_macro_input!(input as LitInt); 24 | //u(input) 25 | let suffix = literal.suffix(); 26 | match get_bitwidth_signed(suffix) { 27 | Ok((bit_width, unsigned)) => { 28 | let digits = literal.base10_digits(); 29 | println!("{} {}", bit_width, unsigned); 30 | let (n, ty) = if bit_width % 64 == 0 { 31 | (bit_width / 64, if unsigned { "BUint" } else { "BInt" }) 32 | } else if bit_width % 32 == 0 { 33 | (bit_width / 32, if unsigned { "BUintD32" } else { "BIntD32" }) 34 | } else if bit_width % 16 == 0 { 35 | (bit_width / 16, if unsigned { "BUintD16" } else { "BIntD16" }) 36 | } else if bit_width % 8 == 0 { 37 | (bit_width / 8, if unsigned { "BUintD8" } else { "BIntD8" }) 38 | } else { 39 | let output = quote! { 40 | compile_error!(concat!("invalid width `", #bit_width, "` for integer literal. the width must be a multiple of 8")) 41 | }; 42 | return output.into(); 43 | }; 44 | let ty = quote::format_ident!("{}", ty); 45 | let output = quote! { 46 | { 47 | const PARSED: bnum::#ty::<#n> = bnum::#ty::<#n>::parse_str_radix(#digits, 10); 48 | PARSED 49 | } 50 | }; 51 | output.into() 52 | }, 53 | Err(()) => { 54 | let output = quote! { 55 | compile_error!(concat!("invalid suffix `", #suffix, "` for number literal")) 56 | }; 57 | output.into() 58 | }, 59 | } 60 | } 61 | 62 | #[proc_macro] 63 | pub fn u(input: TokenStream) -> TokenStream { 64 | //println!("{:?}", input); 65 | let mut iter = input.into_iter(); 66 | let token = iter.next().expect("Expected one argument"); 67 | assert!(iter.next().is_none(), "Expected one argument"); 68 | match token { 69 | TokenTree::Literal(literal) => { 70 | let tt = TokenTree::from(literal); 71 | let ts = TokenStream::from(tt); 72 | let _literal = parse_macro_input!(ts as LitInt); 73 | println!(""); 74 | }, 75 | _ => panic!("Expected number literal") 76 | } 77 | "1".parse().unwrap() 78 | } -------------------------------------------------------------------------------- /lit-parser/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | } -------------------------------------------------------------------------------- /scripts/quickcheck_test.sh: -------------------------------------------------------------------------------- 1 | export QUICKCHECK_TESTS=1000000 2 | while true 3 | do 4 | RUSTFLAGS="--cfg test_int_bits=\"$1\"" cargo test quickcheck_ --quiet --features="$2 rand numtraits nightly" 5 | clear && printf '\e[3J' 6 | if [ $? -ne 0 ] 7 | then 8 | exit 1 9 | fi 10 | done -------------------------------------------------------------------------------- /scripts/quickcheck_test_name.sh: -------------------------------------------------------------------------------- 1 | export QUICKCHECK_TESTS=100000 2 | iters=0 3 | while true 4 | do 5 | cargo test --all-features --lib --quiet $1 6 | if [ $? -ne 0 ] 7 | then 8 | exit 1 9 | fi 10 | clear && printf '\e[3J' 11 | ((iters=iters+1)) 12 | echo "iterations: $iters" 13 | done -------------------------------------------------------------------------------- /scripts/run_all_tests.sh: -------------------------------------------------------------------------------- 1 | CYAN_COLOR="\033[0;36;1m" 2 | RESET_FORMAT="\033[0m" 3 | 4 | test_integer_info () { 5 | echo "\n${CYAN_COLOR}info${RESET_FORMAT}: running tests with $1-bit test integers..." 6 | } 7 | 8 | export QUICKCHECK_TESTS=10000 9 | 10 | run_test () { 11 | echo "using ${QUICKCHECK_TESTS} quickcheck tests per test" 12 | 13 | test_integer_info "$1" 14 | RUSTFLAGS="--cfg test_int_bits=\"$1\"" cargo test int --lib --quiet $2 15 | if [ $? -ne 0 ] 16 | then 17 | exit 1 18 | fi 19 | } 20 | 21 | for flags in "" "--all-features" 22 | do 23 | echo "\n${CYAN_COLOR}info${RESET_FORMAT}: running tests with flags '$flags'..." 24 | for bits in 16 32 64 128 25 | do 26 | run_test $bits $flags 27 | done 28 | done 29 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaacholt100/bnum/948e525d0b78e65b83f0d71eed1a2f58308bf268/src/.DS_Store -------------------------------------------------------------------------------- /src/bint/bigint_helpers.rs: -------------------------------------------------------------------------------- 1 | macro_rules! bigint_helpers { 2 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 3 | #[doc = doc::bigint_helpers::impl_desc!()] 4 | impl $BInt { 5 | crate::int::bigint_helpers::impls!(I); 6 | } 7 | }; 8 | } 9 | 10 | #[cfg(all(test, feature = "nightly"))] // as bigint_helpers not stabilised yet 11 | crate::test::all_digit_tests! { 12 | use crate::test::types::itest; 13 | 14 | crate::int::bigint_helpers::tests!(itest); 15 | } 16 | 17 | use crate::doc; 18 | 19 | crate::macro_impl!(bigint_helpers); 20 | -------------------------------------------------------------------------------- /src/bint/cmp.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::{Ord, Ordering, PartialOrd}; 2 | 3 | macro_rules! cmp { 4 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 5 | impl PartialOrd for $BInt { 6 | #[inline] 7 | fn partial_cmp(&self, other: &Self) -> Option { 8 | Some(self.cmp(other)) 9 | } 10 | } 11 | 12 | impl Ord for $BInt { 13 | #[inline] 14 | fn cmp(&self, other: &Self) -> Ordering { 15 | Self::cmp(self, other) 16 | } 17 | 18 | #[inline] 19 | fn max(self, other: Self) -> Self { 20 | Self::max(self, other) 21 | } 22 | 23 | #[inline] 24 | fn min(self, other: Self) -> Self { 25 | Self::min(self, other) 26 | } 27 | 28 | #[inline] 29 | fn clamp(self, min: Self, max: Self) -> Self { 30 | Self::clamp(self, min, max) 31 | } 32 | } 33 | }; 34 | } 35 | 36 | #[cfg(test)] 37 | crate::test::all_digit_tests! { 38 | use crate::test::types::*; 39 | 40 | crate::int::cmp::tests!(itest); 41 | } 42 | 43 | crate::macro_impl!(cmp); 44 | -------------------------------------------------------------------------------- /src/bint/const_trait_fillers.rs: -------------------------------------------------------------------------------- 1 | use crate::doc; 2 | use crate::ExpType; 3 | use core::cmp::Ordering; 4 | 5 | macro_rules! const_trait_fillers { 6 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 7 | #[doc = doc::const_trait_fillers::impl_desc!()] 8 | impl $BInt { 9 | #[inline] 10 | pub const fn bitand(self, rhs: Self) -> Self { 11 | Self::from_bits(self.bits.bitand(rhs.bits)) 12 | } 13 | 14 | #[inline] 15 | pub const fn bitor(self, rhs: Self) -> Self { 16 | Self::from_bits(self.bits.bitor(rhs.bits)) 17 | } 18 | 19 | #[inline] 20 | pub const fn bitxor(self, rhs: Self) -> Self { 21 | Self::from_bits(self.bits.bitxor(rhs.bits)) 22 | } 23 | 24 | #[inline] 25 | pub const fn not(self) -> Self { 26 | Self::from_bits(self.bits.not()) 27 | } 28 | 29 | #[inline] 30 | pub const fn eq(&self, other: &Self) -> bool { 31 | $BUint::eq(&self.bits, &other.bits) 32 | } 33 | 34 | #[inline] 35 | pub const fn ne(&self, other: &Self) -> bool { 36 | !Self::eq(self, other) 37 | } 38 | 39 | #[inline] 40 | pub const fn cmp(&self, other: &Self) -> Ordering { 41 | let s1 = self.signed_digit(); 42 | let s2 = other.signed_digit(); 43 | 44 | // Don't use match here as `cmp` is not yet const for primitive integers 45 | #[allow(clippy::comparison_chain)] 46 | if s1 == s2 { 47 | $BUint::cmp(&self.bits, &other.bits) 48 | } else if s1 > s2 { 49 | Ordering::Greater 50 | } else { 51 | Ordering::Less 52 | } 53 | } 54 | 55 | crate::int::cmp::impls!(); 56 | #[inline] 57 | pub const fn neg(self) -> Self { 58 | #[cfg(debug_assertions)] 59 | return self.strict_neg(); 60 | 61 | #[cfg(not(debug_assertions))] 62 | self.wrapping_neg() 63 | } 64 | 65 | crate::int::ops::trait_fillers!(); 66 | 67 | #[inline] 68 | pub const fn div(self, rhs: Self) -> Self { 69 | if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { 70 | panic!(crate::errors::err_msg!("attempt to divide with overflow")) 71 | } else { 72 | if rhs.is_zero() { 73 | crate::errors::div_zero!() 74 | } 75 | self.div_rem_unchecked(rhs).0 76 | } 77 | } 78 | 79 | #[inline] 80 | pub const fn rem(self, rhs: Self) -> Self { 81 | if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { 82 | panic!(crate::errors::err_msg!("attempt to calculate remainder with overflow")) 83 | } else { 84 | if rhs.is_zero() { 85 | crate::errors::rem_zero!() 86 | } 87 | self.div_rem_unchecked(rhs).1 88 | } 89 | } 90 | } 91 | }; 92 | } 93 | 94 | crate::macro_impl!(const_trait_fillers); 95 | -------------------------------------------------------------------------------- /src/bint/consts.rs: -------------------------------------------------------------------------------- 1 | macro_rules! pos_const { 2 | ($BUint: ident; $($name: ident $num: literal), *) => { 3 | $( 4 | #[doc = doc::consts::value_desc!($num)] 5 | pub const $name: Self = Self::from_bits($BUint::$name); 6 | )* 7 | } 8 | } 9 | 10 | macro_rules! neg_const { 11 | ($BUint: ident; $($name: ident $num: literal), *) => { 12 | $( 13 | #[doc = doc::consts::value_desc!("-" $num)] 14 | pub const $name: Self = { 15 | let mut u = $BUint::MAX; 16 | u.digits[0] -= ($num - 1); 17 | Self::from_bits(u) 18 | }; 19 | )* 20 | } 21 | } 22 | 23 | use crate::doc; 24 | use crate::ExpType; 25 | 26 | macro_rules! consts { 27 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 28 | #[doc = doc::consts::impl_desc!()] 29 | impl $BInt { 30 | #[doc = doc::consts::min!(I 512)] 31 | pub const MIN: Self = { 32 | let mut digits = [0; N]; 33 | digits[N - 1] = 1 << ($Digit::BITS - 1); 34 | Self::from_bits($BUint::from_digits(digits)) 35 | }; 36 | 37 | #[doc = doc::consts::max!(I 512)] 38 | pub const MAX: Self = { 39 | let mut digits = [$Digit::MAX; N]; 40 | digits[N - 1] >>= 1; 41 | Self::from_bits($BUint::from_digits(digits)) 42 | }; 43 | 44 | #[doc = doc::consts::bits!(I 512, 512)] 45 | pub const BITS: ExpType = $BUint::::BITS; 46 | 47 | #[doc = doc::consts::bytes!(I 512, 512)] 48 | pub const BYTES: ExpType = $BUint::::BYTES; 49 | 50 | #[doc = doc::consts::zero!(I 512)] 51 | pub const ZERO: Self = Self::from_bits($BUint::ZERO); 52 | 53 | #[doc = doc::consts::one!(I 512)] 54 | pub const ONE: Self = Self::from_bits($BUint::ONE); 55 | 56 | pos_const!($BUint; TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); 57 | 58 | neg_const!($BUint; NEG_ONE 1, NEG_TWO 2, NEG_THREE 3, NEG_FOUR 4, NEG_FIVE 5, NEG_SIX 6, NEG_SEVEN 7, NEG_EIGHT 8, NEG_NINE 9, NEG_TEN 10); 59 | 60 | pub(crate) const N_MINUS_1: usize = N - 1; 61 | } 62 | } 63 | } 64 | 65 | crate::macro_impl!(consts); 66 | -------------------------------------------------------------------------------- /src/bint/fmt.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, UpperExp, UpperHex}; 2 | 3 | macro_rules! fmt_trait { 4 | ($BInt: ident, $trait: tt) => { 5 | impl $trait for $BInt { 6 | #[inline] 7 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 8 | $trait::fmt(&self.bits, f) 9 | } 10 | } 11 | }; 12 | } 13 | 14 | macro_rules! fmt { 15 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 16 | fmt_trait!($BInt, Binary); 17 | 18 | impl Display for $BInt { 19 | #[inline] 20 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 21 | f.pad_integral(!self.is_negative(), "", &format!("{}", self.unsigned_abs())) 22 | } 23 | } 24 | 25 | impl Debug for $BInt { 26 | #[inline] 27 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 28 | Display::fmt(&self, f) 29 | } 30 | } 31 | 32 | impl LowerExp for $BInt { 33 | #[inline] 34 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 35 | let uint = self.unsigned_abs(); 36 | f.pad_integral(!self.is_negative(), "", &format!("{:e}", uint)) 37 | } 38 | } 39 | fmt_trait!($BInt, LowerHex); 40 | fmt_trait!($BInt, Octal); 41 | 42 | impl UpperExp for $BInt { 43 | #[inline] 44 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 45 | let uint = self.unsigned_abs(); 46 | f.pad_integral(!self.is_negative(), "", &format!("{:E}", uint)) 47 | } 48 | } 49 | 50 | fmt_trait!($BInt, UpperHex); 51 | }; 52 | } 53 | 54 | #[cfg(test)] 55 | crate::test::all_digit_tests! { 56 | crate::int::fmt::tests!(itest); 57 | } 58 | 59 | crate::macro_impl!(fmt); 60 | -------------------------------------------------------------------------------- /src/bint/ops.rs: -------------------------------------------------------------------------------- 1 | use crate::ExpType; 2 | use core::ops::{ 3 | Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, 4 | Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, 5 | }; 6 | 7 | macro_rules! ops { 8 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 9 | impl Neg for $BInt { 10 | type Output = Self; 11 | 12 | #[inline] 13 | fn neg(self) -> Self { 14 | Self::neg(self) 15 | } 16 | } 17 | 18 | impl Neg for &$BInt { 19 | type Output = $BInt; 20 | 21 | #[inline] 22 | fn neg(self) -> $BInt { 23 | $BInt::neg(*self) 24 | } 25 | } 26 | 27 | impl BitAnd for $BInt { 28 | type Output = Self; 29 | 30 | #[inline] 31 | fn bitand(self, rhs: Self) -> Self { 32 | Self::bitand(self, rhs) 33 | } 34 | } 35 | 36 | impl BitOr for $BInt { 37 | type Output = Self; 38 | 39 | #[inline] 40 | fn bitor(self, rhs: Self) -> Self { 41 | Self::bitor(self, rhs) 42 | } 43 | } 44 | 45 | impl BitXor for $BInt { 46 | type Output = Self; 47 | 48 | #[inline] 49 | fn bitxor(self, rhs: Self) -> Self { 50 | Self::bitxor(self, rhs) 51 | } 52 | } 53 | 54 | impl Div for $BInt { 55 | type Output = Self; 56 | 57 | #[inline] 58 | fn div(self, rhs: Self) -> Self { 59 | Self::div(self, rhs) 60 | } 61 | } 62 | 63 | impl Not for $BInt { 64 | type Output = Self; 65 | 66 | fn not(self) -> Self { 67 | Self::not(self) 68 | } 69 | } 70 | 71 | impl Rem for $BInt { 72 | type Output = Self; 73 | 74 | #[inline] 75 | fn rem(self, rhs: Self) -> Self { 76 | Self::rem(self, rhs) 77 | } 78 | } 79 | 80 | crate::int::ops::impls!($BInt, $BUint, $BInt); 81 | }; 82 | } 83 | 84 | #[cfg(test)] 85 | crate::test::all_digit_tests! { 86 | use crate::test::{debug_skip, test_bignum, types::itest}; 87 | use core::ops::Neg; 88 | 89 | test_bignum! { 90 | function: ::neg(a: itest), 91 | skip: debug_skip!(a == itest::MIN) 92 | } 93 | } 94 | 95 | crate::macro_impl!(ops); 96 | -------------------------------------------------------------------------------- /src/bint/saturating.rs: -------------------------------------------------------------------------------- 1 | use crate::{doc, ExpType}; 2 | 3 | macro_rules! saturating { 4 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 5 | #[doc = doc::saturating::impl_desc!()] 6 | impl $BInt { 7 | #[doc = doc::saturating::saturating_add!(I)] 8 | #[must_use = doc::must_use_op!()] 9 | #[inline] 10 | pub const fn saturating_add(self, rhs: Self) -> Self { 11 | match self.checked_add(rhs) { 12 | Some(add) => add, 13 | None => { 14 | if self.is_negative() { 15 | Self::MIN 16 | } else { 17 | Self::MAX 18 | } 19 | } 20 | } 21 | } 22 | 23 | #[doc = doc::saturating::saturating_add_unsigned!(I)] 24 | #[must_use = doc::must_use_op!()] 25 | #[inline] 26 | pub const fn saturating_add_unsigned(self, rhs: $BUint) -> Self { 27 | match self.checked_add_unsigned(rhs) { 28 | Some(i) => i, 29 | None => Self::MAX, 30 | } 31 | } 32 | 33 | #[doc = doc::saturating::saturating_sub!(I)] 34 | #[must_use = doc::must_use_op!()] 35 | #[inline] 36 | pub const fn saturating_sub(self, rhs: Self) -> Self { 37 | match self.checked_sub(rhs) { 38 | Some(add) => add, 39 | None => { 40 | if self.is_negative() { 41 | Self::MIN 42 | } else { 43 | Self::MAX 44 | } 45 | } 46 | } 47 | } 48 | 49 | #[doc = doc::saturating::saturating_sub_unsigned!(I)] 50 | #[must_use = doc::must_use_op!()] 51 | #[inline] 52 | pub const fn saturating_sub_unsigned(self, rhs: $BUint) -> Self { 53 | match self.checked_sub_unsigned(rhs) { 54 | Some(i) => i, 55 | None => Self::MIN, 56 | } 57 | } 58 | 59 | #[doc = doc::saturating::saturating_mul!(I)] 60 | #[must_use = doc::must_use_op!()] 61 | #[inline] 62 | pub const fn saturating_mul(self, rhs: Self) -> Self { 63 | match self.checked_mul(rhs) { 64 | Some(mul) => mul, 65 | None => { 66 | if self.is_negative() == rhs.is_negative() { 67 | Self::MAX 68 | } else { 69 | Self::MIN 70 | } 71 | } 72 | } 73 | } 74 | 75 | #[doc = doc::saturating::saturating_div!(I)] 76 | #[must_use = doc::must_use_op!()] 77 | #[inline] 78 | pub const fn saturating_div(self, rhs: Self) -> Self { 79 | let (div, overflow) = self.overflowing_div(rhs); 80 | if overflow { 81 | Self::MAX 82 | } else { 83 | div 84 | } 85 | } 86 | 87 | #[doc = doc::saturating::saturating_neg!(I)] 88 | #[must_use = doc::must_use_op!()] 89 | #[inline] 90 | pub const fn saturating_neg(self) -> Self { 91 | match self.checked_neg() { 92 | Some(abs) => abs, 93 | None => Self::MAX, 94 | } 95 | } 96 | 97 | #[doc = doc::saturating::saturating_abs!(I)] 98 | #[must_use = doc::must_use_op!()] 99 | #[inline] 100 | pub const fn saturating_abs(self) -> Self { 101 | match self.checked_abs() { 102 | Some(abs) => abs, 103 | None => Self::MAX, 104 | } 105 | } 106 | 107 | #[doc = doc::saturating::saturating_pow!(I)] 108 | #[must_use = doc::must_use_op!()] 109 | #[inline] 110 | pub const fn saturating_pow(self, exp: ExpType) -> Self { 111 | match self.checked_pow(exp) { 112 | Some(pow) => pow, 113 | None => { 114 | if self.is_negative() && exp & 1 != 0 { 115 | Self::MIN 116 | } else { 117 | Self::MAX 118 | } 119 | } 120 | } 121 | } 122 | } 123 | }; 124 | } 125 | 126 | #[cfg(test)] 127 | crate::test::all_digit_tests! { 128 | use crate::test::{test_bignum, types::*}; 129 | 130 | test_bignum! { 131 | function: ::saturating_add(a: itest, b: itest) 132 | } 133 | test_bignum! { 134 | function: ::saturating_add_unsigned(a: itest, b: utest) 135 | } 136 | test_bignum! { 137 | function: ::saturating_sub(a: itest, b: itest) 138 | } 139 | test_bignum! { 140 | function: ::saturating_sub_unsigned(a: itest, b: utest) 141 | } 142 | test_bignum! { 143 | function: ::saturating_div(a: itest, b: itest), 144 | skip: b == 0, 145 | cases: [ 146 | (itest::MIN, -1i8) 147 | ] 148 | } 149 | test_bignum! { 150 | function: ::saturating_neg(a: itest), 151 | cases: [ 152 | (itest::MIN) 153 | ] 154 | } 155 | test_bignum! { 156 | function: ::saturating_abs(a: itest), 157 | cases: [ 158 | (itest::MIN) 159 | ] 160 | } 161 | test_bignum! { 162 | function: ::saturating_mul(a: itest, b: itest) 163 | } 164 | test_bignum! { 165 | function: ::saturating_pow(a: itest, b: u16) 166 | } 167 | } 168 | 169 | crate::macro_impl!(saturating); 170 | -------------------------------------------------------------------------------- /src/bint/strict.rs: -------------------------------------------------------------------------------- 1 | macro_rules! strict { 2 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 3 | #[doc = doc::strict::impl_desc!()] 4 | impl $BInt { 5 | crate::int::strict::impls!(I); 6 | 7 | #[doc = doc::strict::strict_abs!(I)] 8 | #[must_use = doc::must_use_op!()] 9 | #[inline] 10 | pub const fn strict_abs(self) -> Self { 11 | crate::errors::option_expect!( 12 | self.checked_abs(), 13 | crate::errors::err_msg!("attempt to negate with overflow") 14 | ) 15 | } 16 | 17 | #[doc = doc::strict::strict_add_unsigned!(I)] 18 | #[must_use = doc::must_use_op!()] 19 | #[inline] 20 | pub const fn strict_add_unsigned(self, rhs: $BUint) -> Self { 21 | crate::errors::option_expect!( 22 | self.checked_add_unsigned(rhs), 23 | crate::errors::err_msg!("attempt to add with overflow") 24 | ) 25 | } 26 | 27 | #[doc = doc::strict::strict_sub_unsigned!(I)] 28 | #[must_use = doc::must_use_op!()] 29 | #[inline] 30 | pub const fn strict_sub_unsigned(self, rhs: $BUint) -> Self { 31 | crate::errors::option_expect!( 32 | self.checked_sub_unsigned(rhs), 33 | crate::errors::err_msg!("attempt to subtract with overflow") 34 | ) 35 | } 36 | } 37 | }; 38 | } 39 | 40 | #[cfg(all(test, feature = "nightly"))] // as strict_overflow_ops not stabilised yet 41 | crate::test::all_digit_tests! { 42 | crate::int::strict::tests!(itest); 43 | 44 | test_bignum! { 45 | function: ::strict_abs(a: itest), 46 | skip: a.checked_abs().is_none() 47 | } 48 | test_bignum! { 49 | function: ::strict_add_unsigned(a: itest, b: utest), 50 | skip: a.checked_add_unsigned(b).is_none() 51 | } 52 | test_bignum! { 53 | function: ::strict_sub_unsigned(a: itest, b: utest), 54 | skip: a.checked_sub_unsigned(b).is_none() 55 | } 56 | } 57 | 58 | use crate::doc; 59 | 60 | crate::macro_impl!(strict); 61 | -------------------------------------------------------------------------------- /src/bint/unchecked.rs: -------------------------------------------------------------------------------- 1 | macro_rules! unchecked { 2 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 3 | crate::int::unchecked::impls!($BInt, I); 4 | }; 5 | } 6 | 7 | #[cfg(test)] 8 | crate::test::all_digit_tests! { 9 | crate::int::unchecked::tests!(itest); 10 | } 11 | 12 | use crate::doc; 13 | 14 | crate::macro_impl!(unchecked); 15 | -------------------------------------------------------------------------------- /src/bint/wrapping.rs: -------------------------------------------------------------------------------- 1 | use crate::{doc, ExpType}; 2 | 3 | macro_rules! wrapping { 4 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 5 | #[doc = doc::wrapping::impl_desc!()] 6 | impl $BInt { 7 | #[doc = doc::wrapping::wrapping_add!(I)] 8 | #[must_use = doc::must_use_op!()] 9 | #[inline] 10 | pub const fn wrapping_add(self, rhs: Self) -> Self { 11 | Self::from_bits(self.bits.wrapping_add(rhs.bits)) 12 | } 13 | 14 | #[doc = doc::wrapping::wrapping_add_unsigned!(I)] 15 | #[must_use = doc::must_use_op!()] 16 | #[inline] 17 | pub const fn wrapping_add_unsigned(self, rhs: $BUint) -> Self { 18 | self.overflowing_add_unsigned(rhs).0 19 | } 20 | 21 | #[doc = doc::wrapping::wrapping_sub!(I)] 22 | #[must_use = doc::must_use_op!()] 23 | #[inline] 24 | pub const fn wrapping_sub(self, rhs: Self) -> Self { 25 | Self::from_bits(self.bits.wrapping_sub(rhs.bits)) 26 | } 27 | 28 | #[doc = doc::wrapping::wrapping_sub_unsigned!(I)] 29 | #[must_use = doc::must_use_op!()] 30 | #[inline] 31 | pub const fn wrapping_sub_unsigned(self, rhs: $BUint) -> Self { 32 | self.overflowing_sub_unsigned(rhs).0 33 | } 34 | 35 | #[doc = doc::wrapping::wrapping_mul!(I)] 36 | #[must_use = doc::must_use_op!()] 37 | #[inline] 38 | pub const fn wrapping_mul(self, rhs: Self) -> Self { 39 | Self::from_bits(self.bits.wrapping_mul(rhs.bits)) 40 | } 41 | 42 | #[doc = doc::wrapping::wrapping_div!(I)] 43 | #[must_use = doc::must_use_op!()] 44 | #[inline] 45 | pub const fn wrapping_div(self, rhs: Self) -> Self { 46 | self.overflowing_div(rhs).0 47 | } 48 | 49 | #[doc = doc::wrapping::wrapping_div_euclid!(I)] 50 | #[must_use = doc::must_use_op!()] 51 | #[inline] 52 | pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { 53 | self.overflowing_div_euclid(rhs).0 54 | } 55 | 56 | #[doc = doc::wrapping::wrapping_rem!(I)] 57 | #[must_use = doc::must_use_op!()] 58 | #[inline] 59 | pub const fn wrapping_rem(self, rhs: Self) -> Self { 60 | self.overflowing_rem(rhs).0 61 | } 62 | 63 | #[doc = doc::wrapping::wrapping_rem_euclid!(I)] 64 | #[must_use = doc::must_use_op!()] 65 | #[inline] 66 | pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { 67 | self.overflowing_rem_euclid(rhs).0 68 | } 69 | 70 | #[doc = doc::wrapping::wrapping_neg!(I)] 71 | #[must_use = doc::must_use_op!()] 72 | #[inline] 73 | pub const fn wrapping_neg(self) -> Self { 74 | self.overflowing_neg().0 75 | } 76 | 77 | #[doc = doc::wrapping::wrapping_shl!(I)] 78 | #[must_use = doc::must_use_op!()] 79 | #[inline] 80 | pub const fn wrapping_shl(self, rhs: ExpType) -> Self { 81 | self.overflowing_shl(rhs).0 82 | } 83 | 84 | #[doc = doc::wrapping::wrapping_shr!(I)] 85 | #[must_use = doc::must_use_op!()] 86 | #[inline] 87 | pub const fn wrapping_shr(self, rhs: ExpType) -> Self { 88 | self.overflowing_shr(rhs).0 89 | } 90 | 91 | #[doc = doc::wrapping::wrapping_abs!(I)] 92 | #[must_use = doc::must_use_op!()] 93 | #[inline] 94 | pub const fn wrapping_abs(self) -> Self { 95 | self.overflowing_abs().0 96 | } 97 | 98 | #[doc = doc::wrapping::wrapping_pow!(I)] 99 | #[must_use = doc::must_use_op!()] 100 | #[inline] 101 | pub const fn wrapping_pow(self, pow: ExpType) -> Self { 102 | // as wrapping_mul for signed and unsigned is the same 103 | Self::from_bits(self.bits.wrapping_pow(pow)) 104 | } 105 | } 106 | }; 107 | } 108 | 109 | #[cfg(test)] 110 | crate::test::all_digit_tests! { 111 | use crate::test::{test_bignum, types::{itest, utest}}; 112 | 113 | test_bignum! { 114 | function: ::wrapping_add(a: itest, b: itest) 115 | } 116 | test_bignum! { 117 | function: ::wrapping_add_unsigned(a: itest, b: utest) 118 | } 119 | test_bignum! { 120 | function: ::wrapping_sub(a: itest, b: itest) 121 | } 122 | test_bignum! { 123 | function: ::wrapping_sub_unsigned(a: itest, b: utest) 124 | } 125 | test_bignum! { 126 | function: ::wrapping_mul(a: itest, b: itest) 127 | } 128 | test_bignum! { 129 | function: ::wrapping_div(a: itest, b: itest), 130 | skip: b == 0 131 | } 132 | test_bignum! { 133 | function: ::wrapping_div_euclid(a: itest, b: itest), 134 | skip: b == 0 135 | } 136 | test_bignum! { 137 | function: ::wrapping_rem(a: itest, b: itest), 138 | skip: b == 0, 139 | cases: [ 140 | (itest::MIN, -1i8), 141 | (185892231884832768i64 as itest, 92946115942416385i64 as itest) 142 | ] 143 | } 144 | test_bignum! { 145 | function: ::wrapping_rem_euclid(a: itest, b: itest), 146 | skip: b == 0 147 | } 148 | test_bignum! { 149 | function: ::wrapping_neg(a: itest), 150 | cases: [ 151 | (itest::MIN) 152 | ] 153 | } 154 | test_bignum! { 155 | function: ::wrapping_shl(a: itest, b: u16) 156 | } 157 | test_bignum! { 158 | function: ::wrapping_shr(a: itest, b: u16) 159 | } 160 | test_bignum! { 161 | function: ::wrapping_abs(a: itest) 162 | } 163 | test_bignum! { 164 | function: ::wrapping_pow(a: itest, b: u16) 165 | } 166 | } 167 | 168 | crate::macro_impl!(wrapping); 169 | -------------------------------------------------------------------------------- /src/buint/bigint_helpers.rs: -------------------------------------------------------------------------------- 1 | use crate::digit; 2 | use crate::doc; 3 | 4 | macro_rules! bigint_helpers { 5 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 6 | #[doc = doc::bigint_helpers::impl_desc!()] 7 | impl $BUint { 8 | crate::int::bigint_helpers::impls!(U); 9 | 10 | #[doc = doc::bigint_helpers::widening_mul!(U)] 11 | #[must_use = doc::must_use_op!()] 12 | #[inline] 13 | pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { 14 | let mut low = Self::ZERO; 15 | let mut high = Self::ZERO; 16 | let mut carry: $Digit; 17 | 18 | let mut i = 0; 19 | while i < N { 20 | carry = 0; 21 | let mut j = 0; 22 | while j < N - i { 23 | let index = i + j; 24 | let d = low.digits[index]; 25 | let (new_digit, new_carry) = 26 | digit::$Digit::carrying_mul(self.digits[i], rhs.digits[j], carry, d); 27 | carry = new_carry; 28 | low.digits[index] = new_digit; 29 | j += 1; 30 | } 31 | while j < N { 32 | let index = i + j - N; 33 | let d = high.digits[index]; 34 | let (new_digit, new_carry) = 35 | digit::$Digit::carrying_mul(self.digits[i], rhs.digits[j], carry, d); 36 | carry = new_carry; 37 | high.digits[index] = new_digit; 38 | j += 1; 39 | } 40 | high.digits[i] = carry; 41 | i += 1; 42 | } 43 | 44 | (low, high) 45 | } 46 | 47 | #[doc = doc::bigint_helpers::carrying_mul!(U)] 48 | #[must_use = doc::must_use_op!()] 49 | #[inline] 50 | pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { 51 | let (low, high) = self.widening_mul(rhs); 52 | let (low, overflow) = low.overflowing_add(carry); 53 | if overflow { 54 | (low, high.wrapping_add(Self::ONE)) 55 | } else { 56 | (low, high) 57 | } 58 | } 59 | } 60 | }; 61 | } 62 | 63 | #[cfg(all(test, feature = "nightly"))] // as bigint_helpers not stabilised yet 64 | crate::test::all_digit_tests! { 65 | crate::int::bigint_helpers::tests!(utest); 66 | 67 | #[cfg(test_int_bits = "64")] 68 | test_bignum! { 69 | function: ::widening_mul(a: utest, b: utest), 70 | cases: [ 71 | (utest::MAX, utest::MAX) 72 | ] 73 | } 74 | 75 | #[cfg(test_int_bits = "64")] 76 | test_bignum! { 77 | function: ::carrying_mul(a: utest, b: utest, c: utest), 78 | cases: [ 79 | (utest::MAX, utest::MAX, utest::MAX), 80 | (utest::MAX, utest::MAX, 1 as utest) 81 | ] 82 | } 83 | } 84 | 85 | crate::macro_impl!(bigint_helpers); 86 | -------------------------------------------------------------------------------- /src/buint/cmp.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::{Ord, Ordering, PartialOrd}; 2 | 3 | macro_rules! cmp { 4 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 5 | impl PartialOrd for $BUint { 6 | #[inline] 7 | fn partial_cmp(&self, other: &Self) -> Option { 8 | Some(self.cmp(other)) 9 | } 10 | } 11 | 12 | impl Ord for $BUint { 13 | #[inline] 14 | fn cmp(&self, other: &Self) -> Ordering { 15 | Self::cmp(self, other) 16 | } 17 | 18 | #[inline] 19 | fn max(self, other: Self) -> Self { 20 | Self::max(self, other) 21 | } 22 | 23 | #[inline] 24 | fn min(self, other: Self) -> Self { 25 | Self::min(self, other) 26 | } 27 | 28 | #[inline] 29 | fn clamp(self, min: Self, max: Self) -> Self { 30 | Self::clamp(self, min, max) 31 | } 32 | } 33 | }; 34 | } 35 | 36 | #[cfg(test)] 37 | crate::test::all_digit_tests! { 38 | crate::int::cmp::tests!(utest); 39 | } 40 | 41 | crate::macro_impl!(cmp); 42 | -------------------------------------------------------------------------------- /src/buint/const_trait_fillers.rs: -------------------------------------------------------------------------------- 1 | use crate::doc; 2 | use crate::ExpType; 3 | use core::cmp::Ordering; 4 | 5 | macro_rules! const_trait_fillers { 6 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 7 | #[doc = doc::const_trait_fillers::impl_desc!()] 8 | impl $BUint { 9 | #[inline] 10 | pub const fn bitand(self, rhs: Self) -> Self { 11 | let mut out = Self::ZERO; 12 | let mut i = 0; 13 | while i < N { 14 | out.digits[i] = self.digits[i] & rhs.digits[i]; 15 | i += 1; 16 | } 17 | out 18 | } 19 | 20 | #[inline] 21 | pub const fn bitor(self, rhs: Self) -> Self { 22 | let mut out = Self::ZERO; 23 | let mut i = 0; 24 | while i < N { 25 | out.digits[i] = self.digits[i] | rhs.digits[i]; 26 | i += 1; 27 | } 28 | out 29 | } 30 | 31 | #[inline] 32 | pub const fn bitxor(self, rhs: Self) -> Self { 33 | let mut out = Self::ZERO; 34 | let mut i = 0; 35 | while i < N { 36 | out.digits[i] = self.digits[i] ^ rhs.digits[i]; 37 | i += 1; 38 | } 39 | out 40 | } 41 | 42 | #[inline] 43 | pub const fn not(self) -> Self { 44 | let mut out = Self::ZERO; 45 | let mut i = 0; 46 | while i < N { 47 | out.digits[i] = !self.digits[i]; 48 | i += 1; 49 | } 50 | out 51 | } 52 | 53 | #[inline] 54 | pub const fn eq(&self, other: &Self) -> bool { 55 | let mut i = 0; 56 | while i < N { 57 | if self.digits[i] != other.digits[i] { 58 | return false; 59 | } 60 | i += 1; 61 | } 62 | true 63 | } 64 | 65 | #[inline] 66 | pub const fn ne(&self, other: &Self) -> bool { 67 | !Self::eq(self, other) 68 | } 69 | 70 | #[inline] 71 | pub const fn cmp(&self, other: &Self) -> Ordering { 72 | let mut i = N; 73 | while i > 0 { 74 | i -= 1; 75 | let a = self.digits[i]; 76 | let b = other.digits[i]; 77 | 78 | // Clippy: don't use match here as `cmp` is not yet const for primitive integers 79 | #[allow(clippy::comparison_chain)] 80 | if a > b { 81 | return Ordering::Greater; 82 | } else if a < b { 83 | return Ordering::Less; 84 | } 85 | } 86 | Ordering::Equal 87 | } 88 | 89 | crate::int::cmp::impls!(); 90 | 91 | crate::int::ops::trait_fillers!(); 92 | 93 | #[inline] 94 | pub const fn div(self, rhs: Self) -> Self { 95 | self.wrapping_div(rhs) 96 | } 97 | 98 | #[inline] 99 | pub const fn rem(self, rhs: Self) -> Self { 100 | self.wrapping_rem(rhs) 101 | } 102 | } 103 | }; 104 | } 105 | 106 | crate::macro_impl!(const_trait_fillers); 107 | -------------------------------------------------------------------------------- /src/buint/consts.rs: -------------------------------------------------------------------------------- 1 | macro_rules! pos_const { 2 | ($($name: ident $num: literal), *) => { 3 | $( 4 | #[doc = doc::consts::value_desc!($num)] 5 | pub const $name: Self = Self::from_digit($num); 6 | )* 7 | } 8 | } 9 | 10 | use crate::digit; 11 | use crate::doc; 12 | use crate::ExpType; 13 | 14 | macro_rules! consts { 15 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 16 | #[doc = doc::consts::impl_desc!()] 17 | impl $BUint { 18 | #[doc = doc::consts::min!(U 512)] 19 | pub const MIN: Self = Self::from_digits([$Digit::MIN; N]); 20 | 21 | #[doc = doc::consts::max!(U 512)] 22 | pub const MAX: Self = Self::from_digits([$Digit::MAX; N]); 23 | 24 | #[doc = doc::consts::bits!(U 512, 512)] 25 | pub const BITS: ExpType = digit::$Digit::BITS * N as ExpType; 26 | 27 | #[doc = doc::consts::bytes!(U 512, 512)] 28 | pub const BYTES: ExpType = Self::BITS / 8; 29 | 30 | #[doc = doc::consts::zero!(U 512)] 31 | pub const ZERO: Self = Self::MIN; 32 | 33 | pos_const!(ONE 1, TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); 34 | } 35 | }; 36 | } 37 | 38 | crate::macro_impl!(consts); 39 | -------------------------------------------------------------------------------- /src/buint/fmt.rs: -------------------------------------------------------------------------------- 1 | use crate::digit; 2 | use alloc::string::String; 3 | use core::fmt::Write; 4 | use core::fmt::{Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, UpperExp, UpperHex}; 5 | 6 | macro_rules! fmt { 7 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 8 | macro_rules! fmt_method { 9 | ($format: expr, $format_pad: expr, $pad: expr, $prefix: expr) => { 10 | #[inline] 11 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 12 | let mut format_string = String::new(); 13 | for digit in self.digits.iter().rev() { 14 | if format_string.is_empty() { 15 | if digit != &0 { 16 | write!(format_string, $format, digit)?; 17 | } 18 | } else { 19 | write!(format_string, $format_pad, digit, $pad)?; 20 | } 21 | } 22 | f.pad_integral( 23 | true, 24 | $prefix, 25 | if format_string.is_empty() { 26 | "0" 27 | } else { 28 | &format_string 29 | }, 30 | ) 31 | } 32 | }; 33 | } 34 | 35 | impl Binary for $BUint { 36 | /*#[inline] 37 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 38 | f.pad_integral(true, "0b", &self.to_str_radix(2)) 39 | }*/ 40 | fmt_method!("{:b}", "{:01$b}", digit::$Digit::BITS as usize, "0b"); 41 | } 42 | 43 | impl Debug for $BUint { 44 | #[inline] 45 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 46 | Display::fmt(&self, f) 47 | } 48 | } 49 | 50 | impl Display for $BUint { 51 | #[inline] 52 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 53 | f.pad_integral(true, "", &self.to_str_radix(10)) 54 | } 55 | } 56 | 57 | macro_rules! exp_fmt { 58 | ($e: expr) => { 59 | #[inline] 60 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 61 | let decimal_str = self.to_str_radix(10); 62 | let buf = if decimal_str == "0" { 63 | format!("{}{}0", 0, $e) 64 | } else { 65 | let exp = decimal_str.len() - 1; 66 | let decimal_str = decimal_str.trim_end_matches('0'); 67 | if decimal_str.len() == 1 { 68 | format!("{}{}{}", &decimal_str[0..1], $e, exp) 69 | } else { 70 | format!( 71 | "{}.{}{}{}", 72 | &decimal_str[0..1], 73 | &decimal_str[1..], 74 | $e, 75 | exp 76 | ) 77 | } 78 | }; 79 | f.pad_integral(true, "", &buf) 80 | } 81 | }; 82 | } 83 | 84 | impl LowerExp for $BUint { 85 | exp_fmt!("e"); 86 | } 87 | 88 | impl LowerHex for $BUint { 89 | fmt_method!("{:x}", "{:01$x}", digit::$Digit::HEX_PADDING, "0x"); 90 | } 91 | 92 | impl Octal for $BUint { 93 | #[inline] 94 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 95 | let string = self.to_str_radix(8); 96 | f.pad_integral(true, "0o", &string) 97 | } 98 | } 99 | 100 | impl UpperExp for $BUint { 101 | exp_fmt!("E"); 102 | } 103 | 104 | impl UpperHex for $BUint { 105 | fmt_method!("{:X}", "{:01$X}", digit::$Digit::HEX_PADDING, "0x"); 106 | } 107 | }; 108 | } 109 | 110 | #[cfg(test)] 111 | crate::test::all_digit_tests! { 112 | crate::int::fmt::tests!(utest); 113 | } 114 | 115 | crate::macro_impl!(fmt); -------------------------------------------------------------------------------- /src/buint/mask.rs: -------------------------------------------------------------------------------- 1 | // macro_rules! mask { 2 | // ($BUint: ident, $BInt: ident, $Digit: ident) => { 3 | // impl $BUint { 4 | // #[inline] 5 | // pub(crate) const fn least_significant_n_bits(self, n: ExpType) -> Self { 6 | // let mut mask = Self::ZERO; 7 | // let mut digit_index = n as usize >> digit::$Digit::BIT_SHIFT; 8 | // let mut i = 0; 9 | // while i < digit_index { 10 | // mask.digits[i] = $Digit::MAX; 11 | // i += 1; 12 | // } 13 | 14 | // self.bitand(mask) 15 | // } 16 | // } 17 | // }; 18 | // } -------------------------------------------------------------------------------- /src/buint/mul.rs: -------------------------------------------------------------------------------- 1 | use crate::digit; 2 | 3 | macro_rules! mul { 4 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 5 | impl $BUint { 6 | #[inline] 7 | pub(super) const fn long_mul(self, rhs: Self) -> (Self, bool) { 8 | let mut overflow = false; 9 | let mut out = Self::ZERO; 10 | let mut carry: $Digit; 11 | 12 | let mut i = 0; 13 | while i < N { 14 | carry = 0; 15 | let mut j = 0; 16 | while j < N { 17 | let index = i + j; 18 | if index < N { 19 | let (prod, c) = digit::$Digit::carrying_mul( 20 | self.digits[i], 21 | rhs.digits[j], 22 | carry, 23 | out.digits[index], 24 | ); 25 | out.digits[index] = prod; 26 | carry = c; 27 | } else if self.digits[i] != 0 && rhs.digits[j] != 0 { 28 | overflow = true; 29 | break; 30 | } 31 | j += 1; 32 | } 33 | if carry != 0 { 34 | overflow = true; 35 | } 36 | i += 1; 37 | } 38 | (out, overflow) 39 | } 40 | } 41 | } 42 | } 43 | 44 | // fn karatsuba(a: BUintD8, b: BUintD8, start_index: usize, end_index: usize) -> BUintD8 { 45 | // if a.last_digit_index() == 0 { 46 | // return b * a.digits[0]; 47 | // } 48 | // if b.last_digit_index() == 0 { 49 | // return a * b.digits[0]; 50 | // } 51 | // let mid_index = (start_index + end_index) / 2; // TODO: replace this with midpoint 52 | // let z2 = karatsuba(a, b, mid_index, end_index); 53 | // let z0 = karatsuba(a, b, end_index, mid_index); 54 | // // let d1 = abs_diff(x0, x1); 55 | // // let d2 = abs_diff(y0, y1); 56 | // // 57 | // // let a = karatsuba((x0 - x1)(y1 - y0)) 58 | // // let z1 = a + z2 59 | 60 | // todo!() 61 | // } 62 | 63 | // fn karat_widening(x: &mut [u8], y: &mut [u8]) -> (&mut [u8], &mut [u8]) { 64 | // debug_assert_eq!(x.len(), y.len()); 65 | // if x.len() == 1 { 66 | // let (a, b) = (x[0], y[0]); 67 | // let (c, d) = a.widening_mul(b); 68 | // x[0] = c; 69 | // y[0] = d; 70 | // return (x, y); 71 | // } 72 | // let m = x.len().div_ceil(2); // midpoint index 73 | // let (x0, x1) = x.split_at_mut(m); 74 | // let (y0, y1) = y.split_at_mut(m); 75 | // let (a1karat_widening(x1, y1); 76 | // karat_widening(x0, y0); 77 | // } 78 | 79 | crate::macro_impl!(mul); -------------------------------------------------------------------------------- /src/buint/ops.rs: -------------------------------------------------------------------------------- 1 | use crate::digit; 2 | use crate::ExpType; 3 | use core::ops::{ 4 | Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, 5 | Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, 6 | }; 7 | 8 | macro_rules! ops { 9 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 10 | impl Add<$Digit> for $BUint { 11 | type Output = Self; 12 | 13 | #[inline] 14 | fn add(self, rhs: $Digit) -> Self { 15 | let mut out = self; 16 | let result = digit::$Digit::carrying_add(out.digits[0], rhs, false); 17 | out.digits[0] = result.0; 18 | let mut carry = result.1; 19 | let mut i = 1; 20 | while i < N && carry { 21 | let result = out.digits[i].overflowing_add(1); 22 | out.digits[i] = result.0; 23 | carry = result.1; 24 | i += 1; 25 | } 26 | out 27 | } 28 | } 29 | 30 | impl BitAnd for $BUint { 31 | type Output = Self; 32 | 33 | #[inline] 34 | fn bitand(self, rhs: Self) -> Self { 35 | Self::bitand(self, rhs) 36 | } 37 | } 38 | 39 | impl BitOr for $BUint { 40 | type Output = Self; 41 | 42 | #[inline] 43 | fn bitor(self, rhs: Self) -> Self { 44 | Self::bitor(self, rhs) 45 | } 46 | } 47 | 48 | impl BitXor for $BUint { 49 | type Output = Self; 50 | 51 | #[inline] 52 | fn bitxor(self, rhs: Self) -> Self { 53 | Self::bitxor(self, rhs) 54 | } 55 | } 56 | 57 | impl Div for $BUint { 58 | type Output = Self; 59 | 60 | #[inline] 61 | fn div(self, rhs: Self) -> Self { 62 | Self::div(self, rhs) 63 | } 64 | } 65 | 66 | impl Div<$Digit> for $BUint { 67 | type Output = Self; 68 | 69 | #[inline] 70 | fn div(self, rhs: $Digit) -> Self { 71 | self.div_rem_digit(rhs).0 72 | } 73 | } 74 | 75 | impl Not for $BUint { 76 | type Output = Self; 77 | 78 | #[inline] 79 | fn not(self) -> Self { 80 | Self::not(self) 81 | } 82 | } 83 | 84 | impl Rem for $BUint { 85 | type Output = Self; 86 | 87 | #[inline] 88 | fn rem(self, rhs: Self) -> Self { 89 | Self::rem(self, rhs) 90 | } 91 | } 92 | 93 | impl Rem<$Digit> for $BUint { 94 | type Output = $Digit; 95 | 96 | #[inline] 97 | fn rem(self, rhs: $Digit) -> $Digit { 98 | self.div_rem_digit(rhs).1 99 | } 100 | } 101 | 102 | crate::int::ops::impls!($BUint, $BUint, $BInt); 103 | 104 | #[cfg(all(test, test_int_bits = "64"))] 105 | paste::paste! { 106 | mod [<$Digit _add_digit_test>] { 107 | use super::*; 108 | use crate::test::{test_bignum, types::utest}; 109 | use crate::test::types::big_types::$Digit::*; 110 | 111 | quickcheck::quickcheck! { 112 | fn add_digit(a: utest, b: $Digit) -> quickcheck::TestResult { 113 | use crate::cast::As; 114 | 115 | let c: utest = b.as_(); 116 | match a.checked_add(c) { 117 | None => quickcheck::TestResult::discard(), 118 | Some(_d) => { 119 | let e: UTEST = b.as_(); 120 | let f: UTEST = a.as_(); 121 | quickcheck::TestResult::from_bool(f + e == f + b) 122 | } 123 | } 124 | } 125 | } 126 | } 127 | } 128 | }; 129 | } 130 | 131 | #[cfg(test)] 132 | crate::test::all_digit_tests! { 133 | use crate::test::{test_bignum, types::utest}; 134 | 135 | crate::int::ops::tests!(utest); 136 | } 137 | 138 | crate::macro_impl!(ops); 139 | -------------------------------------------------------------------------------- /src/buint/saturating.rs: -------------------------------------------------------------------------------- 1 | use crate::doc; 2 | use crate::ExpType; 3 | 4 | macro_rules! saturating { 5 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 6 | #[doc = doc::saturating::impl_desc!()] 7 | impl $BUint { 8 | #[inline] 9 | const fn saturate_up((int, overflow): ($BUint, bool)) -> $BUint { 10 | if overflow { 11 | $BUint::MAX 12 | } else { 13 | int 14 | } 15 | } 16 | 17 | #[inline] 18 | const fn saturate_down((int, overflow): ($BUint, bool)) -> $BUint { 19 | if overflow { 20 | $BUint::MIN 21 | } else { 22 | int 23 | } 24 | } 25 | 26 | #[doc = doc::saturating::saturating_add!(U)] 27 | #[must_use = doc::must_use_op!()] 28 | #[inline] 29 | pub const fn saturating_add(self, rhs: Self) -> Self { 30 | Self::saturate_up(self.overflowing_add(rhs)) 31 | } 32 | 33 | #[doc = doc::saturating::saturating_add_signed!(U)] 34 | #[must_use = doc::must_use_op!()] 35 | #[inline] 36 | pub const fn saturating_add_signed(self, rhs: $BInt) -> Self { 37 | if rhs.is_negative() { 38 | Self::saturate_down(self.overflowing_add_signed(rhs)) 39 | } else { 40 | Self::saturate_up(self.overflowing_add_signed(rhs)) 41 | } 42 | } 43 | 44 | #[doc = doc::saturating::saturating_sub!(U)] 45 | #[must_use = doc::must_use_op!()] 46 | #[inline] 47 | pub const fn saturating_sub(self, rhs: Self) -> Self { 48 | Self::saturate_down(self.overflowing_sub(rhs)) 49 | } 50 | 51 | #[doc = doc::saturating::saturating_mul!(U)] 52 | #[must_use = doc::must_use_op!()] 53 | #[inline] 54 | pub const fn saturating_mul(self, rhs: Self) -> Self { 55 | Self::saturate_up(self.overflowing_mul(rhs)) 56 | } 57 | 58 | #[doc = doc::saturating::saturating_div!(U)] 59 | #[must_use = doc::must_use_op!()] 60 | #[inline] 61 | pub const fn saturating_div(self, rhs: Self) -> Self { 62 | self.div_euclid(rhs) 63 | } 64 | 65 | #[doc = doc::saturating::saturating_pow!(U)] 66 | #[must_use = doc::must_use_op!()] 67 | #[inline] 68 | pub const fn saturating_pow(self, exp: ExpType) -> Self { 69 | Self::saturate_up(self.overflowing_pow(exp)) 70 | } 71 | } 72 | }; 73 | } 74 | 75 | #[cfg(test)] 76 | crate::test::all_digit_tests! { 77 | use crate::test::test_bignum; 78 | use crate::test::types::*; 79 | 80 | test_bignum! { 81 | function: ::saturating_add(a: utest, b: utest) 82 | } 83 | test_bignum! { 84 | function: ::saturating_add_signed(a: utest, b: itest) 85 | } 86 | test_bignum! { 87 | function: ::saturating_sub(a: utest, b: utest) 88 | } 89 | test_bignum! { 90 | function: ::saturating_mul(a: utest, b: utest) 91 | } 92 | test_bignum! { 93 | function: ::saturating_div(a: utest, b: utest), 94 | skip: b == 0 95 | } 96 | test_bignum! { 97 | function: ::saturating_pow(a: utest, b: u16) 98 | } 99 | } 100 | 101 | crate::macro_impl!(saturating); 102 | -------------------------------------------------------------------------------- /src/buint/strict.rs: -------------------------------------------------------------------------------- 1 | macro_rules! strict { 2 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 3 | #[doc = doc::strict::impl_desc!()] 4 | impl $BUint { 5 | crate::int::strict::impls!(U); 6 | 7 | #[doc = doc::strict::strict_add_signed!(U)] 8 | #[must_use = doc::must_use_op!()] 9 | #[inline] 10 | pub const fn strict_add_signed(self, rhs: $BInt) -> Self { 11 | crate::errors::option_expect!( 12 | self.checked_add_signed(rhs), 13 | crate::errors::err_msg!("attempt to add with overflow") 14 | ) 15 | } 16 | } 17 | }; 18 | } 19 | 20 | #[cfg(all(test, feature = "nightly"))] // as strict_overflow_ops not stabilised yet 21 | crate::test::all_digit_tests! { 22 | crate::int::strict::tests!(utest); 23 | 24 | test_bignum! { 25 | function: ::strict_add_signed(a: utest, b: itest), 26 | skip: a.checked_add_signed(b).is_none() 27 | } 28 | } 29 | 30 | use crate::doc; 31 | 32 | crate::macro_impl!(strict); 33 | -------------------------------------------------------------------------------- /src/buint/unchecked.rs: -------------------------------------------------------------------------------- 1 | macro_rules! unchecked { 2 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 3 | crate::int::unchecked::impls!($BUint, U); 4 | }; 5 | } 6 | 7 | #[cfg(test)] 8 | crate::test::all_digit_tests! { 9 | use crate::test::types::*; 10 | 11 | crate::int::unchecked::tests!(utest); 12 | } 13 | 14 | use crate::doc; 15 | 16 | crate::macro_impl!(unchecked); 17 | -------------------------------------------------------------------------------- /src/cast/float/float_from_uint.rs: -------------------------------------------------------------------------------- 1 | use crate::helpers::{Bits, One}; 2 | use crate::cast::CastFrom; 3 | use crate::ExpType; 4 | use super::FloatCastHelper; 5 | use core::ops::{Shr, Add}; 6 | 7 | pub trait CastFloatFromUintHelper: Bits + Shr { 8 | fn trailing_zeros(self) -> ExpType; 9 | } 10 | 11 | macro_rules! impl_cast_float_from_uint_helper_for_primitive_uint { 12 | ($($uint: ty), *) => { 13 | $( 14 | impl CastFloatFromUintHelper for $uint { 15 | #[inline] 16 | fn trailing_zeros(self) -> ExpType { 17 | Self::trailing_zeros(self) as ExpType 18 | } 19 | } 20 | )* 21 | }; 22 | } 23 | 24 | impl_cast_float_from_uint_helper_for_primitive_uint!(u8, u16, u32, u64, u128, usize); 25 | 26 | pub fn cast_float_from_uint(value: U) -> F 27 | where 28 | F: FloatCastHelper, 29 | F::SignedExp: TryFrom + One + Add, 30 | F::Mantissa: CastFrom + One, 31 | U: CastFloatFromUintHelper + Copy 32 | { 33 | let bit_width = value.bits(); // number of bits needed to specify value = exponent of largest power of two smaller than value. so bit_width will be one less than the exponent of the float 34 | // let mant = if F::M::BITS < U::BITS { 35 | 36 | // } 37 | if bit_width == 0 { 38 | // in this case, value is zero 39 | return F::ZERO; 40 | } 41 | let exponent = bit_width - 1; // value lies in range [2^(bit_width - 1), 2^bit_width) 42 | 43 | match F::SignedExp::try_from(exponent) { 44 | Ok(mut exponent) => { 45 | if exponent >= F::MAX_EXP { 46 | // exponent is too large 47 | return F::INFINITY; 48 | } 49 | let mantissa = if bit_width <= F::MANTISSA_DIGITS { 50 | // in this case, we can safely cast which preserves the value (no truncation) 51 | F::Mantissa::cast_from(value) << (F::MANTISSA_DIGITS - bit_width) 52 | } else { 53 | // note: we know that exponent >= F::MANTISSA_DIGITS, so only way 54 | // TODO: we could generalise the round_mantissa_exponent code so that this could just be a call of round_mantissa_exponent instead 55 | let shift = bit_width - F::MANTISSA_DIGITS; 56 | let gte_half = value.bit(shift - 1); // is the discarded part greater than or equal to a half? 57 | let mut shifted_mantissa = F::Mantissa::cast_from(value >> shift); 58 | if gte_half && (shifted_mantissa.bit(0) || value.trailing_zeros() != shift - 1) { 59 | // by ties-to-even rule, round up 60 | shifted_mantissa = shifted_mantissa + F::Mantissa::ONE; 61 | if shifted_mantissa.bit(F::MANTISSA_DIGITS) { 62 | // adding one overflowed to greater than mantissa width, so increment exponent and renormalised mantissa 63 | shifted_mantissa = shifted_mantissa >> 1; 64 | exponent = exponent + F::SignedExp::ONE; 65 | } 66 | } 67 | shifted_mantissa 68 | }; 69 | F::from_signed_parts(false, exponent, mantissa) 70 | }, 71 | _ => F::INFINITY, // in this case, the exponent doesn't even fit into the float signed exponent, so is too big to be stored by F 72 | } 73 | } -------------------------------------------------------------------------------- /src/cast/float/uint_from_float.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Neg, Shl}; 2 | use crate::cast::CastFrom; 3 | use crate::ExpType; 4 | use super::FloatMantissa; 5 | use super::FloatCastHelper; 6 | use crate::helpers::{Bits, One, Zero}; 7 | 8 | pub trait CastUintFromFloatHelper: Zero + One + Bits { 9 | const MAX: Self; 10 | const MIN: Self; 11 | } 12 | 13 | macro_rules! impl_cast_uint_from_float_helper_for_primitive_uint { 14 | ($($uint: ident), *) => { 15 | $( 16 | impl CastUintFromFloatHelper for $uint { 17 | const MAX: Self = Self::MAX; 18 | const MIN: Self = Self::MIN; 19 | } 20 | )* 21 | }; 22 | } 23 | 24 | impl_cast_uint_from_float_helper_for_primitive_uint!(u8, u16, u32, u64, u128, usize); 25 | 26 | pub fn cast_uint_from_float(value: F) -> U 27 | where 28 | F: FloatCastHelper + core::fmt::Debug, 29 | F::Mantissa: Bits, 30 | ExpType: TryFrom, 31 | U: CastUintFromFloatHelper 32 | + CastFrom 33 | + Shl 34 | + core::fmt::Debug, 35 | F::SignedExp: One + Neg, 36 | { 37 | if value.is_nan() { 38 | return U::ZERO; 39 | } 40 | let is_infinite = value.is_infinite(); // store this value first, as then we check if value is infinite after checking if it is negative, as we don't want to return MAX for negative infinity 41 | let (sign, exp, mant) = value.into_normalised_signed_parts(); 42 | if sign { 43 | return U::MIN; 44 | } 45 | if is_infinite { 46 | return U::MAX; 47 | } 48 | if mant == F::Mantissa::ZERO { 49 | return U::ZERO; 50 | } 51 | if exp < -F::SignedExp::ONE { 52 | // in this case, the value is at most a half, so we round (ties to even) to zero 53 | return U::ZERO; 54 | } 55 | if exp == -F::SignedExp::ONE { 56 | // exponent is -1, so value is in range [1/2, 1) 57 | if mant.is_power_of_two() { 58 | // in this case, the value is exactly 1/2, so we round (ties to even) to zero 59 | return U::ZERO; 60 | } 61 | return U::ONE; 62 | } 63 | // now we know that the exponent is non-negative so can shift 64 | // As per Rust's numeric casting semantics (https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast), casting a float to an integer truncates rather than using ties to even 65 | 66 | match ExpType::try_from(exp) { 67 | Ok(exp) => { 68 | if exp >= U::BITS { 69 | return U::MAX; 70 | } 71 | let mant_bit_width = mant.bits(); 72 | if exp <= mant_bit_width - 1 { 73 | // in this case, we have a fractional part to truncate 74 | U::cast_from(mant >> (mant_bit_width - 1 - exp)) // the right shift means the mantissa now has exp + 1 bits, and as we must have exp < U::BITS, the shifted mantissa is no wider than U 75 | } else { 76 | U::cast_from(mant) << (exp - (mant_bit_width - 1)) 77 | } 78 | } 79 | _ => U::MAX, 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/cast/mod.rs: -------------------------------------------------------------------------------- 1 | //! Panic-free casting between numeric types. 2 | 3 | /// Backend implementation trait for panic-free casting between numeric types. 4 | pub trait CastFrom { 5 | fn cast_from(from: T) -> Self; 6 | } 7 | 8 | #[cfg(test)] 9 | pub(crate) trait CastTo { 10 | fn cast_to(self) -> U; 11 | } 12 | 13 | macro_rules! as_trait_doc { 14 | () => { 15 | "Trait which allows panic-free casting between numeric types. 16 | 17 | The behavior matches the behavior of the `as` conversion operator between primitive integers. This trait can be used to convert between bnum's integer types, as well as between bnum's integer types and Rust's primitive integers. Conversions between Rust's primitive integers themselves are also defined for consistency." 18 | }; 19 | } 20 | 21 | macro_rules! as_method_doc { 22 | () => { 23 | "Casts `self` to type `T`. The [semantics of numeric casting](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics) with the `as` operator are followed, so `::as_::` can be used in the same way as `T as U` for numeric conversions. 24 | 25 | # Examples 26 | 27 | ``` 28 | use bnum::types::{U256, I512, I256, U1024}; 29 | use bnum::cast::As; 30 | 31 | // Cast `u64` to `U256`: 32 | let a = 399872465243u64; 33 | let b: U256 = a.as_(); 34 | assert_eq!(a.as_::(), b.as_()); 35 | 36 | // Cast `i128` to `I512`: 37 | let c = -2098409234529234584094i128; 38 | let d = c.as_::(); 39 | //assert_eq!(c.as::(), d.as_()); 40 | 41 | // Cast `I512` to `U1024` (result will be sign-extended with leading ones): 42 | let e: U1024 = d.as_(); 43 | assert_eq!(d, e.as_()); 44 | 45 | // Cast `U256` to `f64` and back: 46 | let f: f64 = b.as_(); 47 | assert_eq!(b, f.as_()); 48 | ```" 49 | }; 50 | } 51 | 52 | #[cfg(feature = "nightly")] 53 | macro_rules! as_trait { 54 | () => { 55 | // impl const CastTo for T 56 | #[cfg(test)] 57 | impl CastTo for T 58 | where 59 | // U: ~const CastFrom, 60 | U: CastFrom, 61 | { 62 | fn cast_to(self) -> U { 63 | U::cast_from(self) 64 | } 65 | } 66 | 67 | #[doc = as_trait_doc!()] 68 | // #[const_trait] 69 | pub trait As { 70 | #[doc = as_method_doc!()] 71 | fn as_(self) -> T 72 | where 73 | T: CastFrom, 74 | Self: Sized; 75 | } 76 | 77 | // impl const As for U { 78 | impl As for U { 79 | #[inline] 80 | fn as_(self) -> T 81 | where 82 | // T: ~const CastFrom, 83 | T: CastFrom, 84 | Self: Sized, 85 | { 86 | T::cast_from(self) 87 | } 88 | } 89 | }; 90 | } 91 | 92 | #[cfg(not(feature = "nightly"))] 93 | macro_rules! as_trait { 94 | () => { 95 | #[cfg(test)] 96 | impl CastTo for T 97 | where 98 | U: CastFrom, 99 | { 100 | fn cast_to(self) -> U { 101 | U::cast_from(self) 102 | } 103 | } 104 | 105 | #[doc = as_trait_doc!()] 106 | pub trait As { 107 | #[doc = as_method_doc!()] 108 | fn as_(self) -> T 109 | where 110 | T: CastFrom, 111 | Self: Sized; 112 | } 113 | 114 | impl As for U { 115 | #[inline] 116 | fn as_(self) -> T 117 | where 118 | T: CastFrom, 119 | Self: Sized, 120 | { 121 | T::cast_from(self) 122 | } 123 | } 124 | }; 125 | } 126 | 127 | as_trait!(); 128 | 129 | macro_rules! primitive_cast_impl { 130 | ($from: ty as [$($ty: ty), *]) => { 131 | $( 132 | impl CastFrom<$from> for $ty { 133 | #[inline] 134 | fn cast_from(from: $from) -> Self { 135 | from as Self 136 | } 137 | } 138 | )* 139 | }; 140 | } 141 | 142 | macro_rules! multiple_impls { 143 | ($($from: ty), *) => { 144 | $( 145 | primitive_cast_impl!($from as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64]); 146 | )* 147 | }; 148 | } 149 | 150 | primitive_cast_impl!(bool as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool]); 151 | primitive_cast_impl!(char as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, char]); 152 | primitive_cast_impl!(u8 as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, char]); 153 | multiple_impls!(u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); 154 | 155 | pub(crate) mod float; -------------------------------------------------------------------------------- /src/digit.rs: -------------------------------------------------------------------------------- 1 | macro_rules! digit_module { 2 | ($Digit: ident, $SignedDigit: ty, $DoubleDigit: ty) => { 3 | pub mod $Digit { 4 | mod types { 5 | pub type Digit = $Digit; 6 | 7 | pub type SignedDigit = $SignedDigit; 8 | 9 | pub type DoubleDigit = $DoubleDigit; 10 | } 11 | 12 | use crate::ExpType; 13 | 14 | pub use types::*; 15 | 16 | pub const BITS: ExpType = $Digit::BITS as ExpType; 17 | 18 | pub const BITS_U8: u8 = BITS as u8; 19 | 20 | pub const BITS_MINUS_1: ExpType = BITS - 1; 21 | 22 | pub const BYTES: ExpType = BITS / 8; 23 | 24 | // This calculates log2 of BYTES as BYTES is guaranteed to only have one '1' bit, since it must be a power of two. 25 | pub const BYTE_SHIFT: ExpType = BYTES.trailing_zeros() as ExpType; 26 | 27 | pub const BIT_SHIFT: ExpType = BITS.trailing_zeros() as ExpType; 28 | 29 | #[inline] 30 | pub const fn to_double_digit(low: Digit, high: Digit) -> DoubleDigit { 31 | ((high as DoubleDigit) << BITS) | low as DoubleDigit 32 | } 33 | 34 | // TODO: these will no longer be necessary once const_bigint_helper_methods is stabilised: https://github.com/rust-lang/rust/issues/85532 35 | 36 | #[inline] 37 | pub const fn carrying_add(a: Digit, b: Digit, carry: bool) -> (Digit, bool) { 38 | let (s1, o1) = a.overflowing_add(b); 39 | if carry { 40 | let (s2, o2) = s1.overflowing_add(1); 41 | (s2, o1 || o2) 42 | } else { 43 | (s1, o1) 44 | } 45 | } 46 | 47 | #[inline] 48 | pub const fn borrowing_sub(a: Digit, b: Digit, borrow: bool) -> (Digit, bool) { 49 | let (s1, o1) = a.overflowing_sub(b); 50 | if borrow { 51 | let (s2, o2) = s1.overflowing_sub(1); 52 | (s2, o1 || o2) 53 | } else { 54 | (s1, o1) 55 | } 56 | } 57 | 58 | #[inline] 59 | pub const fn carrying_add_signed( 60 | a: SignedDigit, 61 | b: SignedDigit, 62 | carry: bool, 63 | ) -> (SignedDigit, bool) { 64 | let (s1, o1) = a.overflowing_add(b); 65 | if carry { 66 | let (s2, o2) = s1.overflowing_add(1); 67 | (s2, o1 != o2) 68 | } else { 69 | (s1, o1) 70 | } 71 | } 72 | 73 | #[inline] 74 | pub const fn borrowing_sub_signed( 75 | a: SignedDigit, 76 | b: SignedDigit, 77 | borrow: bool, 78 | ) -> (SignedDigit, bool) { 79 | let (s1, o1) = a.overflowing_sub(b); 80 | if borrow { 81 | let (s2, o2) = s1.overflowing_sub(1); 82 | (s2, o1 != o2) 83 | } else { 84 | (s1, o1) 85 | } 86 | } 87 | 88 | #[inline] 89 | pub const fn widening_mul(a: Digit, b: Digit) -> (Digit, Digit) { 90 | let prod = a as DoubleDigit * b as DoubleDigit; 91 | (prod as Digit, (prod >> BITS) as Digit) 92 | } 93 | 94 | #[inline] 95 | pub const fn carrying_mul( 96 | a: Digit, 97 | b: Digit, 98 | carry: Digit, 99 | current: Digit, 100 | ) -> (Digit, Digit) { 101 | let prod = carry as DoubleDigit 102 | + current as DoubleDigit 103 | + (a as DoubleDigit) * (b as DoubleDigit); 104 | (prod as Digit, (prod >> BITS) as Digit) 105 | } 106 | 107 | #[inline] 108 | pub const fn div_rem_wide(low: Digit, high: Digit, rhs: Digit) -> (Digit, Digit) { 109 | debug_assert!(high < rhs); 110 | 111 | let a = to_double_digit(low, high); 112 | ( 113 | (a / rhs as DoubleDigit) as Digit, 114 | (a % rhs as DoubleDigit) as Digit, 115 | ) 116 | } 117 | 118 | pub const HEX_PADDING: usize = BITS as usize / 4; 119 | } 120 | }; 121 | } 122 | 123 | digit_module!(u8, i8, u16); 124 | digit_module!(u16, i16, u32); 125 | digit_module!(u32, i32, u64); 126 | digit_module!(u64, i64, u128); 127 | -------------------------------------------------------------------------------- /src/doc/bigint_helpers.rs: -------------------------------------------------------------------------------- 1 | use crate::doc; 2 | 3 | macro_rules! impl_desc { 4 | () => { 5 | "Bigint helper methods: common functions used to implement big integer arithmetic." 6 | }; 7 | } 8 | 9 | pub(crate) use impl_desc; 10 | 11 | doc::link_doc_comment_method!(carrying_add, borrowing_sub, widening_mul, carrying_mul); 12 | -------------------------------------------------------------------------------- /src/doc/checked.rs: -------------------------------------------------------------------------------- 1 | use crate::doc; 2 | 3 | macro_rules! impl_desc { 4 | () => { 5 | doc::arithmetic_impl_desc!( 6 | "Checked", 7 | "checked", 8 | "Each method cannot panic and returns an `Option`. `None` is returned when overflow would have occurred or there was an attempt to divide by zero or calculate a remainder with a divisor of zero." 9 | ) 10 | }; 11 | } 12 | 13 | pub(crate) use impl_desc; 14 | 15 | doc::link_doc_comment_method!( 16 | checked_abs, 17 | checked_add, 18 | checked_add_signed, 19 | checked_add_unsigned, 20 | checked_div, 21 | checked_div_euclid, 22 | checked_ilog, 23 | checked_ilog10, 24 | checked_ilog2, 25 | checked_mul, 26 | checked_neg, 27 | checked_next_multiple_of, 28 | checked_pow, 29 | checked_rem, 30 | checked_rem_euclid, 31 | checked_shl, 32 | checked_shr, 33 | checked_sub, 34 | checked_sub_unsigned 35 | ); 36 | 37 | macro_rules! checked_next_power_of_two { 38 | ($sign: ident $bits: literal) => { 39 | doc::doc_comment! { 40 | #method.checked_next_power_of_two, 41 | $sign $bits, 42 | "Returns the smallest power of two greater than or equal to `self`. If the next power of two is greater than `Self::MAX`, `None` is returned, otherwise the power of two is wrapped in `Some`.", 43 | 44 | "let n = " doc::type_str!($sign $bits) "::from(2u8);\n" 45 | "assert_eq!(n.checked_next_power_of_two(), Some(n));\n" 46 | "let m = " doc::type_str!($sign $bits) "::from(3u8);\n" 47 | "assert_eq!(" doc::type_str!($sign $bits) "::MAX.checked_next_power_of_two(), None);" 48 | } 49 | }; 50 | } 51 | 52 | pub(crate) use checked_next_power_of_two; 53 | -------------------------------------------------------------------------------- /src/doc/classify.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | "Classification methods: used to determine properties about the storage of the number." 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | is_sign_positive, 11 | is_sign_negative, 12 | is_finite, 13 | is_infinite, 14 | is_nan, 15 | is_subnormal, 16 | is_normal, 17 | classify 18 | ); -------------------------------------------------------------------------------- /src/doc/cmp.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | "Comparison methods." 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | max, 11 | min, 12 | maximum, 13 | minimum, 14 | clamp, 15 | total_cmp 16 | ); -------------------------------------------------------------------------------- /src/doc/const_trait_fillers.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | "The latest version of the nightly Rust compiler at the time `v0.7.0` was published (`v1.71.0-nightly`) unfortunately dropped support for the `const` implementation of common standard library traits such as `Add`, `BitOr`, etc. These methods below have therefore been provided to allow use of some of the methods these traits provided, in a const context." 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | -------------------------------------------------------------------------------- /src/doc/consts.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | "Associated constants for this type." 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | macro_rules! min { 10 | ($sign: ident $bits: literal) => { 11 | doc::doc_comment! { 12 | $sign $bits, 13 | "The minimum value that this type can represent.", 14 | 15 | "assert_eq!(!" doc::type_str!($sign $bits) "::MIN, " doc::type_str!($sign $bits) "::MAX);" 16 | } 17 | }; 18 | } 19 | 20 | pub(crate) use min; 21 | 22 | macro_rules! max { 23 | ($sign: ident $bits: literal) => { 24 | doc::doc_comment! { 25 | $sign $bits, 26 | "The maximum value that this type can represent.", 27 | 28 | "assert_eq!(" doc::type_str!($sign $bits) "::MAX.wrapping_add(" doc::type_str!($sign $bits) "::ONE), " doc::type_str!($sign $bits) "::MIN);" 29 | } 30 | }; 31 | } 32 | 33 | pub(crate) use max; 34 | 35 | macro_rules! zero { 36 | ($sign: ident $bits: literal) => { 37 | doc::doc_comment! { 38 | $sign $bits, 39 | doc::consts::value_desc!(0), 40 | 41 | "assert_eq!(" doc::type_str!($sign $bits) "::ZERO, " doc::type_str!($sign $bits) "::from(0u8));" 42 | } 43 | } 44 | } 45 | 46 | pub(crate) use zero; 47 | 48 | macro_rules! one { 49 | ($sign: ident $bits: literal) => { 50 | doc::doc_comment! { 51 | $sign $bits, 52 | doc::consts::value_desc!(1), 53 | 54 | "assert_eq!(" doc::type_str!($sign $bits) "::ONE, " doc::type_str!($sign $bits) "::from(1u8));" 55 | } 56 | } 57 | } 58 | 59 | pub(crate) use one; 60 | 61 | macro_rules! bits { 62 | ($sign: ident $bits: literal, $digit_bits: literal) => { 63 | doc::doc_comment! { 64 | $sign $bits, 65 | "The total number of bits that this type contains.", 66 | 67 | "assert_eq!(" doc::type_str!($sign $bits) "::BITS, " $digit_bits ");" 68 | } 69 | }; 70 | } 71 | 72 | pub(crate) use bits; 73 | 74 | macro_rules! bytes { 75 | ($sign: ident $bits: literal, $digit_bits: literal) => { 76 | doc::doc_comment! { 77 | $sign $bits, 78 | "The total number of bytes that this type contains.", 79 | 80 | "assert_eq!(" doc::type_str!($sign $bits) "::BYTES, " $digit_bits " / 8);" 81 | } 82 | }; 83 | } 84 | 85 | pub(crate) use bytes; 86 | 87 | macro_rules! value_desc { 88 | ($($lit: literal) +) => { 89 | concat!("The value of `", $($lit,)+ "` represented by this type.") 90 | } 91 | } 92 | 93 | pub(crate) use value_desc; 94 | 95 | // #[cfg(feature = "float")] 96 | // crate::doc::link_doc_comment_constant!( 97 | // RADIX, 98 | // MANTISSA_DIGITS, 99 | // DIGITS, 100 | // EPSILON, 101 | // MIN, 102 | // MIN_POSITIVE, 103 | // MAX, 104 | // MIN_EXP, 105 | // MAX_EXP, 106 | // // MIN_10_EXP, 107 | // // MAX_10_EXP, 108 | // NAN, 109 | // INFINITY, 110 | // NEG_INFINITY 111 | // ); -------------------------------------------------------------------------------- /src/doc/endian.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | ($ty: ty) => { 3 | concat!( 4 | "Methods which convert a `", 5 | stringify!($ty), 6 | "` to and from data stored in different endianness." 7 | ) 8 | }; 9 | } 10 | 11 | pub(crate) use impl_desc; 12 | 13 | macro_rules! from_be { 14 | ($sign: ident $bits: literal) => { 15 | doc::doc_comment! { 16 | #method.from_be, 17 | $sign $bits, 18 | "Converts an integer from big endian to the target’s endianness." 19 | "On big endian this is a no-op. On little endian the bytes are swapped." 20 | } 21 | }; 22 | } 23 | 24 | pub(crate) use from_be; 25 | 26 | macro_rules! from_le { 27 | ($sign: ident $bits: literal) => { 28 | doc::doc_comment! { 29 | #method.from_le, 30 | $sign $bits, 31 | "Converts an integer from little endian to the target’s endianness." 32 | "On little endian this is a no-op. On big endian the bytes are swapped." 33 | } 34 | }; 35 | } 36 | 37 | pub(crate) use from_le; 38 | 39 | macro_rules! to_be { 40 | ($sign: ident $bits: literal) => { 41 | doc::doc_comment! { 42 | #method.to_be, 43 | $sign $bits, 44 | "Converts `self` from big endian to the target’s endianness." 45 | "On big endian this is a no-op. On little endian the bytes are swapped." 46 | } 47 | }; 48 | } 49 | 50 | pub(crate) use to_be; 51 | 52 | macro_rules! to_le { 53 | ($sign: ident $bits: literal) => { 54 | doc::doc_comment! { 55 | #method.to_le, 56 | $sign $bits, 57 | "Converts `self` from little endian to the target’s endianness." 58 | "On little endian this is a no-op. On big endian the bytes are swapped." 59 | } 60 | }; 61 | } 62 | 63 | pub(crate) use to_le; 64 | 65 | #[cfg(feature = "nightly")] 66 | crate::doc::link_doc_comment_method! { 67 | to_be_bytes, 68 | to_le_bytes, 69 | to_ne_bytes, 70 | from_be_bytes, 71 | from_le_bytes, 72 | from_ne_bytes 73 | } 74 | -------------------------------------------------------------------------------- /src/doc/math.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | "Bigint helper methods: common functions used to implement big integer arithmetic." 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | abs, 11 | sqrt, 12 | div_euclid, 13 | rem_euclid, 14 | powi 15 | ); -------------------------------------------------------------------------------- /src/doc/overflowing.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | doc::arithmetic_impl_desc!("Overflowing", "overflowing", "Each method returns a tuple of type `(Self, bool)` where the first item of the tuple is the result of the calculation truncated to the number of bits of `self`, and the second item is a boolean which indicates whether overflow occurred (i.e. if the number of bits of the result of the calculation exceeded the number of bits of `self`).") 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | overflowing_abs, 11 | overflowing_add, 12 | overflowing_add_signed, 13 | overflowing_add_unsigned, 14 | overflowing_div, 15 | overflowing_div_euclid, 16 | overflowing_mul, 17 | overflowing_neg, 18 | overflowing_pow, 19 | overflowing_rem, 20 | overflowing_rem_euclid, 21 | overflowing_shl, 22 | overflowing_shr, 23 | overflowing_sub, 24 | overflowing_sub_unsigned 25 | ); 26 | -------------------------------------------------------------------------------- /src/doc/radix.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | ($ty: ty) => { 3 | concat!( 4 | "Methods which convert a `", 5 | stringify!($ty), 6 | "` between different types in a given radix (base)." 7 | ) 8 | }; 9 | } 10 | 11 | pub(crate) use impl_desc; 12 | 13 | macro_rules! parse_str_radix { 14 | ($ty: ty) => { 15 | concat!( 16 | "This function works the same as `from_str_radix` except that it returns a `", 17 | stringify!($ty), 18 | "` instead of a `Result<", 19 | stringify!($ty), 20 | ", ParseIntError>`. 21 | 22 | # Panics 23 | 24 | This function panics if `radix` is not in the range from 2 to 36 inclusive, or if the string cannot be parsed successfully. 25 | 26 | # Examples 27 | 28 | Basic usage: 29 | 30 | ```compile_fail 31 | // The below example will fail to compile, as the function will panic at compile time: 32 | use bnum::types::U256; 33 | 34 | const DOESNT_COMPILE: U256 = U256::parse_str_radix(\"a13423\", 10); 35 | // Gives a compile error of \"error[E0080]: evaluation of constant value failed... the evaluated program panicked at 'attempt to parse integer from string containing invalid digit'\", 36 | ```" 37 | ) 38 | } 39 | } 40 | 41 | pub(crate) use parse_str_radix; 42 | -------------------------------------------------------------------------------- /src/doc/rounding.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | "Rounding methods." 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | round, 11 | ceil, 12 | floor, 13 | trunc, 14 | fract 15 | ); -------------------------------------------------------------------------------- /src/doc/saturating.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | doc::arithmetic_impl_desc!("Saturating", "saturating", "For each method, if overflow or underflow occurs, the largest or smallest value that can be represented by `Self` is returned instead.") 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | saturating_abs, 11 | saturating_add, 12 | saturating_add_signed, 13 | saturating_add_unsigned, 14 | saturating_div, 15 | saturating_mul, 16 | saturating_neg, 17 | saturating_pow, 18 | saturating_sub, 19 | saturating_sub_unsigned 20 | ); 21 | -------------------------------------------------------------------------------- /src/doc/strict.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | doc::arithmetic_impl_desc!("Strict", "strict", "Each method will always panic if overflow/underflow occurs (i.e. when the checked equivalent would return `None`), regardless of whether overflow checks are enabled.") 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | strict_abs, 11 | strict_add, 12 | strict_add_signed, 13 | strict_add_unsigned, 14 | strict_div, 15 | strict_div_euclid, 16 | strict_mul, 17 | strict_neg, 18 | strict_pow, 19 | strict_rem, 20 | strict_rem_euclid, 21 | strict_shl, 22 | strict_shr, 23 | strict_sub, 24 | strict_sub_unsigned 25 | ); 26 | -------------------------------------------------------------------------------- /src/doc/unchecked.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | doc::arithmetic_impl_desc!("Unchecked", "unchecked", "Each method results in undefined behavior if overflow/underflow occurs (i.e. when the checked equivalent would return `None`).") 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | unchecked_add, 11 | unchecked_mul, 12 | unchecked_shl, 13 | unchecked_shr, 14 | unchecked_sub 15 | ); 16 | -------------------------------------------------------------------------------- /src/doc/wrapping.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_desc { 2 | () => { 3 | doc::arithmetic_impl_desc!("Wrapping", "wrapping", "Each method returns of the calculation truncated to the number of bits of `self` (i.e. they each return the first item in the tuple returned by their overflowing equivalent).") 4 | }; 5 | } 6 | 7 | pub(crate) use impl_desc; 8 | 9 | crate::doc::link_doc_comment_method!( 10 | wrapping_abs, 11 | wrapping_add, 12 | wrapping_add_signed, 13 | wrapping_add_unsigned, 14 | wrapping_div, 15 | wrapping_div_euclid, 16 | wrapping_mul, 17 | wrapping_neg, 18 | wrapping_pow, 19 | wrapping_rem, 20 | wrapping_rem_euclid, 21 | wrapping_shl, 22 | wrapping_shr, 23 | wrapping_sub, 24 | wrapping_sub_unsigned 25 | ); 26 | 27 | macro_rules! wrapping_next_power_of_two { 28 | ($sign: ident $bits: literal) => { 29 | doc::doc_comment! { 30 | #method.wrapping_next_power_of_two, 31 | $sign $bits, 32 | concat!("Returns the smallest power of two greater than or equal to `self`. If the next power of two is greater than `Self::MAX`, the return value is wrapped to `Self::MIN`."), 33 | 34 | "let n = " doc::type_str!($sign $bits) "::from(31u8);\n" 35 | "assert_eq!(n.wrapping_next_power_of_two(), 32u8.into());\n" 36 | "assert_eq!(" doc::type_str!($sign $bits) "::MAX.wrapping_next_power_of_two(), " doc::type_str!($sign $bits) "::MIN);" 37 | } 38 | }; 39 | } 40 | 41 | pub(crate) use wrapping_next_power_of_two; 42 | -------------------------------------------------------------------------------- /src/errors/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! err_prefix { 2 | () => { 3 | "(bnum)" 4 | }; 5 | } 6 | 7 | pub(crate) use err_prefix; 8 | 9 | macro_rules! err_msg { 10 | ($msg: expr) => { 11 | concat!(crate::errors::err_prefix!(), " ", $msg) 12 | }; 13 | } 14 | 15 | pub(crate) use err_msg; 16 | 17 | macro_rules! div_by_zero_message { 18 | () => { 19 | "attempt to divide by zero" 20 | }; 21 | } 22 | 23 | pub(crate) use div_by_zero_message; 24 | 25 | macro_rules! div_zero { 26 | () => { 27 | panic!(crate::errors::err_msg!(crate::errors::div_by_zero_message!())) 28 | }; 29 | } 30 | 31 | pub(crate) use div_zero; 32 | 33 | macro_rules! rem_by_zero_message { 34 | () => { 35 | "attempt to calculate the remainder with a divisor of zero" 36 | }; 37 | } 38 | 39 | pub(crate) use rem_by_zero_message; 40 | 41 | macro_rules! non_positive_log_message { 42 | () => { 43 | "argument of integer logarithm must be positive" 44 | } 45 | } 46 | 47 | pub(crate) use non_positive_log_message; 48 | 49 | macro_rules! invalid_log_base { 50 | () => { 51 | "base of integer logarithm must be at least 2" 52 | } 53 | } 54 | 55 | pub(crate) use invalid_log_base; 56 | 57 | macro_rules! rem_zero { 58 | () => { 59 | panic!(crate::errors::err_msg!(crate::errors::rem_by_zero_message!())) 60 | }; 61 | } 62 | 63 | pub(crate) use rem_zero; 64 | 65 | // TODO: this will become unnecessary when `const_option` is stabilised: https://github.com/rust-lang/rust/issues/67441. 66 | macro_rules! option_expect { 67 | ($option: expr, $msg: expr) => { 68 | match $option { 69 | Some(value) => value, 70 | _ => panic!($msg), 71 | } 72 | }; 73 | } 74 | pub(crate) use option_expect; 75 | 76 | macro_rules! result_expect { 77 | ($option: expr, $msg: expr) => { 78 | match $option { 79 | Ok(value) => value, 80 | _ => panic!($msg), 81 | } 82 | }; 83 | } 84 | pub(crate) use result_expect; 85 | -------------------------------------------------------------------------------- /src/errors/mod.rs: -------------------------------------------------------------------------------- 1 | //! A collection of errors specific to this crate's types that can occur when using them. 2 | 3 | mod macros; 4 | 5 | #[allow(unused_imports)] 6 | pub use macros::*; 7 | 8 | mod parseint; 9 | pub use parseint::*; 10 | 11 | mod tryfrom; 12 | pub use tryfrom::*; 13 | -------------------------------------------------------------------------------- /src/errors/parseint.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Debug, Display, Formatter}; 2 | use core::num::IntErrorKind; 3 | 4 | /// The error type that is returned when parsing an integer from an invalid source. 5 | /// 6 | /// This error can occur when the `from_str_radix` or [`FromStr::from_str`](https://doc.rust-lang.org/core/str/trait.FromStr.html#tymethod.from_str) methods of e.g. [`BUint`](crate::BUint::from_str_radix) are called with an invalid input string. 7 | #[derive(PartialEq, Eq, Clone, Debug)] 8 | pub struct ParseIntError { 9 | pub(crate) kind: IntErrorKind, 10 | } 11 | 12 | impl ParseIntError { 13 | /// Returns the enum [`IntErrorKind`](https://doc.rust-lang.org/core/num/enum.IntErrorKind.html), which shows the reason that the parsing input was invalid. 14 | pub const fn kind(&self) -> &IntErrorKind { 15 | &self.kind 16 | } 17 | 18 | pub(crate) const fn description(&self) -> &str { 19 | match &self.kind { 20 | IntErrorKind::Empty => "attempt to parse integer from empty string", 21 | IntErrorKind::InvalidDigit => { 22 | "attempt to parse integer from string containing invalid digit" 23 | } 24 | IntErrorKind::PosOverflow => { 25 | "attempt to parse integer too large to be represented by the target type" 26 | } 27 | IntErrorKind::NegOverflow => { 28 | "attempt to parse integer too small to be represented by the target type" 29 | } 30 | IntErrorKind::Zero => { 31 | "attempt to parse the integer `0` which cannot be represented by the target type" // for now this should never occur, unless we implement NonZeroU... types 32 | } 33 | _ => panic!("unsupported `IntErrorKind` variant"), // necessary as `IntErrorKind` is non-exhaustive 34 | } 35 | } 36 | } 37 | 38 | impl Display for ParseIntError { 39 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 40 | write!(f, "{} {}", super::err_prefix!(), self.description()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/errors/tryfrom.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Formatter}; 2 | 3 | /// The error type that is returned when a failed conversion from an integer occurs. 4 | /// 5 | /// This error will occur for example when using the [`TryFrom`](https://doc.rust-lang.org/core/convert/trait.TryFrom.html) trait to convert a negative [`i32`] to a [`BUint`](crate::BUint). 6 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] 7 | pub struct TryFromIntError(pub(crate) ()); 8 | 9 | const ERROR_MESSAGE: &str = concat!( 10 | super::err_prefix!(), 11 | "out of range integral type conversion attempted" 12 | ); 13 | 14 | impl Display for TryFromIntError { 15 | #[inline] 16 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 17 | write!(f, "{}", ERROR_MESSAGE) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/float/classify.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use crate::BUintD8; 3 | use core::num::FpCategory; 4 | use crate::doc; 5 | 6 | type Digit = u8; 7 | 8 | struct Masks; 9 | 10 | impl Masks { 11 | const FINITE_MASK: BUintD8 = Float::::INFINITY.to_bits(); 12 | } 13 | 14 | #[doc = doc::classify::impl_desc!()] 15 | impl Float { 16 | #[doc = doc::classify::is_sign_positive!(F)] 17 | #[inline(always)] 18 | pub const fn is_sign_positive(self) -> bool { 19 | !self.is_sign_negative() 20 | } 21 | 22 | #[doc = doc::classify::is_sign_negative!(F)] 23 | #[inline(always)] 24 | pub const fn is_sign_negative(self) -> bool { 25 | const A: Digit = (1 as Digit).rotate_right(1); 26 | self.bits.digits[W - 1] >= A 27 | } 28 | 29 | #[doc = doc::classify::is_finite!(F)] 30 | #[inline] 31 | pub const fn is_finite(self) -> bool { 32 | self.to_bits() 33 | .bitand(Masks::::FINITE_MASK) 34 | .ne(&Masks::::FINITE_MASK) 35 | } 36 | 37 | #[doc = doc::classify::is_infinite!(F)] 38 | #[inline] 39 | pub const fn is_infinite(self) -> bool { 40 | self.abs().to_bits().eq(&Masks::::FINITE_MASK) 41 | } 42 | 43 | #[doc = doc::classify::is_nan!(F)] 44 | #[inline] 45 | pub const fn is_nan(self) -> bool { 46 | !self.is_finite() && self.to_bits().trailing_zeros() < Self::MB 47 | } 48 | 49 | #[doc = doc::classify::is_subnormal!(F)] 50 | #[inline] 51 | pub const fn is_subnormal(self) -> bool { 52 | let lz = self.abs().to_bits().leading_zeros(); 53 | lz < Self::BITS && lz > Self::EXPONENT_BITS 54 | } 55 | 56 | #[doc = doc::classify::is_normal!(F)] 57 | #[inline] 58 | pub const fn is_normal(self) -> bool { 59 | matches!(self.classify(), FpCategory::Normal) 60 | } 61 | 62 | #[inline] 63 | pub const fn is_zero(&self) -> bool { 64 | let words = self.words(); 65 | let mut i = 0; 66 | while i < W - 1 { 67 | if words[i] != 0 { 68 | return false; 69 | } 70 | i += 1; 71 | } 72 | let last = words[W - 1]; 73 | last.trailing_zeros() >= Digit::BITS - 1 74 | } 75 | 76 | #[doc = doc::classify::classify!(F)] 77 | #[inline] 78 | pub const fn classify(self) -> FpCategory { 79 | let u = self.abs().to_bits(); 80 | if u.is_zero() { 81 | FpCategory::Zero 82 | } else if u.eq(&Self::INFINITY.to_bits()) { 83 | FpCategory::Infinite 84 | } else { 85 | let u = u.bitand(Masks::::FINITE_MASK); 86 | if u.is_zero() { 87 | FpCategory::Subnormal 88 | } else if u.eq(&Masks::::FINITE_MASK) { 89 | FpCategory::Nan 90 | } else { 91 | FpCategory::Normal 92 | } 93 | } 94 | } 95 | } 96 | 97 | #[cfg(test)] 98 | mod tests { 99 | use crate::test::test_bignum; 100 | use crate::test::types::{ftest, FTEST}; 101 | 102 | test_bignum! { 103 | function: ::is_sign_positive(a: ftest) 104 | } 105 | test_bignum! { 106 | function: ::is_sign_negative(a: ftest) 107 | } 108 | test_bignum! { 109 | function: ::is_finite(a: ftest) 110 | } 111 | test_bignum! { 112 | function: ::is_infinite(a: ftest) 113 | } 114 | test_bignum! { 115 | function: ::is_nan(a: ftest) 116 | } 117 | test_bignum! { 118 | function: ::is_subnormal(a: ftest) 119 | } 120 | test_bignum! { 121 | function: ::is_normal(a: ftest) 122 | } 123 | test_bignum! { 124 | function: ::classify(a: ftest) 125 | } 126 | 127 | #[test] 128 | fn is_zero() { 129 | let z1 = FTEST::ZERO; 130 | let z2 = FTEST::NEG_ZERO; 131 | assert!(z1.is_zero()); 132 | assert!(z2.is_zero()); 133 | assert!(!FTEST::ONE.is_zero()); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/float/cmp.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use crate::BIntD8; 3 | use crate::doc; 4 | use core::cmp::{Ordering, PartialEq, PartialOrd}; 5 | 6 | #[doc = doc::cmp::impl_desc!()] 7 | impl Float { 8 | #[doc = doc::cmp::max!(F)] 9 | #[must_use = doc::must_use_op!(comparison)] 10 | #[inline] 11 | pub const fn max(self, other: Self) -> Self { 12 | handle_nan!(other; self); 13 | handle_nan!(self; other); 14 | if let Ordering::Less = self.total_cmp(&other) { 15 | other 16 | } else { 17 | self 18 | } 19 | } 20 | 21 | #[doc = doc::cmp::min!(F)] 22 | #[must_use = doc::must_use_op!(comparison)] 23 | #[inline] 24 | pub const fn min(self, other: Self) -> Self { 25 | handle_nan!(other; self); 26 | handle_nan!(self; other); 27 | if let Ordering::Greater = self.total_cmp(&other) { 28 | other 29 | } else { 30 | self 31 | } 32 | } 33 | 34 | #[doc = doc::cmp::maximum!(F)] 35 | #[must_use = doc::must_use_op!(comparison)] 36 | #[inline] 37 | pub const fn maximum(self, other: Self) -> Self { 38 | handle_nan!(self; self); 39 | handle_nan!(other; other); 40 | if let Ordering::Less = self.total_cmp(&other) { 41 | other 42 | } else { 43 | self 44 | } 45 | } 46 | 47 | #[doc = doc::cmp::minimum!(F)] 48 | #[must_use = doc::must_use_op!(comparison)] 49 | #[inline] 50 | pub const fn minimum(self, other: Self) -> Self { 51 | handle_nan!(self; self); 52 | handle_nan!(other; other); 53 | if let Ordering::Greater = self.total_cmp(&other) { 54 | other 55 | } else { 56 | self 57 | } 58 | } 59 | 60 | #[doc = doc::cmp::clamp!(F)] 61 | #[must_use = doc::must_use_op!(float)] 62 | #[inline] 63 | pub const fn clamp(self, min: Self, max: Self) -> Self { 64 | assert!(min.le(&max)); 65 | let mut x = self; 66 | if x.lt(&min) { 67 | x = min; 68 | } 69 | if x.gt(&max) { 70 | x = max; 71 | } 72 | x 73 | } 74 | 75 | #[doc = doc::cmp::total_cmp!(F)] 76 | #[must_use] 77 | #[inline] 78 | pub const fn total_cmp(&self, other: &Self) -> Ordering { 79 | let left = self.to_signed_bits(); 80 | let right = other.to_signed_bits(); 81 | if left.is_negative() && right.is_negative() { 82 | BIntD8::cmp(&left, &right).reverse() 83 | } else { 84 | BIntD8::cmp(&left, &right) 85 | } 86 | } 87 | } 88 | 89 | impl PartialEq for Float { 90 | #[inline] 91 | fn eq(&self, other: &Self) -> bool { 92 | Self::eq(&self, other) 93 | } 94 | } 95 | 96 | impl PartialOrd for Float { 97 | #[inline] 98 | fn partial_cmp(&self, other: &Self) -> Option { 99 | Self::partial_cmp(&self, other) 100 | } 101 | } 102 | 103 | #[cfg(test)] 104 | mod tests { 105 | use crate::test::test_bignum; 106 | use crate::test::types::{ftest, FTEST}; 107 | 108 | test_bignum! { 109 | function: ::max(a: ftest, b: ftest), 110 | cases: [(0.0, -0.0), (-0.0, 0.0)] 111 | } 112 | test_bignum! { 113 | function: ::min(a: ftest, b: ftest), 114 | cases: [(0.0, -0.0), (-0.0, 0.0)] 115 | } 116 | test_bignum! { 117 | function: ::maximum(a: ftest, b: ftest), 118 | cases: [(0.0, -0.0), (-0.0, 0.0)] 119 | } 120 | test_bignum! { 121 | function: ::minimum(a: ftest, b: ftest), 122 | cases: [(0.0, -0.0), (-0.0, 0.0)] 123 | } 124 | test_bignum! { 125 | function: ::clamp(a: ftest, b: ftest, c: ftest), 126 | skip: !(b <= c) 127 | } 128 | test_bignum! { 129 | function: ::total_cmp(a: ref &ftest, b: ref &ftest) 130 | } 131 | test_bignum! { 132 | function: ::partial_cmp(a: ref &ftest, b: ref &ftest) 133 | } 134 | test_bignum! { 135 | function: ::eq(a: ref &ftest, b: ref &ftest) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/float/const_trait_fillers.rs: -------------------------------------------------------------------------------- 1 | use crate::doc; 2 | use crate::BUintD8; 3 | use super::Float; 4 | use core::cmp::Ordering; 5 | 6 | #[doc = doc::const_trait_fillers::impl_desc!()] 7 | impl Float { 8 | #[inline] 9 | pub const fn eq(&self, other: &Self) -> bool { 10 | handle_nan!(false; self, other); 11 | (self.is_zero() && other.is_zero()) || BUintD8::eq(&self.to_bits(), &other.to_bits()) 12 | } 13 | 14 | #[inline] 15 | pub const fn ne(&self, other: &Self) -> bool { 16 | !Self::eq(&self, other) 17 | } 18 | 19 | #[inline] 20 | pub const fn partial_cmp(&self, other: &Self) -> Option { 21 | handle_nan!(None; self, other); 22 | if self.is_zero() && other.is_zero() { 23 | return Some(Ordering::Equal); 24 | } 25 | Some(self.total_cmp(other)) 26 | } 27 | 28 | #[inline] 29 | pub const fn lt(&self, other: &Self) -> bool { 30 | matches!(self.partial_cmp(&other), Some(Ordering::Less)) 31 | } 32 | 33 | #[inline] 34 | pub const fn le(&self, other: &Self) -> bool { 35 | matches!(self.partial_cmp(&other), Some(Ordering::Less | Ordering::Equal)) 36 | } 37 | 38 | #[inline] 39 | pub const fn gt(&self, other: &Self) -> bool { 40 | matches!(self.partial_cmp(&other), Some(Ordering::Greater)) 41 | } 42 | 43 | #[inline] 44 | pub const fn ge(&self, other: &Self) -> bool { 45 | matches!(self.partial_cmp(&other), Some(Ordering::Greater | Ordering::Equal)) 46 | } 47 | 48 | #[inline] 49 | pub(crate) const fn neg(mut self) -> Self { 50 | type Digit = u8; 51 | 52 | self.bits.digits[W - 1] ^= 1 << (Digit::BITS - 1); 53 | self 54 | } 55 | } -------------------------------------------------------------------------------- /src/float/endian.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use crate::BUintD8; 3 | use crate::doc; 4 | 5 | #[cfg(feature = "nightly")] 6 | impl Float { 7 | #[cfg(feature = "nightly")] 8 | #[doc = doc::endian::to_be_bytes!(F)] 9 | #[doc = doc::requires_feature!("nightly")] 10 | #[must_use = doc::must_use_op!()] 11 | #[inline] 12 | pub const fn to_be_bytes(self) -> [u8; BUintD8::::BYTES_USIZE] { 13 | self.to_bits().to_be_bytes() 14 | } 15 | 16 | #[cfg(feature = "nightly")] 17 | #[doc = doc::endian::to_le_bytes!(F)] 18 | #[doc = doc::requires_feature!("nightly")] 19 | #[must_use = doc::must_use_op!()] 20 | #[inline] 21 | pub const fn to_le_bytes(self) -> [u8; BUintD8::::BYTES_USIZE] { 22 | self.to_bits().to_le_bytes() 23 | } 24 | 25 | #[cfg(feature = "nightly")] 26 | #[doc = doc::endian::to_ne_bytes!(F)] 27 | #[doc = doc::requires_feature!("nightly")] 28 | #[must_use = doc::must_use_op!()] 29 | #[inline] 30 | pub const fn to_ne_bytes(self) -> [u8; BUintD8::::BYTES_USIZE] { 31 | self.to_bits().to_ne_bytes() 32 | } 33 | 34 | #[cfg(feature = "nightly")] 35 | #[doc = doc::endian::from_be_bytes!(F)] 36 | #[doc = doc::requires_feature!("nightly")] 37 | #[must_use] 38 | #[inline] 39 | pub const fn from_be_bytes(bytes: [u8; BUintD8::::BYTES_USIZE]) -> Self { 40 | Self::from_bits(BUintD8::from_be_bytes(bytes)) 41 | } 42 | 43 | #[cfg(feature = "nightly")] 44 | #[doc = doc::endian::from_le_bytes!(F)] 45 | #[doc = doc::requires_feature!("nightly")] 46 | #[must_use] 47 | #[inline] 48 | pub const fn from_le_bytes(bytes: [u8; BUintD8::::BYTES_USIZE]) -> Self { 49 | Self::from_bits(BUintD8::from_le_bytes(bytes)) 50 | } 51 | 52 | #[cfg(feature = "nightly")] 53 | #[doc = doc::endian::from_ne_bytes!(F)] 54 | #[doc = doc::requires_feature!("nightly")] 55 | #[must_use] 56 | #[inline] 57 | pub const fn from_ne_bytes(bytes: [u8; BUintD8::::BYTES_USIZE]) -> Self { 58 | Self::from_bits(BUintD8::from_ne_bytes(bytes)) 59 | } 60 | } 61 | 62 | #[cfg(feature = "nightly")] 63 | #[cfg(test)] 64 | mod tests { 65 | use crate::test::test_bignum; 66 | use crate::test::types::{ftest, FTEST}; 67 | use crate::test::U8ArrayWrapper; 68 | 69 | test_bignum! { 70 | function: ::to_be_bytes(a: ftest) 71 | } 72 | test_bignum! { 73 | function: ::to_le_bytes(a: ftest) 74 | } 75 | test_bignum! { 76 | function: ::to_ne_bytes(a: ftest) 77 | } 78 | test_bignum! { 79 | function: ::from_be_bytes(a: U8ArrayWrapper<{FTEST::BITS as usize / 8}>) 80 | } 81 | test_bignum! { 82 | function: ::from_le_bytes(a: U8ArrayWrapper<{FTEST::BITS as usize / 8}>) 83 | } 84 | test_bignum! { 85 | function: ::from_ne_bytes(a: U8ArrayWrapper<{FTEST::BITS as usize / 8}>) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/float/math/mod.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use crate::doc; 3 | 4 | mod sqrt; 5 | 6 | /* 7 | All functions: 8 | mul_add, div_euclid, rem_euclid, powi, powf, exp, exp2, ln, log, log2, log10, cbrt, hypot, sin, cos, tan, asin, acos, atan, atan2, sin_cos, exp_m1, ln_1p, sinh, cosh, tanh, asinh, acosh, atanh, to_degrees, to_radians 9 | */ 10 | 11 | /* 12 | TODO: acos, acosh, asin, asinh, atan, atan2, atanh, cbrt, cos, cosh, exp, exp2, exp_m1, gamma, hypot, ln, ln_1p, ln_gamma, log, log10, log2, midpoint, mul_add, powf, recip, round_ties_even, tan, tanh, to_degrees, to_radians, 13 | */ 14 | 15 | #[doc = doc::math::impl_desc!()] 16 | impl Float { 17 | #[doc = doc::math::abs!(F)] 18 | #[must_use = doc::must_use_op!(float)] 19 | #[inline] 20 | pub const fn abs(self) -> Self { 21 | if self.is_sign_negative() { 22 | self.neg() 23 | } else { 24 | self 25 | } 26 | } 27 | 28 | #[doc = doc::math::sqrt!(F)] 29 | #[must_use = doc::must_use_op!(float)] 30 | pub fn sqrt(self) -> Self { 31 | self.sqrt_internal() 32 | } 33 | 34 | #[cfg(feature = "nightly")] 35 | #[doc = doc::math::div_euclid!(F)] 36 | #[must_use = doc::must_use_op!(float)] 37 | #[inline] 38 | pub fn div_euclid(self, rhs: Self) -> Self 39 | where 40 | [(); W * 2]:, 41 | { 42 | let div = (self / rhs).trunc(); 43 | if self % rhs < Self::ZERO { 44 | return if rhs > Self::ZERO { 45 | div - Self::ONE 46 | } else { 47 | div + Self::ONE 48 | }; 49 | } 50 | div 51 | } 52 | 53 | #[doc = doc::math::rem_euclid!(F)] 54 | #[must_use = doc::must_use_op!(float)] 55 | #[inline] 56 | pub fn rem_euclid(self, rhs: Self) -> Self { 57 | let rem = self % rhs; 58 | if rem < Self::NEG_ZERO { 59 | rem + rhs.abs() 60 | } else { 61 | rem 62 | } 63 | } 64 | 65 | #[cfg(feature = "nightly")] 66 | #[doc = doc::math::powi!(F)] 67 | #[must_use = doc::must_use_op!(float)] 68 | #[inline] 69 | pub fn powi(mut self, n: i32) -> Self 70 | where 71 | [(); W * 2]:, 72 | { 73 | if n == 0 { 74 | return Self::ONE; 75 | } 76 | let mut n_abs = n.unsigned_abs(); // unsigned abs since otherwise overflow could occur (if n == i32::MIN) 77 | let mut y = Self::ONE; 78 | while n_abs > 1 { 79 | if n_abs & 1 == 1 { 80 | // out = out * self; 81 | y = y * self; 82 | } 83 | self = self * self; 84 | n_abs >>= 1; 85 | } 86 | if n.is_negative() { 87 | Self::ONE / (self * y) 88 | } else { 89 | self * y 90 | } 91 | } 92 | } 93 | 94 | #[cfg(test)] 95 | mod tests { 96 | use crate::test::test_bignum; 97 | use crate::test::types::{ftest, FTEST}; 98 | 99 | test_bignum! { 100 | function: ::abs(f: ftest) 101 | } 102 | test_bignum! { 103 | function: ::sqrt(f: ftest) 104 | } 105 | test_bignum! { 106 | function: ::div_euclid(f1: ftest, f2: ftest) 107 | } 108 | test_bignum! { 109 | function: ::rem_euclid(f1: ftest, f2: ftest) 110 | } 111 | test_bignum! { 112 | function: ::powi(f: ftest, n: i32) 113 | } 114 | } -------------------------------------------------------------------------------- /src/float/math/remquof.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | /*pub fn remquof(mut self, mut y: Self) -> /*(Self, BIntD8)*/(Self, Self) { 4 | handle_nan!(self; self); 5 | handle_nan!(y; y); 6 | if self.is_infinite() || y.is_infinite() { 7 | return (Self::NAN, Self::NAN); 8 | } 9 | 10 | if y.is_zero() { 11 | return (Self::QNAN, Self::QNAN); 12 | } 13 | if self.is_zero() { 14 | return (self, self); 15 | } 16 | let ux = self.to_bits(); 17 | let mut uy = y.to_bits(); 18 | let mut ex = self.exponent(); 19 | let mut ey = y.exponent(); 20 | let sx = self.is_sign_negative(); 21 | let sy = y.is_sign_negative(); 22 | let mut uxi = ux; 23 | 24 | /* normalize x and y */ 25 | let mut i; 26 | if ex.is_zero() { 27 | i = uxi << (Self::BITS - Self::MB); 28 | while !BIntD8::from_bits(i).is_negative() { 29 | ex -= BIntD8::ONE; 30 | i <<= 1u8; 31 | } 32 | uxi <<= -ex + BIntD8::ONE; 33 | } else { 34 | uxi &= BUintD8::MAX >> (Self::BITS - Self::MB); 35 | uxi |= BUintD8::ONE << Self::MB; 36 | } 37 | if ey.is_zero() { 38 | i = uy << (Self::BITS - Self::MB); 39 | while !BIntD8::from_bits(i).is_negative() { 40 | ey -= BIntD8::ONE; 41 | i <<= 1u8; 42 | } 43 | uy <<= -ey + BIntD8::ONE; 44 | } else { 45 | uy &= BUintD8::MAX >> (Self::BITS - Self::MB); 46 | uy |= BUintD8::ONE << Self::MB; 47 | } 48 | 49 | let mut q = BUintD8::::ZERO; 50 | if ex + BIntD8::ONE != ey { 51 | if ex < ey { 52 | return (self, 0); 53 | } 54 | /* x mod y */ 55 | while ex > ey { 56 | i = uxi.wrapping_sub(uy); 57 | if !BIntD8::from_bits(i).is_negative() { 58 | uxi = i; 59 | q += BUintD8::ONE; 60 | } 61 | uxi <<= 1u8; 62 | q <<= 1u8; 63 | ex -= BIntD8::ONE; 64 | } 65 | i = uxi.wrapping_sub(uy); 66 | if !BIntD8::from_bits(i).is_negative() { 67 | uxi = i; 68 | q += BUintD8::ONE; 69 | } 70 | if uxi.is_zero() { 71 | //ex = BIntD8::TWO - BIntD8::from(Self::BITS); 72 | ex = BIntD8::from(-60i8); 73 | } else { 74 | while (uxi >> Self::MB).is_zero() { 75 | uxi <<= 1u8; 76 | ex -= BIntD8::ONE; 77 | } 78 | } 79 | } 80 | 81 | /* scale result and decide between |x| and |x|-|y| */ 82 | if ex.is_positive() { 83 | uxi -= BUintD8::ONE << Self::MB; 84 | uxi |= ex.to_bits() << Self::MB; 85 | } else { 86 | uxi >>= -ex + BIntD8::ONE; 87 | } 88 | self = Self::from_bits(uxi); 89 | if sy { 90 | y = -y; 91 | } 92 | if ex == ey || (ex + BIntD8::ONE == ey && (Self::TWO * self > y || (Self::TWO * self == y && !(q % BUintD8::TWO).is_zero()))) { 93 | self = self - y; 94 | q += BUintD8::ONE; 95 | } 96 | q &= BUintD8::MAX >> 1u8; 97 | let quo = if sx ^ sy { -BIntD8::from_bits(q) } else { BIntD8::from_bits(q) }; 98 | if sx { 99 | (-self, quo) 100 | } else { 101 | (self, quo) 102 | } 103 | }*/ -------------------------------------------------------------------------------- /src/float/math/sqrt.rs: -------------------------------------------------------------------------------- 1 | use crate::{float::{FloatExponent, UnsignedFloatExponent}, BIntD8, BUintD8}; 2 | use super::Float; 3 | 4 | impl Float { 5 | pub(super) fn sqrt_internal(self) -> Self { 6 | handle_nan!(self; self); 7 | if self.is_zero() { 8 | return self; 9 | } 10 | let bits = self.to_bits(); 11 | if bits == Self::INFINITY.to_bits() { 12 | return Self::INFINITY; 13 | } 14 | if self.is_sign_negative() { 15 | return Self::NAN; 16 | /*let u = BUintD8::MAX << (Self::MB - 1); 17 | return Self::from_bits(u);*/ 18 | } 19 | 20 | let tiny = Self::from_bits(BUintD8::from(0b11011u8) << Self::MB); // TODO: may not work for exponents stored with very few bits 21 | 22 | let mut ix = BIntD8::from_bits(bits); 23 | let mut i: FloatExponent; 24 | let mut m = (bits >> Self::MB).cast_to_unsigned_float_exponent() as FloatExponent; 25 | if m == 0 { 26 | /* subnormal x */ 27 | i = 0; 28 | while (ix & (BIntD8::ONE << Self::MB)).is_zero() { 29 | ix <<= 1; 30 | i = i + 1; 31 | } 32 | m -= i - 1; 33 | } 34 | m -= Self::EXP_BIAS; /* unbias exponent */ 35 | ix = (ix & BIntD8::from_bits(BUintD8::MAX >> (Self::BITS - Self::MB))) 36 | | (BIntD8::ONE << Self::MB); 37 | if m & 1 == 1 { 38 | /* odd m, double x to make it even */ 39 | ix += ix; 40 | } 41 | m >>= 1; /* m = [m/2] */ 42 | 43 | /* generate sqrt(x) bit by bit */ 44 | ix += ix; 45 | let mut q = BIntD8::ZERO; 46 | let mut s = BIntD8::ZERO; 47 | let mut r = BUintD8::ONE << (Self::MB + 1); /* r = moving bit from right to left */ 48 | 49 | let mut t: BIntD8; 50 | while !r.is_zero() { 51 | t = s + BIntD8::from_bits(r); 52 | if t <= ix { 53 | s = t + BIntD8::from_bits(r); 54 | ix -= t; 55 | q += BIntD8::from_bits(r); 56 | } 57 | ix += ix; 58 | r = r >> 1u8; 59 | } 60 | 61 | /* use floating add to find out rounding direction */ 62 | let mut z: Self; 63 | if !ix.is_zero() { 64 | z = Self::ONE - tiny; /* raise inexact flag */ 65 | if z >= Self::ONE { 66 | z = Self::ONE + tiny; 67 | if z > Self::ONE { 68 | q += BIntD8::TWO; 69 | } else { 70 | q += q & BIntD8::ONE; 71 | } 72 | } 73 | } 74 | 75 | ix = (q >> 1u8) + BIntD8::from_bits((BUintD8::MAX << (Self::MB + 1 + 2)) >> 2u8); 76 | ix += (BUintD8::cast_from_unsigned_float_exponent(m as UnsignedFloatExponent) << Self::MB).cast_signed(); 77 | Self::from_bits(ix.to_bits()) 78 | } 79 | } -------------------------------------------------------------------------------- /src/float/numtraits.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use num_traits::{Bounded, ConstZero, ConstOne, One, Zero, AsPrimitive, float::TotalOrder}; 3 | use crate::cast::CastFrom; 4 | 5 | impl Bounded for Float { 6 | #[inline] 7 | fn min_value() -> Self { 8 | Self::MIN 9 | } 10 | 11 | #[inline] 12 | fn max_value() -> Self { 13 | Self::MAX 14 | } 15 | } 16 | 17 | impl ConstZero for Float { 18 | const ZERO: Self = Self::ZERO; 19 | } 20 | 21 | impl ConstOne for Float { 22 | const ONE: Self = Self::ONE; 23 | } 24 | 25 | impl Zero for Float { 26 | #[inline] 27 | fn zero() -> Self { 28 | Self::ZERO 29 | } 30 | 31 | #[inline] 32 | fn is_zero(&self) -> bool { 33 | Self::is_zero(&self) 34 | } 35 | } 36 | 37 | impl One for Float { 38 | #[inline] 39 | fn one() -> Self { 40 | Self::ONE 41 | } 42 | 43 | #[inline] 44 | fn is_one(&self) -> bool { 45 | Self::ONE.eq(&self) 46 | } 47 | } 48 | 49 | // impl Signed for Float { 50 | // #[inline] 51 | // fn is_negative(&self) -> bool { 52 | // Self::is_sign_negative(*self) 53 | // } 54 | 55 | // #[inline] 56 | // fn is_positive(&self) -> bool { 57 | // Self::is_sign_positive(*self) 58 | // } 59 | 60 | // #[inline] 61 | // fn abs(&self) -> Self { 62 | // Self::abs(*self) 63 | // } 64 | 65 | // #[inline] 66 | // fn abs_sub(&self, other: &Self) -> Self { 67 | // if self <= other { 68 | // Self::ZERO 69 | // } else { 70 | // *self - *other 71 | // } 72 | // } 73 | 74 | // #[inline] 75 | // fn signum(&self) -> Self { 76 | // Self::signum(*self) 77 | // } 78 | // } 79 | 80 | macro_rules! impl_as_primitive { 81 | ($($primitive: ty), *) => { 82 | $( 83 | impl AsPrimitive<$primitive> for Float { 84 | #[inline] 85 | fn as_(self) -> $primitive { 86 | <$primitive>::cast_from(self) 87 | } 88 | } 89 | 90 | impl AsPrimitive> for $primitive { 91 | #[inline] 92 | fn as_(self) -> Float { 93 | Float::cast_from(self) 94 | } 95 | } 96 | )* 97 | }; 98 | } 99 | 100 | impl_as_primitive!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); 101 | 102 | impl TotalOrder for Float { 103 | #[inline] 104 | fn total_cmp(&self, other: &Self) -> core::cmp::Ordering { 105 | Self::total_cmp(&self, other) 106 | } 107 | } 108 | 109 | #[cfg(test)] 110 | mod tests { 111 | use crate::test::test_bignum; 112 | use crate::test::types::{ftest, FTEST}; 113 | use super::*; 114 | 115 | test_bignum! { 116 | function: ::is_zero(a: ref &ftest) 117 | } 118 | test_bignum! { 119 | function: ::is_one(a: ref &ftest) 120 | } 121 | test_bignum! { 122 | function: ::total_cmp(a: ref &ftest, b: ref &ftest) 123 | } 124 | } -------------------------------------------------------------------------------- /src/float/ops/mod.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use core::iter::{Iterator, Product, Sum}; 3 | use core::ops::{Add, Div, Mul, Neg, Rem, Sub, AddAssign, SubAssign, MulAssign, RemAssign}; 4 | 5 | mod add; 6 | mod sub; 7 | mod mul; 8 | #[cfg(feature = "nightly")] 9 | mod div; 10 | mod rem; 11 | 12 | macro_rules! impl_assign_op { 13 | ($AssignTrait: ident, $assign_fn: ident, $op_fn: ident) => { 14 | impl $AssignTrait for Float { 15 | #[inline] 16 | fn $assign_fn(&mut self, rhs: Self) { 17 | *self = self.$op_fn(rhs); 18 | } 19 | } 20 | 21 | impl $AssignTrait<&Self> for Float { 22 | #[inline] 23 | fn $assign_fn(&mut self, rhs: &Self) { 24 | *self = self.$op_fn(*rhs); 25 | } 26 | } 27 | }; 28 | } 29 | 30 | impl Add for Float { 31 | type Output = Self; 32 | 33 | #[inline] 34 | fn add(self, rhs: Self) -> Self { 35 | Self::add(self, rhs) 36 | } 37 | } 38 | 39 | crate::int::ops::op_ref_impl!(Add> for Float, add); 40 | impl_assign_op!(AddAssign, add_assign, add); 41 | 42 | impl Sum for Float { 43 | #[inline] 44 | fn sum>(iter: I) -> Self { 45 | iter.fold(Self::ZERO, |a, b| a + b) 46 | } 47 | } 48 | 49 | impl<'a, const W: usize, const MB: usize> Sum<&'a Self> for Float { 50 | #[inline] 51 | fn sum>(iter: I) -> Self { 52 | iter.fold(Self::ONE, |a, b| a + *b) 53 | } 54 | } 55 | 56 | impl Sub for Float { 57 | type Output = Self; 58 | 59 | #[inline] 60 | fn sub(self, rhs: Self) -> Self { 61 | Self::sub(self, rhs) 62 | } 63 | } 64 | 65 | crate::int::ops::op_ref_impl!(Sub> for Float, sub); 66 | impl_assign_op!(SubAssign, sub_assign, sub); 67 | 68 | impl Mul for Float { 69 | type Output = Self; 70 | 71 | #[inline] 72 | fn mul(self, rhs: Self) -> Self { 73 | Self::mul(self, rhs) 74 | } 75 | } 76 | 77 | crate::int::ops::op_ref_impl!(Mul> for Float, mul); 78 | 79 | impl Product for Float { 80 | #[inline] 81 | fn product>(iter: I) -> Self { 82 | iter.fold(Self::ONE, |a, b| a * b) 83 | } 84 | } 85 | 86 | impl<'a, const W: usize, const MB: usize> Product<&'a Self> for Float { 87 | #[inline] 88 | fn product>(iter: I) -> Self { 89 | iter.fold(Self::ONE, |a, b| a * *b) 90 | } 91 | } 92 | 93 | #[cfg(feature = "nightly")] 94 | impl Div for Float 95 | where 96 | [(); W * 2]:, 97 | { 98 | type Output = Self; 99 | 100 | #[inline] 101 | fn div(self, rhs: Self) -> Self { 102 | Self::div(self, rhs) 103 | } 104 | } 105 | 106 | // crate::int::ops::op_ref_impl!(Div> for Float, div); 107 | // impl_assign_op!(DivAssign, div_assign, div); 108 | 109 | impl Rem for Float { 110 | type Output = Self; 111 | 112 | #[inline] 113 | fn rem(self, rhs: Self) -> Self { 114 | Self::rem(self, rhs) 115 | } 116 | } 117 | 118 | crate::int::ops::op_ref_impl!(Rem> for Float, rem); 119 | impl_assign_op!(RemAssign, rem_assign, rem); 120 | 121 | impl Neg for Float { 122 | type Output = Self; 123 | 124 | #[inline] 125 | fn neg(self) -> Self { 126 | Self::neg(self) 127 | } 128 | } 129 | 130 | impl Neg for &Float { 131 | type Output = Float; 132 | 133 | #[inline] 134 | fn neg(self) -> Float { 135 | (*self).neg() 136 | } 137 | } 138 | 139 | #[cfg(test)] 140 | mod tests { 141 | use super::*; 142 | use crate::test::test_bignum; 143 | use crate::test::types::{ftest, FTEST}; 144 | 145 | test_bignum! { 146 | function: ::add(a: ftest, b: ftest), 147 | skip: a.is_sign_negative() != b.is_sign_negative(), 148 | cases: [(1.3952888382785755e33, 1.466527384898436e33)] 149 | } 150 | test_bignum! { 151 | function: ::sub(a: ftest, b: ftest) 152 | } 153 | test_bignum! { 154 | function: ::mul(a: ftest, b: ftest), 155 | cases: [ 156 | (5.6143642e23f64 as ftest, 35279.223f64 as ftest) 157 | ] 158 | } 159 | test_bignum! { 160 | function: ::div(a: ftest, b: ftest) 161 | } 162 | test_bignum! { 163 | function: ::rem(a: ftest, b: ftest) 164 | } 165 | test_bignum! { 166 | function: ::neg(f: ftest) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/float/ops/mul.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | use crate::float::FloatExponent; 3 | use crate::float::UnsignedFloatExponent; 4 | use crate::BIntD8; 5 | use crate::BUintD8; 6 | use crate::ExpType; 7 | use core::num::FpCategory; 8 | 9 | impl Float { 10 | #[inline] 11 | pub(crate) fn mul_internal(self, rhs: Self, negative: bool) -> Self { 12 | let (a, b) = (self, rhs); 13 | let (_, exp_a, mant_a) = a.into_biased_parts(); 14 | let (_, exp_b, mant_b) = b.into_biased_parts(); 15 | 16 | // TODO: make so as_ can infer type so can switch trait definition if needed 17 | let mut mant_prod = mant_a.widening_mul(mant_b); 18 | 19 | let prod_bits = if mant_prod.1.bits() == 0 { 20 | mant_prod.0.bits() 21 | } else { 22 | mant_prod.1.bits() + Self::BITS 23 | }; 24 | 25 | if prod_bits == 0 { 26 | return if negative { Self::NEG_ZERO } else { Self::ZERO }; 27 | } 28 | 29 | let extra_bits = if prod_bits > (Self::MB + 1) { 30 | prod_bits - (Self::MB + 1) 31 | } else { 32 | 0 33 | }; 34 | 35 | let mut exp = 36 | (exp_a as FloatExponent) - Self::EXP_BIAS + (exp_b as FloatExponent) + (extra_bits as FloatExponent) 37 | - (MB as FloatExponent); 38 | 39 | if exp > Self::MAX_EXP + Self::EXP_BIAS - 1 { 40 | return if negative { 41 | Self::NEG_INFINITY 42 | } else { 43 | Self::INFINITY 44 | }; 45 | } 46 | 47 | let mut extra_shift = 0; 48 | if !exp.is_positive() { 49 | extra_shift = (1 - exp) as UnsignedFloatExponent; 50 | exp = 1; 51 | } 52 | let total_shift = (extra_bits as UnsignedFloatExponent) + extra_shift; 53 | 54 | let mp0tz = mant_prod.0.trailing_zeros(); 55 | let tz = if mp0tz == Self::BITS { 56 | mant_prod.1.trailing_zeros() + Self::BITS 57 | } else { 58 | mp0tz 59 | }; 60 | 61 | let sticky_bit = (tz as UnsignedFloatExponent + 1) < total_shift; 62 | let mut mant = match ExpType::try_from(total_shift - 1) { 63 | Ok(sub) => { 64 | if sub > Self::BITS * 2 { 65 | (BUintD8::ZERO, BUintD8::ZERO) 66 | } else if sub >= Self::BITS { 67 | (mant_prod.1 >> (sub - Self::BITS), BUintD8::ZERO) 68 | } else { 69 | let mask = BUintD8::MAX >> (Self::BITS - sub); 70 | let carry = mant_prod.1 & mask; 71 | mant_prod.1 >>= sub; 72 | mant_prod.0 = (mant_prod.0 >> sub) | (carry << (Self::BITS - sub)); 73 | mant_prod 74 | } 75 | } 76 | Err(_) => (BUintD8::ZERO, BUintD8::ZERO), 77 | }; 78 | if mant.0.bit(0) { 79 | if sticky_bit || mant.0.bit(1) { 80 | // Round up 81 | let (sum, carry) = mant.0.overflowing_add(BUintD8::ONE); 82 | mant.0 = sum; 83 | if carry { 84 | mant.1 += BUintD8::ONE; 85 | } 86 | } 87 | } 88 | { 89 | let carry = mant.1.bit(0); 90 | //mant.1 >>= 1 as ExpType; 91 | mant.0 >>= 1 as ExpType; 92 | if carry { 93 | mant.0 |= BIntD8::MIN.to_bits(); 94 | } 95 | } 96 | 97 | let mut m1b = mant.1.bits(); 98 | if m1b != 0 { 99 | m1b -= 1; 100 | } 101 | /*let bits = if m1b == 0 { 102 | mant.0.bits() 103 | } else { 104 | m1b + Self::BITS 105 | };*/ 106 | let m0b = mant.0.bits(); 107 | if m0b > Self::MB + 1 { 108 | // it's possible that the mantissa has too many bits, so shift it right and increase the exponent until it has the correct number of bits 109 | let inc = m0b - (Self::MB + 1); 110 | mant.0 = mant.0 >> inc; 111 | exp += inc as FloatExponent; 112 | } 113 | 114 | if exp > Self::MAX_EXP + Self::EXP_BIAS - 1 { 115 | return if negative { 116 | Self::NEG_INFINITY 117 | } else { 118 | Self::INFINITY 119 | }; 120 | } 121 | 122 | if exp == 1 && m1b < Self::MB + 1 { 123 | return Self::from_raw_parts(negative, 0, mant.0); 124 | } 125 | //if mant >> Self::MB != BUintD8::ZERO { 126 | mant.0 ^= BUintD8::ONE << Self::MB; 127 | //} 128 | Self::from_raw_parts(negative, exp as UnsignedFloatExponent, mant.0) 129 | } 130 | 131 | #[inline] 132 | pub(super) fn mul(self, rhs: Self) -> Self { 133 | let negative = self.is_sign_negative() ^ rhs.is_sign_negative(); 134 | match (self.classify(), rhs.classify()) { 135 | (FpCategory::Nan, _) | (_, FpCategory::Nan) => return Self::NAN, 136 | (FpCategory::Infinite, FpCategory::Zero) | (FpCategory::Zero, FpCategory::Infinite) => { 137 | Self::NAN 138 | } 139 | (FpCategory::Infinite, _) | (_, FpCategory::Infinite) => { 140 | if negative { 141 | Self::NEG_INFINITY 142 | } else { 143 | Self::INFINITY 144 | } 145 | } 146 | (_, _) => self.mul_internal(rhs, negative), 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/float/ops/rem.rs: -------------------------------------------------------------------------------- 1 | use crate::float::UnsignedFloatExponent; 2 | use crate::BUintD8; 3 | use crate::BIntD8; 4 | use crate::ExpType; 5 | use super::Float; 6 | 7 | impl Float { 8 | #[inline] 9 | pub(super) fn rem(self, y: Self) -> Self { 10 | handle_nan!(self; self); 11 | handle_nan!(y; y); 12 | 13 | if y.is_zero() { 14 | return Self::NAN; 15 | } 16 | if self.is_zero() { 17 | return self; 18 | } 19 | if self.is_infinite() { 20 | return Self::NAN; 21 | } 22 | if y.is_infinite() { 23 | return self; 24 | } 25 | 26 | let mut uxi = self.to_bits(); 27 | let mut uyi = y.to_bits(); 28 | let mut ex = self.signed_biased_exponent(); 29 | let mut ey = y.signed_biased_exponent(); 30 | let mut i; 31 | 32 | if uxi << 1 as ExpType <= uyi << 1 as ExpType { 33 | if uxi << 1 as ExpType == uyi << 1 as ExpType { 34 | return if self.is_sign_negative() { 35 | Self::NEG_ZERO 36 | } else { 37 | Self::ZERO 38 | }; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | /* normalize x and y */ 45 | if ex == 0 { 46 | i = uxi << (Self::BITS - Self::MB); 47 | while !BIntD8::from_bits(i).is_negative() { 48 | ex -= 1; 49 | i <<= 1 as ExpType; 50 | } 51 | 52 | uxi <<= -ex + 1; 53 | } else { 54 | uxi &= BUintD8::MAX >> (Self::BITS - Self::MB); 55 | uxi |= BUintD8::ONE << Self::MB; 56 | } 57 | 58 | if ey == 0 { 59 | i = uyi << (Self::BITS - Self::MB); 60 | while !BIntD8::from_bits(i).is_negative() { 61 | ey -= 1; 62 | i <<= 1 as ExpType; 63 | } 64 | 65 | uyi <<= -ey + 1; 66 | } else { 67 | uyi &= BUintD8::MAX >> (Self::BITS - Self::MB); 68 | uyi |= BUintD8::ONE << Self::MB; 69 | } 70 | /* x mod y */ 71 | while ex > ey { 72 | i = uxi.wrapping_sub(uyi); 73 | if !BIntD8::from_bits(i).is_negative() { 74 | if i.is_zero() { 75 | return if self.is_sign_negative() { 76 | Self::NEG_ZERO 77 | } else { 78 | Self::ZERO 79 | }; 80 | } 81 | uxi = i; 82 | } 83 | uxi <<= 1 as ExpType; 84 | 85 | ex -= 1; 86 | } 87 | 88 | i = uxi.wrapping_sub(uyi); 89 | if !BIntD8::from_bits(i).is_negative() { 90 | if i.is_zero() { 91 | return if self.is_sign_negative() { 92 | Self::NEG_ZERO 93 | } else { 94 | Self::ZERO 95 | }; 96 | } 97 | uxi = i; 98 | } 99 | 100 | while (uxi >> Self::MB).is_zero() { 101 | uxi <<= 1 as ExpType; 102 | ex -= 1; 103 | } 104 | 105 | /* scale result up */ 106 | if ex.is_positive() { 107 | uxi -= BUintD8::ONE << Self::MB; 108 | uxi |= BUintD8::cast_from_unsigned_float_exponent(ex as UnsignedFloatExponent) << Self::MB; 109 | } else { 110 | uxi >>= -ex + 1; 111 | } 112 | 113 | let f = Self::from_bits(uxi); 114 | if self.is_sign_negative() { 115 | -f 116 | } else { 117 | f 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/float/ops/sub.rs: -------------------------------------------------------------------------------- 1 | use core::num::FpCategory; 2 | use crate::cast::As; 3 | use crate::float::FloatExponent; 4 | use crate::float::UnsignedFloatExponent; 5 | use crate::BUintD8; 6 | use crate::ExpType; 7 | use super::Float; 8 | 9 | // TODO: this very occasionally fails quickcheck tests, need to fix 10 | impl Float { 11 | #[inline] 12 | pub(crate) fn sub_internal(mut self, mut rhs: Self, mut negative: bool) -> Self { 13 | if rhs.abs() > self.abs() { 14 | // If b has a larger exponent than a, swap a and b so that a has the larger exponent 15 | negative = !negative; 16 | core::mem::swap(&mut self, &mut rhs); 17 | } 18 | if self.abs() == rhs.abs() { 19 | return Self::ZERO; 20 | } 21 | 22 | let (_, a_exp, mut a_mant) = self.into_biased_parts(); 23 | let (_, b_exp, mut b_mant) = rhs.into_biased_parts(); 24 | let exp_diff = a_exp - b_exp; 25 | 26 | let mut a_exp = a_exp as FloatExponent; 27 | 28 | let sticky_bit2 = exp_diff != 0 29 | && exp_diff < BUintD8::::BITS.into() 30 | && b_mant.bit(exp_diff.as_::() - 1); 31 | let all_zeros = 32 | exp_diff != 0 && b_mant.trailing_zeros() + 1 == exp_diff.as_::(); 33 | 34 | // Append extra bits to the mantissas to ensure correct rounding 35 | a_mant = a_mant << 1 as ExpType; 36 | b_mant = b_mant << 1 as ExpType; 37 | 38 | let sticky_bit = b_mant.trailing_zeros() < exp_diff.as_(); 39 | 40 | // If the shift causes an overflow, the b_mant is too small so is set to 0 41 | let shifted_b_mant = match exp_diff.try_into().ok() { 42 | Some(exp_diff) => b_mant.checked_shr(exp_diff).unwrap_or(BUintD8::ZERO), 43 | None => BUintD8::ZERO, 44 | }; 45 | 46 | // If the shift causes an overflow, the b_mant is too small so is set to 0 47 | 48 | if sticky_bit { 49 | //b_mant |= 1; 50 | } 51 | 52 | let mut mant = a_mant - shifted_b_mant; 53 | 54 | if mant.bits() == Self::MB + 2 { 55 | if mant & BUintD8::from(0b10u8) == BUintD8::from(0b10u8) && !sticky_bit { 56 | mant += BUintD8::ONE; 57 | } 58 | 59 | mant >>= 1 as ExpType; 60 | } else { 61 | a_exp -= 1; 62 | a_mant <<= 1 as ExpType; 63 | b_mant <<= 1 as ExpType; 64 | 65 | let sticky_bit = b_mant.trailing_zeros() < exp_diff.as_(); 66 | 67 | // If the shift causes an overflow, the b_mant is too small so is set to 0 68 | let shifted_b_mant = match exp_diff.try_into().ok() { 69 | Some(exp_diff) => b_mant.checked_shr(exp_diff).unwrap_or(BUintD8::ZERO), 70 | None => BUintD8::ZERO, 71 | }; 72 | 73 | // If the shift causes an overflow, the b_mant is too small so is set to 0 74 | 75 | if sticky_bit { 76 | //b_mant |= 1; 77 | } 78 | 79 | mant = a_mant - shifted_b_mant; 80 | 81 | if mant.bits() == Self::MB + 2 { 82 | if mant & BUintD8::from(0b10u8) == BUintD8::from(0b10u8) && !sticky_bit { 83 | mant += BUintD8::ONE; 84 | } 85 | 86 | mant >>= 1 as ExpType; 87 | } else { 88 | let _half_way = (); // TODO 89 | if sticky_bit2 && !all_zeros 90 | || (sticky_bit2 91 | && all_zeros 92 | && b_mant & BUintD8::from(0b1u8) == BUintD8::from(0b1u8)) 93 | { 94 | mant -= BUintD8::ONE; 95 | } 96 | let bits = mant.bits(); 97 | mant <<= Self::MB + 1 - bits; 98 | a_exp -= MB as FloatExponent + 2 - bits as FloatExponent; 99 | if !a_exp.is_positive() { 100 | a_exp = 1; 101 | mant >>= 1 - a_exp; 102 | } 103 | } 104 | } 105 | 106 | if (mant >> Self::MB).is_zero() { 107 | a_exp = 0; 108 | } else { 109 | mant ^= BUintD8::ONE << Self::MB; 110 | } 111 | 112 | Self::from_raw_parts(negative, a_exp as UnsignedFloatExponent, mant) 113 | } 114 | 115 | #[inline] 116 | pub(super) fn sub(self, rhs: Self) -> Self { 117 | match (self.classify(), rhs.classify()) { 118 | (FpCategory::Nan, _) => self, 119 | (_, FpCategory::Nan) => rhs, 120 | (FpCategory::Infinite, FpCategory::Infinite) => { 121 | match (self.is_sign_negative(), rhs.is_sign_negative()) { 122 | (true, false) => Self::NEG_INFINITY, 123 | (false, true) => Self::INFINITY, 124 | _ => Self::NAN, 125 | } 126 | } 127 | (FpCategory::Infinite, _) => self, 128 | (_, FpCategory::Infinite) => rhs.neg(), 129 | (_, _) => { 130 | let self_negative = self.is_sign_negative(); 131 | let rhs_negative = rhs.is_sign_negative(); 132 | if self_negative ^ rhs_negative { 133 | self.add_internal(rhs, self_negative) 134 | } else { 135 | self.sub_internal(rhs, self_negative) 136 | } 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/float/random.rs: -------------------------------------------------------------------------------- 1 | use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler}; 2 | use rand::distributions::{Distribution, Open01, OpenClosed01, Standard}; 3 | use rand::{Error, Fill, Rng, SeedableRng}; 4 | 5 | use super::{Float, FloatExponent}; 6 | use crate::BUintD8; 7 | 8 | fn seeded_rngs(seed: u64) -> (R, R) { 9 | let rng = R::seed_from_u64(seed); 10 | let rng2 = rng.clone(); // need to clone `rng` to produce the same results before it is used as `gen` mutates it 11 | (rng, rng2) 12 | } 13 | 14 | impl Distribution> for Standard { 15 | fn sample(&self, rng: &mut R) -> Float { 16 | let random_bits: BUintD8 = rng.gen(); 17 | let mantissa = random_bits.shr(Float::::BITS - Float::::MB - 1); 18 | if mantissa.is_zero() { 19 | return Float::ZERO; 20 | } 21 | if mantissa.is_one() { 22 | return Float::HALF_EPSILON; 23 | } 24 | let mantissa_bits = mantissa.bits(); 25 | let abs_exponent = Float::::MB + 2 - mantissa_bits; // has to be in this order to prevent overflow 26 | Float::from_signed_parts(false, -(abs_exponent as FloatExponent), mantissa.shl(abs_exponent - 1)) 27 | } 28 | } 29 | 30 | impl Distribution> for OpenClosed01 { 31 | fn sample(&self, rng: &mut R) -> Float { 32 | let random_bits: BUintD8 = rng.gen(); 33 | let mantissa = random_bits.shr(Float::::BITS - Float::::MB - 1); 34 | let mantissa = mantissa.add(BUintD8::ONE); // add one so mantissa is never zero 35 | if mantissa.is_zero() { 36 | return Float::HALF_EPSILON; 37 | } 38 | let mantissa_bits = mantissa.bits(); 39 | let abs_exponent = Float::::MB + 2 - mantissa_bits; // has to be in this order to prevent overflow 40 | Float::from_signed_parts(false, -(abs_exponent as FloatExponent), mantissa.shl(abs_exponent - 1)) 41 | } 42 | } 43 | 44 | impl Distribution> for Open01 { 45 | fn sample(&self, rng: &mut R) -> Float { 46 | let random_bits: BUintD8 = rng.gen(); 47 | let mantissa = random_bits.shr(Float::::BITS - Float::::MB); 48 | if mantissa.is_zero() { 49 | return Float::HALF_EPSILON; 50 | } 51 | let mantissa_bits = mantissa.bits(); 52 | let abs_exponent = Float::::MB + 1 - mantissa_bits; // has to be in this order to prevent overflow 53 | let exponent = -(abs_exponent as FloatExponent); 54 | let mantissa = mantissa.shl(1).bitor(BUintD8::ONE); // = 2*mantissa + 1 55 | let mantissa = mantissa.shl(Float::::MB - mantissa_bits); 56 | let a = Float::from_signed_parts(false, exponent, mantissa); 57 | a 58 | } 59 | } 60 | 61 | #[cfg(test)] 62 | mod tests { 63 | use rand::distributions::OpenClosed01; 64 | use rand::rngs::StdRng; 65 | use rand::{distributions::Open01, rngs::SmallRng}; 66 | use rand::{Rng, SeedableRng}; 67 | use crate::{float::F32, test::convert}; 68 | 69 | use super::seeded_rngs; 70 | 71 | #[test] 72 | fn test_random() { 73 | let mut r = StdRng::from_entropy(); 74 | let seed = r.gen(); 75 | let (mut r1, mut r2) = seeded_rngs::(seed); 76 | let big: F32 = r1.gen(); 77 | let prim: f32 = r2.gen(); 78 | 79 | assert!(convert::test_eq(big, prim)); 80 | 81 | let big: F32 = r1.sample(OpenClosed01); 82 | let prim: f32 = r2.sample(OpenClosed01); 83 | 84 | assert!(convert::test_eq(big, prim)); 85 | } 86 | } -------------------------------------------------------------------------------- /src/float/to_str.rs: -------------------------------------------------------------------------------- 1 | use super::Float; 2 | 3 | impl Float {} 4 | 5 | // TODO: include copyright notice as described in dragon4 paper 6 | -------------------------------------------------------------------------------- /src/helpers.rs: -------------------------------------------------------------------------------- 1 | use crate::ExpType; 2 | 3 | pub trait Bits { 4 | const BITS: ExpType; 5 | 6 | fn bits(&self) -> ExpType; 7 | fn bit(&self, index: ExpType) -> bool; 8 | } 9 | 10 | macro_rules! impl_bits_for_uint { 11 | ($($uint: ty), *) => { 12 | $(impl Bits for $uint { 13 | const BITS: ExpType = Self::BITS as ExpType; 14 | 15 | #[inline] 16 | fn bits(&self) -> ExpType { 17 | (Self::BITS - self.leading_zeros()) as ExpType 18 | } 19 | 20 | #[inline] 21 | fn bit(&self, index: ExpType) -> bool { 22 | self & (1 << index) != 0 23 | } 24 | })* 25 | }; 26 | } 27 | 28 | impl_bits_for_uint!(u8, u16, u32, u64, u128, usize); 29 | 30 | macro_rules! impl_bits_for_buint { 31 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 32 | impl crate::helpers::Bits for $BUint { 33 | const BITS: ExpType = Self::BITS; 34 | 35 | #[inline] 36 | fn bits(&self) -> ExpType { 37 | Self::bits(&self) 38 | } 39 | 40 | #[inline] 41 | fn bit(&self, index: ExpType) -> bool { 42 | Self::bit(&self, index) 43 | } 44 | } 45 | }; 46 | } 47 | 48 | crate::macro_impl!(impl_bits_for_buint); 49 | 50 | pub trait Zero: Sized + PartialEq { 51 | const ZERO: Self; 52 | 53 | fn is_zero(&self) -> bool { 54 | self == &Self::ZERO 55 | } 56 | } 57 | 58 | pub trait One: Sized + PartialEq { 59 | const ONE: Self; 60 | 61 | fn is_one(&self) -> bool { 62 | self == &Self::ONE 63 | } 64 | } 65 | 66 | macro_rules! impl_zero_for_uint { 67 | ($($uint: ty), *) => { 68 | $(impl Zero for $uint { 69 | const ZERO: Self = 0; 70 | })* 71 | }; 72 | } 73 | 74 | impl_zero_for_uint!(u8, u16, u32, u64, u128, usize); 75 | 76 | macro_rules! impl_one_for_int { 77 | ($($uint: ty), *) => { 78 | $(impl One for $uint { 79 | const ONE: Self = 1; 80 | })* 81 | }; 82 | } 83 | 84 | impl_one_for_int!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); 85 | 86 | macro_rules! impl_zero_for_buint { 87 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 88 | impl crate::helpers::Zero for $BUint { 89 | const ZERO: Self = Self::ZERO; 90 | } 91 | }; 92 | } 93 | 94 | crate::macro_impl!(impl_zero_for_buint); 95 | 96 | macro_rules! impl_one_for_buint { 97 | ($BUint: ident, $BInt: ident, $Digit: ident) => { 98 | impl crate::helpers::One for $BUint { 99 | const ONE: Self = Self::ONE; 100 | } 101 | }; 102 | } 103 | 104 | crate::macro_impl!(impl_one_for_buint); 105 | 106 | #[inline] 107 | pub const fn tuple_to_option((int, overflow): (T, bool)) -> Option { 108 | if overflow { 109 | None 110 | } else { 111 | Some(int) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/int/bigint_helpers.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impls { 2 | ($sign: ident) => { 3 | #[doc = doc::bigint_helpers::carrying_add!($sign)] 4 | #[must_use = doc::must_use_op!()] 5 | #[inline] 6 | pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { 7 | let (s1, o1) = self.overflowing_add(rhs); 8 | if carry { 9 | let (s2, o2) = s1.overflowing_add(Self::ONE); 10 | (s2, o1 ^ o2) 11 | } else { 12 | (s1, o1) 13 | } 14 | } 15 | 16 | #[doc = doc::bigint_helpers::borrowing_sub!($sign)] 17 | #[must_use = doc::must_use_op!()] 18 | #[inline] 19 | pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { 20 | let (s1, o1) = self.overflowing_sub(rhs); 21 | if borrow { 22 | let (s2, o2) = s1.overflowing_sub(Self::ONE); 23 | (s2, o1 ^ o2) 24 | } else { 25 | (s1, o1) 26 | } 27 | } 28 | }; 29 | } 30 | 31 | pub(crate) use impls; 32 | 33 | #[cfg(test)] 34 | macro_rules! tests { 35 | ($int: ty) => { 36 | use crate::test::{test_bignum, types::*}; 37 | 38 | test_bignum! { 39 | function: <$int>::carrying_add(a: $int, b: $int, carry: bool), 40 | cases: [ 41 | (<$int>::MAX, 1u8, true), 42 | (<$int>::MAX, 1u8, false) 43 | ] 44 | } 45 | test_bignum! { 46 | function: <$int>::borrowing_sub(a: $int, b: $int, borrow: bool), 47 | cases: [ 48 | (<$int>::MIN, 1u8, false), 49 | (<$int>::MIN, 1u8, true) 50 | ] 51 | } 52 | }; 53 | } 54 | 55 | #[cfg(test)] 56 | pub(crate) use tests; 57 | -------------------------------------------------------------------------------- /src/int/cast.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | macro_rules! tests { 3 | ($($int: ty), *) => { 4 | use crate::test::types::*; 5 | use crate::test; 6 | #[allow(unused_imports)] 7 | use crate::test::types::*; 8 | use crate::cast::{CastTo, CastFrom}; 9 | 10 | use crate::test::cast_types::*; 11 | 12 | $( 13 | test::test_from! { 14 | function: <$int as CastFrom>::cast_from, 15 | from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool, char, TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10) 16 | } 17 | 18 | test::test_into! { 19 | function: <$int as CastTo>::cast_to, 20 | into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64) 21 | } 22 | 23 | crate::int::cast::test_cast_to_bigint!($int; TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8); 24 | )* 25 | }; 26 | } 27 | 28 | #[cfg(test)] 29 | pub(crate) use tests; 30 | 31 | #[cfg(test)] 32 | macro_rules! test_cast_to_bigint { 33 | ($primitive: ty; $($Int: ty), *) => { 34 | paste::paste! { 35 | quickcheck::quickcheck! { 36 | $( 37 | #[allow(non_snake_case)] 38 | fn [](a: $primitive) -> bool { 39 | use crate::cast::CastTo; 40 | 41 | let primitive = <$primitive as CastTo<$Int>>::cast_to(a); 42 | let big = <[<$primitive:upper>] as CastTo<$Int>>::cast_to(Into::into(a)); 43 | 44 | primitive == big 45 | } 46 | )* 47 | } 48 | } 49 | }; 50 | } 51 | 52 | #[cfg(test)] 53 | pub(crate) use test_cast_to_bigint; -------------------------------------------------------------------------------- /src/int/checked.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaacholt100/bnum/948e525d0b78e65b83f0d71eed1a2f58308bf268/src/int/checked.rs -------------------------------------------------------------------------------- /src/int/cmp.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impls { 2 | () => { 3 | #[inline] 4 | pub const fn max(self, other: Self) -> Self { 5 | match self.cmp(&other) { 6 | Ordering::Less | Ordering::Equal => other, 7 | _ => self, 8 | } 9 | } 10 | 11 | #[inline] 12 | pub const fn min(self, other: Self) -> Self { 13 | match self.cmp(&other) { 14 | Ordering::Less | Ordering::Equal => self, 15 | _ => other, 16 | } 17 | } 18 | 19 | #[inline] 20 | pub const fn clamp(self, min: Self, max: Self) -> Self { 21 | assert!(min.le(&max)); 22 | if let Ordering::Less = self.cmp(&min) { 23 | min 24 | } else if let Ordering::Greater = self.cmp(&max) { 25 | max 26 | } else { 27 | self 28 | } 29 | } 30 | 31 | #[inline] 32 | pub const fn lt(&self, other: &Self) -> bool { 33 | match self.cmp(&other) { 34 | Ordering::Less => true, 35 | _ => false, 36 | } 37 | } 38 | 39 | #[inline] 40 | pub const fn le(&self, other: &Self) -> bool { 41 | match self.cmp(&other) { 42 | Ordering::Less | Ordering::Equal => true, 43 | _ => false, 44 | } 45 | } 46 | 47 | #[inline] 48 | pub const fn gt(&self, other: &Self) -> bool { 49 | match self.cmp(&other) { 50 | Ordering::Greater => true, 51 | _ => false, 52 | } 53 | } 54 | 55 | #[inline] 56 | pub const fn ge(&self, other: &Self) -> bool { 57 | match self.cmp(&other) { 58 | Ordering::Greater | Ordering::Equal => true, 59 | _ => false, 60 | } 61 | } 62 | }; 63 | } 64 | 65 | pub(crate) use impls; 66 | 67 | #[cfg(test)] 68 | macro_rules! tests { 69 | ($int: ty) => { 70 | use crate::test::{test_bignum, types::*}; 71 | use core::cmp::Ord; 72 | 73 | test_bignum! { 74 | function: <$int>::eq(a: ref &$int, b: ref &$int) 75 | } 76 | test_bignum! { 77 | function: <$int as PartialEq>::eq(a: ref &$int, b: ref &$int) 78 | } 79 | test_bignum! { 80 | function: <$int>::partial_cmp(a: ref &$int, b: ref &$int) 81 | } 82 | test_bignum! { 83 | function: <$int as PartialOrd>::lt(a: ref &$int, b: ref &$int) 84 | } 85 | test_bignum! { 86 | function: <$int as PartialOrd>::le(a: ref &$int, b: ref &$int) 87 | } 88 | test_bignum! { 89 | function: <$int as PartialOrd>::gt(a: ref &$int, b: ref &$int) 90 | } 91 | test_bignum! { 92 | function: <$int as PartialOrd>::ge(a: ref &$int, b: ref &$int) 93 | } 94 | 95 | test_bignum! { 96 | function: <$int>::cmp(a: ref &$int, b: ref &$int) 97 | } 98 | test_bignum! { 99 | function: <$int>::max(a: $int, b: $int) 100 | } 101 | test_bignum! { 102 | function: <$int>::min(a: $int, b: $int) 103 | } 104 | test_bignum! { 105 | function: <$int>::clamp(a: $int, min: $int, max: $int), 106 | skip: min > max 107 | } 108 | 109 | test_bignum! { 110 | function: <$int as Ord>::cmp(a: ref &$int, b: ref &$int) 111 | } 112 | test_bignum! { 113 | function: <$int as Ord>::max(a: $int, b: $int) 114 | } 115 | test_bignum! { 116 | function: <$int as Ord>::min(a: $int, b: $int) 117 | } 118 | test_bignum! { 119 | function: <$int as Ord>::clamp(a: $int, min: $int, max: $int), 120 | skip: min > max 121 | } 122 | }; 123 | } 124 | 125 | #[cfg(test)] 126 | pub(crate) use tests; 127 | -------------------------------------------------------------------------------- /src/int/fmt.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | macro_rules! format_trait { 3 | ($($method: ident), *) => { 4 | // This trait allows us to use the default tester macro instead of creating a custom one 5 | pub trait Format { 6 | $( 7 | fn $method(&self, width: Option, extra: bool) -> alloc::string::String; 8 | )* 9 | } 10 | }; 11 | } 12 | 13 | #[cfg(test)] 14 | format_trait!(binary, lower_hex, upper_hex, octal, display, debug, lower_exp, upper_exp); 15 | 16 | #[cfg(test)] 17 | macro_rules! impl_format_method { 18 | { $($name: ident : $format: literal), * } => { 19 | $( 20 | fn $name(&self, width: Option, extra: bool) -> alloc::string::String { 21 | if let Some(width) = width { 22 | if extra { 23 | format!(concat!("{:+#0width$", $format, "}"), self, width = width as usize) 24 | } else { 25 | format!(concat!("{:width$", $format, "}"), self, width = width as usize) 26 | } 27 | } else if extra { 28 | format!(concat!("{:+#", $format, "}"), self) 29 | } else { 30 | format!(concat!("{:", $format, "}"), self) 31 | } 32 | } 33 | )* 34 | }; 35 | } 36 | 37 | #[cfg(test)] 38 | pub(crate) use impl_format_method; 39 | 40 | #[cfg(test)] 41 | macro_rules! impl_format { 42 | ($($ty: ty), *) => { 43 | $( 44 | impl Format for $ty { 45 | crate::int::fmt::impl_format_method! { 46 | binary: "b", 47 | lower_hex: "x", 48 | upper_hex: "X", 49 | octal: "o", 50 | display: "", 51 | debug: "?", 52 | lower_exp: "e", 53 | upper_exp: "E" 54 | } 55 | } 56 | )* 57 | }; 58 | } 59 | 60 | #[cfg(test)] 61 | pub(crate) use impl_format; 62 | 63 | #[cfg(test)] 64 | macro_rules! test_formats { 65 | ($ty: ty; $($name: ident), *) => { 66 | $( 67 | test_bignum! { 68 | function: <$ty as Format>::$name(a: ref &$ty, width: Option, extra: bool) 69 | } 70 | )* 71 | }; 72 | } 73 | 74 | #[cfg(test)] 75 | pub(crate) use test_formats; 76 | 77 | #[cfg(test)] 78 | macro_rules! tests { 79 | ($ty: ty) => { 80 | use crate::int::fmt::{Format, self}; 81 | use crate::test::{test_bignum, types::*}; 82 | 83 | paste::paste! { 84 | fmt::impl_format!([<$ty:upper>]); 85 | } 86 | 87 | fmt::test_formats!($ty; binary, lower_hex, upper_hex, octal, display, debug, lower_exp, upper_exp); 88 | }; 89 | } 90 | 91 | #[cfg(test)] 92 | pub(crate) use tests; 93 | 94 | #[cfg(test)] 95 | crate::int::fmt::impl_format!(u128, i128, u64, i64, u32, i32, u16, i16); 96 | -------------------------------------------------------------------------------- /src/int/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bigint_helpers; 2 | pub mod cast; 3 | pub mod checked; 4 | pub mod cmp; 5 | pub mod endian; 6 | pub mod fmt; 7 | 8 | #[cfg(feature = "numtraits")] 9 | pub mod numtraits; 10 | 11 | pub mod ops; 12 | pub mod radix; 13 | pub mod strict; 14 | pub mod unchecked; 15 | 16 | #[cfg(test)] 17 | macro_rules! tests { 18 | ($int: ty) => { 19 | test_bignum! { 20 | function: <$int>::count_ones(a: $int) 21 | } 22 | test_bignum! { 23 | function: <$int>::count_zeros(a: $int) 24 | } 25 | test_bignum! { 26 | function: <$int>::leading_zeros(a: $int) 27 | } 28 | test_bignum! { 29 | function: <$int>::trailing_zeros(a: $int) 30 | } 31 | test_bignum! { 32 | function: <$int>::leading_ones(a: $int) 33 | } 34 | test_bignum! { 35 | function: <$int>::trailing_ones(a: $int) 36 | } 37 | test_bignum! { 38 | function: <$int>::rotate_left(a: $int, b: u8) 39 | } 40 | test_bignum! { 41 | function: <$int>::rotate_right(a: $int, b: u8) 42 | } 43 | #[cfg(feature = "nightly")] // as unbounded_shifts not yet stabilised 44 | test_bignum! { 45 | function: <$int>::unbounded_shl(a: $int, b: u16) 46 | } 47 | #[cfg(feature = "nightly")] // as unbounded_shifts not yet stabilised 48 | test_bignum! { 49 | function: <$int>::unbounded_shr(a: $int, b: u16) 50 | } 51 | test_bignum! { 52 | function: <$int>::swap_bytes(a: $int) 53 | } 54 | test_bignum! { 55 | function: <$int>::reverse_bits(a: $int) 56 | } 57 | test_bignum! { 58 | function: <$int>::pow(a: $int, b: u16), 59 | skip: crate::test::debug_skip!(a.checked_pow(b as u32).is_none()) 60 | } 61 | test_bignum! { 62 | function: <$int>::div_euclid(a: $int, b: $int), 63 | skip: a.checked_div_euclid(b).is_none() 64 | } 65 | test_bignum! { 66 | function: <$int>::rem_euclid(a: $int, b: $int), 67 | skip: a.checked_rem_euclid(b).is_none() 68 | } 69 | test_bignum! { 70 | function: <$int>::abs_diff(a: $int, b: $int) 71 | } 72 | #[cfg(feature = "nightly")] // as num_midpoint_signed not yet stabilised 73 | test_bignum! { 74 | function: <$int>::midpoint(a: $int, b: $int) 75 | } 76 | test_bignum! { 77 | function: <$int>::ilog(a: $int, base: $int), 78 | skip: a <= 0 || base <= 1 79 | } 80 | test_bignum! { 81 | function: <$int>::ilog2(a: $int), 82 | skip: a <= 0 83 | } 84 | test_bignum! { 85 | function: <$int>::ilog10(a: $int), 86 | skip: a <= 0 87 | } 88 | // requires nightly as int_roundings not yet stabilised 89 | #[cfg(feature = "nightly")] 90 | test_bignum! { 91 | function: <$int>::checked_next_multiple_of(a: $int, b: $int) 92 | } 93 | #[cfg(feature = "nightly")] 94 | test_bignum! { 95 | function: <$int>::next_multiple_of(a: $int, b: $int), 96 | skip: crate::test::debug_skip!(a.checked_next_multiple_of(b).is_none()) || b == 0 97 | } 98 | #[cfg(feature = "nightly")] 99 | test_bignum! { 100 | function: <$int>::div_floor(a: $int, b: $int), 101 | skip: a.checked_div(b).is_none() 102 | } 103 | #[cfg(feature = "nightly")] 104 | test_bignum! { 105 | function: <$int>::div_ceil(a: $int, b: $int), 106 | skip: a.checked_div(b).is_none() 107 | } 108 | }; 109 | } 110 | 111 | #[cfg(test)] 112 | pub(crate) use tests; 113 | -------------------------------------------------------------------------------- /src/int/radix.rs: -------------------------------------------------------------------------------- 1 | macro_rules! assert_range { 2 | ($radix: expr, $max: expr) => { 3 | assert!( 4 | $radix >= 2 && $radix <= $max, 5 | crate::errors::err_msg!(concat!( 6 | "Radix must be in range [2, ", 7 | stringify!($max), 8 | "]" 9 | )) 10 | ) 11 | }; 12 | } 13 | 14 | pub(crate) use assert_range; 15 | -------------------------------------------------------------------------------- /src/int/strict.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impls { 2 | ($sign: ident) => { 3 | #[doc = doc::strict::strict_add!($sign)] 4 | #[must_use = doc::must_use_op!()] 5 | #[inline] 6 | pub const fn strict_add(self, rhs: Self) -> Self { 7 | crate::errors::option_expect!( 8 | self.checked_add(rhs), 9 | crate::errors::err_msg!("attempt to add with overflow") 10 | ) 11 | } 12 | 13 | #[doc = doc::strict::strict_sub!($sign)] 14 | #[must_use = doc::must_use_op!()] 15 | #[inline] 16 | pub const fn strict_sub(self, rhs: Self) -> Self { 17 | crate::errors::option_expect!( 18 | self.checked_sub(rhs), 19 | crate::errors::err_msg!("attempt to subtract with overflow") 20 | ) 21 | } 22 | 23 | #[doc = doc::strict::strict_mul!($sign)] 24 | #[must_use = doc::must_use_op!()] 25 | #[inline] 26 | pub const fn strict_mul(self, rhs: Self) -> Self { 27 | crate::errors::option_expect!( 28 | self.checked_mul(rhs), 29 | crate::errors::err_msg!("attempt to multiply with overflow") 30 | ) 31 | } 32 | 33 | #[doc = doc::strict::strict_div!($sign)] 34 | #[must_use = doc::must_use_op!()] 35 | #[inline] 36 | pub const fn strict_div(self, rhs: Self) -> Self { 37 | self.div(rhs) 38 | } 39 | 40 | #[doc = doc::strict::strict_div_euclid!($sign)] 41 | #[must_use = doc::must_use_op!()] 42 | #[inline] 43 | pub const fn strict_div_euclid(self, rhs: Self) -> Self { 44 | self.div_euclid(rhs) 45 | } 46 | 47 | #[doc = doc::strict::strict_rem!($sign)] 48 | #[must_use = doc::must_use_op!()] 49 | #[inline] 50 | pub const fn strict_rem(self, rhs: Self) -> Self { 51 | self.rem(rhs) 52 | } 53 | 54 | #[doc = doc::strict::strict_rem_euclid!($sign)] 55 | #[must_use = doc::must_use_op!()] 56 | #[inline] 57 | pub const fn strict_rem_euclid(self, rhs: Self) -> Self { 58 | self.rem_euclid(rhs) 59 | } 60 | 61 | #[doc = doc::strict::strict_neg!($sign)] 62 | #[must_use = doc::must_use_op!()] 63 | #[inline] 64 | pub const fn strict_neg(self) -> Self { 65 | crate::errors::option_expect!( 66 | self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow") 67 | ) 68 | } 69 | 70 | #[doc = doc::strict::strict_shl!($sign)] 71 | #[must_use = doc::must_use_op!()] 72 | #[inline] 73 | pub const fn strict_shl(self, rhs: crate::ExpType) -> Self { 74 | crate::errors::option_expect!( 75 | self.checked_shl(rhs), 76 | crate::errors::err_msg!("attempt to shift left with overflow") 77 | ) 78 | } 79 | 80 | #[doc = doc::strict::strict_shr!($sign)] 81 | #[must_use = doc::must_use_op!()] 82 | #[inline] 83 | pub const fn strict_shr(self, rhs: crate::ExpType) -> Self { 84 | crate::errors::option_expect!( 85 | self.checked_shr(rhs), 86 | crate::errors::err_msg!("attempt to shift right with overflow") 87 | ) 88 | } 89 | 90 | #[doc = doc::strict::strict_pow!($sign)] 91 | #[must_use = doc::must_use_op!()] 92 | #[inline] 93 | pub const fn strict_pow(self, exp: crate::ExpType) -> Self { 94 | crate::errors::option_expect!( 95 | self.checked_pow(exp), 96 | crate::errors::err_msg!("attempt to calculate power with overflow") 97 | ) 98 | } 99 | } 100 | } 101 | 102 | pub(crate) use impls; 103 | 104 | #[cfg(test)] 105 | macro_rules! tests { 106 | ($int: ty) => { 107 | use crate::test::{test_bignum, types::*}; 108 | 109 | test_bignum! { 110 | function: <$int>::strict_add(a: $int, b: $int), 111 | skip: a.checked_add(b).is_none() 112 | } 113 | test_bignum! { 114 | function: <$int>::strict_sub(a: $int, b: $int), 115 | skip: a.checked_sub(b).is_none() 116 | } 117 | test_bignum! { 118 | function: <$int>::strict_mul(a: $int, b: $int), 119 | skip: a.checked_mul(b).is_none() 120 | } 121 | test_bignum! { 122 | function: <$int>::strict_div(a: $int, b: $int), 123 | skip: a.checked_div(b).is_none() 124 | } 125 | test_bignum! { 126 | function: <$int>::strict_div_euclid(a: $int, b: $int), 127 | skip: a.checked_div_euclid(b).is_none() 128 | } 129 | test_bignum! { 130 | function: <$int>::strict_rem(a: $int, b: $int), 131 | skip: a.checked_rem(b).is_none() 132 | } 133 | test_bignum! { 134 | function: <$int>::strict_rem_euclid(a: $int, b: $int), 135 | skip: a.checked_rem_euclid(b).is_none() 136 | } 137 | test_bignum! { 138 | function: <$int>::strict_neg(a: $int), 139 | skip: a.checked_neg().is_none() 140 | } 141 | test_bignum! { 142 | function: <$int>::strict_shl(a: $int, b: u8), 143 | skip: a.checked_shl(b as u32).is_none() 144 | } 145 | test_bignum! { 146 | function: <$int>::strict_shr(a: $int, b: u8), 147 | skip: a.checked_shr(b as u32).is_none() 148 | } 149 | test_bignum! { 150 | function: <$int>::strict_pow(a: $int, b: u8), 151 | skip: a.checked_pow(b as u32).is_none() 152 | } 153 | } 154 | } 155 | 156 | #[cfg(test)] 157 | pub(crate) use tests; 158 | -------------------------------------------------------------------------------- /src/int/unchecked.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impls { 2 | ($Int: ident, $sign: ident) => { 3 | #[doc = doc::unchecked::impl_desc!()] 4 | impl $Int { 5 | crate::nightly::const_fns! { 6 | #[doc = doc::unchecked::unchecked_add!($sign)] 7 | #[must_use = doc::must_use_op!()] 8 | #[inline] 9 | pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { 10 | self.checked_add(rhs).unwrap_unchecked() 11 | } 12 | 13 | #[doc = doc::unchecked::unchecked_sub!($sign)] 14 | #[must_use = doc::must_use_op!()] 15 | #[inline] 16 | pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { 17 | self.checked_sub(rhs).unwrap_unchecked() 18 | } 19 | 20 | #[doc = doc::unchecked::unchecked_mul!($sign)] 21 | #[must_use = doc::must_use_op!()] 22 | #[inline] 23 | pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { 24 | self.checked_mul(rhs).unwrap_unchecked() 25 | } 26 | 27 | #[doc = doc::unchecked::unchecked_shl!($sign)] 28 | #[must_use = doc::must_use_op!()] 29 | #[inline] 30 | pub const unsafe fn unchecked_shl(self, rhs: crate::ExpType) -> Self { 31 | self.checked_shl(rhs).unwrap_unchecked() 32 | } 33 | 34 | #[doc = doc::unchecked::unchecked_shr!($sign)] 35 | #[must_use = doc::must_use_op!()] 36 | #[inline] 37 | pub const unsafe fn unchecked_shr(self, rhs: crate::ExpType) -> Self { 38 | self.checked_shr(rhs).unwrap_unchecked() 39 | } 40 | } 41 | } 42 | }; 43 | } 44 | 45 | pub(crate) use impls; 46 | 47 | #[cfg(test)] 48 | macro_rules! tests { 49 | ($int: ty) => { 50 | use crate::test::{test_bignum, types::*}; 51 | 52 | test_bignum! { 53 | function: unsafe <$int>::unchecked_add(a: $int, b: $int), 54 | skip: a.checked_add(b).is_none() 55 | } 56 | test_bignum! { 57 | function: unsafe <$int>::unchecked_sub(a: $int, b: $int), 58 | skip: a.checked_sub(b).is_none() 59 | } 60 | test_bignum! { 61 | function: unsafe <$int>::unchecked_mul(a: $int, b: $int), 62 | skip: a.checked_mul(b).is_none() 63 | } 64 | #[cfg(feature = "nightly")] // as unchecked_shifts not stabilised yet 65 | test_bignum! { 66 | function: unsafe <$int>::unchecked_shl(a: $int, b: u8), 67 | skip: a.checked_shl(b as u32).is_none() 68 | } 69 | #[cfg(feature = "nightly")] // as unchecked_shifts not stabilised yet 70 | test_bignum! { 71 | function: unsafe <$int>::unchecked_shr(a: $int, b: u8), 72 | skip: a.checked_shr(b as u32).is_none() 73 | } 74 | } 75 | } 76 | 77 | #[cfg(test)] 78 | pub(crate) use tests; -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "nightly", allow(incomplete_features))] 2 | #![cfg_attr( 3 | feature = "nightly", 4 | feature( 5 | generic_const_exprs, 6 | const_trait_impl, 7 | const_option, 8 | ) 9 | )] 10 | #![cfg_attr( 11 | all(test, feature = "nightly"), 12 | feature( 13 | bigint_helper_methods, 14 | int_roundings, 15 | float_minimum_maximum, 16 | wrapping_next_power_of_two, 17 | float_next_up_down, 18 | unchecked_shifts, 19 | integer_sign_cast, 20 | num_midpoint_signed, 21 | strict_overflow_ops, 22 | unbounded_shifts 23 | ) 24 | )] 25 | #![doc = include_str!("../README.md")] 26 | #![cfg_attr(not(any(feature = "arbitrary", feature = "quickcheck")), no_std)] 27 | // TODO: MAKE SURE NO_STD IS ENABLED WHEN PUBLISHING NEW VERSION 28 | 29 | #[macro_use] 30 | extern crate alloc; 31 | 32 | mod bint; 33 | mod buint; 34 | 35 | pub mod cast; 36 | mod digit; 37 | mod doc; 38 | pub mod errors; 39 | mod int; 40 | mod helpers; 41 | mod nightly; 42 | pub mod prelude; 43 | 44 | #[cfg(feature = "rand")] 45 | pub mod random; 46 | 47 | pub mod types; 48 | 49 | // #[cfg(feature = "float")] 50 | // mod float; 51 | 52 | // #[cfg(feature = "float")] 53 | // pub use float::Float; 54 | 55 | #[cfg(test)] 56 | mod test; 57 | 58 | #[cfg(test)] 59 | use test::types::*; 60 | 61 | type ExpType = u32; 62 | 63 | mod bigints { 64 | pub use crate::bint::{BInt, BIntD16, BIntD32, BIntD8}; 65 | pub use crate::buint::{BUint, BUintD16, BUintD32, BUintD8}; 66 | } 67 | 68 | pub use bigints::*; 69 | 70 | macro_rules! macro_impl { 71 | ($name: ident) => { 72 | #[allow(unused_imports)] 73 | use crate::bigints::*; 74 | 75 | crate::main_impl!($name); 76 | }; 77 | } 78 | 79 | pub(crate) use macro_impl; 80 | 81 | macro_rules! main_impl { 82 | ($name: ident) => { 83 | $name!(BUint, BInt, u64); 84 | $name!(BUintD32, BIntD32, u32); 85 | $name!(BUintD16, BIntD16, u16); 86 | $name!(BUintD8, BIntD8, u8); 87 | }; 88 | } 89 | 90 | use crate::buint::cast::buint_as_different_digit_bigint; 91 | use crate::bint::cast::bint_as_different_digit_bigint; 92 | 93 | buint_as_different_digit_bigint!(BUint, BInt, u64; (BUintD32, u32), (BUintD16, u16), (BUintD8, u8)); 94 | buint_as_different_digit_bigint!(BUintD32, BIntD32, u32; (BUint, u64), (BUintD16, u16), (BUintD8, u8)); 95 | buint_as_different_digit_bigint!(BUintD16, BIntD16, u16; (BUint, u64), (BUintD32, u32), (BUintD8, u8)); 96 | buint_as_different_digit_bigint!(BUintD8, BIntD8, u8; (BUint, u64), (BUintD32, u32), (BUintD16, u16)); 97 | 98 | bint_as_different_digit_bigint!(BUint, BInt, u64; (BIntD32, u32), (BIntD16, u16), (BIntD8, u8)); 99 | bint_as_different_digit_bigint!(BUintD32, BIntD32, u32; (BInt, u64), (BIntD16, u16), (BIntD8, u8)); 100 | bint_as_different_digit_bigint!(BUintD16, BIntD16, u16; (BInt, u64), (BIntD32, u32), (BIntD8, u8)); 101 | bint_as_different_digit_bigint!(BUintD8, BIntD8, u8; (BInt, u64), (BIntD32, u32), (BIntD16, u16)); 102 | 103 | pub(crate) use main_impl; 104 | 105 | /// Trait for fallible conversions between `bnum` integer types. 106 | /// 107 | /// Unfortunately, [`TryFrom`] cannot currently be used for conversions between `bnum` integers, since [`TryFrom for T`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html#impl-TryFrom%3CU%3E-for-T) is already implemented by the standard library (and so it is not possible to implement `TryFrom> for BUint`). When the [`generic_const_exprs`](https://github.com/rust-lang/rust/issues/76560) feature becomes stabilised, it may be possible to use [`TryFrom`] instead of `BTryFrom`. `BTryFrom` is designed to have the same behaviour as [`TryFrom`] for conversions between two primitive types, and conversions between a primitive type and a bnum type. `BTryFrom` is a workaround for the issue described above, and so you should not implement it yourself. It should only be used for conversions between `bnum` integers. 108 | pub trait BTryFrom: Sized { 109 | type Error; 110 | 111 | fn try_from(from: T) -> Result; 112 | } -------------------------------------------------------------------------------- /src/nightly.rs: -------------------------------------------------------------------------------- 1 | macro_rules! const_fn { 2 | { $(#[$attr: meta]) * $vis: vis const $($rest: tt) + } => { 3 | #[cfg(feature = "nightly")] 4 | $(#[$attr]) * 5 | #[doc = "\n\nNB: this method is only `const` when the `nightly` feature is enabled."] 6 | $vis const $($rest) + 7 | 8 | #[cfg(not(feature = "nightly"))] 9 | $(#[$attr]) * 10 | $vis $($rest) + 11 | }; 12 | } 13 | 14 | pub(crate) use const_fn; 15 | 16 | macro_rules! const_fns { 17 | { $($(#[$attr: meta]) * $vis: vis const fn $name: ident ($($args: tt) *) -> $ret : ty { $($f: tt) + }) * } => { 18 | $( 19 | crate::nightly::const_fn! { 20 | $(#[$attr]) * $vis const fn $name ($($args) *) -> $ret { $($f) + } 21 | } 22 | )* 23 | }; 24 | { $($(#[$attr: meta]) * $vis: vis const unsafe fn $name: ident ($($args: tt) *) -> $ret : ty { $($f: tt) + }) * } => { 25 | $( 26 | crate::nightly::const_fn! { 27 | $(#[$attr]) * $vis const unsafe fn $name ($($args) *) -> $ret { $($f) + } 28 | } 29 | )* 30 | }; 31 | } 32 | 33 | pub(crate) use const_fns; 34 | 35 | macro_rules! option_try { 36 | ($e: expr) => { 37 | match $e { 38 | Some(v) => v, 39 | None => return None, 40 | } 41 | }; 42 | } 43 | 44 | pub(crate) use option_try; 45 | 46 | macro_rules! ok { 47 | { $e: expr } => { 48 | match $e { 49 | Ok(v) => Some(v), 50 | Err(_) => None, 51 | } 52 | }; 53 | } 54 | 55 | pub(crate) use ok; 56 | -------------------------------------------------------------------------------- /src/prelude.rs: -------------------------------------------------------------------------------- 1 | //! A collection of common use items. 2 | 3 | pub use crate::cast::{As, CastFrom}; 4 | pub use crate::BInt; 5 | pub use crate::BUint; 6 | -------------------------------------------------------------------------------- /src/test/convert.rs: -------------------------------------------------------------------------------- 1 | use crate::cast::CastFrom; 2 | use crate::test::types::*; 3 | use crate::*; 4 | 5 | pub trait TestConvert { 6 | type Output; 7 | 8 | fn into(self) -> Self::Output; 9 | } 10 | 11 | #[allow(unused)] // since this is only used with certain crate feature but these are likely to change often 12 | pub fn test_eq(t: T, u: U) -> bool 13 | where 14 | T: TestConvert, 15 | U: TestConvert, 16 | ::Output: PartialEq<::Output> 17 | { 18 | t.into() == u.into() 19 | } 20 | 21 | macro_rules! test_convert_big { 22 | ($($big: ty), *; $output: ty) => { 23 | $( 24 | impl TestConvert for $big { 25 | type Output = $output; 26 | 27 | #[inline] 28 | fn into(self) -> Self::Output { 29 | Self::Output::cast_from(self) 30 | } 31 | } 32 | )* 33 | }; 34 | } 35 | 36 | macro_rules! test_convert_bigints { 37 | ($($bits: literal), *) => { 38 | paste::paste! { 39 | $( 40 | test_convert_big!(BUint<{$bits / 64}>, BUintD32<{$bits / 32}>, BUintD16<{$bits / 16}>, BUintD8<{$bits / 8}>; []); 41 | 42 | test_convert_big!(BInt<{$bits / 64}>, BIntD32<{$bits / 32}>, BIntD16<{$bits / 16}>, BIntD8<{$bits / 8}>; []); 43 | )* 44 | } 45 | }; 46 | } 47 | 48 | test_convert_bigints!(128, 64); 49 | 50 | test_convert_big!(BUintD32<{32 / 32}>, BUintD16<{32 / 16}>, BUintD8<{32 / 8}>; u32); 51 | test_convert_big!(BIntD32<{32 / 32}>, BIntD16<{32 / 16}>, BIntD8<{32 / 8}>; i32); 52 | test_convert_big!(BUintD16<{16 / 16}>, BUintD8<{16 / 8}>; u16); 53 | test_convert_big!(BIntD16<{16 / 16}>, BIntD8<{16 / 8}>; i16); 54 | 55 | impl TestConvert for Option { 56 | type Output = Option<::Output>; 57 | 58 | #[inline] 59 | fn into(self) -> Self::Output { 60 | self.map(TestConvert::into) 61 | } 62 | } 63 | 64 | impl TestConvert for f64 { 65 | type Output = u64; 66 | 67 | #[inline] 68 | fn into(self) -> Self::Output { 69 | self.to_bits() 70 | } 71 | } 72 | 73 | impl TestConvert for f32 { 74 | type Output = u32; 75 | 76 | #[inline] 77 | fn into(self) -> Self::Output { 78 | self.to_bits() 79 | } 80 | } 81 | 82 | // #[cfg(feature = "float")] 83 | // impl TestConvert for crate::float::F64 { 84 | // type Output = u64; 85 | 86 | // #[inline] 87 | // fn into(self) -> Self::Output { 88 | // use crate::cast::As; 89 | 90 | // self.to_bits().as_() 91 | // } 92 | // } 93 | 94 | // #[cfg(feature = "float")] 95 | // impl TestConvert for crate::float::F32 { 96 | // type Output = u32; 97 | 98 | // #[inline] 99 | // fn into(self) -> Self::Output { 100 | // use crate::cast::As; 101 | 102 | // self.to_bits().as_() 103 | // } 104 | // } 105 | 106 | impl TestConvert for (T, U) { 107 | type Output = (::Output, ::Output); 108 | 109 | #[inline] 110 | fn into(self) -> Self::Output { 111 | (TestConvert::into(self.0), TestConvert::into(self.1)) 112 | } 113 | } 114 | 115 | impl TestConvert for [T; N] { 116 | type Output = Self; 117 | 118 | #[inline] 119 | fn into(self) -> Self::Output { 120 | self 121 | } 122 | } 123 | 124 | impl TestConvert for crate::errors::ParseIntError { 125 | type Output = core::num::IntErrorKind; 126 | 127 | #[inline] 128 | fn into(self) -> Self::Output { 129 | self.kind().clone() 130 | } 131 | } 132 | 133 | impl TestConvert for core::num::ParseIntError { 134 | type Output = core::num::IntErrorKind; 135 | 136 | #[inline] 137 | fn into(self) -> Self::Output { 138 | self.kind().clone() 139 | } 140 | } 141 | 142 | impl TestConvert for Result { 143 | type Output = Result<::Output, ::Output>; 144 | 145 | #[inline] 146 | fn into(self) -> Self::Output { 147 | self 148 | .map(TestConvert::into) 149 | .map_err(TestConvert::into) 150 | } 151 | } 152 | 153 | impl TestConvert for core::num::TryFromIntError { 154 | type Output = (); 155 | 156 | #[inline] 157 | fn into(self) -> Self::Output { 158 | () 159 | } 160 | } 161 | 162 | impl TestConvert for crate::errors::TryFromIntError { 163 | type Output = (); 164 | 165 | #[inline] 166 | fn into(self) -> Self::Output { 167 | () 168 | } 169 | } 170 | 171 | impl TestConvert for core::convert::Infallible { 172 | type Output = (); 173 | 174 | #[inline] 175 | fn into(self) -> Self::Output { 176 | () 177 | } 178 | } 179 | 180 | macro_rules! test_convert_to_self { 181 | ($($ty: ty), *) => { 182 | $( 183 | impl TestConvert for $ty { 184 | type Output = Self; 185 | 186 | #[inline] 187 | fn into(self) -> Self::Output { 188 | self 189 | } 190 | } 191 | )* 192 | }; 193 | } 194 | 195 | test_convert_to_self!( 196 | core::num::FpCategory, 197 | core::cmp::Ordering, 198 | bool, 199 | u8, 200 | u16, 201 | u32, 202 | u64, 203 | u128, 204 | usize, 205 | i8, 206 | i16, 207 | i32, 208 | i64, 209 | i128, 210 | isize, 211 | alloc::string::String 212 | ); 213 | -------------------------------------------------------------------------------- /src/test/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod convert; 2 | pub use convert::TestConvert; 3 | 4 | mod macros; 5 | 6 | #[allow(unused_imports)] 7 | pub use macros::*; 8 | 9 | pub mod types; 10 | 11 | #[derive(Clone, Copy)] 12 | pub struct U8ArrayWrapper(pub [u8; N]); 13 | 14 | impl From> for [u8; N] { 15 | fn from(a: U8ArrayWrapper) -> Self { 16 | a.0 17 | } 18 | } 19 | 20 | use quickcheck::{Arbitrary, Gen}; 21 | 22 | impl Arbitrary for U8ArrayWrapper { 23 | fn arbitrary(g: &mut Gen) -> Self { 24 | let mut arr = [0u8; N]; 25 | for x in arr.iter_mut() { 26 | *x = u8::arbitrary(g); 27 | } 28 | Self(arr) 29 | } 30 | } 31 | 32 | use core::fmt::{self, Debug, Formatter}; 33 | 34 | impl Debug for U8ArrayWrapper { 35 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 36 | self.0.fmt(f) 37 | } 38 | } 39 | 40 | pub mod cast_types { 41 | use crate::{BUint, BUintD32, BUintD16, BUintD8, BInt, BIntD32, BIntD16, BIntD8}; 42 | 43 | pub use crate::big_types::u8::{UTEST as UTESTD8, ITEST as ITESTD8}; 44 | pub use crate::big_types::u16::{UTEST as UTESTD16, ITEST as ITESTD16}; 45 | pub use crate::big_types::u32::{UTEST as UTESTD32, ITEST as ITESTD32}; 46 | pub use crate::big_types::u64::{UTEST as UTESTD64, ITEST as ITESTD64}; 47 | 48 | pub type TestUint1 = BUint<3>; 49 | pub type TestUint2 = BUintD32<5>; 50 | pub type TestUint3 = BUintD16<6>; 51 | pub type TestUint4 = BUintD8<11>; 52 | pub type TestUint5 = BUintD16<3>; 53 | pub type TestUint6 = BUintD8<7>; 54 | pub type TestUint7 = BUintD8<3>; 55 | pub type TestUint8 = BUintD16<1>; 56 | pub type TestUint9 = BUintD8<15>; 57 | pub type TestUint10 = BUintD8<17>; 58 | 59 | pub type TestInt1 = BInt<3>; 60 | pub type TestInt2 = BIntD32<5>; 61 | pub type TestInt3 = BIntD16<6>; 62 | pub type TestInt4 = BIntD8<11>; 63 | pub type TestInt5 = BIntD16<3>; 64 | pub type TestInt6 = BIntD8<7>; 65 | pub type TestInt7 = BIntD8<3>; 66 | pub type TestInt8 = BIntD16<1>; 67 | pub type TestInt9 = BIntD8<15>; 68 | pub type TestInt10 = BIntD8<17>; 69 | } -------------------------------------------------------------------------------- /src/test/types.rs: -------------------------------------------------------------------------------- 1 | pub mod big_types { 2 | macro_rules! big_types_modules { 3 | ($bits: literal) => { 4 | pub mod u8 { 5 | pub type UTEST = crate::BUintD8<{ $bits / 8 }>; 6 | pub type ITEST = crate::BIntD8<{ $bits / 8 }>; 7 | } 8 | pub mod u16 { 9 | pub type UTEST = crate::BUintD16<{ $bits / 16 }>; 10 | pub type ITEST = crate::BIntD16<{ $bits / 16 }>; 11 | } 12 | pub mod u32 { 13 | pub type UTEST = crate::BUintD32<{ $bits / 32 }>; 14 | pub type ITEST = crate::BIntD32<{ $bits / 32 }>; 15 | } 16 | pub mod u64 { 17 | pub type UTEST = crate::BUint<{ $bits / 64 }>; 18 | pub type ITEST = crate::BInt<{ $bits / 64 }>; 19 | } 20 | }; 21 | } 22 | 23 | #[cfg(test_int_bits = "16")] 24 | big_types_modules!(16); 25 | 26 | #[cfg(test_int_bits = "32")] 27 | big_types_modules!(32); 28 | 29 | #[cfg(test_int_bits = "128")] 30 | big_types_modules!(128); 31 | 32 | #[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] 33 | big_types_modules!(64); 34 | } 35 | 36 | #[cfg(test_int_bits = "16")] 37 | mod small_types { 38 | #[allow(non_camel_case_types)] 39 | pub type utest = u16; 40 | 41 | #[allow(non_camel_case_types)] 42 | pub type itest = i16; 43 | 44 | // #[cfg(feature = "float")] 45 | // #[allow(non_camel_case_types)] 46 | // pub type ftest = f16; 47 | } 48 | 49 | #[cfg(test_int_bits = "32")] 50 | mod small_types { 51 | #[allow(non_camel_case_types)] 52 | pub type utest = u32; 53 | 54 | #[allow(non_camel_case_types)] 55 | pub type itest = i32; 56 | 57 | // #[cfg(feature = "float")] 58 | // #[allow(non_camel_case_types)] 59 | // pub type ftest = f32; 60 | } 61 | 62 | #[cfg(test_int_bits = "128")] 63 | mod small_types { 64 | #[allow(non_camel_case_types)] 65 | pub type utest = u128; 66 | 67 | #[allow(non_camel_case_types)] 68 | pub type itest = i128; 69 | 70 | // #[cfg(feature = "float")] 71 | // #[allow(non_camel_case_types)] 72 | // pub type ftest = f128; 73 | } 74 | 75 | #[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] // default is 64 76 | mod small_types { 77 | #[allow(non_camel_case_types)] 78 | pub type utest = u64; 79 | 80 | #[allow(non_camel_case_types)] 81 | pub type itest = i64; 82 | 83 | // #[cfg(feature = "float")] 84 | // #[allow(non_camel_case_types)] 85 | // pub type ftest = f64; 86 | } 87 | 88 | pub use core::primitive::*; 89 | pub use small_types::*; 90 | 91 | // #[cfg(feature = "float")] 92 | // #[cfg(not(test_int_bits = "32"))] 93 | // pub type FTEST = crate::float::Float<8, 52>; 94 | 95 | // #[cfg(feature = "float")] 96 | // #[cfg(test_int_bits = "32")] 97 | // pub type FTEST = crate::float::Float<4, 23>; -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | //! Type aliases for big signed and unsigned integers. Each is an alias for either a [`BUint`] or a [`BInt`]. 2 | 3 | use crate::{BInt, BUint}; 4 | 5 | macro_rules! int_type_doc { 6 | ($bits: literal, $sign: literal) => { 7 | concat!($bits, "-bit ", $sign, " integer type.") 8 | }; 9 | } 10 | 11 | macro_rules! int_types { 12 | { $($bits: literal $u: ident $i: ident; ) *} => { 13 | $( 14 | #[doc = int_type_doc!($bits, "unsigned")] 15 | pub type $u = BUint::<{$bits / 64}>; 16 | 17 | #[doc = int_type_doc!($bits, "signed")] 18 | pub type $i = BInt::<{$bits / 64}>; 19 | )* 20 | }; 21 | } 22 | 23 | macro_rules! call_types_macro { 24 | ($name: ident) => { 25 | $name! { 26 | 128 U128 I128; 27 | 256 U256 I256; 28 | 512 U512 I512; 29 | 1024 U1024 I1024; 30 | 2048 U2048 I2048; 31 | 4096 U4096 I4096; 32 | 8192 U8192 I8192; 33 | } 34 | }; 35 | } 36 | 37 | call_types_macro!(int_types); 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use super::*; 42 | 43 | macro_rules! assert_int_bits { 44 | { $($bits: literal $u: ident $i: ident; ) *} => { 45 | $( 46 | assert_eq!($u::BITS, $bits); 47 | assert_eq!($i::BITS, $bits); 48 | )* 49 | } 50 | } 51 | 52 | #[test] 53 | fn test_int_bits() { 54 | call_types_macro!(assert_int_bits); 55 | } 56 | } 57 | --------------------------------------------------------------------------------