Add _be/_le postfix to from/to_radix functions (BigInt)

This commit is contained in:
Phaiax 2017-06-13 15:36:59 +02:00
parent fc09503d3d
commit 1ea02d8d0c
3 changed files with 161 additions and 70 deletions

View File

@ -1033,10 +1033,9 @@ impl BigInt {
unsafe { String::from_utf8_unchecked(v) } unsafe { String::from_utf8_unchecked(v) }
} }
/// Returns the integer in a given base. Each digit is given as an u8 /// Returns the integer in the requested base in big-endian digit order.
/// number. Conversion to an alphabet has to be performed afterwards. /// The output is not given in a human readable alphabet but as a zero
/// In contrast to the usual arabic style of written numbers as returned by /// based u8 number.
/// `to_str_radix`, the most significant digit comes last.
/// `radix` must be in the range `2...256`. /// `radix` must be in the range `2...256`.
/// ///
/// # Examples /// # Examples
@ -1044,13 +1043,32 @@ impl BigInt {
/// ``` /// ```
/// use num_bigint::{BigInt, Sign}; /// use num_bigint::{BigInt, Sign};
/// ///
/// assert_eq!(BigInt::from(-0xFFFFi64).to_radix(159), /// assert_eq!(BigInt::from(-0xFFFFi64).to_radix_be(159),
/// (Sign::Minus, vec![2, 94, 27]));
/// // 0xFFFF = 65535 = 2*(159^2) + 94*159 + 27
/// ```
#[inline]
pub fn to_radix_be(&self, radix: u32) -> (Sign, Vec<u8>) {
(self.sign, self.data.to_radix_be(radix))
}
/// Returns the integer in the requested base in little-endian digit order.
/// The output is not given in a human readable alphabet but as a zero
/// based u8 number.
/// `radix` must be in the range `2...256`.
///
/// # Examples
///
/// ```
/// use num_bigint::{BigInt, Sign};
///
/// assert_eq!(BigInt::from(-0xFFFFi64).to_radix_le(159),
/// (Sign::Minus, vec![27, 94, 2])); /// (Sign::Minus, vec![27, 94, 2]));
/// // 0xFFFF = 65535 = 27 + 94*159 + 2*(159^2) /// // 0xFFFF = 65535 = 27 + 94*159 + 2*(159^2)
/// ``` /// ```
#[inline] #[inline]
pub fn to_radix(&self, radix: u32) -> (Sign, Vec<u8>) { pub fn to_radix_le(&self, radix: u32) -> (Sign, Vec<u8>) {
(self.sign, self.data.to_radix(radix)) (self.sign, self.data.to_radix_le(radix))
} }
/// Returns the sign of the `BigInt` as a `Sign`. /// Returns the sign of the `BigInt` as a `Sign`.

View File

@ -887,7 +887,7 @@ fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec<u8> {
res res
} }
pub fn to_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> { pub fn to_radix_le(u: &BigUint, radix: u32) -> Vec<u8> {
if u.is_zero() { if u.is_zero() {
vec![0] vec![0]
} else if radix.is_power_of_two() { } else if radix.is_power_of_two() {
@ -914,7 +914,7 @@ pub fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> {
return vec![b'0']; return vec![b'0'];
} }
let mut res = to_radix_reversed(u, radix); let mut res = to_radix_le(u, radix);
// Now convert everything to ASCII digits. // Now convert everything to ASCII digits.
for r in &mut res { for r in &mut res {
@ -986,6 +986,108 @@ impl BigUint {
} }
} }
/// Creates and initializes a `BigUint`. The input slice must contain
/// ascii/utf8 characters in [0-9a-zA-Z].
/// `radix` must be in the range `2...36`.
///
/// The function `from_str_radix` from the `Num` trait provides the same logic
/// for `&str` buffers.
///
/// # Examples
///
/// ```
/// use num_bigint::{BigUint, ToBigUint};
///
/// assert_eq!(BigUint::parse_bytes(b"1234", 10), ToBigUint::to_biguint(&1234));
/// assert_eq!(BigUint::parse_bytes(b"ABCD", 16), ToBigUint::to_biguint(&0xABCD));
/// assert_eq!(BigUint::parse_bytes(b"G", 16), None);
/// ```
#[inline]
pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigUint> {
str::from_utf8(buf).ok().and_then(|s| BigUint::from_str_radix(s, radix).ok())
}
/// Creates and initializes a `BigUint`. Each u8 of the input slice is
/// interpreted as one digit of the number
/// and must therefore be less than `radix`.
///
/// The bytes are in big-endian byte order.
/// `radix` must be in the range `2...256`.
///
/// # Examples
///
/// ```
/// use num_bigint::{BigUint};
///
/// let inbase190 = &[15, 33, 125, 12, 14];
/// let a = BigUint::from_radix_be(inbase190, 190).unwrap();
/// assert_eq!(a.to_radix_be(190), inbase190);
/// ```
pub fn from_radix_be(buf: &[u8], radix: u32) -> Option<BigUint> {
assert!(2 <= radix && radix <= 256, "The radix must be within 2...256");
if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
return None;
}
let res = if radix.is_power_of_two() {
// Powers of two can use bitwise masks and shifting instead of multiplication
let bits = ilog2(radix);
let mut v = Vec::from(buf);
v.reverse();
if big_digit::BITS % bits == 0 {
from_bitwise_digits_le(&v, bits)
} else {
from_inexact_bitwise_digits_le(&v, bits)
}
} else {
from_radix_digits_be(buf, radix)
};
Some(res)
}
/// Creates and initializes a `BigUint`. Each u8 of the input slice is
/// interpreted as one digit of the number
/// and must therefore be less than `radix`.
///
/// The bytes are in little-endian byte order.
/// `radix` must be in the range `2...256`.
///
/// # Examples
///
/// ```
/// use num_bigint::{BigUint};
///
/// let inbase190 = &[14, 12, 125, 33, 15];
/// let a = BigUint::from_radix_be(inbase190, 190).unwrap();
/// assert_eq!(a.to_radix_be(190), inbase190);
/// ```
pub fn from_radix_le(buf: &[u8], radix: u32) -> Option<BigUint> {
assert!(2 <= radix && radix <= 256, "The radix must be within 2...256");
if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
return None;
}
let res = if radix.is_power_of_two() {
// Powers of two can use bitwise masks and shifting instead of multiplication
let bits = ilog2(radix);
if big_digit::BITS % bits == 0 {
from_bitwise_digits_le(buf, bits)
} else {
from_inexact_bitwise_digits_le(buf, bits)
}
} else {
let mut v = Vec::from(buf);
v.reverse();
from_radix_digits_be(&v, radix)
};
Some(res)
}
/// Returns the byte representation of the `BigUint` in little-endian byte order. /// Returns the byte representation of the `BigUint` in little-endian byte order.
/// ///
/// # Examples /// # Examples
@ -1040,10 +1142,9 @@ impl BigUint {
unsafe { String::from_utf8_unchecked(v) } unsafe { String::from_utf8_unchecked(v) }
} }
/// Returns the integer in a given base. Each digit is given as an u8 /// Returns the integer in the requested base in little-endian digit order.
/// number. (The output is not given in a human readable alphabet.) /// The output is not given in a human readable alphabet but as a zero
/// In contrast to the usual arabic ordering of written digits as returned by /// based u8 number.
/// `to_str_radix`, the most significant digit comes last.
/// `radix` must be in the range `2...256`. /// `radix` must be in the range `2...256`.
/// ///
/// # Examples /// # Examples
@ -1051,70 +1152,34 @@ impl BigUint {
/// ``` /// ```
/// use num_bigint::BigUint; /// use num_bigint::BigUint;
/// ///
/// assert_eq!(BigUint::from(0xFFFFu64).to_radix(159), /// assert_eq!(BigUint::from(0xFFFFu64).to_radix_le(159),
/// vec![27, 94, 2]); /// vec![27, 94, 2]);
/// // 0xFFFF = 65535 = 27 + 94*159 + 2*(159^2) /// // 0xFFFF = 65535 = 27 + 94*159 + 2*(159^2)
/// ``` /// ```
#[inline] #[inline]
pub fn to_radix(&self, radix: u32) -> Vec<u8> { pub fn to_radix_le(&self, radix: u32) -> Vec<u8> {
to_radix_reversed(self, radix) to_radix_le(self, radix)
} }
/// Creates and initializes a `BigUint`. The input slice must contrain /// Returns the integer in the requested base in big-endian digit order.
/// ascii/utf8 characters in [0-9a-zA-Z]. /// The output is not given in a human readable alphabet but as a zero
/// `radix` must be in the range `2...36`. /// based u8 number.
///
/// # Examples
///
/// ```
/// use num_bigint::{BigUint, ToBigUint};
///
/// assert_eq!(BigUint::parse_bytes(b"1234", 10), ToBigUint::to_biguint(&1234));
/// assert_eq!(BigUint::parse_bytes(b"ABCD", 16), ToBigUint::to_biguint(&0xABCD));
/// assert_eq!(BigUint::parse_bytes(b"G", 16), None);
/// ```
#[inline]
pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigUint> {
str::from_utf8(buf).ok().and_then(|s| BigUint::from_str_radix(s, radix).ok())
}
/// Creates and initializes a `BigUint`. Each u8 of the input slice is
/// interpreted as one digit of the number and must therefore be less than `radix`.
/// In contrast to the usual arabic ordering of written digits as required by
/// `from_str_radix`, the most significant digit comes last.
/// `radix` must be in the range `2...256`. /// `radix` must be in the range `2...256`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use num_bigint::{BigUint}; /// use num_bigint::BigUint;
/// ///
/// let inbase190 = &[15, 33, 125, 12, 14]; /// assert_eq!(BigUint::from(0xFFFFu64).to_radix_be(159),
/// let a = BigUint::from_radix(inbase190, 190).unwrap(); /// vec![2, 94, 27]);
/// assert_eq!(a.to_radix(190), inbase190); /// // 0xFFFF = 65535 = 2*(159^2) + 94*159 + 27
/// ``` /// ```
pub fn from_radix(buf: &[u8], radix: u32) -> Option<BigUint> { #[inline]
assert!(2 <= radix && radix <= 256, "The radix must be within 2...256"); pub fn to_radix_be(&self, radix: u32) -> Vec<u8> {
let mut v = to_radix_le(self, radix);
if radix != 256 && buf.iter().any(|&b| b >= radix as u8) { v.reverse();
return None; v
}
let res = if radix.is_power_of_two() {
// Powers of two can use bitwise masks and shifting instead of multiplication
let bits = ilog2(radix);
if big_digit::BITS % bits == 0 {
from_bitwise_digits_le(buf, bits)
} else {
from_inexact_bitwise_digits_le(buf, bits)
}
} else {
let mut v = Vec::from(buf);
v.reverse();
from_radix_digits_be(&v, radix)
};
Some(res)
} }
/// Determines the fewest bits necessary to express the `BigUint`. /// Determines the fewest bits necessary to express the `BigUint`.

View File

@ -1286,15 +1286,23 @@ fn test_from_and_to_radix() {
(b"ffffeeffbb", 256, &[187, 255, 238, 255, 255]), (b"ffffeeffbb", 256, &[187, 255, 238, 255, 255]),
]; ];
for &(bigint, radix, inbaseradix) in GROUND_TRUTH.iter() { for &(bigint, radix, inbaseradix_le) in GROUND_TRUTH.iter() {
let bigint = BigUint::parse_bytes(bigint, 16).unwrap(); let bigint = BigUint::parse_bytes(bigint, 16).unwrap();
// to_radix // to_radix_le
assert_eq!(bigint.to_radix(radix), inbaseradix); assert_eq!(bigint.to_radix_le(radix), inbaseradix_le);
// from_radix // to_radix_be
assert_eq!(BigUint::from_radix(inbaseradix, radix).unwrap(), bigint); let mut inbase_be = bigint.to_radix_be(radix);
inbase_be.reverse(); // now le
assert_eq!(inbase_be, inbaseradix_le);
// from_radix_le
assert_eq!(BigUint::from_radix_le(inbaseradix_le, radix).unwrap(), bigint);
// from_radix_be
let mut inbaseradix_be = Vec::from(inbaseradix_le);
inbaseradix_be.reverse();
assert_eq!(BigUint::from_radix_be(&inbaseradix_be, radix).unwrap(), bigint);
} }
assert!(BigUint::from_radix(&[10,100,10], 50).is_none()); assert!(BigUint::from_radix_le(&[10,100,10], 50).is_none());
} }
#[test] #[test]