Merge commit 'refs/pull/304/head' of github.com:rust-num/num
This commit is contained in:
commit
8dd6890ddc
|
@ -1,5 +1,5 @@
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub};
|
use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Not};
|
||||||
use std::str::{self, FromStr};
|
use std::str::{self, FromStr};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::cmp::Ordering::{self, Less, Greater, Equal};
|
use std::cmp::Ordering::{self, Less, Greater, Equal};
|
||||||
|
@ -16,8 +16,8 @@ use serde;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use integer::Integer;
|
use integer::Integer;
|
||||||
use traits::{ToPrimitive, FromPrimitive, Num, CheckedAdd, CheckedSub, CheckedMul,
|
use traits::{ToPrimitive, FromPrimitive, Num, CheckedAdd, CheckedSub,
|
||||||
CheckedDiv, Signed, Zero, One};
|
CheckedMul, CheckedDiv, Signed, Zero, One};
|
||||||
|
|
||||||
use self::Sign::{Minus, NoSign, Plus};
|
use self::Sign::{Minus, NoSign, Plus};
|
||||||
|
|
||||||
|
@ -926,6 +926,49 @@ impl BigInt {
|
||||||
BigInt::from_biguint(sign, BigUint::new(digits))
|
BigInt::from_biguint(sign, BigUint::new(digits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates and initializes a `BigInt` from an array of bytes in two's complement.
|
||||||
|
///
|
||||||
|
/// The digits are in little-endian base 2^8.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_signed_bytes_le(digits: &[u8]) -> BigInt {
|
||||||
|
let sign = match digits.last() {
|
||||||
|
Some(v) if *v > 0x7f => Sign::Minus,
|
||||||
|
Some(_) => Sign::Plus,
|
||||||
|
None => return BigInt::zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if sign == Sign::Minus {
|
||||||
|
// two's-complement the content to retrieve the magnitude
|
||||||
|
let mut digits = Vec::from(digits);
|
||||||
|
twos_complement_le(&mut digits);
|
||||||
|
BigInt::from_biguint(sign, BigUint::from_bytes_le(&*digits))
|
||||||
|
} else {
|
||||||
|
BigInt::from_biguint(sign, BigUint::from_bytes_le(digits))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates and initializes a `BigInt` from an array of bytes in
|
||||||
|
/// two's complement binary representation.
|
||||||
|
///
|
||||||
|
/// The digits are in big-endian base 2^8.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_signed_bytes_be(digits: &[u8]) -> BigInt {
|
||||||
|
let sign = match digits.first() {
|
||||||
|
Some(v) if *v > 0x7f => Sign::Minus,
|
||||||
|
Some(_) => Sign::Plus,
|
||||||
|
None => return BigInt::zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if sign == Sign::Minus {
|
||||||
|
// two's-complement the content to retrieve the magnitude
|
||||||
|
let mut digits = Vec::from(digits);
|
||||||
|
twos_complement_be(&mut digits);
|
||||||
|
BigInt::from_biguint(sign, BigUint::from_bytes_be(&*digits))
|
||||||
|
} else {
|
||||||
|
BigInt::from_biguint(sign, BigUint::from_bytes_be(digits))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates and initializes a `BigInt`.
|
/// Creates and initializes a `BigInt`.
|
||||||
///
|
///
|
||||||
/// The digits are in little-endian base 2^32.
|
/// The digits are in little-endian base 2^32.
|
||||||
|
@ -1035,6 +1078,30 @@ impl BigInt {
|
||||||
(self.sign, self.data.to_bytes_le())
|
(self.sign, self.data.to_bytes_le())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the two's complement byte representation of the `BigInt` in little-endian byte order.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use num_bigint::ToBigInt;
|
||||||
|
///
|
||||||
|
/// let i = -1125.to_bigint().unwrap();
|
||||||
|
/// assert_eq!(i.to_signed_bytes_le(), vec![155, 251]);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn to_signed_bytes_le(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = self.data.to_bytes_le();
|
||||||
|
let last_byte = bytes.last().map(|v| *v).unwrap_or(0);
|
||||||
|
if last_byte > 0x7f && !(last_byte == 0x80 && bytes.iter().rev().skip(1).all(Zero::is_zero)) {
|
||||||
|
// msb used by magnitude, extend by 1 byte
|
||||||
|
bytes.push(0);
|
||||||
|
}
|
||||||
|
if self.sign == Sign::Minus {
|
||||||
|
twos_complement_le(&mut bytes);
|
||||||
|
}
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the sign and the byte representation of the `BigInt` in big-endian byte order.
|
/// Returns the sign and the byte representation of the `BigInt` in big-endian byte order.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -1050,6 +1117,30 @@ impl BigInt {
|
||||||
(self.sign, self.data.to_bytes_be())
|
(self.sign, self.data.to_bytes_be())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the two's complement byte representation of the `BigInt` in big-endian byte order.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use num_bigint::ToBigInt;
|
||||||
|
///
|
||||||
|
/// let i = -1125.to_bigint().unwrap();
|
||||||
|
/// assert_eq!(i.to_signed_bytes_be(), vec![251, 155]);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn to_signed_bytes_be(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = self.data.to_bytes_be();
|
||||||
|
let first_byte = bytes.first().map(|v| *v).unwrap_or(0);
|
||||||
|
if first_byte > 0x7f && !(first_byte == 0x80 && bytes.iter().skip(1).all(Zero::is_zero)) {
|
||||||
|
// msb used by magnitude, extend by 1 byte
|
||||||
|
bytes.insert(0, 0);
|
||||||
|
}
|
||||||
|
if self.sign == Sign::Minus {
|
||||||
|
twos_complement_be(&mut bytes);
|
||||||
|
}
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the integer formatted as a string in the given radix.
|
/// Returns the integer formatted as a string in the given radix.
|
||||||
/// `radix` must be in the range `2...36`.
|
/// `radix` must be in the range `2...36`.
|
||||||
///
|
///
|
||||||
|
@ -1183,3 +1274,33 @@ impl BigInt {
|
||||||
return Some(self.div(v));
|
return Some(self.div(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform in-place two's complement of the given binary representation,
|
||||||
|
/// in little-endian byte order.
|
||||||
|
#[inline]
|
||||||
|
fn twos_complement_le(digits: &mut [u8]) {
|
||||||
|
twos_complement(digits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform in-place two's complement of the given binary representation
|
||||||
|
/// in big-endian byte order.
|
||||||
|
#[inline]
|
||||||
|
fn twos_complement_be(digits: &mut [u8]) {
|
||||||
|
twos_complement(digits.iter_mut().rev())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform in-place two's complement of the given digit iterator
|
||||||
|
/// starting from the least significant byte.
|
||||||
|
#[inline]
|
||||||
|
fn twos_complement<'a, I>(digits: I)
|
||||||
|
where I: IntoIterator<Item = &'a mut u8>
|
||||||
|
{
|
||||||
|
let mut carry = true;
|
||||||
|
for mut d in digits {
|
||||||
|
*d = d.not();
|
||||||
|
if carry {
|
||||||
|
*d = d.wrapping_add(1);
|
||||||
|
carry = d.is_zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -106,6 +106,76 @@ fn test_to_bytes_le() {
|
||||||
assert_eq!(b.to_bytes_le(), (Plus, vec![0, 2, 0, 0, 0, 0, 0, 0, 1]));
|
assert_eq!(b.to_bytes_le(), (Plus, vec![0, 2, 0, 0, 0, 0, 0, 0, 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_signed_bytes_le() {
|
||||||
|
fn check(s: &str, result: Vec<u8>) {
|
||||||
|
assert_eq!(BigInt::parse_bytes(s.as_bytes(), 10).unwrap().to_signed_bytes_le(),
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
|
||||||
|
check("0", vec![0]);
|
||||||
|
check("32767", vec![0xff, 0x7f]);
|
||||||
|
check("-1", vec![0xff]);
|
||||||
|
check("16777216", vec![0, 0, 0, 1]);
|
||||||
|
check("-100", vec![156]);
|
||||||
|
check("-8388608", vec![0, 0, 0x80]);
|
||||||
|
check("-192", vec![0x40, 0xff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_signed_bytes_le() {
|
||||||
|
fn check(s: &[u8], result: &str) {
|
||||||
|
assert_eq!(BigInt::from_signed_bytes_le(s),
|
||||||
|
BigInt::parse_bytes(result.as_bytes(), 10).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
check(&[], "0");
|
||||||
|
check(&[0], "0");
|
||||||
|
check(&[0; 10], "0");
|
||||||
|
check(&[0xff, 0x7f], "32767");
|
||||||
|
check(&[0xff], "-1");
|
||||||
|
check(&[0, 0, 0, 1], "16777216");
|
||||||
|
check(&[156], "-100");
|
||||||
|
check(&[0, 0, 0x80], "-8388608");
|
||||||
|
check(&[0xff; 10], "-1");
|
||||||
|
check(&[0x40, 0xff], "-192");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_signed_bytes_be() {
|
||||||
|
fn check(s: &str, result: Vec<u8>) {
|
||||||
|
assert_eq!(BigInt::parse_bytes(s.as_bytes(), 10).unwrap().to_signed_bytes_be(),
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
|
||||||
|
check("0", vec![0]);
|
||||||
|
check("32767", vec![0x7f, 0xff]);
|
||||||
|
check("-1", vec![255]);
|
||||||
|
check("16777216", vec![1, 0, 0, 0]);
|
||||||
|
check("-100", vec![156]);
|
||||||
|
check("-8388608", vec![128, 0, 0]);
|
||||||
|
check("-192", vec![0xff, 0x40]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_signed_bytes_be() {
|
||||||
|
fn check(s: &[u8], result: &str) {
|
||||||
|
assert_eq!(BigInt::from_signed_bytes_be(s),
|
||||||
|
BigInt::parse_bytes(result.as_bytes(), 10).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
check(&[], "0");
|
||||||
|
check(&[0], "0");
|
||||||
|
check(&[0; 10], "0");
|
||||||
|
check(&[127, 255], "32767");
|
||||||
|
check(&[255], "-1");
|
||||||
|
check(&[1, 0, 0, 0], "16777216");
|
||||||
|
check(&[156], "-100");
|
||||||
|
check(&[128, 0, 0], "-8388608");
|
||||||
|
check(&[255; 10], "-1");
|
||||||
|
check(&[0xff, 0x40], "-192");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cmp() {
|
fn test_cmp() {
|
||||||
let vs: [&[BigDigit]; 4] = [&[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1]];
|
let vs: [&[BigDigit]; 4] = [&[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1]];
|
||||||
|
|
Loading…
Reference in New Issue