diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 92e2feb..902cf7e 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -1011,7 +1011,7 @@ impl BigInt { } /// 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`. /// /// # Examples /// @@ -1037,7 +1037,7 @@ impl BigInt { /// number. Conversion to an alphabet has to be performed afterwards. /// In contrast to the usual arabic style of written numbers as returned by /// `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 /// diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 8b06f6a..54046a8 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -1023,7 +1023,7 @@ impl BigUint { } /// 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`. /// /// # Examples /// @@ -1041,10 +1041,10 @@ impl BigUint { } /// Returns the integer in a given base. Each digit is given as an u8 - /// number. Conversion to an alphabet has to be performed afterwards. - /// In contrast to the usual arabic style of written numbers as returned by + /// number. (The output is not given in a human readable alphabet.) + /// In contrast to the usual arabic ordering of written digits as returned by /// `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 /// @@ -1060,7 +1060,9 @@ impl BigUint { to_radix_reversed(self, radix) } - /// Creates and initializes a `BigUint`. + /// Creates and initializes a `BigUint`. The input slice must contrain + /// ascii/utf8 characters in [0-9a-zA-Z]. + /// `radix` must be in the range `2...36`. /// /// # Examples /// @@ -1076,6 +1078,45 @@ impl 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`. + /// + /// # Examples + /// + /// ``` + /// use num_bigint::{BigUint}; + /// + /// let inbase190 = &[15, 33, 125, 12, 14]; + /// let a = BigUint::from_radix(inbase190, 190).unwrap(); + /// assert_eq!(a.to_radix(190), inbase190); + /// ``` + pub fn from_radix(buf: &[u8], radix: u32) -> Option { + 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) + } + /// Determines the fewest bits necessary to express the `BigUint`. #[inline] pub fn bits(&self) -> usize { diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index 1ab3f9a..c229ad1 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -1021,8 +1021,8 @@ fn test_to_str_radix() { } #[test] -fn test_to_radix() { - const GROUND_TRUTH : &[(&[u8], u32, &[u8])] = &[ +fn test_from_and_to_radix() { + const GROUND_TRUTH : &'static[(&'static[u8], u32, &'static[u8])] = &[ (b"0", 42, &[0]), (b"ffffeeffbb", 2, &[1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1286,10 +1286,15 @@ fn test_to_radix() { (b"ffffeeffbb", 256, &[187, 255, 238, 255, 255]), ]; - for &(bigint, radix, solution) in GROUND_TRUTH.iter() { + for &(bigint, radix, inbaseradix) in GROUND_TRUTH.iter() { let bigint = BigUint::parse_bytes(bigint, 16).unwrap(); - assert_eq!(bigint.to_radix(radix), solution); + // to_radix + assert_eq!(bigint.to_radix(radix), inbaseradix); + // from_radix + assert_eq!(BigUint::from_radix(inbaseradix, radix).unwrap(), bigint); } + + assert!(BigUint::from_radix(&[10,100,10], 50).is_none()); } #[test]