Skip to content

Commit

Permalink
early near zero support
Browse files Browse the repository at this point in the history
  • Loading branch information
ZoeyR committed Oct 16, 2017
1 parent d5c9129 commit 8550b0f
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/flif/numbers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use num_traits::{PrimInt, Unsigned};
pub mod rac;
pub mod varint;
pub mod symbol;
pub mod near_zero;

pub trait FlifReadExt {
fn read_u8(&mut self) -> Result<u8>;
Expand Down
79 changes: 79 additions & 0 deletions src/flif/numbers/near_zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::io::Read;
use error::*;
use num_traits::{PrimInt, Signed};
use numbers::rac::ChanceTable;
use numbers::rac::ChanceTableEntry;
use numbers::rac::Rac;

pub fn read_near_zero<R: Read, I: PrimInt + Signed>(
min: i32,
max: i32,
rac: &mut Rac<R>,
context: &mut ChanceTable,
) -> Result<i32> {
assert!(min < max);

if min == max {
return Ok(min);
}

if rac.read(context, ChanceTableEntry::Zero)? {
return Ok(0);
}

let sign = if min < 0 && max > 0 {
rac.read(context, ChanceTableEntry::Sign)?
} else if min < 0 && max < 0 {
false
} else {
true
};

let absolute_max = ::std::cmp::max(max, -min);
let largest_exponent =
(::std::mem::size_of::<I>() * 8) - absolute_max.leading_zeros() as usize - 1;

let mut exponent = 0;
loop {
if exponent as usize == largest_exponent || rac.read(context, ChanceTableEntry::Exp(exponent, sign))? {
break;
}

exponent += 1;
}

// the first mantissa bit is always 1
let mut have = 1 << exponent;

// if all other mantissa bits are 1, then the total is have+left
let mut left = have-1;

// read mantissa bits from most-significant to least-significant
for pos in (exponent - 1)..0 {
left >>= 1;

// if the bit is 1, then the value will be at least minabs1
let minabs1 = have | (1<<pos);
// if the bit is 0, then the value will be at most maxabs0
let maxabs0 = have | left;
if minabs1 > absolute_max {
// 1-bit is impossible (would bump value above maximum),
// so assume the bit is 0 without reading it
} else if maxabs0 >= 1 {
// 0-bit and 1-bit are both possible,
// so we read the bit and adjust what we have if it is a 1
if rac.read(context, ChanceTableEntry::Mant(pos))? {
have = minabs1;
}
} else {
// 0-bit is impossible (would make the value zero),
// so assume the bit is 1 without reading it
have = minabs1;
}
}
Ok(if sign {
have
} else {
-have
})
}

0 comments on commit 8550b0f

Please sign in to comment.