add octal and hex
This commit is contained in:
parent
f8630a63f6
commit
4187d84e41
|
@ -32,24 +32,63 @@ where
|
||||||
I: SealedInt<IsSigned = False> + Shl<u32, Output = I> + Add<Output = I> + From<u8>,
|
I: SealedInt<IsSigned = False> + Shl<u32, Output = I> + Add<Output = I> + From<u8>,
|
||||||
{
|
{
|
||||||
debug_assert!(!a.is_empty());
|
debug_assert!(!a.is_empty());
|
||||||
let mut digits = 8 - dump_bits;
|
let mut bits = I::NBITS - dump_bits;
|
||||||
let mut acc = I::ZERO;
|
let mut acc = I::ZERO;
|
||||||
let mut bytes = a.as_bytes().iter();
|
for byte in a.as_bytes() {
|
||||||
while let Some(byte) = bytes.next() {
|
let val = byte - b'0';
|
||||||
if digits == 0 {
|
if bits < 1 {
|
||||||
break;
|
// round
|
||||||
|
return acc.checked_add(I::from(val));
|
||||||
}
|
}
|
||||||
acc = (acc << 1) + I::from(byte - b'0');
|
acc = (acc << 1) + I::from(val);
|
||||||
digits -= 1;
|
bits -= 1;
|
||||||
}
|
}
|
||||||
|
Some(acc << bits)
|
||||||
|
}
|
||||||
|
|
||||||
if digits > 0 {
|
fn oct_str_to_bin<I>(a: &str, dump_bits: u32) -> Option<I>
|
||||||
Some(acc << digits)
|
where
|
||||||
} else if let Some(byte) = bytes.next() {
|
I: SealedInt<IsSigned = False> + Shl<u32, Output = I> + Add<Output = I> + From<u8>,
|
||||||
acc.checked_add(I::from(byte - b'0'))
|
{
|
||||||
} else {
|
debug_assert!(!a.is_empty());
|
||||||
Some(acc)
|
let mut bits = I::NBITS - dump_bits;
|
||||||
|
let mut acc = I::ZERO;
|
||||||
|
for byte in a.as_bytes() {
|
||||||
|
let val = byte - b'0';
|
||||||
|
if bits < 3 {
|
||||||
|
acc = (acc << bits) + I::from(val >> (3 - bits));
|
||||||
|
// round
|
||||||
|
return acc.checked_add(I::from((val >> (2 - bits)) & 1));
|
||||||
|
}
|
||||||
|
acc = (acc << 3) + I::from(val);
|
||||||
|
bits -= 3;
|
||||||
}
|
}
|
||||||
|
Some(acc << bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_str_to_bin<I>(a: &str, dump_bits: u32) -> Option<I>
|
||||||
|
where
|
||||||
|
I: SealedInt<IsSigned = False> + Shl<u32, Output = I> + Add<Output = I> + From<u8>,
|
||||||
|
{
|
||||||
|
debug_assert!(!a.is_empty());
|
||||||
|
let mut bits = I::NBITS - dump_bits;
|
||||||
|
let mut acc = I::ZERO;
|
||||||
|
for byte in a.as_bytes() {
|
||||||
|
let val = match byte {
|
||||||
|
b @ b'0'..=b'9' => b - b'0',
|
||||||
|
b @ b'A'..=b'F' => b - b'A' + 10,
|
||||||
|
b @ b'a'..=b'f' => b - b'a' + 10,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
if bits < 4 {
|
||||||
|
acc = (acc << bits) + I::from(val >> (4 - bits));
|
||||||
|
// round
|
||||||
|
return acc.checked_add(I::from((val >> (3 - bits)) & 1));
|
||||||
|
}
|
||||||
|
acc = (acc << 4) + I::from(val);
|
||||||
|
bits -= 4;
|
||||||
|
}
|
||||||
|
Some(acc << bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5^3 × 2 < 2^8 => (10^3 - 1) × 2^(8-3+1) < 2^16
|
// 5^3 × 2 < 2^8 => (10^3 - 1) × 2^(8-3+1) < 2^16
|
||||||
|
@ -343,7 +382,7 @@ macro_rules! impl_from_str_signed {
|
||||||
int_nbits: u32,
|
int_nbits: u32,
|
||||||
frac_nbits: u32,
|
frac_nbits: u32,
|
||||||
) -> Result<$Bits, ParseFixedError> {
|
) -> Result<$Bits, ParseFixedError> {
|
||||||
let Parse { neg, int, frac } = parse(s, true, 10)?;
|
let Parse { neg, int, frac } = parse(s, true, radix)?;
|
||||||
let (abs_frac, whole_frac) = match $frac(frac, radix, frac_nbits) {
|
let (abs_frac, whole_frac) = match $frac(frac, radix, frac_nbits) {
|
||||||
Some(frac) => (frac, false),
|
Some(frac) => (frac, false),
|
||||||
None => (0, true),
|
None => (0, true),
|
||||||
|
@ -381,7 +420,7 @@ macro_rules! impl_from_str_unsigned {
|
||||||
int_nbits: u32,
|
int_nbits: u32,
|
||||||
frac_nbits: u32,
|
frac_nbits: u32,
|
||||||
) -> Result<$Bits, ParseFixedError> {
|
) -> Result<$Bits, ParseFixedError> {
|
||||||
let Parse { int, frac, .. } = parse(s, false, 10)?;
|
let Parse { int, frac, .. } = parse(s, false, radix)?;
|
||||||
let (frac, whole_frac) = match $frac(frac, radix, frac_nbits) {
|
let (frac, whole_frac) = match $frac(frac, radix, frac_nbits) {
|
||||||
Some(frac) => (frac, false),
|
Some(frac) => (frac, false),
|
||||||
None => (0, true),
|
None => (0, true),
|
||||||
|
@ -449,6 +488,8 @@ macro_rules! impl_from_str_unsigned_not128 {
|
||||||
}
|
}
|
||||||
match radix {
|
match radix {
|
||||||
2 => bin_str_to_bin(frac, nbits),
|
2 => bin_str_to_bin(frac, nbits),
|
||||||
|
8 => oct_str_to_bin(frac, nbits),
|
||||||
|
16 => hex_str_to_bin(frac, nbits),
|
||||||
10 => {
|
10 => {
|
||||||
let end = cmp::min(frac.len(), $dec_frac_digits);
|
let end = cmp::min(frac.len(), $dec_frac_digits);
|
||||||
let rem = $dec_frac_digits - end;
|
let rem = $dec_frac_digits - end;
|
||||||
|
@ -694,6 +735,8 @@ mod tests {
|
||||||
assert_eq!((neg, int, frac), (false, "", "34"));
|
assert_eq!((neg, int, frac), (false, "", "34"));
|
||||||
let Parse { neg, int, frac } = parse("0", false, 10).unwrap();
|
let Parse { neg, int, frac } = parse("0", false, 10).unwrap();
|
||||||
assert_eq!((neg, int, frac), (false, "0", ""));
|
assert_eq!((neg, int, frac), (false, "0", ""));
|
||||||
|
let Parse { neg, int, frac } = parse("-.C1A0", true, 16).unwrap();
|
||||||
|
assert_eq!((neg, int, frac), (true, "", "C1A0"));
|
||||||
|
|
||||||
let ParseFixedError { kind } = parse("0 ", true, 10).unwrap_err();
|
let ParseFixedError { kind } = parse("0 ", true, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
||||||
|
|
|
@ -1227,7 +1227,7 @@ assert_eq!(Fix::overflowing_from_float(large), (wrapped, true));
|
||||||
);
|
);
|
||||||
|
|
||||||
comment!(
|
comment!(
|
||||||
"Converts a string slice in the binary radix.
|
"Converts a string slice containing binary digits to a fixed-point number.
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
@ -1236,7 +1236,7 @@ type Fix = fixed::",
|
||||||
$s_fixed,
|
$s_fixed,
|
||||||
"<fixed::frac::U4>;
|
"<fixed::frac::U4>;
|
||||||
// 1.75 is 1.11 in binary
|
// 1.75 is 1.11 in binary
|
||||||
let f = Fix::from_str_bin(\"01.1100\");
|
let f = Fix::from_str_bin(\"1.11\");
|
||||||
let check = Fix::from_bits(0b111 << (4 - 2));
|
let check = Fix::from_bits(0b111 << (4 - 2));
|
||||||
assert_eq!(f, Ok(check));
|
assert_eq!(f, Ok(check));
|
||||||
",
|
",
|
||||||
|
@ -1253,5 +1253,61 @@ assert_eq!(neg, Ok(-check));
|
||||||
FromStrRadix::from_str_radix(src, 2)
|
FromStrRadix::from_str_radix(src, 2)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
comment!(
|
||||||
|
"Converts a string slice containing octal digits to a fixed-point number.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
```rust
|
||||||
|
type Fix = fixed::",
|
||||||
|
$s_fixed,
|
||||||
|
"<fixed::frac::U4>;
|
||||||
|
// 1.75 is 1.11 in binary, 1.6 in octal
|
||||||
|
let f = Fix::from_str_octal(\"1.6\");
|
||||||
|
let check = Fix::from_bits(0b111 << (4 - 2));
|
||||||
|
assert_eq!(f, Ok(check));
|
||||||
|
",
|
||||||
|
if_signed_else_empty_str!(
|
||||||
|
$Signedness,
|
||||||
|
"let neg = Fix::from_str_octal(\"-1.6\");
|
||||||
|
assert_eq!(neg, Ok(-check));
|
||||||
|
",
|
||||||
|
),
|
||||||
|
"```
|
||||||
|
";
|
||||||
|
#[inline]
|
||||||
|
pub fn from_str_octal(src: &str) -> Result<$Fixed<Frac>, ParseFixedError> {
|
||||||
|
FromStrRadix::from_str_radix(src, 8)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
comment!(
|
||||||
|
"Converts a string slice containing hexadecimal digits to a fixed-point number.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
```rust
|
||||||
|
type Fix = fixed::",
|
||||||
|
$s_fixed,
|
||||||
|
"<fixed::frac::U4>;
|
||||||
|
// 1.75 is 1.11 in binary, 1.C in hexadecimal
|
||||||
|
let f = Fix::from_str_hex(\"1.C\");
|
||||||
|
let check = Fix::from_bits(0b111 << (4 - 2));
|
||||||
|
assert_eq!(f, Ok(check));
|
||||||
|
",
|
||||||
|
if_signed_else_empty_str!(
|
||||||
|
$Signedness,
|
||||||
|
"let neg = Fix::from_str_hex(\"-1.C\");
|
||||||
|
assert_eq!(neg, Ok(-check));
|
||||||
|
",
|
||||||
|
),
|
||||||
|
"```
|
||||||
|
";
|
||||||
|
#[inline]
|
||||||
|
pub fn from_str_hex(src: &str) -> Result<$Fixed<Frac>, ParseFixedError> {
|
||||||
|
FromStrRadix::from_str_radix(src, 16)
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue