From b669126b9454bec6d6e4a1f103edfe6812f5a031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charlotte=20=F0=9F=A6=9D=20Delenk?= Date: Thu, 19 Sep 2024 13:43:06 +0200 Subject: [PATCH 1/3] Begin rewrite --- Cargo.lock | 28 +- Cargo.nix | 58 +- Cargo.toml | 11 +- README.md | 8 +- build.rs | 138 ++ flake.lock | 11 +- flake.nix | 8 +- src/gamma.rs | 67 - src/gamma/f64.rs | 239 ---- src/lib.rs | 3 +- src/n_choose_k.rs | 36 - src/u256/mod.rs | 3103 +++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 3268 insertions(+), 442 deletions(-) create mode 100644 build.rs delete mode 100644 src/gamma.rs delete mode 100644 src/gamma/f64.rs delete mode 100644 src/n_choose_k.rs create mode 100644 src/u256/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 372c638..4ba13c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,32 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - [[package]] name = "extra-math" -version = "0.1.1" -dependencies = [ - "libm", - "num-traits", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] +version = "0.2.0" diff --git a/Cargo.nix b/Cargo.nix index 16262db..a165254 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -22,7 +22,7 @@ args @ { workspaceSrc, ignoreLockHash, }: let - nixifiedLockHash = "c2eb36fad35932f80d6eec4c083c16822de79c56cace0639af21e9933c2ca6f9"; + nixifiedLockHash = "74f9e44cc52b70b46b1a8e880aaaa90232d5db51c515bd0708c4b6732faf788b"; workspaceSrc = if args.workspaceSrc == null then ./. @@ -59,63 +59,17 @@ in in { cargo2nixVersion = "0.11.0"; workspace = { - extra-math = rustPackages.unknown.extra-math."0.1.1"; + extra-math = rustPackages.unknown.extra-math."0.2.0"; }; - "registry+https://github.com/rust-lang/crates.io-index".autocfg."1.3.0" = overridableMkRustCrate (profileName: rec { - name = "autocfg"; - version = "1.3.0"; - registry = "registry+https://github.com/rust-lang/crates.io-index"; - src = fetchCratesIo { - inherit name version; - sha256 = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"; - }; - }); - - "unknown".extra-math."0.1.1" = overridableMkRustCrate (profileName: rec { + "unknown".extra-math."0.2.0" = overridableMkRustCrate (profileName: rec { name = "extra-math"; - version = "0.1.1"; + version = "0.2.0"; registry = "unknown"; src = fetchCrateLocal workspaceSrc; features = builtins.concatLists [ (lib.optional (rootFeatures' ? "extra-math/default") "default") - (lib.optional (rootFeatures' ? "extra-math/std") "std") + (lib.optional (rootFeatures' ? "extra-math/u256") "u256") + (lib.optional (rootFeatures' ? "extra-math/unstable") "unstable") ]; - dependencies = { - libm = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libm."0.2.8" {inherit profileName;}).out; - num_traits = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".num-traits."0.2.19" {inherit profileName;}).out; - }; - }); - - "registry+https://github.com/rust-lang/crates.io-index".libm."0.2.8" = overridableMkRustCrate (profileName: rec { - name = "libm"; - version = "0.2.8"; - registry = "registry+https://github.com/rust-lang/crates.io-index"; - src = fetchCratesIo { - inherit name version; - sha256 = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"; - }; - features = builtins.concatLists [ - ["default"] - ]; - }); - - "registry+https://github.com/rust-lang/crates.io-index".num-traits."0.2.19" = overridableMkRustCrate (profileName: rec { - name = "num-traits"; - version = "0.2.19"; - registry = "registry+https://github.com/rust-lang/crates.io-index"; - src = fetchCratesIo { - inherit name version; - sha256 = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"; - }; - features = builtins.concatLists [ - ["libm"] - (lib.optional (rootFeatures' ? "extra-math/std") "std") - ]; - dependencies = { - libm = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libm."0.2.8" {inherit profileName;}).out; - }; - buildDependencies = { - autocfg = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".autocfg."1.3.0" {profileName = "__noProfile";}).out; - }; }); } diff --git a/Cargo.toml b/Cargo.toml index d0c9732..817c4ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,20 @@ [package] name = "extra-math" -version = "0.1.1" +version = "0.2.0" edition = "2021" authors = ["Charlotte šŸ¦ Delenk "] -description = "Additional math functions not found in the standard library or libm" +description = "Support for extra maths functions and floating point types" license = "MIT OR Apache-2.0" repository = "https://git.chir.rs/ProcyOS/rust-template" keywords = ["mathematics"] categories = ["mathematics", "no-std", "no-std::no-alloc"] [dependencies] -libm = "0.2.8" -num-traits = { version = "0.2.19", default-features = false, features = [ - "libm", -] } [features] default = [] -std = ["num-traits/std"] +unstable = [] +u256 = [] [lints.rust] deprecated-safe = "forbid" diff --git a/README.md b/README.md index 3153d7e..097d669 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ # extra_math -Mathematical functions that are used in procyosā€™s code that arenā€™t found in either `libm` or the standard library. +Maths support code for various floating point types -It is not intended to be accurate, just useful in a no-std environment. +## Features + +Each floating point type is feature gated. Some other functionality is enabled in some cases. + +- `u256`: Enable a 256 bit unsigned integer type. This is *NOT* a constant time implementation. ## Running the tests diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..dbd47a4 --- /dev/null +++ b/build.rs @@ -0,0 +1,138 @@ +//! Build script for compiler feature detection +use std::env; + +fn main() { + #[cfg(all(feature = "unstable"))] + { + // Feature detection whether native f16/f128 support works + // This is taken from https://github.com/rust-lang/rust/blob/master/library/std/build.rs + println!("cargo:rerun-if-changed=build.rs"); + let target_arch = + env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set"); + let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); + let target_vendor = + env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set"); + let target_pointer_width: u32 = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") + .parse() + .unwrap(); + let is_miri = env::var_os("CARGO_CFG_MIRI").is_some(); + // Emit these on platforms that have no known ABI bugs, LLVM selection bugs, lowering bugs, + // missing symbols, or other problems, to determine when tests get run. + // If more broken platforms are found, please update the tracking issue at + // + // + // Some of these match arms are redundant; the goal is to separate reasons that the type is + // unreliable, even when multiple reasons might fail the same platform. + println!("cargo:rustc-check-cfg=cfg(reliable_f16)"); + println!("cargo:rustc-check-cfg=cfg(reliable_f128)"); + + // This is a step beyond only having the types and basic functions available. Math functions + // aren't consistently available or correct. + println!("cargo:rustc-check-cfg=cfg(reliable_f16_math)"); + println!("cargo:rustc-check-cfg=cfg(reliable_f128_math)"); + + let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { + // We can always enable these in Miri as that is not affected by codegen bugs. + _ if is_miri => true, + // Selection failure until recent LLVM + // FIXME(llvm19): can probably be removed at the version bump + ("loongarch64", _) => false, + // Selection failure + ("s390x", _) => false, + // Unsupported + ("arm64ec", _) => false, + // MinGW ABI bugs + ("x86_64", "windows") => false, + // Apple has a special ABI for `f16` that we do not yet support + // FIXME(builtins): fixed by + ("x86" | "x86_64", _) if target_vendor == "apple" => false, + // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` + ("powerpc" | "powerpc64", _) => false, + // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` + ("mips" | "mips32r6" | "mips64" | "mips64r6", _) => false, + // Missing `__extendhfsf` and `__truncsfhf` + ("riscv32" | "riscv64", _) => false, + // Most OSs are missing `__extendhfsf` and `__truncsfhf` + (_, "linux" | "macos") => true, + // Almost all OSs besides Linux and MacOS are missing symbols until compiler-builtins can + // be updated. will get some of these, the + // next CB update should get the rest. + _ => false, + }; + + let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) { + // We can always enable these in Miri as that is not affected by codegen bugs. + _ if is_miri => true, + // Unsupported + ("arm64ec", _) => false, + // ABI and precision bugs + // + ("powerpc" | "powerpc64", _) => false, + // Selection bug + ("nvptx64", _) => false, + // ABI unsupported + ("sparc", _) => false, + // MinGW ABI bugs + ("x86_64", "windows") => false, + // 64-bit Linux is about the only platform to have f128 symbols by default + (_, "linux") if target_pointer_width == 64 => true, + // Same as for f16, except MacOS is also missing f128 symbols. + _ => false, + }; + + // Configure platforms that have reliable basics but may have unreliable math. + + // LLVM is currently adding missing routines, + let has_reliable_f16_math = has_reliable_f16 + && match (target_arch.as_str(), target_os.as_str()) { + // FIXME: Disabled on Miri as the intrinsics are not implemented yet. + _ if is_miri => false, + // x86 has a crash for `powi`: + ("x86" | "x86_64", _) => false, + // Assume that working `f16` means working `f16` math for most platforms, since + // operations just go through `f32`. + _ => true, + }; + + let has_reliable_f128_math = has_reliable_f128 + && match (target_arch.as_str(), target_os.as_str()) { + // FIXME: Disabled on Miri as the intrinsics are not implemented yet. + _ if is_miri => false, + // LLVM lowers `fp128` math to `long double` symbols even on platforms where + // `long double` is not IEEE binary128. See + // . + // + // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits + // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86` + // (ld is 80-bit extended precision). + ("x86_64", _) => false, + (_, "linux") if target_pointer_width == 64 => true, + _ => false, + }; + + if has_reliable_f16 { + println!("cargo:rustc-cfg=reliable_f16"); + } + if has_reliable_f128 { + println!("cargo:rustc-cfg=reliable_f128"); + } + if has_reliable_f16_math { + println!("cargo:rustc-cfg=reliable_f16_math"); + } + if has_reliable_f128_math { + println!("cargo:rustc-cfg=reliable_f128_math"); + } + } + + println!("cargo:rustc-check-cfg=cfg(overflow_checks_stable)"); + + if std::panic::catch_unwind(|| { + #[allow(arithmetic_overflow)] + let _ = 255_u8 + 1; + }) + .is_err() + { + println!("cargo:rustc-cfg=overflow_checks_stable"); + } +} diff --git a/flake.lock b/flake.lock index b5b9470..287e973 100644 --- a/flake.lock +++ b/flake.lock @@ -14,16 +14,15 @@ ] }, "locked": { - "lastModified": 1713199118, - "narHash": "sha256-MlLdAvk+zXCFUy280sY6LqtykqWXIkKVXo72J7a6HlU=", - "owner": "cargo2nix", + "lastModified": 1726552619, + "narHash": "sha256-ytTBILVMnRZYvjiLYz+J6IFf/TOXdGuP6RDesMx9qgA=", + "owner": "DarkKirb", "repo": "cargo2nix", - "rev": "1efb03f2f794ad5eed17e807e858c4da001dbc3e", + "rev": "baa12124e2de09e1cbbdac320f14809fa55af1a2", "type": "github" }, "original": { - "owner": "cargo2nix", - "ref": "main", + "owner": "DarkKirb", "repo": "cargo2nix", "type": "github" } diff --git a/flake.nix b/flake.nix index 708a530..fa53a3f 100644 --- a/flake.nix +++ b/flake.nix @@ -2,17 +2,17 @@ description = "extra-math"; inputs = { - nixpkgs.url = github:NixOS/nixpkgs; - flake-utils.url = github:numtide/flake-utils; + nixpkgs.url = "github:NixOS/nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; rust-overlay = { - url = github:oxalica/rust-overlay; + url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; }; cargo2nix = { - url = github:cargo2nix/cargo2nix/main; + url = "github:DarkKirb/cargo2nix"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; inputs.rust-overlay.follows = "rust-overlay"; diff --git a/src/gamma.rs b/src/gamma.rs deleted file mode 100644 index 61eb638..0000000 --- a/src/gamma.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Gamma function approximation -//! -//! This module calculates various gamma functions - -use num_traits::Float; - -mod f64; - -/// Trait implementing the gamma functions -pub trait Gamma: Float { - /// Calculates the logarithm of the Gamma function. - fn ln_gamma(self) -> Self { - self.gamma().ln() - } - /// Calculates the Gamma function. - fn gamma(self) -> Self; - /// Returns the upper incomplete regularized gamma function Q(a, x) - fn upper_gamma_regularized(self, x: Self) -> Self { - Self::one() - self.lower_gamma_regularized(x) - } - /// Returns the upper incomplete gamma function Q(a, x) - fn upper_gamma_incomplete(self, x: Self) -> Self { - self.upper_gamma_regularized(x) * self.gamma() - } - /// Returns the lower incomplete regularized gamma function P(a, x) - fn lower_gamma_regularized(self, x: Self) -> Self; - /// Returns the lower incomplete gamma function P(a, x) - fn lower_gamma_incomplete(self, x: Self) -> Self { - self.lower_gamma_regularized(x) * self.gamma() - } -} - -impl Gamma for f32 { - fn gamma(self) -> Self { - Gamma::gamma(self as f64) as f32 - } - - fn lower_gamma_regularized(self, x: Self) -> Self { - Gamma::lower_gamma_regularized(self as f64, x as f64) as f32 - } - - fn ln_gamma(self) -> Self { - Gamma::ln_gamma(self as f64) as f32 - } - - fn upper_gamma_regularized(self, x: Self) -> Self { - Gamma::upper_gamma_regularized(self as f64, x as f64) as f32 - } - - fn upper_gamma_incomplete(self, x: Self) -> Self { - Gamma::upper_gamma_incomplete(self as f64, x as f64) as f32 - } - - fn lower_gamma_incomplete(self, x: Self) -> Self { - Gamma::lower_gamma_incomplete(self as f64, x as f64) as f32 - } -} - -#[cfg(test)] -mod tests { - use crate::gamma::Gamma; - - #[test] - fn upper_gamma_accuracy() { - assert!((Gamma::upper_gamma_regularized(1.5, 0.5) - 0.801252f64).abs() < 0.001); - } -} diff --git a/src/gamma/f64.rs b/src/gamma/f64.rs deleted file mode 100644 index 073d0f7..0000000 --- a/src/gamma/f64.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! 64 bit float implementation for gamma -//! -//! This implementation is based on the Math.NET library. - -// Copyright (c) 2009-2010 Math.NET -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -use core::f64::NAN; -#[allow(unused_imports)] -use num_traits::Float; - -use super::Gamma; - -impl Gamma for f64 { - fn ln_gamma(self) -> Self { - libm::lgamma(self) - } - fn gamma(self) -> Self { - libm::tgamma(self) - } - fn lower_gamma_regularized(self, x: Self) -> Self { - if self.is_nan() { - return NAN; - } - if x.is_nan() { - return NAN; - } - const EPSILON: f64 = 0.000000000000001; - const BIG: f64 = 4503599627370496.0; - const BIG_INV: f64 = 2.22044604925031308085e-16; - if self < 0.0 { - return NAN; - } - if x < 0.0 { - return NAN; - } - if self < 0.000000000000001 { - return 1.0; - } - if x < 0.000000000000001 { - return 0.0; - } - let ax = self * x.ln() - x - Gamma::ln_gamma(self); - if ax < -709.78271289338399 { - return if self < x { 1.0 } else { 0.0 }; - } - if x <= 1.0 || x <= self { - let mut r2 = self; - let mut c2 = 1.0; - let mut ans2 = 1.0; - loop { - r2 += 1.0; - c2 *= x / r2; - ans2 += c2; - if (c2 / ans2) <= EPSILON { - break; - } - } - return ax.exp() * ans2 / self; - } - let mut c = 0; - let mut y = 1.0 - self; - let mut z = x + y + 1.0; - let mut p3 = 1.0; - let mut q3 = x; - let mut p2 = x + 1.0; - let mut q2 = z * x; - let mut ans = p2 / q2; - let mut error; - - loop { - c += 1; - y += 1.0; - z += 2.0; - let yc = y * (c as f64); - let p = p2 * z - p3 * yc; - let q = q2 * z - q3 * yc; - if q != 0.0 { - let nextans = p / q; - error = ((ans - nextans) / nextans).abs(); - ans = nextans; - } else { - error = 1.0; - } - p3 = p2; - p2 = p; - q3 = q2; - q2 = q; - if p.abs() > BIG { - p3 *= BIG_INV; - p2 *= BIG_INV; - q3 *= BIG_INV; - q2 *= BIG_INV; - } - if error <= EPSILON { - break; - } - } - 1.0 - ax.exp() * ans - } -} - -#[cfg(test)] -mod tests { - use crate::gamma::Gamma; - macro_rules! assert_almost_eq { - ($a:expr, $b:expr, $prec:expr) => { - #[allow(trivial_numeric_casts)] - if (($a - $b) as f64).abs() > $prec { - panic!( - "assertion failed: `abs(left - right) < {:e}`, (left: `{}`, right: `{}`)", - $prec, $a, $b - ); - } - }; - } - - #[test] - fn test_gamma_lr() { - assert!(Gamma::lower_gamma_regularized(f64::NAN, f64::NAN).is_nan()); - assert_almost_eq!( - Gamma::lower_gamma_regularized(0.1, 1.0), - 0.97587265627367222115949155252812057714751052498477013, - 1e-14 - ); - assert_eq!( - Gamma::lower_gamma_regularized(0.1, 2.0), - 0.99432617602018847196075251078067514034772764693462125 - ); - assert_eq!( - Gamma::lower_gamma_regularized(0.1, 8.0), - 0.99999507519205198048686442150578226823401842046310854 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(1.5, 1.0), - 0.42759329552912016600095238564127189392715996802703368, - 1e-13 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(1.5, 2.0), - 0.73853587005088937779717792402407879809718939080920993, - 1e-15 - ); - assert_eq!( - Gamma::lower_gamma_regularized(1.5, 8.0), - 0.99886601571021467734329986257903021041757398191304284 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(2.5, 1.0), - 0.15085496391539036377410688601371365034788861473418704, - 1e-13 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(2.5, 2.0), - 0.45058404864721976739416885516693969548484517509263197, - 1e-14 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(2.5, 8.0), - 0.99315592607757956900093935107222761316136944145439676, - 1e-15 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(5.5, 1.0), - 0.0015041182825838038421585211353488839717739161316985392, - 1e-15 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(5.5, 2.0), - 0.030082976121226050615171484772387355162056796585883967, - 1e-14 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(5.5, 8.0), - 0.85886911973294184646060071855669224657735916933487681, - 1e-14 - ); - assert_almost_eq!(Gamma::lower_gamma_regularized(100.0, 0.5), 0.0, 1e-188); - assert_almost_eq!(Gamma::lower_gamma_regularized(100.0, 1.5), 0.0, 1e-141); - assert_almost_eq!( - Gamma::lower_gamma_regularized(100.0, 90.0), - 0.1582209891864301681049696996709105316998233457433473, - 1e-13 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(100.0, 100.0), - 0.5132987982791486648573142565640291634709251499279450, - 1e-13 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(100.0, 110.0), - 0.8417213299399129061982996209829688531933500308658222, - 1e-13 - ); - assert_almost_eq!(Gamma::lower_gamma_regularized(100.0, 200.0), 1.0, 1e-14); - assert_eq!(Gamma::lower_gamma_regularized(500.0, 0.5), 0.0); - assert_eq!(Gamma::lower_gamma_regularized(500.0, 1.5), 0.0); - assert_almost_eq!(Gamma::lower_gamma_regularized(500.0, 200.0), 0.0, 1e-70); - assert_almost_eq!( - Gamma::lower_gamma_regularized(500.0, 450.0), - 0.0107172380912897415573958770655204965434869949241480, - 1e-14 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(500.0, 500.0), - 0.5059471461707603580470479574412058032802735425634263, - 1e-13 - ); - assert_almost_eq!( - Gamma::lower_gamma_regularized(500.0, 550.0), - 0.9853855918737048059548470006900844665580616318702748, - 1e-14 - ); - assert_almost_eq!(Gamma::lower_gamma_regularized(500.0, 700.0), 1.0, 1e-15); - assert_eq!(Gamma::lower_gamma_regularized(1000.0, 10000.0), 1.0); - assert_eq!(Gamma::lower_gamma_regularized(1e+50, 1e+48), 0.0); - assert_eq!(Gamma::lower_gamma_regularized(1e+50, 1e+52), 1.0); - } -} diff --git a/src/lib.rs b/src/lib.rs index 576f1f1..eacd9e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] #![no_std] -pub mod gamma; -pub mod n_choose_k; +pub mod u256; diff --git a/src/n_choose_k.rs b/src/n_choose_k.rs deleted file mode 100644 index 3b8ee37..0000000 --- a/src/n_choose_k.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Calculates the binomial coefficient N-choose-K. - -use num_traits::{Num, NumCast, PrimInt}; - -/// Calculates the binomial coefficient -pub trait BinomialCoefficient: Num + NumCast { - /// Calculates the binary coefficient N-choose-K. - /// - /// # Return - /// Returns None if k cannot be represented in the current number type. - fn choose(self, k: I) -> Option; -} - -impl BinomialCoefficient for N { - fn choose(self, k: I) -> Option { - let mut num = Self::one(); - let mut denom = Self::one(); - let mut i = I::one(); - while i <= k { - num = num * (self + Self::one() - Self::from(i)?); - denom = denom * Self::from(i)?; - i = i + I::one(); - } - Some(num / denom) - } -} - -#[cfg(test)] -mod tests { - use crate::n_choose_k::BinomialCoefficient; - - #[test] - fn test_binomial() { - assert_eq!(BinomialCoefficient::choose(4, 2), Some(6)); - } -} diff --git a/src/u256/mod.rs b/src/u256/mod.rs new file mode 100644 index 0000000..50af961 --- /dev/null +++ b/src/u256/mod.rs @@ -0,0 +1,3103 @@ +//! 256 bit unsigned integer + +use core::{ + cmp::Ordering, + fmt::{self, Binary, Display, Formatter, LowerHex, Octal}, + iter::{Product, Sum}, + num::{IntErrorKind, ParseIntError}, + ops::{ + Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, + DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, + }, + str::{self, FromStr}, +}; + +/// The 256-bit unsigned integer type. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Hash)] +pub struct U256(pub u128, pub u128); + +impl U256 { + /// The smallest value that can be represented by this integer type. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::MIN, 0); + /// ``` + pub const MIN: Self = Self(0, 0); + /// The largest value that can be represented by this integer type (2^256 āˆ’ 1). + pub const MAX: Self = Self(u128::MAX, u128::MAX); + /// The size of this integer type in bits. + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::BITS, 256); + /// ``` + pub const BITS: u32 = 256; + + /// Returns the number of ones in the binary representation of `self`. + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0b01001100u128).count_ones(), 3); + /// ``` + pub const fn count_ones(self) -> u32 { + self.0.count_ones() + self.1.count_ones() + } + + /// Returns the number of zeros in the binary representation of `self`. + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::MAX.count_zeros(), 0); + /// ``` + pub const fn count_zeros(self) -> u32 { + self.0.count_zeros() + self.1.count_zeros() + } + + /// Returns the number of leading zeros in the binary representation of `self`. + /// + /// Depending on what youā€™re doing with the value, you might also be interested in the [`ilog2`] function which returns a consistent number, even if the type widens. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::MAX >> 2; + /// + /// assert_eq!(n.leading_zeros(), 2); + /// ``` + pub const fn leading_zeros(self) -> u32 { + let zeros = self.0.leading_zeros(); + if zeros == 128 { + 128 + self.1.leading_zeros() + } else { + zeros + } + } + + /// Returns the number of trailing zeros in the binary representation of `self`. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::from(0b01001100u128); + /// + /// assert_eq!(n.trailing_zeros(), 2); + /// ``` + pub const fn trailing_zeros(self) -> u32 { + let zeros = self.1.trailing_zeros(); + if zeros == 128 { + 128 + self.0.trailing_zeros() + } else { + zeros + } + } + + /// Returns the number of leading ones in the binary representation of `self`. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = !(U256::MAX >> 2); + /// + /// assert_eq!(n.leading_ones(), 2); + /// ``` + pub const fn leading_ones(self) -> u32 { + let zeros = self.0.leading_ones(); + if zeros == 128 { + 128 + self.1.leading_ones() + } else { + zeros + } + } + + /// Returns the number of trailing ones in the binary representation of `self`. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::from(0b1010111u128); + /// + /// assert_eq!(n.trailing_ones(), 3); + /// ``` + pub const fn trailing_ones(self) -> u32 { + let zeros = self.1.trailing_ones(); + if zeros == 128 { + 128 + self.0.trailing_ones() + } else { + zeros + } + } + + /// Shifts the bits to the left by a specified amount, `n`, wrapping the truncated bits to the end of the resulting integer. + /// + /// Please note this isnā€™t the same operation as the `<<` shifting operator! + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// + /// let n = U256(0x13f40000000000000000000000000000, 0x4f76); + /// let m = U256::from(0x4f7613f4u32); + /// + /// assert_eq!(n.rotate_left(16), m); + /// ``` + pub const fn rotate_left(self, n: u32) -> Self { + (self.wrapping_shl(n)).bit_or(self.wrapping_shr(Self::BITS - n)) + } + + /// Shifts the bits to the right by a specified amount, `n`, wrapping the truncated bits to the beginning of the resulting integer. + /// + /// Please note this isnā€™t the same operation as the `>>` shifting operator! + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// + /// let m = U256(0x13f40000000000000000000000000000, 0x4f76); + /// let n = U256::from(0x4f7613f4u32); + /// + /// assert_eq!(n.rotate_right(16), m); + /// ``` + pub const fn rotate_right(self, n: u32) -> Self { + (self.wrapping_shr(n)).bit_or(self.wrapping_shl(Self::BITS - n)) + } + + /// Reverses the byte order of the integer. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256(0x12345678901234567890123456789012, 0x34567890123456789012345678901234); + /// let m = U256(0x34129078563412907856341290785634, 0x12907856341290785634129078563412); + /// + /// assert_eq!(n.swap_bytes(), m); + /// ``` + pub const fn swap_bytes(self) -> Self { + Self(self.1.swap_bytes(), self.0.swap_bytes()) + } + + /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256(0x12345678901234567890123456789012, 0x34567890123456789012345678901234); + /// let m = U256(0x2c48091e6a2c48091e6a2c48091e6a2c, 0x48091e6a2c48091e6a2c48091e6a2c48); + /// + /// assert_eq!(n.reverse_bits(), m); + /// assert_eq!(U256::default().reverse_bits(), 0u128); + /// ``` + pub const fn reverse_bits(self) -> Self { + Self(self.1.reverse_bits(), self.0.reverse_bits()) + } + + /// Converts an integer from big endian to the targetā€™s endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::from(0x1Au8); + /// if cfg!(target_endian = "big") { + /// assert_eq!(U256::from_be(n), n) + /// } else { + /// assert_eq!(U256::from_be(n), n.swap_bytes()) + /// } + /// ``` + pub const fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { + x + } else { + x.swap_bytes() + } + } + + /// Converts an integer from little endian to the targetā€™s endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::from(0x1Au8); + /// if cfg!(target_endian = "little") { + /// assert_eq!(U256::from_le(n), n) + /// } else { + /// assert_eq!(U256::from_le(n), n.swap_bytes()) + /// } + /// ``` + pub const fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { + x + } else { + x.swap_bytes() + } + } + + /// Converts `self` to big endian from the targetā€™s endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::from(0x1Au8); + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_be(), n) + /// } else { + /// assert_eq!(n.to_be(), n.swap_bytes()) + /// } + /// ``` + pub const fn to_be(self) -> Self { + if cfg!(target_endian = "big") { + self + } else { + self.swap_bytes() + } + } + + /// Converts `self` to little endian from the targetā€™s endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// let n = U256::from(0x1Au8); + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_le(), n) + /// } else { + /// assert_eq!(n.to_le(), n.swap_bytes()) + /// } + /// ``` + pub const fn to_le(self) -> Self { + if cfg!(target_endian = "little") { + self + } else { + self.swap_bytes() + } + } + + /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!((U256::MAX - U256::from(2u8)).checked_add(U256::from(1u8)), Some(U256::MAX - U256::from(1u8))); + /// assert_eq!((U256::MAX - U256::from(2u8)).checked_add(U256::from(3u8)), None); + /// ``` + pub const fn checked_add(self, rhs: Self) -> Option { + match self.overflowing_add(rhs) { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict integer addition. Computes self + rhs, panicking if overflow occurred. + /// + /// # Panics + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!((U256::MAX - U256::from(2u8)).strict_add(U256::from(1u8)), U256::MAX - U256::from(1u8)); + /// ``` + /// + /// The following panics because of overflow: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = (U256::MAX - U256::from(2u8)).strict_add(U256::from(3u8)); + /// ``` + pub const fn strict_add(self, rhs: Self) -> Self { + match self.checked_add(rhs) { + Some(n) => n, + None => panic!("Integer overflow!"), + } + } + + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(1u8).checked_sub(U256::from(1u8)), Some(U256::from(0u8))); + /// assert_eq!(U256::from(0u8).checked_sub(U256::from(1u8)), None) + /// ``` + pub const fn checked_sub(self, rhs: Self) -> Option { + match self.overflowing_sub(rhs) { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict integer subtraction. Computes self - rhs, panicking if overflow occurred. + /// + /// # Panics + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(1u8).strict_sub(U256::from(1u8)), U256::from(0u8)); + /// ``` + /// + /// The following panics because of overflow: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::from(0u8).strict_sub(U256::from(1u8)); + /// ``` + pub const fn strict_sub(self, rhs: Self) -> Self { + match self.checked_sub(rhs) { + Some(n) => n, + None => panic!("Integer overflow!"), + } + } + + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow occurred. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).checked_mul(U256::from(1u8)), Some(U256::from(5u8))); + /// assert_eq!(U256::MAX.checked_sub(U256::from(2u8)), None) + /// ``` + pub const fn checked_mul(self, rhs: Self) -> Option { + match self.overflowing_mul(rhs) { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict integer multiplication. Computes self * rhs, panicking if overflow occurred. + /// + /// # Panics + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).strict_mul(U256::from(1u8)), U256::from(5u8)); + /// ``` + /// + /// The following panics because of overflow: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::MAX.strict_mul(U256::from(2u8)); + /// ``` + pub const fn strict_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(n) => n, + None => panic!("Integer overflow!"), + } + } + + /// Checked integer divrem. Computes `(self / rhs, self % rhs)`, returning `None` if `rhs == 0` + pub const fn checked_div_rem(mut self, rhs: Self) -> Option<(Self, Self)> { + if rhs.eq(Self(0, 0)) { + return None; + } + + if rhs.gt(self) { + // divisor > numerator + return Some((Self(0, 0), rhs)); + } + if rhs.eq(Self(0, 1)) { + // divisor == 1 + return Some((self, Self(0, 0))); + } + + if self.lt(Self(1, 0)) && rhs.lt(Self(1, 0)) { + let div = match self.1.checked_div(rhs.1) { + Some(v) => v, + None => return None, + }; + let rem = match self.1.checked_rem(rhs.1) { + Some(v) => v, + None => return None, + }; + return Some((Self(0, div), Self(0, rem))); + } + + let mut bits = rhs.leading_zeros() - self.leading_zeros() + 1; + let mut rem = self.wrapping_shr(bits); + self = self.wrapping_shl(Self::BITS - bits); + let mut wrap = Self(0, 0); + while bits > 0 { + bits -= 1; + rem = (rem.wrapping_shl(1)).bit_or(self.wrapping_shr(Self::BITS - 1)); + self = (self.wrapping_shl(1)).bit_or(wrap); + if rhs.gt(rem) { + wrap = Self(0, 0); + } else { + wrap = Self(0, 1); + rem = rem.wrapping_sub(rhs); + } + } + + Some((self.wrapping_shl(1).bit_or(wrap), rem)) + } + + /// Checked integer division. Computes self / rhs, returning None if rhs == 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(128u8).checked_div(U256::from(2u8)), Some(U256::from(64u8))); + /// assert_eq!(U256::from(1u8).checked_div(U256::from(0u8)), None); + /// ``` + pub const fn checked_div(self, rhs: Self) -> Option { + if let Some((d, _)) = self.checked_div_rem(rhs) { + Some(d) + } else { + None + } + } + + /// Strict integer division. Computes self / rhs. + /// + /// # Panics + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(128u8).strict_div(U256::from(2u8)), U256::from(64u8)); + /// ``` + /// + /// The following function panics because of division by zero: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::from(1u8).strict_div(U256::from(0u8)); + /// ``` + pub const fn strict_div(self, rhs: Self) -> Self { + if let Some((d, _)) = self.checked_div_rem(rhs) { + d + } else { + panic!("Division by zero!"); + } + } + + /// Checked euclidian division. Computes self / rhs, returning None if rhs == 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(128u8).checked_div_euclid(U256::from(2u8)), Some(U256::from(64u8))); + /// assert_eq!(U256::from(1u8).checked_div_euclid(U256::from(0u8)), None); + /// ``` + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if let Some((d, _)) = self.checked_div_rem(rhs) { + Some(d) + } else { + None + } + } + + /// Strict euclidian division. Computes self / rhs. + /// + /// # Panics + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(128u8).strict_div_euclid(U256::from(2u8)), U256::from(64u8)); + /// ``` + /// + /// The following function panics because of division by zero: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::from(1u8).strict_div_euclid(U256::from(0u8)); + /// ``` + pub const fn strict_div_euclid(self, rhs: Self) -> Self { + if let Some((d, _)) = self.checked_div_rem(rhs) { + d + } else { + panic!("Division by zero!"); + } + } + + /// Checked integer remainder. Computes self % rhs, returning None if rhs == 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).checked_rem(U256::from(2u8)), Some(U256::from(1u8))); + /// assert_eq!(U256::from(5u8).checked_rem(U256::from(0u8)), None); + /// ``` + pub const fn checked_rem(self, rhs: Self) -> Option { + if let Some((_, d)) = self.checked_div_rem(rhs) { + Some(d) + } else { + None + } + } + + /// Strict integer remainder. Computes self % rhs. + /// + /// # Panics + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).strict_rem(U256::from(2u8)), U256::from(1u8)); + /// ``` + /// + /// The following function panics because of division by zero: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::from(5u8).strict_rem(U256::from(0u8)); + /// ``` + pub const fn strict_rem(self, rhs: Self) -> Self { + if let Some((_, d)) = self.checked_div_rem(rhs) { + d + } else { + panic!("Division by zero!"); + } + } + + /// Checked euclidian remainder. Computes self % rhs, returning None if rhs == 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).checked_rem_euclid(U256::from(2u8)), Some(U256::from(1u8))); + /// assert_eq!(U256::from(5u8).checked_rem_euclid(U256::from(0u8)), None); + /// ``` + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if let Some((_, d)) = self.checked_div_rem(rhs) { + Some(d) + } else { + None + } + } + + /// Strict euclidian remainder. Computes self % rhs. + /// + /// # Panics + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).strict_rem_euclid(U256::from(2u8)), U256::from(uu8)); + /// ``` + /// + /// The following function panics because of division by zero: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::from(5u8).strict_rem_euclid(U256::from(0u8)); + /// ``` + pub const fn strict_rem_euclid(self, rhs: Self) -> Self { + if let Some((_, d)) = self.checked_div_rem(rhs) { + d + } else { + panic!("Division by zero!"); + } + } + + /// Returns the logarithm of the number with respect to an arbitrary base, rounded down. + /// + /// This method might not be optimized owing to implementation details; `ilog2` can produce results more efficiently for base 2, and `ilog10` can produce results more efficiently for base 10. + /// + /// # Panics + /// This function will panic if `self` is zero, or if `base` is less than 2. + /// + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).ilog(U256::from(5u8)), 1); + /// ``` + pub const fn ilog(self, base: Self) -> u32 { + assert!( + base.gt(Self(0, 2)), + "base of integer logarithm must be at least 2" + ); + if let Some(log) = self.checked_ilog(base) { + log + } else { + panic!("Integer logarithm must be taken of a strictly positive number!"); + } + } + + /// Returns the base 2 logarithm of the number, rounded down. + /// + /// # Panics + /// This function will panic if `self` is zero. + /// + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).ilog2(), 1); + /// ``` + pub const fn ilog2(self) -> u32 { + if let Some(log) = self.checked_ilog2() { + log + } else { + panic!("Integer logarithm must be taken of a strictly positive number!"); + } + } + + /// Returns the base 10 logarithm of the number, rounded down. + /// + /// # Panics + /// This function will panic if `self` is zero. + /// + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(10u8).ilog10(), 1); + /// ``` + pub const fn ilog10(self) -> u32 { + if let Some(log) = self.checked_ilog10() { + log + } else { + panic!("Integer logarithm must be taken of a strictly positive number!"); + } + } + + /// Returns the logarithm of the number with respect to an arbitrary base, rounded down. + /// + /// Returns `None` if the number is zero, or if the base is not at least 2. + /// + /// This method might not be optimized owing to implementation details; `checked_ilog2` can produce results more efficiently for base 2, and `checked_ilog10` can produce results more efficiently for base 10. + /// + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).checked_ilog(U256::from(5u8)), Some(1)); + /// ``` + pub const fn checked_ilog(self, base: Self) -> Option { + if base.lt(Self(0, 2)) { + return None; + } + if self.eq(Self(0, 0)) { + return None; + } + if self.lt(base) { + return Some(0); + } + let mut n = 1; + let mut r = base; + while r.le(self.strict_div(base)) { + n += 1; + r = r.wrapping_mul(base); + } + Some(n) + } + + /// Returns the base 2 logarithm of the number, rounded down. + /// + /// Returns None if the number is zero. + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).checked_ilog2(), Some(1)); + /// ``` + pub const fn checked_ilog2(self) -> Option { + if self.eq(Self(0, 0)) { + None + } else { + Some(Self::BITS - 1 - self.leading_zeros()) + } + } + + /// Returns the base 10 logarithm of the number, rounded down. + /// + /// Returns None if the number is zero. + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(10u8).checked_ilog10(), Some(1)); + /// ``` + pub const fn checked_ilog10(self) -> Option { + self.checked_ilog(Self(0, 10)) + } + + /// Checked negation. Computes `-self`, returning None unless `self == 0`. + /// + /// Note that negating any positive integer will overflow. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0u8).checked_neg(), Some(U256::from(0u8))); + /// assert_eq!(U256::from(1u8).checked_neg(), None); + /// ``` + pub const fn checked_neg(self) -> Option { + match self.overflowing_neg() { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict negation. Computes `-self`, panicking unless `self == 0`. + /// + /// Note that negating any positive integer will overflow. + /// + /// # Panics + /// This function will panic if `self != 0` + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0u8).strict_neg(), U256::from(0u8)); + /// ``` + /// + /// The following panics because of overflow: + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = U256::from(1u8).strict_neg(); + /// ``` + pub const fn strict_neg(self) -> Self { + match self.checked_neg() { + Some(n) => n, + None => panic!("Tried to negate positive number in an unsigned integer!"), + } + } + + /// Checked shift left. Computes self << rhs, returning None if rhs is larger than or equal to the number of bits in self. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x1u8).checked_shl(4), Some(U256::from(0x10u8))); + /// assert_eq!(U256::from(0x10u8).checked_shl(257), None); + /// assert_eq!(U256::from(0x10u8).checked_shl(255), Some(U256::from(0u8))); + /// ``` + pub const fn checked_shl(self, rhs: u32) -> Option { + match self.overflowing_shl(rhs) { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict shift left. Computes self << rhs, panicking if rhs is larger than or equal to the number of bits in self. + /// + /// # Panics + /// This function will always panic if `n > 255` + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x1u8).strict_shl(4), U256::from(0x10u8)); + /// ``` + /// + /// This following panics because of overflow: + /// ```should_panic + /// let _ = U256::from(0x10u8).strict_shl(257); + /// ``` + pub const fn strict_shl(self, rhs: u32) -> Self { + match self.overflowing_shl(rhs) { + (n, false) => n, + (_, true) => panic!("Overflow on left shift!"), + } + } + + /// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs` + /// + /// If `rhs` is larger or equal to the number of bits in `self`, the entire value is shifted out, and 0 is returned. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x1u8).unbounded_shl(4), U256::from(0x10u8)); + /// assert_eq!(U256::from(0x10u8).unbounded_shl(257), U256::from(0u8)); + /// ``` + pub const fn unbounded_shl(self, rhs: u32) -> Self { + match self.checked_shl(rhs) { + Some(n) => n, + None => Self(0, 0), + } + } + + /// Checked shift right. Computes self >> rhs, returning None if rhs is larger than or equal to the number of bits in self. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x10u8).checked_shr(4), Some(U256::from(0x1u8))); + /// assert_eq!(U256::from(0x10u8).checked_shr(257), None); + /// assert_eq!(U256::from(0x10u8).checked_shr(255), Some(U256::from(0u8))); + /// ``` + pub const fn checked_shr(self, rhs: u32) -> Option { + match self.overflowing_shr(rhs) { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict shift right. Computes self >> rhs, panicking if rhs is larger than or equal to the number of bits in self. + /// + /// # Panics + /// This function will always panic if `n > 255` + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x10u8).strict_shr(4), U256::from(0x11u8)); + /// ``` + /// + /// This following panics because of overflow: + /// ```should_panic + /// let _ = U256::from(0x10u8).strict_shr(257); + /// ``` + pub const fn strict_shr(self, rhs: u32) -> Self { + match self.overflowing_shr(rhs) { + (n, false) => n, + (_, true) => panic!("Overflow on left shift!"), + } + } + + /// Unbounded shift right. Computes `self << rhs`, without bounding the value of `rhs` + /// + /// If `rhs` is larger or equal to the number of bits in `self`, the entire value is shifted out, and 0 is returned. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x10u8).unbounded_shr(4), U256::from(0x1u8)); + /// assert_eq!(U256::from(0x10u8).unbounded_shr(257), U256::from(0u8)); + /// ``` + pub const fn unbounded_shr(self, rhs: u32) -> Self { + match self.checked_shr(rhs) { + Some(n) => n, + None => Self(0, 0), + } + } + + /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if + /// overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).checked_pow(5), Some(U256::from(25u8))); + /// assert_eq!(U256::MAX.checked_pow(2), None); + /// ``` + pub const fn checked_pow(self, exp: u32) -> Option { + match self.overflowing_pow(exp) { + (n, false) => Some(n), + (_, true) => None, + } + } + + /// Strict exponentiation. Computes `self.pow(exp)`, panicking if + /// overflow occurred. + /// + /// # Panics + /// + /// ## Overflow behavior + /// + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).strict_pow(5), U256::from(25u8)); + /// ``` + /// + /// The following panics because of overflow: + /// + /// ```should_panic + /// # use extra_math::u256::U256; + /// let _ = Self::MAX.strict_pow(2); + /// ``` + pub const fn strict_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(n) => n, + None => panic!("Tried to pow with overflow!"), + } + } + + /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds instead of overflowing + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!((U256::MAX - U256::from(2u8)).saturating_add(U256::from(1u8)), U256::MAX - U256::from(1u8)); + /// assert_eq!((U256::MAX - U256::from(2u8)).saturating_add(U256::from(3u8)), U256::MAX); + /// ``` + pub const fn saturating_add(self, other: Self) -> Self { + match self.checked_add(other) { + Some(n) => n, + None => Self::MAX, + } + } + + /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric bounds instead of overflowing + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).saturating_sub(U256::from(27u8)), U256::from(73u8)); + /// assert_eq!(U256::from(13u8).saturating_sub(U256::from(127u8)), U256::from(0u8)); + /// ``` + pub const fn saturating_sub(self, other: Self) -> Self { + match self.checked_sub(other) { + Some(n) => n, + None => Self::MIN, + } + } + + /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric bounds instead of overflowing + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).saturating_mul(U256::from(10u8)), U256::from(20u8)); + /// assert_eq!(U256::MAX.saturating_mul(U256::from(2u8)), U256::MAX); + /// ``` + pub const fn saturating_mul(self, other: Self) -> Self { + match self.checked_mul(other) { + Some(n) => n, + None => Self::MAX, + } + } + + /// Saturating integer division. Computes `self / rhs`, saturating at the numeric bounds instead of overflowing + /// + /// # Panics + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).saturating_div(U256::from(2u8)), U256::from(2u8)); + /// ``` + pub const fn saturating_div(self, other: Self) -> Self { + self.strict_div(other) + } + + /// Saturating integer exponentiation. Computes `self.pow(rhs)`, saturating at the numeric bounds instead of overflowing + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(4u8).saturating_pow(3), U256::from(64u8)); + /// assert_eq!(U256::MAX.saturating_pow(2), U256::MAX); + /// ``` + pub const fn saturating_pow(self, other: u32) -> Self { + match self.checked_pow(other) { + Some(n) => n, + None => Self::MAX, + } + } + + /// Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the boundary of the type + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(200u8).wrapping_add(U256::from(55u8)), U256::from(255u8)); + /// assert_eq!(U256::from(200u8).wrapping_add(U256::MAX), U256::from(199u8)); + /// ``` + pub const fn wrapping_add(self, other: Self) -> Self { + self.overflowing_add(other).0 + } + + /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the boundary of the type + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).wrapping_sub(U256::from(100u8)), U256::from(0u8)); + /// assert_eq!(U256::from(100u8).wrapping_sub(U256::MAX), U256::from(101u8)); + /// ``` + pub const fn wrapping_sub(self, other: Self) -> Self { + self.overflowing_sub(other).0 + } + + /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at the boundary of the type + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(10u8).wrapping_mul(U256::from(12u8)), U256::from(120u8)); + /// assert_eq!(U256::MAX.wrapping_mul(U256::from(2u8)), U256::MAX - U256::from(1u8)); + /// ``` + pub const fn wrapping_mul(self, other: Self) -> Self { + self.overflowing_mul(other).0 + } + + /// Wrapping (modular) division. Computes self / rhs. + /// + /// Wrapped division on unsigned types is just normal division. Thereā€™s no way wrapping could ever happen. This function exists so that all operations are accounted for in the wrapping operations. + /// + /// # Panics + /// this function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).wrapping_div(U256::from(10u8)), U256::from(10u8)); + /// ``` + pub const fn wrapping_div(self, other: Self) -> Self { + self.strict_div(other) + } + + /// Wrapping (modular) euclidian division. Computes self / rhs. + /// + /// Wrapped division on unsigned types is just normal division. Thereā€™s no way wrapping could ever happen. This function exists so that all operations are accounted for in the wrapping operations. Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self.wrapping_div(rhs)`. + /// + /// # Panics + /// this function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).wrapping_div_euclid(U256::from(10u8)), U256::from(10u8)); + /// ``` + pub const fn wrapping_div_euclid(self, other: Self) -> Self { + self.strict_div_euclid(other) + } + + /// Wrapping (modular) remainder. Computes self % rhs. + /// + /// Wrapped remainder calculation on unsigned types is just the regular remainder calculation. Thereā€™s no way wrapping could ever happen. This function exists so that all operations are accounted for in the wrapping operations. + /// + /// # Panics + /// this function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).wrapping_rem(U256::from(10u8)), U256::from(0u8)); + /// ``` + pub const fn wrapping_rem(self, other: Self) -> Self { + self.strict_rem(other) + } + + /// Wrapping (modular) euclidian remainder. Computes self % rhs. + /// + /// Wrapped modulo calculation on unsigned types is just the regular remainder calculation. Thereā€™s no way wrapping could ever happen. This function exists so that all operations are accounted for in the wrapping operations. Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self.wrapping_rem(rhs)`. + /// + /// # Panics + /// this function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).wrapping_rem_euclid(U256::from(10u8)), U256::from(0u8)); + /// ``` + pub const fn wrapping_rem_euclid(self, other: Self) -> Self { + self.strict_rem_euclid(other) + } + + /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary of the type. + /// + /// Since unsigned types do not have negative equivalents all applications of this function will wrap (except for -0). For values smaller than the corresponding signed typeā€™s maximum the result is the same as casting the corresponding signed value. Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where `MAX` is the corresponding signed typeā€™s maximum. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0u8).wrapping_neg(), U256::from(0u8)); + /// assert_eq!(U256::MAX.wrapping_neg(), U256::from(1u8)); + /// assert_eq!(U256::from(13u8).wrapping_neg, !U256::from(13u8) + U256::from(1u8)); + /// assert_eq!(U256::from(42u8).wrapping_neg, !(U256::from(42u8) - U256::from(1u8))); + /// ``` + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + + /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where mask removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + /// + /// Note that this is not the same as a rotate-left; the RHS of a wrapping shift-left is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. The primitive integer types all implement a `rotate_left` function, which may be what you want instead. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(1u8).wrapping_shl(7), U256::from(127u8)); + /// assert_eq!(U256::from(1u8).wrapping_shl(256), U256::from(1u8)); + /// ``` + pub const fn wrapping_shl(self, n: u32) -> Self { + self.overflowing_shl(n).0 + } + + /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where mask removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + /// + /// Note that this is not the same as a rotate-right; the RHS of a wrapping shift-right is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. The primitive integer types all implement a `rotate_right` function, which may be what you want instead. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(127u8).wrapping_shr(7), U256::from(1u8)); + /// assert_eq!(U256::from(127u8).wrapping_shl(256), U256::from(127u8)); + /// ``` + pub const fn wrapping_shr(self, n: u32) -> Self { + self.overflowing_shr(n).0 + } + + /// Wrapping (modular) exponentiation. Computes `self.pow(rhs)`, wrapping around at the boundary of the type + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(3u8).wrapping_pow(5), U256::from(243u8)); + /// assert_eq!(U256::MAX.wrapping_pow(2), U256::from(1u8)); + /// ``` + pub const fn wrapping_pow(self, other: u32) -> Self { + self.overflowing_pow(other).0 + } + + /// Calculates self + rhs. + /// + /// Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would occur. If an overflow would have occurred then the wrapped value is returned. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_add(U256::from(2u8)), (U256::from(7u8), false)); + /// assert_eq!(U256::MAX.overflowing_add(U256::from(1u8)), (U256::from(0u8), true)); + /// ``` + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (lo, carry0) = self.1.overflowing_add(rhs.1); + let (hi1, carry1) = self.0.overflowing_add(rhs.0); + let (hi2, carry2) = hi1.overflowing_add(if carry0 { 1 } else { 0 }); + (Self(hi2, lo), carry1 || carry2) + } + + /// Calculates `self + rhs + carry` and returns a tuple containing the sum and the output carry. + /// + /// Performs ā€œternary additionā€ of two integer operands and a carry-in bit, and returns an output integer and a carry-out bit. This allows chaining together multiple additions to create a wider addition, and can be useful for bignum addition. + /// + /// This can be thought of as a 256-bit ā€œfull adderā€, in the electronics sense. + /// + /// If the input carry is false, this method is equivalent to overflowing_add, and the output carry is equal to the overflow flag. Note that although carry and overflow flags are similar for unsigned integers, they are different for signed integers. + /// + /// # Examples + /// + /// ``` + /// # use extra_math::u256::U256; + /// // 3 MAX (a = 3 Ɨ 2^128 + 2^256 - 1) + /// // + 5 7 (b = 5 Ɨ 2^128 + 7) + /// // --------- + /// // 9 6 (sum = 9 Ɨ 2^256 + 6) + /// + /// let (a1, a0) = (U256::from(3u8), U256::MAX); + /// let (b1, b0) = (U256::from(5u8), U256::from(7u8)); + /// let carry0 = false; + /// + /// let (sum0, carry1) = a0.carrying_add(b0, carry0); + /// assert_eq!(carry1, true); + /// let (sum1, carry2) = a1.carrying_add(b1, carry1); + /// assert_eq!(carry2, false); + /// + /// assert_eq!((sum1, sum0), (U256::from(9u8), U256::from(6u8))); + /// ``` + pub const fn carrying_add(self, other: Self, carry: bool) -> (Self, bool) { + let (o1, c1) = self.overflowing_add(other); + let (o2, c2) = o1.overflowing_add(if carry { Self(0, 1) } else { Self(0, 0) }); + + (o2, c1 || c2) + } + + /// Calculates self - rhs. + /// + /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow would occur. If an overflow would have occurred then the wrapped value is returned. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_sub(U256::from(2u8)), (U256::from(3u8), false)); + /// assert_eq!(U256::from(0u8).overflowing_sub(U256::from(1u8)), (U256::MAX, true)); + /// ``` + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (lo, carry0) = self.1.overflowing_sub(rhs.1); + let (hi1, carry1) = self.0.overflowing_sub(rhs.0); + let (hi2, carry2) = hi1.overflowing_sub(if carry0 { 1 } else { 0 }); + (Self(hi2, lo), carry1 || carry2) + } + + /// Calculates self āˆ’ rhs āˆ’ borrow and returns a tuple containing the difference and the output borrow. + /// + /// Performs ā€œternary subtractionā€ by subtracting both an integer operand and a borrow-in bit from self, and returns an output integer and a borrow-out bit. This allows chaining together multiple subtractions to create a wider subtraction, and can be useful for bignum subtraction. + /// + /// # Examples + /// ``` + /// # use extra_math::u256::U256; + /// // 9 6 (a = 9 Ɨ 2^256 + 6) + /// // - 5 7 (b = 5 Ɨ 2^256 + 7) + /// // --------- + /// // 3 MAX (diff = 3 Ɨ 2^256 + 2^256 - 1) + /// + /// let (a1, a0) = (U256::from(9u8), U256::from(6u8)); + /// let (b1, b0) = (U256::from(5u8), U256::from(7u8)); + /// let borrow0 = false; + /// + /// let (diff0, borrow1) = a0.borrowing_sub(b0, borrow0); + /// assert_eq!(borrow1, true); + /// let (diff1, borrow2) = a1.borrowing_sub(b1, borrow1); + /// assert_eq!(borrow2, false); + /// + /// assert_eq!((diff1, diff0), (U256::from(3u8), U256::MAX)); + /// ``` + pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { + let (o1, c1) = self.overflowing_sub(rhs); + let (o2, c2) = o1.overflowing_sub(if borrow { Self(0, 1) } else { Self(0, 0) }); + + (o2, c1 || c2) + } + + /// Computes the absolute difference between `self` and `other`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(100u8).abs_diff(U256::from(80u8)), U256::from(20u8)); + /// assert_eq!(U256::from(100u8).abs_diff(U256::from(110u8)), U256::from(10u8)); + /// ``` + pub const fn abs_diff(self, other: Self) -> Self { + if self.lt(other) { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } + } + + /// Constant version of `self == rhs` + pub const fn eq(self, rhs: Self) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } + + /// Constant version of `self > rhs` + pub const fn gt(self, rhs: Self) -> bool { + self.0 > rhs.0 || self.1 > rhs.1 + } + + /// Constant version of `self < rhs` + pub const fn lt(self, rhs: Self) -> bool { + self.0 < rhs.0 || self.1 < rhs.1 + } + + /// Constant version of `self <= rhs` + pub const fn le(self, rhs: Self) -> bool { + self.lt(rhs) || self.eq(rhs) + } + + /// Constant version of `self != rhs` + pub const fn ne(self, rhs: Self) -> bool { + !self.eq(rhs) + } + + const fn upcasting_mul128(a: u128, b: u128) -> Self { + let va_high = (a >> 64) as u64; + let va_low = a as u64; + let vb_high = (b >> 64) as u64; + let vb_low = b as u64; + + let mul_high_high = Self(va_high as u128 * vb_high as u128, 0); + let mul_high_low = va_high as u128 * vb_low as u128; + let mul_high_low = Self(mul_high_low >> 64, mul_high_low << 64); + let mul_low_high = vb_high as u128 * va_low as u128; + let mul_low_high = Self(mul_low_high >> 64, mul_low_high << 64); + let mul_low_low = Self(0, va_low as u128 * vb_low as u128); + mul_high_high + .wrapping_add(mul_high_low) + .wrapping_add(mul_low_high) + .wrapping_add(mul_high_low) + .wrapping_add(mul_low_low) + } + + /// Calculates the multiplication of `self` and `rhs`. + /// + /// Returns a tuple of the multiplication along with a boolean + /// indicating whether an arithmetic overflow would occur. If an + /// overflow would have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_mul(U256::from(2u8)), (U256::from(10u8), false)); + /// assert_eq!(U256::MAX.overflowing_mul(U256::from(2u8)), (U256::MAX - U256::from(1), true)); + /// ``` + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (l, h) = self.widening_mul(rhs); + (l, h.ne(U256(0, 0))) + } + + /// Calculates the divisor when `self` is divided by `rhs`. + /// + /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would occur. Note that for unsigned integers overflow never occurs, so the second value is always `false`. + /// + /// # Panics + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_div(U256::from(2u8)), (U256::from(2u8), false)); + /// ``` + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + (self.strict_div(rhs), false) + } + + /// Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + /// + /// Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would occur. Note that for unsigned integers overflow never occurs, so the second value is always `false`. Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self.overflowing_div(rhs)`. + /// + /// # Panics + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_div_euclid(U256::from(2u8)), (U256::from(2u8), false)); + /// ``` + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + (self.strict_div_euclid(rhs), false) + } + + /// Calculates the remainder when `self` is divided by `rhs`. + /// + /// Returns a tuple of the remainder after dividing along with a boolean indicating whether an arithmetic overflow would occur. Note that for unsigned integers overflow never occurs, so the second value is always `false`. + /// + /// # Panics + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_rem(U256::from(2u8)), (U256::from(1u8), false)); + /// ``` + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + (self.strict_rem(rhs), false) + } + + /// Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. + /// + /// Returns a tuple of the modulo after dividing along with a boolean indicating whether an arithmetic overflow would occur. Note that for unsigned integers overflow never occurs, so the second value is always `false`. Since, for the positive integers, all common definitions of division are equal, this operation is exactly equal to `self.overflowing_rem(rhs)`. + /// + /// # Panics + /// This function will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).overflowing_rem_euclid(U256::from(2u8)), (U256::from(1u8), false)); + /// ``` + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + (self.strict_rem_euclid(rhs), false) + } + + /// Negates self in an overflowing fashion. + /// + /// Returns !self + 1 using wrapping operations to return the value that represents the negation of this unsigned value. Note that for positive unsigned values overflow always occurs, but negating 0 does not overflow. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0u8).overflowing_neg(), (U256::from(0u8), false)); + /// assert_eq!(U256::from(1u8).overflowing_neg(), (!U256::from(0u8), true)); + /// ``` + pub const fn overflowing_neg(self) -> (Self, bool) { + (self.not().wrapping_add(Self(0, 1)), self.ne(Self(0, 0))) + } + + /// Shifts self left by `rhs` bits. + /// + /// Returns a tuple of the shifted version of `self` along with a boolean indicating whether the shift value was larger than or equal to the number of bits. If the shift value is too large, then value is masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x1u8).overflowing_shl(4), (U256::from(0x10u8), false)); + /// assert_eq!(U256::from(0x1u8).overflowing_shl(260), (U256::from(0x10u8), true)); + /// assert_eq!(U256::from(0x10u8).overflowing_shl(255), (U256::from(0x0u8), false)); + /// ``` + pub const fn overflowing_shl(self, mut n: u32) -> (Self, bool) { + let overflow = n >= Self::BITS; + n &= Self::BITS - 1; + + let mut hi = self.0.wrapping_shl(n); + + hi |= self.1.wrapping_shr(256 - n); + + (Self(hi, self.1.wrapping_shl(n)), overflow) + } + + /// Shifts self right by `rhs` bits. + /// + /// Returns a tuple of the shifted version of `self` along with a boolean indicating whether the shift value was larger than or equal to the number of bits. If the shift value is too large, then value is masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + /// + /// # Examples + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0x10u8).overflowing_shr(4), (U256::from(0x1u8), false)); + /// assert_eq!(U256::from(0x10u8).overflowing_shr(260), (U256::from(0x1u8), true)); + /// ``` + pub const fn overflowing_shr(self, mut n: u32) -> (Self, bool) { + let overflow = n >= Self::BITS; + n &= Self::BITS - 1; + + let mut lo = self.1.wrapping_shr(n); + lo |= self.0.wrapping_shl(256 - n); + (Self(self.0.wrapping_shr(n), lo), overflow) + } + + /// Raises self to the power of `exp`, using exponentiation by squaring. + /// + /// Returns a tuple of the exponentiation along with a bool indicating whether an overflow happened. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(3u8).overflowing_pow(5), (U256::from(243u8), false)); + /// assert_eq!(U256::MAX.overflowing_pow(2), (U256::from(1u8), true)); + /// ``` + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0 { + return (Self(0, 1), false); + } + let mut base = self; + let mut acc = Self(0, 1); + let mut overflow = false; + loop { + if (exp & 1) == 1 { + acc = match acc.overflowing_mul(base) { + (n, false) => n, + (n, true) => { + overflow = true; + n + } + }; + if exp == 1 { + return (acc, overflow); + } + } + exp /= 2; + base = match base.overflowing_mul(base) { + (n, false) => n, + (n, true) => { + overflow = true; + n + } + } + } + } + + /// Raises self to the power of `exp`, using exponentiation by squaring. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(3u8).pow(5), U256::from(243u8)); + /// ``` + pub const fn pow(self, exp: u32) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_pow(exp) + } else { + self.wrapping_pow(exp) + } + } + + /// Returns the square root of the number, rounded down. + /// + /// Unlike `std` methods, this uses binary search for determining the integer square root. this will be significantly slower. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(10u8).isqrt(), U256::from(3u8)); + /// ``` + pub const fn isqrt(self) -> Self { + let mut l = Self(0, 0); + let mut m; + let mut r = self.wrapping_add(Self(0, 1)); + while l.ne(r.wrapping_sub(Self(0, 1))) { + m = l.midpoint(r); + if m.wrapping_mul(m).le(self) { + l = m; + } else { + r = m; + } + } + l + } + + /// Performs Euclidean division. + /// + /// Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self / rhs`. + /// + /// # Panics + /// This funciton will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(7u8).div_euclid(U256::from(4u8)), U256::from(1u8)); + /// ``` + pub const fn div_euclid(self, rhs: Self) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_div_euclid(rhs) + } else { + self.wrapping_div_euclid(rhs) + } + } + + /// Calculates the least remainder of `self (mod rhs)`. + /// + /// Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self % rhs`. + /// + /// # Panics + /// This funciton will panic if `rhs` is 0. + /// + /// # Examples + /// Basic usage: + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(7u8).rem_euclid(U256::from(4u8)), U256::from(3u8)); + /// ``` + pub const fn rem_euclid(self, rhs: Self) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_rem_euclid(rhs) + } else { + self.wrapping_rem_euclid(rhs) + } + } + + /// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity. + /// + /// This is the same as performing `self / rhs` for all unsigned integers. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(7u8).div_floor(U256::from(4u8)), U256::from(1u8)); + /// ``` + pub const fn div_floor(self, rhs: Self) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_div(rhs) + } else { + self.wrapping_div(rhs) + } + } + + /// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(7u8).div_ceil(U256::from(4u8)), U256::from(2u8)); + /// ``` + pub const fn div_ceil(self, rhs: Self) -> Self { + if let Some((d, r)) = self.checked_div_rem(rhs) { + if r.gt(Self(0, 0)) { + d.wrapping_add(Self(0, 1)) + } else { + d + } + } else { + panic!("Division by zero!"); + } + } + + /// Calculates the smallest value greater than or equal to `self` that + /// is a multiple of `rhs`. + /// + /// # Panics + /// + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// On overflow, this function will panic if overflow checks are enabled (default in debug + /// mode) and wrap if overflow checks are disabled (default in release mode). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(16u8).next_multiple_of(U256::from(8u8)), U256::from(16u8)); + /// assert_eq!(U256::from(23u8).next_multiple_of(U256::from(8u8)), U256::from(24u8)); + /// ``` + pub const fn next_multiple_of(self, rhs: Self) -> Self { + match self.rem(rhs) { + Self(0, 0) => self, + r => self.add(rhs.sub(r)), + } + } + + /// Calculates the smallest value greater than or equal to `self` that + /// is a multiple of `rhs`. Returns `None` if `rhs` is zero or the + /// operation would result in overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(16u8).checked_next_multiple_of(U256::from(8u8)), Some(U256::from(16u8))); + /// assert_eq!(U256::from(23u8).checked_next_multiple_of(U256::from(8u8)), Some(U256::from(24u8))); + /// assert_eq!(U256::from(1u8).checked_next_multiple_of(U256::from(0u8)), None); + /// assert_eq!(U256::MAX.checked_next_multiple_of(U256::from(2u8)), None); + /// ``` + pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { + match self.checked_rem(rhs) { + None => None, + Some(Self(0, 0)) => Some(self), + Some(r) => self.checked_add(rhs.sub(r)), + } + } + + /// Returns `true` if `self` is an integer multiple of `rhs`, and false otherwise. + /// + /// This function is equivalent to `self % rhs == 0`, except that it will not panic + /// for `rhs == 0`. Instead, `0.is_multiple_of(0) == true`, and for any non-zero `n`, + /// `n.is_multiple_of(0) == false`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert!(U256::from(6u8).is_multiple_of(U256::from(2u8))); + /// assert!(!U256::from(5u8).is_multiple_of(U256::from(2u8))); + /// assert!(U256::from(0u8).is_multiple_of(U256::from(0u8))); + /// assert!(!U256::from(6u8).is_multiple_of(U256::from(0u8))); + /// ``` + pub const fn is_multiple_of(self, rhs: Self) -> bool { + match rhs { + Self(0, 0) => self.eq(rhs), + _ => self.rem(rhs).eq(Self(0, 0)), + } + } + + /// Returns `true` if and only if `self == 2^k` for some `k`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert!(U256::from(16u8).is_power_of_two()); + /// assert!(!U256::from(10u8).is_power_of_two()); + /// ``` + pub const fn is_power_of_two(self) -> bool { + self.count_ones() == 1 + } + + /// Returns one less than next power of two. + /// (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) + /// + /// 8u8.one_less_than_next_power_of_two() == 7 + /// 6u8.one_less_than_next_power_of_two() == 7 + /// + /// This method cannot overflow, as in the `next_power_of_two` + /// overflow cases it instead ends up returning the maximum value + /// of the type, and can return 0 for 0. + const fn one_less_than_next_power_of_two(self) -> Self { + if self.lt(Self(0, 1)) { + return Self(0, 0); + } + let p = self.sub(Self(0, 1)); + Self::MAX.wrapping_shr(p.leading_zeros()) + } + + /// Returns the smallest power of two greater than or equal to `self`. + /// + /// When return value overflows (i.e., `self > (1 << (N-1))` for type + /// `uN`), it panics in debug mode and the return value is wrapped to 0 in + /// release mode (the only situation in which this method can return 0). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).next_power_of_two(), U256::from(2u8)); + /// assert_eq!(U256::from(3u8).next_power_of_two(), U256::from(4u8)); + /// assert_eq!(U256::from(0u8).next_power_of_two(), U256::from(1u8)); + /// ``` + pub const fn next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two().add(Self(0, 1)) + } + + /// Returns the smallest power of two greater than or equal to `self`. If + /// the next power of two is greater than the type's maximum value, + /// `None` is returned, otherwise the power of two is wrapped in `Some`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).checked_next_power_of_two(), Some(U256::from(2u8))); + /// assert_eq!(U256::from(3u8).checked_next_power_of_two(), Some(U256::from(4u8))); + /// assert_eq!(U256::MAX.checked_next_power_of_two(), None); + /// ``` + pub const fn checked_next_power_of_two(self) -> Option { + self.one_less_than_next_power_of_two() + .checked_add(Self(0, 1)) + } + + /// Returns the smallest power of two greater than or equal to `n`. If + /// the next power of two is greater than the type's maximum value, + /// the return value is wrapped to `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(2u8).wrapping_next_power_of_two(), U256::from(2u8)); + /// assert_eq!(U256::from(3u8).wrapping_next_power_of_two(), U256::from(4u8)); + /// assert_eq!(U256::MAX.wrapping_next_power_of_two(), U256::from(0u8)); + /// ``` + pub const fn wrapping_next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two() + .wrapping_add(Self(0, 1)) + } + + /// Returns the memory representation of this integer as a byte array in + /// big-endian (network) byte order. + /// + pub const fn to_be_bytes(self) -> [u8; 32] { + self.to_be().to_ne_bytes() + } + + /// Returns the memory representation of this integer as a byte array in + /// little-endian byte order. + pub const fn to_le_bytes(self) -> [u8; 32] { + self.to_le().to_ne_bytes() + } + + /// Returns the memory representation of this integer as a byte array in + /// native byte order. + /// + /// As the target platform's native endianness is used, portable code + /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, + /// instead. + /// + /// [`to_be_bytes`]: Self::to_be_bytes + /// [`to_le_bytes`]: Self::to_le_bytes + pub const fn to_ne_bytes(self) -> [u8; 32] { + let mut buf = [0u8; 32]; + let b0 = self.0.to_ne_bytes(); + let b1 = self.1.to_ne_bytes(); + if cfg!(target_endian = "big") { + let mut i = 0; + while i < 16 { + buf[i] = b0[i]; + buf[i + 16] = b1[i]; + i += 1; + } + } else { + let mut i = 0; + while i < 16 { + buf[i] = b1[i]; + buf[i + 16] = b0[i]; + i += 1; + } + } + buf + } + + /// Creates a native endian integer value from its representation as a byte array in big endian + pub const fn from_be_bytes(bytes: [u8; 32]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + + /// Creates a native endian integer value from its representation as a byte array in little endian + pub const fn from_le_bytes(bytes: [u8; 32]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + + /// Creates a native endian integer value from its memory representation as a byte array in native endianness. + /// + /// As the target platformā€™s native endianness is used, portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead. + /// + /// [`from_be_bytes`]: Self::from_be_bytes + /// [`from_le_bytes`]: Self::from_le_bytes + pub const fn from_ne_bytes(bytes: [u8; 32]) -> Self { + let mut b0 = [0u8; 16]; + let mut b1 = [0u8; 16]; + if cfg!(target_endian = "big") { + let mut i = 0; + while i < 16 { + b0[i] = bytes[i]; + b1[i] = bytes[i + 16]; + i += 1; + } + } else { + let mut i = 0; + while i < 16 { + b1[i] = bytes[i]; + b0[i] = bytes[i + 16]; + i += 1; + } + } + Self(u128::from_ne_bytes(b0), u128::from_ne_bytes(b1)) + } + + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards negative infinity and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(0u8).midpoint(U256::from(4u8)), U256::from(2u8)); + /// assert_eq!(U256::from(1u8).midpoint(U256::from(4u8)), U256::from(2u8)); + /// ``` + pub const fn midpoint(self, rhs: Self) -> Self { + self.bit_xor(rhs) + .wrapping_shr(1) + .wrapping_add(self.bit_and(rhs)) + } + + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// If you also need to add a carry to the wide result, then you want + /// [`Self::carrying_mul`] instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from(5u8).widening_mul(U256::from(2u8)), (U256::from(10u8), U256::from(0u8))); + /// assert_eq!(U256::MAX.widening_mul(U256::from(2u8)), (U256::MAX - U256::from(1), U256::from(1u8))); + /// ``` + pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { + let mul_high_high = Self::upcasting_mul128(self.0, rhs.0); + let mul_high_low = Self::upcasting_mul128(self.0, rhs.1); + let mul_low_high = Self::upcasting_mul128(self.1, rhs.0); + let mul_low_low = Self::upcasting_mul128(self.1, rhs.1); + + let low = mul_low_low; + let high = mul_high_high; + + let (low, carry) = low.overflowing_add(Self(mul_high_low.1, 0)); + let (high, _) = high.carrying_add(Self(0, mul_high_low.0), carry); + + let (low, carry) = low.overflowing_add(Self(mul_low_high.1, 0)); + let (high, _) = high.carrying_add(Self(0, mul_low_high.0), carry); + + (low, high) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { + let (lo, hi) = self.widening_mul(rhs); + let (lo, carry) = lo.carrying_add(carry, false); + let (hi, _) = hi.carrying_add(Self(0, 0), carry); + (lo, hi) + } + + /// Converts a string slice in a given base to an integer. + /// + /// The string is expected to be an optional `+` sign + /// followed by digits. + /// Leading and trailing whitespace represent an error. + /// Digits are a subset of these characters, depending on `radix`: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # use extra_math::u256::U256; + /// assert_eq!(U256::from_str_radix("A", 16), Ok(U256::from(10u8))); + /// ``` + pub const fn from_str_radix(src: &str, radix: u32) -> Result { + use core::num::IntErrorKind::*; + + if 2 > radix || radix > 36 { + panic!("Radix out of bounds!"); + } + + if src.is_empty() { + return Err(Empty); + } + + let src = src.as_bytes(); + + let digits = match src { + [b'+' | b'-'] => return Err(InvalidDigit), + [b'-', ..] => return Err(NegOverflow), + [b'+', rest @ ..] => rest, + _ => src, + }; + + let mut acc = Self(0, 0); + let mut i = 0; + while i < digits.len() { + acc = match acc.checked_mul(Self(0, radix as u128)) { + Some(n) => n, + None => return Err(PosOverflow), + }; + + let x = match (digits[i] as char).to_digit(radix) { + Some(n) => n, + None => return Err(InvalidDigit), + }; + + acc = match acc.checked_add(Self(0, x as u128)) { + Some(n) => n, + None => return Err(PosOverflow), + }; + + i += 1; + } + + Ok(acc) + } + + /// Constant version of `self | rhs`. + pub const fn bit_or(self, other: Self) -> Self { + Self(self.0 | other.0, self.1 | other.1) + } + + /// Constant version of `self & rhs`. + pub const fn bit_and(self, other: Self) -> Self { + Self(self.0 & other.0, self.1 & other.1) + } + + /// Constant version of `self ^ rhs`. + pub const fn bit_xor(self, other: Self) -> Self { + Self(self.0 ^ other.0, self.1 ^ other.1) + } + + /// Constant version of `!self` + pub const fn not(self) -> Self { + Self(!self.0, !self.1) + } + + /// Constant version of `self % rhs` + pub const fn rem(self, rhs: Self) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_rem(rhs) + } else { + self.wrapping_rem(rhs) + } + } + /// Constant version of `self + rhs` + pub const fn add(self, rhs: Self) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_add(rhs) + } else { + self.wrapping_add(rhs) + } + } + + /// Constant version of `self % rhs` + pub const fn sub(self, rhs: Self) -> Self { + if cfg!(overflow_checks_stable) { + self.strict_sub(rhs) + } else { + self.wrapping_sub(rhs) + } + } + + /// Formats the integer in a given base + fn fmt_base(self, f: &mut Formatter<'_>, base: u32, uppercase: bool) -> fmt::Result { + let char_table = if uppercase { + [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', + ] + } else { + [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', + ] + }; + + assert!(base >= 2, "Base needs to be at least 2"); + assert!(base <= 36, "Base must be at most 36"); + + let prefix = if base == 2 { + "0b" + } else if base == 8 { + "0o" + } else if base == 16 { + if uppercase { + "0X" + } else { + "0x" + } + } else { + "" + }; + + let mut buf = [0u8; 256]; + let mut curr = buf.len(); + + for byte in buf.iter_mut().rev() { + let (n, x) = self.checked_div_rem(Self::from(base)).unwrap_or_default(); + *byte = char_table[n.1 as usize] as u8; + curr -= 1; + if x == Self(0, 0) { + break; + } + } + + let buf = &buf[curr..]; + let buf = str::from_utf8(buf).expect("Valid UTF-8"); + f.pad_integral(true, prefix, buf) + } +} + +impl Add<&U256> for &U256 { + type Output = ::Output; + + fn add(self, rhs: &U256) -> Self::Output { + *self + *rhs + } +} + +impl Add<&U256> for U256 { + type Output = ::Output; + + fn add(self, rhs: &U256) -> Self::Output { + self + *rhs + } +} + +impl Add for &'_ U256 { + type Output = ::Output; + + fn add(self, rhs: U256) -> Self::Output { + *self + rhs + } +} + +impl Add for U256 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + self.strict_add(rhs) + } else { + self.wrapping_add(rhs) + } + } +} + +impl AddAssign<&U256> for U256 { + fn add_assign(&mut self, rhs: &U256) { + *self = *self + rhs; + } +} + +impl AddAssign for U256 { + fn add_assign(&mut self, rhs: U256) { + *self = *self + rhs; + } +} + +impl Binary for U256 { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_base(f, 2, false) + } +} + +impl BitAnd<&U256> for &U256 { + type Output = ::Output; + + fn bitand(self, rhs: &U256) -> Self::Output { + *self & *rhs + } +} + +impl BitAnd<&U256> for U256 { + type Output = ::Output; + + fn bitand(self, rhs: &U256) -> Self::Output { + self & *rhs + } +} + +impl BitAnd for &'_ U256 { + type Output = ::Output; + + fn bitand(self, rhs: U256) -> Self::Output { + *self & rhs + } +} + +impl BitAnd for U256 { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + self.bit_and(rhs) + } +} + +impl BitAndAssign<&U256> for U256 { + fn bitand_assign(&mut self, rhs: &U256) { + *self = *self & rhs; + } +} + +impl BitAndAssign for U256 { + fn bitand_assign(&mut self, rhs: U256) { + *self = *self & rhs; + } +} + +impl BitOr<&U256> for &U256 { + type Output = ::Output; + + fn bitor(self, rhs: &U256) -> Self::Output { + *self | *rhs + } +} + +impl BitOr<&U256> for U256 { + type Output = ::Output; + + fn bitor(self, rhs: &U256) -> Self::Output { + self | *rhs + } +} + +impl BitOr for &'_ U256 { + type Output = ::Output; + + fn bitor(self, rhs: U256) -> Self::Output { + *self | rhs + } +} + +impl BitOr for U256 { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + self.bit_or(rhs) + } +} + +impl BitOrAssign<&U256> for U256 { + fn bitor_assign(&mut self, rhs: &U256) { + *self = *self | rhs; + } +} + +impl BitOrAssign for U256 { + fn bitor_assign(&mut self, rhs: U256) { + *self = *self | rhs; + } +} + +impl BitXor<&U256> for &U256 { + type Output = ::Output; + + fn bitxor(self, rhs: &U256) -> Self::Output { + *self ^ *rhs + } +} + +impl BitXor<&U256> for U256 { + type Output = ::Output; + + fn bitxor(self, rhs: &U256) -> Self::Output { + self ^ *rhs + } +} + +impl BitXor for &'_ U256 { + type Output = ::Output; + + fn bitxor(self, rhs: U256) -> Self::Output { + *self ^ rhs + } +} + +impl BitXor for U256 { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Self::Output { + self.bit_xor(rhs) + } +} + +impl BitXorAssign<&U256> for U256 { + fn bitxor_assign(&mut self, rhs: &U256) { + *self = *self ^ rhs; + } +} + +impl BitXorAssign for U256 { + fn bitxor_assign(&mut self, rhs: U256) { + *self = *self ^ rhs; + } +} + +impl Div<&U256> for &U256 { + type Output = ::Output; + + fn div(self, rhs: &U256) -> Self::Output { + *self / *rhs + } +} + +impl Div<&U256> for U256 { + type Output = ::Output; + + fn div(self, rhs: &U256) -> Self::Output { + self / *rhs + } +} + +impl Div for &'_ U256 { + type Output = ::Output; + + fn div(self, rhs: U256) -> Self::Output { + *self / rhs + } +} + +impl Div for U256 { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + self.strict_div(rhs) + } else { + self.wrapping_div(rhs) + } + } +} + +impl DivAssign<&U256> for U256 { + fn div_assign(&mut self, rhs: &U256) { + *self = *self / rhs; + } +} + +impl DivAssign for U256 { + fn div_assign(&mut self, rhs: U256) { + *self = *self / rhs; + } +} + +impl From for U256 { + fn from(value: bool) -> Self { + Self(0, value as u128) + } +} + +impl From for U256 { + fn from(value: char) -> Self { + Self(0, value as u128) + } +} + +impl From for U256 { + fn from(value: u128) -> Self { + Self(0, value) + } +} + +impl From for U256 { + fn from(value: u64) -> Self { + Self(0, value as u128) + } +} + +impl From for U256 { + fn from(value: u32) -> Self { + Self(0, value as u128) + } +} + +impl From for U256 { + fn from(value: usize) -> Self { + Self(0, value as u128) + } +} + +impl From for U256 { + fn from(value: u16) -> Self { + Self(0, value as u128) + } +} + +impl From for U256 { + fn from(value: u8) -> Self { + Self(0, value as u128) + } +} + +impl FromStr for U256 { + type Err = IntErrorKind; + fn from_str(src: &str) -> Result { + Self::from_str_radix(src, 10) + } +} + +impl LowerHex for U256 { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_base(f, 16, false) + } +} + +impl PartialEq for U256 { + fn eq(&self, other: &u128) -> bool { + self.eq(&U256::from(*other)) + } +} + +impl PartialOrd for U256 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialOrd for U256 { + fn partial_cmp(&self, other: &u128) -> Option { + self.partial_cmp(&U256::from(*other)) + } +} + +impl Ord for U256 { + fn cmp(&self, other: &Self) -> Ordering { + match self.0.cmp(&other.0) { + Ordering::Equal => {} + ord => return ord, + } + self.1.cmp(&other.1) + } +} + +impl Mul<&U256> for &U256 { + type Output = ::Output; + + fn mul(self, rhs: &U256) -> Self::Output { + *self * *rhs + } +} + +impl Mul<&U256> for U256 { + type Output = ::Output; + + fn mul(self, rhs: &U256) -> Self::Output { + self * *rhs + } +} + +impl Mul for &'_ U256 { + type Output = ::Output; + + fn mul(self, rhs: U256) -> Self::Output { + *self * rhs + } +} + +impl Mul for U256 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + self.strict_mul(rhs) + } else { + self.wrapping_mul(rhs) + } + } +} + +impl MulAssign<&U256> for U256 { + fn mul_assign(&mut self, rhs: &U256) { + *self = *self * rhs; + } +} + +impl MulAssign for U256 { + fn mul_assign(&mut self, rhs: U256) { + *self = *self * rhs; + } +} + +impl Not for &U256 { + type Output = ::Output; + + fn not(self) -> Self::Output { + !*self + } +} + +impl Not for U256 { + type Output = Self; + + fn not(self) -> Self::Output { + self.not() + } +} + +impl Octal for U256 { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_base(f, 8, false) + } +} + +impl<'a> Sum<&'a U256> for U256 { + fn sum>(iter: I) -> Self { + iter.fold(Self(0, 0), |a, b| a + b) + } +} + +impl Sum for U256 { + fn sum>(iter: I) -> Self { + iter.fold(Self(0, 0), |a, b| a + b) + } +} + +impl<'a> Product<&'a U256> for U256 { + fn product>(iter: I) -> Self { + iter.fold(Self(0, 1), |a, b| a * b) + } +} + +impl Product for U256 { + fn product>(iter: I) -> Self { + iter.fold(Self(0, 1), |a, b| a * b) + } +} + +impl Rem<&U256> for &U256 { + type Output = ::Output; + + fn rem(self, rhs: &U256) -> Self::Output { + *self % *rhs + } +} + +impl Rem<&U256> for U256 { + type Output = ::Output; + + fn rem(self, rhs: &U256) -> Self::Output { + self % *rhs + } +} + +impl Rem for &'_ U256 { + type Output = ::Output; + + fn rem(self, rhs: U256) -> Self::Output { + *self % rhs + } +} + +impl Rem for U256 { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + self.strict_rem(rhs) + } else { + self.wrapping_rem(rhs) + } + } +} + +impl RemAssign<&U256> for U256 { + fn rem_assign(&mut self, rhs: &U256) { + *self = *self % rhs; + } +} + +impl RemAssign for U256 { + fn rem_assign(&mut self, rhs: U256) { + *self = *self % rhs; + } +} + +impl Display for U256 { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_base(f, 10, false) + } +} + +impl Shl for U256 { + type Output = Self; + + fn shl(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::from(Self::BITS) { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shl(rhs.0 as u32) + } + } else { + self.wrapping_shl(rhs.0 as u32) + } + } +} + +impl Shl<&'_ U256> for U256 { + type Output = ::Output; + + fn shl(self, rhs: &'_ U256) -> Self::Output { + self << *rhs + } +} + +impl Shl for U256 { + type Output = ::Output; + + fn shl(self, rhs: u128) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::BITS as u128 { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shl(rhs as u32) + } + } else { + self.wrapping_shl(rhs as u32) + } + } +} + +impl Shl<&'_ u128> for U256 { + type Output = ::Output; + + fn shl(self, rhs: &'_ u128) -> Self::Output { + self << *rhs + } +} + +impl Shl for U256 { + type Output = ::Output; + + fn shl(self, rhs: u64) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::BITS as u64 { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shl(rhs as u32) + } + } else { + self.wrapping_shl(rhs as u32) + } + } +} + +impl Shl<&'_ u64> for U256 { + type Output = ::Output; + + fn shl(self, rhs: &'_ u64) -> Self::Output { + self << *rhs + } +} + +impl Shl for U256 { + type Output = ::Output; + + fn shl(self, rhs: u32) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::BITS { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shl(rhs) + } + } else { + self.wrapping_shl(rhs) + } + } +} + +impl Shl<&'_ u32> for U256 { + type Output = ::Output; + + fn shl(self, rhs: &'_ u32) -> Self::Output { + self << *rhs + } +} + +impl Shl for U256 { + type Output = ::Output; + + fn shl(self, rhs: u16) -> Self::Output { + self << u32::from(rhs) + } +} + +impl Shl<&'_ u16> for U256 { + type Output = ::Output; + + fn shl(self, rhs: &'_ u16) -> Self::Output { + self << *rhs + } +} + +impl Shl for U256 { + type Output = ::Output; + + fn shl(self, rhs: u8) -> Self::Output { + self << u32::from(rhs) + } +} + +impl Shl<&'_ u8> for U256 { + type Output = ::Output; + + fn shl(self, rhs: &'_ u8) -> Self::Output { + self << *rhs + } +} + +impl ShlAssign for U256 { + fn shl_assign(&mut self, rhs: Self) { + *self = *self << rhs; + } +} + +impl<'a> ShlAssign<&'a U256> for U256 { + fn shl_assign(&mut self, rhs: &'a Self) { + *self = *self << rhs; + } +} + +impl ShlAssign for U256 { + fn shl_assign(&mut self, rhs: u128) { + *self = *self << rhs; + } +} + +impl<'a> ShlAssign<&'a u128> for U256 { + fn shl_assign(&mut self, rhs: &'a u128) { + *self = *self << rhs; + } +} + +impl ShlAssign for U256 { + fn shl_assign(&mut self, rhs: u64) { + *self = *self << rhs; + } +} + +impl<'a> ShlAssign<&'a u64> for U256 { + fn shl_assign(&mut self, rhs: &'a u64) { + *self = *self << rhs; + } +} + +impl ShlAssign for U256 { + fn shl_assign(&mut self, rhs: u32) { + *self = *self << rhs; + } +} + +impl<'a> ShlAssign<&'a u32> for U256 { + fn shl_assign(&mut self, rhs: &'a u32) { + *self = *self << rhs; + } +} + +impl ShlAssign for U256 { + fn shl_assign(&mut self, rhs: u16) { + *self = *self << rhs; + } +} + +impl<'a> ShlAssign<&'a u16> for U256 { + fn shl_assign(&mut self, rhs: &'a u16) { + *self = *self << rhs; + } +} + +impl ShlAssign for U256 { + fn shl_assign(&mut self, rhs: u8) { + *self = *self << rhs; + } +} + +impl<'a> ShlAssign<&'a u8> for U256 { + fn shl_assign(&mut self, rhs: &'a u8) { + *self = *self << rhs; + } +} + +impl Shr for U256 { + type Output = Self; + + fn shr(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::from(Self::BITS) { + panic!("Tried to shift with overflow: {self} >> {rhs}"); + } else { + self.strict_shr(rhs.0 as u32) + } + } else { + self.wrapping_shr(rhs.0 as u32) + } + } +} + +impl Shr<&'_ U256> for U256 { + type Output = ::Output; + + fn shr(self, rhs: &'_ U256) -> Self::Output { + self >> *rhs + } +} + +impl Shr for U256 { + type Output = ::Output; + + fn shr(self, rhs: u128) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::BITS as u128 { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shr(rhs as u32) + } + } else { + self.wrapping_shr(rhs as u32) + } + } +} + +impl Shr<&'_ u128> for U256 { + type Output = ::Output; + + fn shr(self, rhs: &'_ u128) -> Self::Output { + self >> *rhs + } +} + +impl Shr for U256 { + type Output = ::Output; + + fn shr(self, rhs: u64) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::BITS as u64 { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shr(rhs as u32) + } + } else { + self.wrapping_shr(rhs as u32) + } + } +} + +impl Shr<&'_ u64> for U256 { + type Output = ::Output; + + fn shr(self, rhs: &'_ u64) -> Self::Output { + self >> *rhs + } +} + +impl Shr for U256 { + type Output = ::Output; + + fn shr(self, rhs: u32) -> Self::Output { + if cfg!(overflow_checks_stable) { + if rhs >= Self::BITS { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shr(rhs) + } + } else { + self.wrapping_shr(rhs) + } + } +} + +impl Shr<&'_ u32> for U256 { + type Output = ::Output; + + fn shr(self, rhs: &'_ u32) -> Self::Output { + self >> *rhs + } +} + +impl Shr for U256 { + type Output = ::Output; + + fn shr(self, rhs: u16) -> Self::Output { + self >> U256::from(rhs) + } +} + +impl Shr<&'_ u16> for U256 { + type Output = ::Output; + + fn shr(self, rhs: &'_ u16) -> Self::Output { + self >> *rhs + } +} + +impl Shr for U256 { + type Output = ::Output; + + fn shr(self, rhs: u8) -> Self::Output { + self >> U256::from(rhs) + } +} + +impl Shr<&'_ u8> for U256 { + type Output = ::Output; + + fn shr(self, rhs: &'_ u8) -> Self::Output { + self >> *rhs + } +} + +impl ShrAssign for U256 { + fn shr_assign(&mut self, rhs: Self) { + *self = *self >> rhs; + } +} + +impl<'a> ShrAssign<&'a U256> for U256 { + fn shr_assign(&mut self, rhs: &'a Self) { + *self = *self >> rhs; + } +} + +impl ShrAssign for U256 { + fn shr_assign(&mut self, rhs: u128) { + *self = *self >> rhs; + } +} + +impl<'a> ShrAssign<&'a u128> for U256 { + fn shr_assign(&mut self, rhs: &'a u128) { + *self = *self >> rhs; + } +} + +impl ShrAssign for U256 { + fn shr_assign(&mut self, rhs: u64) { + *self = *self >> rhs; + } +} + +impl<'a> ShrAssign<&'a u64> for U256 { + fn shr_assign(&mut self, rhs: &'a u64) { + *self = *self >> rhs; + } +} + +impl ShrAssign for U256 { + fn shr_assign(&mut self, rhs: u32) { + *self = *self >> rhs; + } +} + +impl<'a> ShrAssign<&'a u32> for U256 { + fn shr_assign(&mut self, rhs: &'a u32) { + *self = *self >> rhs; + } +} + +impl ShrAssign for U256 { + fn shr_assign(&mut self, rhs: u16) { + *self = *self >> rhs; + } +} + +impl<'a> ShrAssign<&'a u16> for U256 { + fn shr_assign(&mut self, rhs: &'a u16) { + *self = *self >> rhs; + } +} + +impl ShrAssign for U256 { + fn shr_assign(&mut self, rhs: u8) { + *self = *self >> rhs; + } +} + +impl<'a> ShrAssign<&'a u8> for U256 { + fn shr_assign(&mut self, rhs: &'a u8) { + *self = *self >> rhs; + } +} -- 2.47.0 From 04935aff82e5a0d3682a2ddd7e7d10a1dc1d8561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charlotte=20=F0=9F=A6=9D=20Delenk?= Date: Thu, 3 Oct 2024 14:34:52 +0200 Subject: [PATCH 2/3] replace division algorithm --- .gitignore | 3 +- src/lib.rs | 1 + src/u256/mod.rs | 346 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 283 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index 2e1e3ed..d2f38eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target /.direnv /result -/resul-bin \ No newline at end of file +/resul-bin +.vscode/ \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index eacd9e1..9258714 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] #![no_std] +#[cfg(feature = "u256")] pub mod u256; diff --git a/src/u256/mod.rs b/src/u256/mod.rs index 50af961..fbf71c3 100644 --- a/src/u256/mod.rs +++ b/src/u256/mod.rs @@ -4,14 +4,30 @@ use core::{ cmp::Ordering, fmt::{self, Binary, Display, Formatter, LowerHex, Octal}, iter::{Product, Sum}, - num::{IntErrorKind, ParseIntError}, + num::IntErrorKind, ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, - DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, + DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, + SubAssign, }, str::{self, FromStr}, }; +/// Creates a U256 literal from a string. +#[macro_export] +macro_rules! u256 { + ($lit:literal) => { + u256!(10, $lit) + }; + ($base:literal, $lit:literal) => {{ + const CONSTANT: $crate::u256::U256 = match $crate::u256::U256::from_str_radix($lit, $base) { + Ok(n) => n, + Err(_) => panic!(concat!("Invalid integer constant: ", $lit)), + }; + CONSTANT + }}; +} + /// The 256-bit unsigned integer type. #[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Hash)] pub struct U256(pub u128, pub u128); @@ -26,7 +42,7 @@ impl U256 { /// # use extra_math::u256::U256; /// assert_eq!(U256::MIN, 0); /// ``` - pub const MIN: Self = Self(0, 0); + pub const MIN: Self = u256!("0"); /// The largest value that can be represented by this integer type (2^256 āˆ’ 1). pub const MAX: Self = Self(u128::MAX, u128::MAX); /// The size of this integer type in bits. @@ -44,8 +60,8 @@ impl U256 { /// Basic usage: /// /// ``` - /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(0b01001100u128).count_ones(), 3); + /// # use extra_math::{u256, u256::U256}; + /// assert_eq!(u256!(2, "01001100").count_ones(), 3); /// ``` pub const fn count_ones(self) -> u32 { self.0.count_ones() + self.1.count_ones() @@ -72,7 +88,7 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// let n = U256::MAX >> 2; + /// let n = U256::MAX >> 2u8; /// /// assert_eq!(n.leading_zeros(), 2); /// ``` @@ -91,8 +107,8 @@ impl U256 { /// Basic usage: /// /// ``` - /// # use extra_math::u256::U256; - /// let n = U256::from(0b01001100u128); + /// # use extra_math::{u256, u256::U256}; + /// let n = u256!(2, "1001100"); /// /// assert_eq!(n.trailing_zeros(), 2); /// ``` @@ -112,7 +128,7 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// let n = !(U256::MAX >> 2); + /// let n = !(U256::MAX >> 2u32); /// /// assert_eq!(n.leading_ones(), 2); /// ``` @@ -131,8 +147,8 @@ impl U256 { /// Basic usage: /// /// ``` - /// # use extra_math::u256::U256; - /// let n = U256::from(0b1010111u128); + /// # use extra_math::{u256, u256::U256}; + /// let n = u256!(2, "1010111"); /// /// assert_eq!(n.trailing_ones(), 3); /// ``` @@ -153,9 +169,9 @@ impl U256 { /// Basic usage: /// /// ``` - /// # use extra_math::u256::U256; + /// # use extra_math::{u256, u256::U256}; /// - /// let n = U256(0x13f40000000000000000000000000000, 0x4f76); + /// let n = u256!(16, "13f4_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_4f76"); /// let m = U256::from(0x4f7613f4u32); /// /// assert_eq!(n.rotate_left(16), m); @@ -403,7 +419,7 @@ impl U256 { /// ``` /// # use extra_math::u256::U256; /// assert_eq!(U256::from(5u8).checked_mul(U256::from(1u8)), Some(U256::from(5u8))); - /// assert_eq!(U256::MAX.checked_sub(U256::from(2u8)), None) + /// assert_eq!(U256::MAX.checked_mul(U256::from(2u8)), None) /// ``` pub const fn checked_mul(self, rhs: Self) -> Option { match self.overflowing_mul(rhs) { @@ -437,50 +453,125 @@ impl U256 { } } + const fn div_rem_256_by_128_to_128_default(u: Self, mut v: u128) -> (u128, u128) { + const N_UDWORD_BITS: u32 = u128::BITS; + const B: u128 = 1 << (N_UDWORD_BITS / 2); // number base + let un1; + let un0; + let vn1; + let vn0; + let mut q1; + let mut q0: u128; + let un64; + let un21: u128; + let un10; + let mut rhat; + let s; + + s = v.leading_zeros(); + if s > 0 { + // Normalize the divisor + v <<= s; + un64 = (u.0 << s) | (u.1 >> (N_UDWORD_BITS - s)); + un10 = u.1 << s; + } else { + // Avoid undefined behavior of (u0 >> 64) + un64 = u.1; + un10 = u.0; + } + + // break divisor up into two 64 bit digits. + vn1 = v >> (N_UDWORD_BITS / 2); + vn0 = (v as u64) as u128; + + // Break right half of dividend into two digits. + un1 = un10 >> (N_UDWORD_BITS / 2); + un0 = (un10 as u64) as u128; + + // Compute the first quotient digit, q1. + q1 = un64 / vn1; + rhat = un64 - q1 * vn1; + + // q1 has at most error 2. No more than 2 iterations. + while q1 >= B || q1 * vn0 > B.wrapping_mul(rhat) + un1 { + q1 -= 1; + rhat += vn1; + if rhat >= B { + break; + } + } + + un21 = un64 + .wrapping_mul(B) + .wrapping_add(un1) + .wrapping_sub(q1.wrapping_mul(v)); + + // Compute the second quotient digit + q0 = un21 / vn1; + rhat = un21 - q0 * vn1; + + // q0 has at most error 2. No more than 2 iterations. + while q0 >= B || q0 * vn0 > B.wrapping_mul(rhat) + un0 { + q0 -= 1; + rhat += vn1; + if rhat >= B { + break; + } + } + + let r = (un21 + .wrapping_mul(B) + .wrapping_add(un0) + .wrapping_sub(q0.wrapping_mul(v))) + >> s; + let q = q1.wrapping_mul(B) + q0; + (q, r) + } + /// Checked integer divrem. Computes `(self / rhs, self % rhs)`, returning `None` if `rhs == 0` - pub const fn checked_div_rem(mut self, rhs: Self) -> Option<(Self, Self)> { + pub const fn checked_div_rem(mut self, mut rhs: Self) -> Option<(Self, Self)> { if rhs.eq(Self(0, 0)) { return None; } + // ported from https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/udivmodti4.c if rhs.gt(self) { - // divisor > numerator - return Some((Self(0, 0), rhs)); - } - if rhs.eq(Self(0, 1)) { - // divisor == 1 - return Some((self, Self(0, 0))); + return Some((Self(0, 0), self)); } - if self.lt(Self(1, 0)) && rhs.lt(Self(1, 0)) { - let div = match self.1.checked_div(rhs.1) { - Some(v) => v, - None => return None, - }; - let rem = match self.1.checked_rem(rhs.1) { - Some(v) => v, - None => return None, - }; - return Some((Self(0, div), Self(0, rem))); - } - - let mut bits = rhs.leading_zeros() - self.leading_zeros() + 1; - let mut rem = self.wrapping_shr(bits); - self = self.wrapping_shl(Self::BITS - bits); - let mut wrap = Self(0, 0); - while bits > 0 { - bits -= 1; - rem = (rem.wrapping_shl(1)).bit_or(self.wrapping_shr(Self::BITS - 1)); - self = (self.wrapping_shl(1)).bit_or(wrap); - if rhs.gt(rem) { - wrap = Self(0, 0); + if rhs.0 == 0 { + let mut remainder = Self(0, 0); + let mut quotient = Self(0, 0); + if self.0 < rhs.1 { + // The result fits in 64 bits. + (quotient.1, remainder.1) = Self::div_rem_256_by_128_to_128_default(self, rhs.1); } else { - wrap = Self(0, 1); - rem = rem.wrapping_sub(rhs); + quotient.0 = self.0 / rhs.1; + self.0 = self.0 % rhs.1; + (quotient.1, remainder.1) = Self::div_rem_256_by_128_to_128_default(self, rhs.1); } + return Some((quotient, remainder)); } - Some((self.wrapping_shl(1).bit_or(wrap), rem)) + let mut shift = (rhs.0.leading_zeros() - self.0.leading_zeros()) as i32; + rhs = rhs.wrapping_shr(shift as u32); + let mut quotient = Self(0, 0); + while shift >= 0 { + quotient.1 <<= 1; + + let carry = if self.ge(rhs) { + self = self.wrapping_sub(rhs); + 1 + } else { + 0 + }; + + quotient.1 |= carry; + rhs = rhs.wrapping_shr(1); + shift -= 1; + } + + Some((quotient, self)) } /// Checked integer division. Computes self / rhs, returning None if rhs == 0. @@ -643,7 +734,7 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(5u8).strict_rem_euclid(U256::from(2u8)), U256::from(uu8)); + /// assert_eq!(U256::from(5u8).strict_rem_euclid(U256::from(2u8)), U256::from(1u8)); /// ``` /// /// The following function panics because of division by zero: @@ -854,6 +945,7 @@ impl U256 { /// /// This following panics because of overflow: /// ```should_panic + /// # use extra_math::u256::U256; /// let _ = U256::from(0x10u8).strict_shl(257); /// ``` pub const fn strict_shl(self, rhs: u32) -> Self { @@ -910,11 +1002,12 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(0x10u8).strict_shr(4), U256::from(0x11u8)); + /// assert_eq!(U256::from(0x10u8).strict_shr(4), U256::from(0x1u8)); /// ``` /// /// This following panics because of overflow: /// ```should_panic + /// # use extra_math::u256::U256; /// let _ = U256::from(0x10u8).strict_shr(257); /// ``` pub const fn strict_shr(self, rhs: u32) -> Self { @@ -952,7 +1045,7 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(2u8).checked_pow(5), Some(U256::from(25u8))); + /// assert_eq!(U256::from(2u8).checked_pow(5), Some(U256::from(32u8))); /// assert_eq!(U256::MAX.checked_pow(2), None); /// ``` pub const fn checked_pow(self, exp: u32) -> Option { @@ -977,14 +1070,14 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(2u8).strict_pow(5), U256::from(25u8)); + /// assert_eq!(U256::from(2u8).strict_pow(5), U256::from(32u8)); /// ``` /// /// The following panics because of overflow: /// /// ```should_panic /// # use extra_math::u256::U256; - /// let _ = Self::MAX.strict_pow(2); + /// let _ = U256::MAX.strict_pow(2); /// ``` pub const fn strict_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -1202,8 +1295,8 @@ impl U256 { /// # use extra_math::u256::U256; /// assert_eq!(U256::from(0u8).wrapping_neg(), U256::from(0u8)); /// assert_eq!(U256::MAX.wrapping_neg(), U256::from(1u8)); - /// assert_eq!(U256::from(13u8).wrapping_neg, !U256::from(13u8) + U256::from(1u8)); - /// assert_eq!(U256::from(42u8).wrapping_neg, !(U256::from(42u8) - U256::from(1u8))); + /// assert_eq!(U256::from(13u8).wrapping_neg(), !U256::from(13u8) + U256::from(1u8)); + /// assert_eq!(U256::from(42u8).wrapping_neg(), !(U256::from(42u8) - U256::from(1u8))); /// ``` pub const fn wrapping_neg(self) -> Self { self.overflowing_neg().0 @@ -1218,7 +1311,7 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(1u8).wrapping_shl(7), U256::from(127u8)); + /// assert_eq!(U256::from(1u8).wrapping_shl(7), U256::from(128u8)); /// assert_eq!(U256::from(1u8).wrapping_shl(256), U256::from(1u8)); /// ``` pub const fn wrapping_shl(self, n: u32) -> Self { @@ -1234,7 +1327,7 @@ impl U256 { /// /// ``` /// # use extra_math::u256::U256; - /// assert_eq!(U256::from(127u8).wrapping_shr(7), U256::from(1u8)); + /// assert_eq!(U256::from(127u8).wrapping_shr(7), U256::from(0u8)); /// assert_eq!(U256::from(127u8).wrapping_shl(256), U256::from(127u8)); /// ``` pub const fn wrapping_shr(self, n: u32) -> Self { @@ -1387,6 +1480,11 @@ impl U256 { self.0 > rhs.0 || self.1 > rhs.1 } + /// Constant version of `self >= rhs` + pub const fn ge(self, rhs: Self) -> bool { + self.gt(rhs) || self.eq(rhs) + } + /// Constant version of `self < rhs` pub const fn lt(self, rhs: Self) -> bool { self.0 < rhs.0 || self.1 < rhs.1 @@ -1417,7 +1515,6 @@ impl U256 { mul_high_high .wrapping_add(mul_high_low) .wrapping_add(mul_low_high) - .wrapping_add(mul_high_low) .wrapping_add(mul_low_low) } @@ -1434,7 +1531,7 @@ impl U256 { /// ``` /// # use extra_math::u256::U256; /// assert_eq!(U256::from(5u8).overflowing_mul(U256::from(2u8)), (U256::from(10u8), false)); - /// assert_eq!(U256::MAX.overflowing_mul(U256::from(2u8)), (U256::MAX - U256::from(1), true)); + /// assert_eq!(U256::MAX.overflowing_mul(U256::from(2u8)), (U256::MAX - U256::from(1u8), true)); /// ``` pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { let (l, h) = self.widening_mul(rhs); @@ -1544,11 +1641,16 @@ impl U256 { /// ``` pub const fn overflowing_shl(self, mut n: u32) -> (Self, bool) { let overflow = n >= Self::BITS; + n &= Self::BITS - 1; + if n >= (Self::BITS / 2) { + return (Self(self.1.wrapping_shl(n), 0), overflow); + } + let mut hi = self.0.wrapping_shl(n); - hi |= self.1.wrapping_shr(256 - n); + hi |= self.1.wrapping_shr(127 - n); (Self(hi, self.1.wrapping_shl(n)), overflow) } @@ -1567,10 +1669,17 @@ impl U256 { /// ``` pub const fn overflowing_shr(self, mut n: u32) -> (Self, bool) { let overflow = n >= Self::BITS; + n &= Self::BITS - 1; + if n >= (Self::BITS / 2) { + return (Self(0, self.0.wrapping_shr(n)), overflow); + } + let mut lo = self.1.wrapping_shr(n); - lo |= self.0.wrapping_shl(256 - n); + + lo |= self.0.wrapping_shl(127 - n); + (Self(self.0.wrapping_shr(n), lo), overflow) } @@ -2029,7 +2138,7 @@ impl U256 { /// ``` /// # use extra_math::u256::U256; /// assert_eq!(U256::from(5u8).widening_mul(U256::from(2u8)), (U256::from(10u8), U256::from(0u8))); - /// assert_eq!(U256::MAX.widening_mul(U256::from(2u8)), (U256::MAX - U256::from(1), U256::from(1u8))); + /// assert_eq!(U256::MAX.widening_mul(U256::from(2u8)), (U256::MAX - U256::from(1u8), U256::from(1u8))); /// ``` pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { let mul_high_high = Self::upcasting_mul128(self.0, rhs.0); @@ -2113,6 +2222,11 @@ impl U256 { let mut acc = Self(0, 0); let mut i = 0; while i < digits.len() { + if digits[i] == b'_' { + // Skip _ separators + i += 1; + continue; + } acc = match acc.checked_mul(Self(0, radix as u128)) { Some(n) => n, None => return Err(PosOverflow), @@ -2181,7 +2295,7 @@ impl U256 { } /// Formats the integer in a given base - fn fmt_base(self, f: &mut Formatter<'_>, base: u32, uppercase: bool) -> fmt::Result { + fn fmt_base(mut self, f: &mut Formatter<'_>, base: u32, uppercase: bool) -> fmt::Result { let char_table = if uppercase { [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', @@ -2217,12 +2331,13 @@ impl U256 { let mut curr = buf.len(); for byte in buf.iter_mut().rev() { - let (n, x) = self.checked_div_rem(Self::from(base)).unwrap_or_default(); + let (x, n) = self.checked_div_rem(Self::from(base)).unwrap_or_default(); *byte = char_table[n.1 as usize] as u8; curr -= 1; if x == Self(0, 0) { break; } + self = x; } let buf = &buf[curr..]; @@ -2636,6 +2751,54 @@ impl Sum for U256 { } } +impl Sub<&U256> for &U256 { + type Output = ::Output; + + fn sub(self, rhs: &U256) -> Self::Output { + *self - *rhs + } +} + +impl Sub<&U256> for U256 { + type Output = ::Output; + + fn sub(self, rhs: &U256) -> Self::Output { + self - *rhs + } +} + +impl Sub for &'_ U256 { + type Output = ::Output; + + fn sub(self, rhs: U256) -> Self::Output { + *self - rhs + } +} + +impl Sub for U256 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + if cfg!(overflow_checks_stable) { + self.strict_sub(rhs) + } else { + self.wrapping_sub(rhs) + } + } +} + +impl SubAssign<&U256> for U256 { + fn sub_assign(&mut self, rhs: &U256) { + *self = *self - rhs; + } +} + +impl SubAssign for U256 { + fn sub_assign(&mut self, rhs: U256) { + *self = *self - rhs; + } +} + impl<'a> Product<&'a U256> for U256 { fn product>(iter: I) -> Self { iter.fold(Self(0, 1), |a, b| a * b) @@ -2802,7 +2965,15 @@ impl Shl for U256 { type Output = ::Output; fn shl(self, rhs: u16) -> Self::Output { - self << u32::from(rhs) + if cfg!(overflow_checks_stable) { + if rhs as u32 >= Self::BITS { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shl(rhs as u32) + } + } else { + self.wrapping_shl(rhs as u32) + } } } @@ -2818,7 +2989,15 @@ impl Shl for U256 { type Output = ::Output; fn shl(self, rhs: u8) -> Self::Output { - self << u32::from(rhs) + if cfg!(overflow_checks_stable) { + if rhs as u32 >= Self::BITS { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shl(rhs as u32) + } + } else { + self.wrapping_shl(rhs as u32) + } } } @@ -3002,7 +3181,15 @@ impl Shr for U256 { type Output = ::Output; fn shr(self, rhs: u16) -> Self::Output { - self >> U256::from(rhs) + if cfg!(overflow_checks_stable) { + if rhs as u32 >= Self::BITS { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shr(rhs as u32) + } + } else { + self.wrapping_shr(rhs as u32) + } } } @@ -3018,7 +3205,15 @@ impl Shr for U256 { type Output = ::Output; fn shr(self, rhs: u8) -> Self::Output { - self >> U256::from(rhs) + if cfg!(overflow_checks_stable) { + if rhs as u32 >= Self::BITS { + panic!("Tried to shift with overflow: {self} << {rhs}"); + } else { + self.strict_shr(rhs as u32) + } + } else { + self.wrapping_shr(rhs as u32) + } } } @@ -3101,3 +3296,22 @@ impl<'a> ShrAssign<&'a u8> for U256 { *self = *self >> rhs; } } + +#[cfg(test)] +pub mod tests { + use super::U256; + extern crate std; + + #[test] + pub fn check_number_parsing() { + let x = U256::from_str_radix( + "13f4_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_4f76", + 16, + ) + .unwrap(); + assert_eq!( + std::format!("{x}"), + "9025054806887987155511483633794827778846787745240661638085164476202701836150" + ); + } +} -- 2.47.0 From 057c365e9ac42788deb8cbd8e60bd0a4f8f9cbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charlotte=20=F0=9F=A6=9D=20Delenk?= Date: Thu, 3 Oct 2024 14:35:40 +0200 Subject: [PATCH 3/3] add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34a952a..1864740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Removed +Rewrite from scratch + +### Added +- a 256 bit integer type, `U256`. ## [0.1.1] - 2024-09-09 -- 2.47.0