Merge remote-tracking branch 'origin/master' into bump
This commit is contained in:
commit
73df9f1556
|
@ -4,7 +4,7 @@ homepage = "http://parity.io"
|
||||||
repository = "https://github.com/ethcore/bigint"
|
repository = "https://github.com/ethcore/bigint"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "bigint"
|
name = "bigint"
|
||||||
version = "1.0.3"
|
version = "2.0.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# bigint
|
# bigint
|
||||||
|
|
||||||
![travis status](https://travis-ci.org/ethcore/bigint.svg?branch=master)
|
[![Build Status](https://travis-ci.org/paritytech/bigint.svg?branch=master)](https://travis-ci.org/paritytech/bigint)
|
||||||
|
|
||||||
Fixed-sized integers arithmetic
|
Fixed-sized integers arithmetic
|
||||||
|
|
||||||
|
|
161
src/uint.rs
161
src/uint.rs
|
@ -490,72 +490,6 @@ fn split(a: u64) -> (u64, u64) {
|
||||||
(a >> 32, a & 0xFFFFFFFF)
|
(a >> 32, a & 0xFFFFFFFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Large, fixed-length unsigned integer type.
|
|
||||||
pub trait Uint: Sized + Default + FromStr + From<u64> + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash {
|
|
||||||
|
|
||||||
/// Returns new instance equalling zero.
|
|
||||||
fn zero() -> Self;
|
|
||||||
/// Returns new instance equalling one.
|
|
||||||
fn one() -> Self;
|
|
||||||
/// Returns the largest value that can be represented by this integer type.
|
|
||||||
fn max_value() -> Self;
|
|
||||||
|
|
||||||
/// Convert from a decimal string.
|
|
||||||
fn from_dec_str(value: &str) -> Result<Self, FromDecStrErr>;
|
|
||||||
|
|
||||||
/// Conversion to u32
|
|
||||||
fn low_u32(&self) -> u32;
|
|
||||||
|
|
||||||
/// Conversion to u64
|
|
||||||
fn low_u64(&self) -> u64;
|
|
||||||
|
|
||||||
/// Conversion to u32 with overflow checking
|
|
||||||
fn as_u32(&self) -> u32;
|
|
||||||
|
|
||||||
/// Conversion to u64 with overflow checking
|
|
||||||
fn as_u64(&self) -> u64;
|
|
||||||
|
|
||||||
/// Return the least number of bits needed to represent the number
|
|
||||||
fn bits(&self) -> usize;
|
|
||||||
/// Return if specific bit is set
|
|
||||||
fn bit(&self, index: usize) -> bool;
|
|
||||||
/// Return single byte
|
|
||||||
fn byte(&self, index: usize) -> u8;
|
|
||||||
/// Convert to the sequence of bytes with a big endian
|
|
||||||
fn to_big_endian(&self, bytes: &mut[u8]);
|
|
||||||
/// Convert to the sequence of bytes with a little endian
|
|
||||||
fn to_little_endian(&self, result: &mut [u8]);
|
|
||||||
/// Convert to a non-zero-prefixed hex representation (not prefixed by `0x`).
|
|
||||||
fn to_hex(&self) -> String;
|
|
||||||
/// Create `Uint(10**n)`
|
|
||||||
fn exp10(n: usize) -> Self;
|
|
||||||
/// Return eponentation `self**other`. Panic on overflow.
|
|
||||||
fn pow(self, other: Self) -> Self;
|
|
||||||
/// Return wrapped eponentation `self**other` and flag if there was an overflow
|
|
||||||
fn overflowing_pow(self, other: Self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Add this `Uint` to other returning result and possible overflow
|
|
||||||
fn overflowing_add(self, other: Self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Subtract another `Uint` from this returning result and possible overflow
|
|
||||||
fn overflowing_sub(self, other: Self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Multiple this `Uint` with other returning result and possible overflow
|
|
||||||
fn overflowing_mul(self, other: Self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Divide this `Uint` by other returning result and possible overflow
|
|
||||||
fn overflowing_div(self, other: Self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Returns reminder of division of this `Uint` by other and possible overflow
|
|
||||||
fn overflowing_rem(self, other: Self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Returns negation of this `Uint` and overflow (always true)
|
|
||||||
fn overflowing_neg(self) -> (Self, bool);
|
|
||||||
|
|
||||||
/// Returns
|
|
||||||
fn is_zero(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! construct_uint {
|
macro_rules! construct_uint {
|
||||||
($name:ident, $n_words:expr) => (
|
($name:ident, $n_words:expr) => (
|
||||||
/// Little-endian large integer type
|
/// Little-endian large integer type
|
||||||
|
@ -563,9 +497,9 @@ macro_rules! construct_uint {
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct $name(pub [u64; $n_words]);
|
pub struct $name(pub [u64; $n_words]);
|
||||||
|
|
||||||
impl Uint for $name {
|
impl $name {
|
||||||
|
/// Convert from a decimal string.
|
||||||
fn from_dec_str(value: &str) -> Result<Self, FromDecStrErr> {
|
pub fn from_dec_str(value: &str) -> Result<Self, FromDecStrErr> {
|
||||||
if !value.bytes().all(|b| b >= 48 && b <= 57) {
|
if !value.bytes().all(|b| b >= 48 && b <= 57) {
|
||||||
return Err(FromDecStrErr::InvalidCharacter)
|
return Err(FromDecStrErr::InvalidCharacter)
|
||||||
}
|
}
|
||||||
|
@ -585,21 +519,23 @@ macro_rules! construct_uint {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Conversion to u32
|
||||||
#[inline]
|
#[inline]
|
||||||
fn low_u32(&self) -> u32 {
|
pub fn low_u32(&self) -> u32 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
arr[0] as u32
|
arr[0] as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Conversion to u64
|
||||||
#[inline]
|
#[inline]
|
||||||
fn low_u64(&self) -> u64 {
|
pub fn low_u64(&self) -> u64 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
arr[0]
|
arr[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conversion to u32 with overflow checking
|
/// Conversion to u32 with overflow checking
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_u32(&self) -> u32 {
|
pub fn as_u32(&self) -> u32 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
if (arr[0] & (0xffffffffu64 << 32)) != 0 {
|
if (arr[0] & (0xffffffffu64 << 32)) != 0 {
|
||||||
panic!("Integer overflow when casting U256")
|
panic!("Integer overflow when casting U256")
|
||||||
|
@ -609,7 +545,7 @@ macro_rules! construct_uint {
|
||||||
|
|
||||||
/// Conversion to u64 with overflow checking
|
/// Conversion to u64 with overflow checking
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_u64(&self) -> u64 {
|
pub fn as_u64(&self) -> u64 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
for i in 1..$n_words {
|
for i in 1..$n_words {
|
||||||
if arr[i] != 0 {
|
if arr[i] != 0 {
|
||||||
|
@ -619,8 +555,9 @@ macro_rules! construct_uint {
|
||||||
arr[0]
|
arr[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this is zero.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_zero(&self) -> bool {
|
pub fn is_zero(&self) -> bool {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
for i in 0..$n_words { if arr[i] != 0 { return false; } }
|
for i in 0..$n_words { if arr[i] != 0 { return false; } }
|
||||||
return true;
|
return true;
|
||||||
|
@ -628,7 +565,7 @@ macro_rules! construct_uint {
|
||||||
|
|
||||||
/// Return the least number of bits needed to represent the number
|
/// Return the least number of bits needed to represent the number
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bits(&self) -> usize {
|
pub fn bits(&self) -> usize {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
for i in 1..$n_words {
|
for i in 1..$n_words {
|
||||||
if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; }
|
if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; }
|
||||||
|
@ -636,36 +573,41 @@ macro_rules! construct_uint {
|
||||||
0x40 - arr[0].leading_zeros() as usize
|
0x40 - arr[0].leading_zeros() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return if specific bit is set.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bit(&self, index: usize) -> bool {
|
pub fn bit(&self, index: usize) -> bool {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
arr[index / 64] & (1 << (index % 64)) != 0
|
arr[index / 64] & (1 << (index % 64)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return specific byte.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn byte(&self, index: usize) -> u8 {
|
pub fn byte(&self, index: usize) -> u8 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
(arr[index / 8] >> (((index % 8)) * 8)) as u8
|
(arr[index / 8] >> (((index % 8)) * 8)) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write to the slice in big-endian format.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_big_endian(&self, bytes: &mut[u8]) {
|
pub fn to_big_endian(&self, bytes: &mut [u8]) {
|
||||||
debug_assert!($n_words * 8 == bytes.len());
|
debug_assert!($n_words * 8 == bytes.len());
|
||||||
for i in 0..$n_words {
|
for i in 0..$n_words {
|
||||||
BigEndian::write_u64(&mut bytes[8 * i..], self.0[$n_words - i - 1]);
|
BigEndian::write_u64(&mut bytes[8 * i..], self.0[$n_words - i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write to the slice in little-endian format.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_little_endian(&self, bytes: &mut [u8]) {
|
pub fn to_little_endian(&self, bytes: &mut [u8]) {
|
||||||
debug_assert!($n_words * 8 == bytes.len());
|
debug_assert!($n_words * 8 == bytes.len());
|
||||||
for i in 0..$n_words {
|
for i in 0..$n_words {
|
||||||
LittleEndian::write_u64(&mut bytes[8 * i..], self.0[i]);
|
LittleEndian::write_u64(&mut bytes[8 * i..], self.0[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert to hex string.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_hex(&self) -> String {
|
pub fn to_hex(&self) -> String {
|
||||||
if self.is_zero() { return "0".to_owned(); } // special case.
|
if self.is_zero() { return "0".to_owned(); } // special case.
|
||||||
let mut bytes = [0u8; 8 * $n_words];
|
let mut bytes = [0u8; 8 * $n_words];
|
||||||
self.to_big_endian(&mut bytes);
|
self.to_big_endian(&mut bytes);
|
||||||
|
@ -675,26 +617,30 @@ macro_rules! construct_uint {
|
||||||
(&bytes_hex[1 - bp7 % 8 / 4..]).to_owned()
|
(&bytes_hex[1 - bp7 % 8 / 4..]).to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create `10**n` as this type.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn exp10(n: usize) -> Self {
|
pub fn exp10(n: usize) -> Self {
|
||||||
match n {
|
match n {
|
||||||
0 => Self::from(1u64),
|
0 => Self::from(1u64),
|
||||||
_ => Self::exp10(n - 1).mul_u32(10)
|
_ => Self::exp10(n - 1).mul_u32(10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Zero (additive identity) of this type.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
From::from(0u64)
|
From::from(0u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// One (multiplicative identity) of this type.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> Self {
|
pub fn one() -> Self {
|
||||||
From::from(1u64)
|
From::from(1u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The maximum value which can be inhabited by this type.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn max_value() -> Self {
|
pub fn max_value() -> Self {
|
||||||
let mut result = [0; $n_words];
|
let mut result = [0; $n_words];
|
||||||
for i in 0..$n_words {
|
for i in 0..$n_words {
|
||||||
result[i] = u64::max_value();
|
result[i] = u64::max_value();
|
||||||
|
@ -704,7 +650,7 @@ macro_rules! construct_uint {
|
||||||
|
|
||||||
/// Fast exponentation by squaring
|
/// Fast exponentation by squaring
|
||||||
/// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
/// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
||||||
fn pow(self, expon: Self) -> Self {
|
pub fn pow(self, expon: Self) -> Self {
|
||||||
if expon.is_zero() {
|
if expon.is_zero() {
|
||||||
return Self::one()
|
return Self::one()
|
||||||
}
|
}
|
||||||
|
@ -731,7 +677,7 @@ macro_rules! construct_uint {
|
||||||
|
|
||||||
/// Fast exponentation by squaring
|
/// Fast exponentation by squaring
|
||||||
/// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
/// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
||||||
fn overflowing_pow(self, expon: Self) -> (Self, bool) {
|
pub fn overflowing_pow(self, expon: Self) -> (Self, bool) {
|
||||||
if expon.is_zero() { return (Self::one(), false) }
|
if expon.is_zero() { return (Self::one(), false) }
|
||||||
|
|
||||||
let is_even = |x : &Self| x.low_u64() & 1 == 0;
|
let is_even = |x : &Self| x.low_u64() & 1 == 0;
|
||||||
|
@ -758,29 +704,58 @@ macro_rules! construct_uint {
|
||||||
|
|
||||||
/// Optimized instructions
|
/// Optimized instructions
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn overflowing_add(self, other: $name) -> ($name, bool) {
|
pub fn overflowing_add(self, other: $name) -> ($name, bool) {
|
||||||
uint_overflowing_add!($name, $n_words, self, other)
|
uint_overflowing_add!($name, $n_words, self, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Addition which saturates at the maximum value.
|
||||||
|
pub fn saturating_add(self, other: $name) -> $name {
|
||||||
|
match self.overflowing_add(other) {
|
||||||
|
(_, true) => $name::max_value(),
|
||||||
|
(val, false) => val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subtraction which underflows and returns a flag if it does.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn overflowing_sub(self, other: $name) -> ($name, bool) {
|
pub fn overflowing_sub(self, other: $name) -> ($name, bool) {
|
||||||
uint_overflowing_sub!($name, $n_words, self, other)
|
uint_overflowing_sub!($name, $n_words, self, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Subtraction which saturates at zero.
|
||||||
|
pub fn saturating_sub(self, other: $name) -> $name {
|
||||||
|
match self.overflowing_sub(other) {
|
||||||
|
(_, true) => $name::zero(),
|
||||||
|
(val, false) => val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiply with overflow, returning a flag if it does.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn overflowing_mul(self, other: $name) -> ($name, bool) {
|
pub fn overflowing_mul(self, other: $name) -> ($name, bool) {
|
||||||
uint_overflowing_mul!($name, $n_words, self, other)
|
uint_overflowing_mul!($name, $n_words, self, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_div(self, other: $name) -> ($name, bool) {
|
/// Multiplication which saturates at the maximum value..
|
||||||
|
pub fn saturating_mul(self, other: $name) -> $name {
|
||||||
|
match self.overflowing_mul(other) {
|
||||||
|
(_, true) => $name::max_value(),
|
||||||
|
(val, false) => val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Division with overflow
|
||||||
|
pub fn overflowing_div(self, other: $name) -> ($name, bool) {
|
||||||
(self / other, false)
|
(self / other, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_rem(self, other: $name) -> ($name, bool) {
|
/// Modulus with overflow.
|
||||||
|
pub fn overflowing_rem(self, other: $name) -> ($name, bool) {
|
||||||
(self % other, false)
|
(self % other, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_neg(self) -> ($name, bool) {
|
/// Negation with overflow.
|
||||||
|
pub fn overflowing_neg(self) -> ($name, bool) {
|
||||||
(!self, true)
|
(!self, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1433,7 +1408,7 @@ known_heap_size!(0, U128, U256);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use uint::{Uint, U128, U256, U512};
|
use uint::{U128, U256, U512};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use super::FromDecStrErr;
|
use super::FromDecStrErr;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue