use crate::decimal::SpecialValue;
use crate::gamma::BitWriter;
use crate::significand::encode_significand;
#[must_use]
pub const fn encode_special_byte(value: SpecialValue) -> u8 {
match value {
SpecialValue::NegativeInfinity => 0b0000_0000, SpecialValue::NegativeZero => 0b0100_0000, SpecialValue::PositiveZero => 0b1000_0000, SpecialValue::PositiveInfinity => 0b1100_0000, SpecialValue::NaN => 0b1110_0000, }
}
pub fn encode_from_parts(
positive: bool,
exponent_positive: bool,
exponent: u64,
significand: &[u8],
) -> Vec<u8> {
let significand_len = significand.len();
let exponent_bits = if exponent == 0 {
3
} else {
2 * (64 - (exponent + 2).leading_zeros()) as usize + 1
};
let significand_bits = if significand_len <= 1 {
4
} else {
4 + (significand_len - 1).div_ceil(3) * 10
};
let total_bits = 2 + exponent_bits + significand_bits;
let estimated_bytes = total_bits.div_ceil(8);
let mut writer = BitWriter::with_capacity(estimated_bytes);
writer.write_bit(positive); writer.write_bit(false);
let negate = positive != exponent_positive;
let offset_exp = exponent + 2;
let n = bit_length(offset_exp);
for _ in 0..(n - 1) {
writer.write_bit(!negate); }
writer.write_bit(negate);
for i in (0..(n - 1)).rev() {
let bit = (offset_exp >> i) & 1 == 1;
writer.write_bit(if negate { !bit } else { bit });
}
encode_significand(&mut writer, significand, !positive);
writer.into_bytes()
}
#[inline]
const fn bit_length(n: u64) -> usize {
if n == 0 {
1
} else {
64 - n.leading_zeros() as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
fn format_binary(bytes: &[u8]) -> String {
bytes
.iter()
.map(|b| format!("{:08b}", b))
.collect::<Vec<_>>()
.join(" ")
}
#[test]
fn test_encode_zero() {
let encoded = encode_special_byte(SpecialValue::PositiveZero);
assert_eq!(encoded & 0xC0, 0x80); }
#[test]
fn test_encode_positive_infinity() {
let encoded = encode_special_byte(SpecialValue::PositiveInfinity);
assert_eq!(encoded & 0xC0, 0xC0); }
#[test]
fn test_paper_examples() {
let e1 = encode_from_parts(false, true, 2, &[1, 0, 3, 2]);
println!("-103.2: {}", format_binary(&e1));
assert_eq!(e1[0] & 0b1100_0000, 0b0000_0000);
let e2 = encode_from_parts(false, false, 2, &[4, 0, 5]);
println!("-0.0405: {}", format_binary(&e2));
assert_eq!(e2[0] & 0b1100_0000, 0b0000_0000);
let e3 = encode_from_parts(true, false, 1, &[7, 0, 7, 1, 0, 6]);
println!("0.707106: {}", format_binary(&e3));
assert_eq!(e3[0] & 0b1100_0000, 0b1000_0000);
let e4 = encode_from_parts(true, true, 9, &[4, 0, 0, 5, 0, 1, 2, 3, 4, 5]);
println!("4005012345: {}", format_binary(&e4));
assert_eq!(e4[0] & 0b1100_0000, 0b1000_0000);
}
#[test]
fn test_small_integers_from_paper() {
let e1 = encode_from_parts(true, true, 0, &[1]);
println!("1: {}", format_binary(&e1));
let em1 = encode_from_parts(false, true, 0, &[1]);
println!("-1: {}", format_binary(&em1));
}
}