Skip to content

Commit

Permalink
expand IEEE754Val enum
Browse files Browse the repository at this point in the history
  • Loading branch information
bksaiki committed Feb 28, 2024
1 parent 843957c commit 6a35627
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 50 deletions.
80 changes: 41 additions & 39 deletions src/ieee754/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ impl Exceptions {
/// the IEEE 754 standard.
#[derive(Clone, Debug)]
pub enum IEEE754Val {
/// Signed zero: `Zero(s)`: where `s` specifies `-0` or `+0`.
Zero(bool),
/// Unsigned zero
PosZero,
/// Signed zero
NegZero,
/// Subnormal numbers: `Subnormal(s, c)` encodes `(-1)^s * c * 2^expmin`.
/// If the float has parameters `es` and `nbits`, then `c` is an
/// integer of bitwidth `nbits - es - 1`.
Expand All @@ -98,8 +100,10 @@ pub enum IEEE754Val {
/// where `exp` is between `expmin` and `expmax` and `c` is an
/// integer of bitwidth `nbits - es`.
Normal(bool, isize, Integer),
/// Signed infinity: `Infinity(s)` encodes `+/- Inf`.
Infinity(bool),
/// Positive infinity: encodes `+Inf`
PosInfinity,
/// Negative infinity: encodes `-Inf`
NegInfinity,
/// Not-a-number: `Nan(s, quiet, payload)` where `s` specifies the
/// sign bit, `quiet` the signaling bit, and `payload` the payload
/// of the NaN value. Either `quiet` must be true or `payload` must
Expand Down Expand Up @@ -171,18 +175,24 @@ impl IEEE754 {
pub fn into_bits(self) -> Integer {
let nbits = self.ctx.nbits();
let (s, unsigned) = match &self.num {
IEEE754Val::Zero(s) => (*s, Integer::zero()),
IEEE754Val::PosZero => (false, Integer::zero()),
IEEE754Val::NegZero => (true, Integer::zero()),
IEEE754Val::Subnormal(s, c) => (*s, c.clone()),
IEEE754Val::Normal(s, exp, c) => {
let m = self.ctx().max_m();
let efield = Integer::from((exp + m as isize) + self.ctx().emax()) << m;
let mfield = c.clone().bitand(bitmask(m));
(*s, mfield.bitor(efield))
}
IEEE754Val::Infinity(s) => {
IEEE754Val::PosInfinity => {
let m = self.ctx().max_m();
let efield = bitmask(self.ctx.es()) << m;
(*s, efield)
(false, efield)
}
IEEE754Val::NegInfinity => {
let m = self.ctx().max_m();
let efield = bitmask(self.ctx.es()) << m;
(true, efield)
}
IEEE754Val::Nan(s, q, payload) => {
let m = self.ctx().max_m() as isize;
Expand Down Expand Up @@ -212,53 +222,48 @@ impl Real for IEEE754 {

fn sign(&self) -> Option<bool> {
match &self.num {
IEEE754Val::Zero(s) => Some(*s),
IEEE754Val::PosZero => Some(false),
IEEE754Val::NegZero => Some(true),
IEEE754Val::Subnormal(s, _) => Some(*s),
IEEE754Val::Normal(s, _, _) => Some(*s),
IEEE754Val::Infinity(s) => Some(*s),
IEEE754Val::PosInfinity => Some(false),
IEEE754Val::NegInfinity => Some(true),
IEEE754Val::Nan(s, _, _) => Some(*s),
}
}

fn exp(&self) -> Option<isize> {
match &self.num {
IEEE754Val::Zero(_) => None,
IEEE754Val::Subnormal(_, _) => Some(self.ctx().expmin()),
IEEE754Val::Normal(_, exp, _) => Some(*exp),
IEEE754Val::Infinity(_) => None,
IEEE754Val::Nan(_, _, _) => None,
_ => None,
}
}

fn e(&self) -> Option<isize> {
match &self.num {
IEEE754Val::Zero(_) => None,
IEEE754Val::Subnormal(_, c) => {
Some((self.ctx().expmin() - 1) + (c.significant_bits() as isize))
let n = self.ctx().expmin() - 1;
Some(n + (c.significant_bits() as isize))
}
IEEE754Val::Normal(_, exp, c) => Some((*exp - 1) + (c.significant_bits() as isize)),
IEEE754Val::Infinity(_) => None,
IEEE754Val::Nan(_, _, _) => None,
_ => None,
}
}

fn n(&self) -> Option<isize> {
match &self.num {
IEEE754Val::Zero(_) => None,
IEEE754Val::Subnormal(_, _) => Some(self.ctx().expmin() - 1),
IEEE754Val::Normal(_, exp, _) => Some(exp - 1),
IEEE754Val::Infinity(_) => None,
IEEE754Val::Nan(_, _, _) => None,
_ => None,
}
}

fn c(&self) -> Option<Integer> {
match &self.num {
IEEE754Val::Zero(_) => Some(Integer::zero()),
IEEE754Val::Subnormal(_, c) => Some(c.clone()),
IEEE754Val::Normal(_, _, c) => Some(c.clone()),
IEEE754Val::Infinity(_) => None,
IEEE754Val::Nan(_, _, _) => None,
_ => None,
}
}

Expand All @@ -268,42 +273,44 @@ impl Real for IEEE754 {

fn prec(&self) -> Option<usize> {
match &self.num {
IEEE754Val::Zero(_) => None,
IEEE754Val::Subnormal(_, c) => Some(c.significant_bits() as usize),
IEEE754Val::Normal(_, _, c) => Some(c.significant_bits() as usize),
IEEE754Val::Infinity(_) => None,
IEEE754Val::Nan(_, _, _) => None,
_ => None,
}
}

fn is_nar(&self) -> bool {
matches!(
&self.num,
IEEE754Val::Infinity(_) | IEEE754Val::Nan(_, _, _)
IEEE754Val::PosInfinity | IEEE754Val::NegInfinity | IEEE754Val::Nan(_, _, _)
)
}

fn is_finite(&self) -> bool {
matches!(
&self.num,
IEEE754Val::Zero(_) | IEEE754Val::Subnormal(_, _) | IEEE754Val::Normal(_, _, _)
IEEE754Val::PosZero
| IEEE754Val::NegZero
| IEEE754Val::Subnormal(_, _)
| IEEE754Val::Normal(_, _, _)
)
}

fn is_infinite(&self) -> bool {
matches!(&self.num, IEEE754Val::Infinity(_))
matches!(&self.num, IEEE754Val::PosInfinity | IEEE754Val::NegInfinity)
}

fn is_zero(&self) -> bool {
matches!(&self.num, IEEE754Val::Zero(_))
matches!(&self.num, IEEE754Val::PosZero | IEEE754Val::NegZero)
}

fn is_negative(&self) -> Option<bool> {
match &self.num {
IEEE754Val::Zero(s) => Some(*s),
IEEE754Val::PosZero | IEEE754Val::NegZero => None,
IEEE754Val::Subnormal(s, _) => Some(*s),
IEEE754Val::Normal(s, _, _) => Some(*s),
IEEE754Val::Infinity(s) => Some(*s),
IEEE754Val::PosInfinity => Some(false),
IEEE754Val::NegInfinity => Some(true),
IEEE754Val::Nan(_, _, _) => None,
}
}
Expand All @@ -316,16 +323,11 @@ impl Real for IEEE754 {
impl From<IEEE754> for RFloat {
fn from(val: IEEE754) -> Self {
match val.num {
IEEE754Val::Zero(_) => RFloat::zero(),
IEEE754Val::PosZero | IEEE754Val::NegZero => RFloat::zero(),
IEEE754Val::Subnormal(s, c) => RFloat::Real(s, val.ctx.expmin(), c),
IEEE754Val::Normal(s, exp, c) => RFloat::Real(s, exp, c),
IEEE754Val::Infinity(s) => {
if s {
RFloat::NegInfinity
} else {
RFloat::PosInfinity
}
}
IEEE754Val::PosInfinity => RFloat::PosInfinity,
IEEE754Val::NegInfinity => RFloat::NegInfinity,
IEEE754Val::Nan(_, _, _) => RFloat::Nan,
}
}
Expand Down
54 changes: 43 additions & 11 deletions src/ieee754/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ impl IEEE754Context {
/// Returns a signed zero.
pub fn zero(&self, sign: bool) -> IEEE754 {
IEEE754 {
num: IEEE754Val::Zero(sign),
num: if sign {
IEEE754Val::NegZero
} else {
IEEE754Val::PosZero
},
flags: Exceptions::default(),
ctx: self.clone(),
}
Expand All @@ -202,7 +206,11 @@ impl IEEE754Context {
/// Constructs an infinity with a sign.
pub fn inf(&self, sign: bool) -> IEEE754 {
IEEE754 {
num: IEEE754Val::Infinity(sign),
num: if sign {
IEEE754Val::NegInfinity
} else {
IEEE754Val::PosInfinity
},
flags: Default::default(),
ctx: self.clone(),
}
Expand Down Expand Up @@ -244,7 +252,11 @@ impl IEEE754Context {
// subnormal or zero
if m.is_zero() {
// zero
IEEE754Val::Zero(s)
if s {
IEEE754Val::NegZero
} else {
IEEE754Val::PosZero
}
} else {
// subnormal
IEEE754Val::Subnormal(s, m)
Expand All @@ -258,7 +270,11 @@ impl IEEE754Context {
// non-real
if m.is_zero() {
// infinity
IEEE754Val::Infinity(s)
if s {
IEEE754Val::NegInfinity
} else {
IEEE754Val::PosInfinity
}
} else {
// nan
let quiet = m.get_bit((p - 2) as u32);
Expand Down Expand Up @@ -345,7 +361,11 @@ impl IEEE754Context {
// rounded result is zero
if unbounded.is_zero() {
return IEEE754 {
num: IEEE754Val::Zero(sign),
num: if sign {
IEEE754Val::NegZero
} else {
IEEE754Val::PosZero
},
flags: Exceptions {
underflow_pre: tiny_pre && inexact,
underflow_post: tiny_post && inexact,
Expand All @@ -363,7 +383,11 @@ impl IEEE754Context {
if e > self.emax() {
if IEEE754Context::overflow_to_infinity(sign, self.rm) {
return IEEE754 {
num: IEEE754Val::Infinity(sign),
num: if sign {
IEEE754Val::NegInfinity
} else {
IEEE754Val::PosInfinity
},
flags: Exceptions {
overflow: true,
inexact: true,
Expand All @@ -383,7 +407,11 @@ impl IEEE754Context {
if self.ftz && tiny_post {
// flush to zero
return IEEE754 {
num: IEEE754Val::Zero(sign),
num: if sign {
IEEE754Val::NegZero
} else {
IEEE754Val::PosZero
},
flags: Exceptions {
underflow_pre: true,
underflow_post: true,
Expand Down Expand Up @@ -438,16 +466,20 @@ impl RoundingContext for IEEE754Context {
fn round<T: Real>(&self, num: &T) -> Self::Format {
// case split by class
if num.is_zero() {
let sign = num.sign().unwrap_or(false);
IEEE754 {
num: IEEE754Val::Zero(sign),
num: match num.sign() {
Some(true) => IEEE754Val::NegZero,
_ => IEEE754Val::PosZero,
},
flags: Exceptions::default(),
ctx: self.clone(),
}
} else if num.is_infinite() {
let sign = num.sign().unwrap_or(false);
IEEE754 {
num: IEEE754Val::Infinity(sign),
num: match num.sign() {
Some(true) => IEEE754Val::NegInfinity,
_ => IEEE754Val::PosInfinity,
},
flags: Exceptions::default(),
ctx: self.clone(),
}
Expand Down

0 comments on commit 6a35627

Please sign in to comment.