-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from bksaiki/posit
Posit support
- Loading branch information
Showing
9 changed files
with
883 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
//! "Posit" numbers as described in the 2022 Posit Standard. | ||
//! | ||
//! This module implements posits with [`PositContext`]. | ||
//! The associated storage type is [`Posit`] which represents | ||
//! a posit number. | ||
|
||
mod number; | ||
mod ops; | ||
mod round; | ||
|
||
pub use number::Posit; | ||
pub(crate) use number::PositVal; | ||
pub use ops::*; | ||
pub use round::PositContext; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
use std::cmp::Ordering; | ||
|
||
use num_traits::{One, Zero}; | ||
use rug::Integer; | ||
|
||
use crate::{rfloat::RFloat, util::bitmask, Real}; | ||
|
||
use super::PositContext; | ||
|
||
/// Posit number encoding viewed as an enumeration. | ||
/// Unlike [`Posit`], [`PositVal`] represents only numerical data. | ||
#[derive(Clone, Debug)] | ||
pub enum PositVal { | ||
/// Exact zero | ||
Zero, | ||
/// Finite, non-zero value | ||
NonZero(bool, isize, isize, Integer), | ||
/// Non-real or undefined | ||
Nar, | ||
} | ||
|
||
/// Posit number format. | ||
/// | ||
/// The associated [`RoundingContext`][crate::RoundingContext] | ||
/// implementation is [`PositContext`]. | ||
/// See [`PositContext`] for more details on numerical properties | ||
/// of the [`Posit`] type. | ||
#[derive(Clone, Debug)] | ||
pub struct Posit { | ||
pub(crate) num: PositVal, | ||
pub(crate) ctx: PositContext, | ||
} | ||
|
||
impl Posit { | ||
/// Returns the rounding context under which this number was created. | ||
pub fn ctx(&self) -> &PositContext { | ||
&self.ctx | ||
} | ||
|
||
/// Converts this [`Posit`] to an [`Integer`] representing a posit bitpattern. | ||
pub fn into_bits(self) -> Integer { | ||
let es = self.ctx.es(); | ||
let nbits = self.ctx.nbits(); | ||
match self.num { | ||
PositVal::Zero => Integer::from(0), | ||
PositVal::Nar => Integer::from(1) << (nbits - 1), | ||
PositVal::NonZero(s, r, exp, c) => { | ||
// convert sign | ||
let sfield = if s { Integer::one() } else { Integer::zero() }; | ||
|
||
// compute size of regime field and regime LSB | ||
let (kbits, r0) = if r < 0 { | ||
(-r as usize, false) | ||
} else { | ||
(r as usize + 1, true) | ||
}; | ||
|
||
// check for special case: format encoded with sign + regime | ||
if kbits == nbits - 1 { | ||
sfield << (nbits - 1) | bitmask(nbits - 1) | ||
} else { | ||
// compute size of exponent and significand fields | ||
let rbits = kbits + 1; | ||
let embits = nbits - (rbits + 1); | ||
let (ebits, mbits) = if embits <= es { | ||
(embits, 0) | ||
} else { | ||
(es, embits - es) | ||
}; | ||
|
||
// convert regime | ||
let rfield = if r0 { | ||
// !r0 => rfield = 11..110 | ||
bitmask(kbits) << 1 | ||
} else { | ||
// r0 => rfield = 00..001 | ||
Integer::one() | ||
}; | ||
|
||
// convert exponent | ||
let e = exp + (c.significant_bits() as isize - 1); | ||
let efield = Integer::from(e >> (es - ebits)); | ||
|
||
// convert significand | ||
let p = c.significant_bits() as usize; | ||
let mfield = bitmask(p - 1) & c; | ||
|
||
// compose | ||
(sfield << (nbits - 1)) | (rfield << embits) | (efield << mbits) | mfield | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl Real for Posit { | ||
fn radix() -> usize { | ||
2 | ||
} | ||
|
||
fn sign(&self) -> bool { | ||
self.is_negative().unwrap_or(false) | ||
} | ||
|
||
fn exp(&self) -> Option<isize> { | ||
match &self.num { | ||
PositVal::Zero => None, | ||
PositVal::NonZero(_, r, exp, _) => Some((r * self.ctx.useed()) + exp), | ||
PositVal::Nar => None, | ||
} | ||
} | ||
|
||
fn e(&self) -> Option<isize> { | ||
match &self.num { | ||
PositVal::Zero => None, | ||
PositVal::NonZero(_, r, exp, c) => { | ||
Some(((r * self.ctx.useed()) + exp - 1) + (c.significant_bits() as isize)) | ||
} | ||
PositVal::Nar => None, | ||
} | ||
} | ||
|
||
fn n(&self) -> Option<isize> { | ||
match &self.num { | ||
PositVal::Zero => None, | ||
PositVal::NonZero(_, r, exp, _) => Some((r * self.ctx.useed()) + exp - 1), | ||
PositVal::Nar => None, | ||
} | ||
} | ||
|
||
fn c(&self) -> Option<Integer> { | ||
match &self.num { | ||
PositVal::Zero => None, | ||
PositVal::NonZero(_, _, _, c) => Some(c.clone()), | ||
PositVal::Nar => None, | ||
} | ||
} | ||
|
||
fn m(&self) -> Option<Integer> { | ||
self.c().map(|c| if self.sign() { -c } else { c }) | ||
} | ||
|
||
fn p(&self) -> usize { | ||
match &self.num { | ||
PositVal::Zero => 0, | ||
PositVal::NonZero(_, _, _, c) => c.significant_bits() as usize, | ||
PositVal::Nar => 0, | ||
} | ||
} | ||
|
||
fn is_nar(&self) -> bool { | ||
matches!(self.num, PositVal::Nar) | ||
} | ||
|
||
fn is_finite(&self) -> bool { | ||
!matches!(self.num, PositVal::Nar) | ||
} | ||
|
||
fn is_infinite(&self) -> bool { | ||
false | ||
} | ||
|
||
fn is_zero(&self) -> bool { | ||
matches!(self.num, PositVal::Zero) | ||
} | ||
|
||
fn is_negative(&self) -> Option<bool> { | ||
match &self.num { | ||
PositVal::Zero => None, | ||
PositVal::NonZero(s, _, _, _) => Some(*s), | ||
PositVal::Nar => None, | ||
} | ||
} | ||
|
||
fn is_numerical(&self) -> bool { | ||
!matches!(self.num, PositVal::Nar) | ||
} | ||
} | ||
|
||
impl PartialEq for Posit { | ||
fn eq(&self, other: &Self) -> bool { | ||
self.partial_cmp(other) == Some(Ordering::Equal) | ||
} | ||
} | ||
|
||
impl PartialOrd for Posit { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
match (&self.num, &other.num) { | ||
(PositVal::Nar, PositVal::Nar) => Some(Ordering::Equal), | ||
(PositVal::Nar, _) => Some(Ordering::Less), | ||
(_, PositVal::Nar) => Some(Ordering::Greater), | ||
(PositVal::Zero, PositVal::Zero) => Some(Ordering::Equal), | ||
(PositVal::Zero, PositVal::NonZero(s, _, _, _)) => { | ||
if *s { | ||
// 0 > -x | ||
Some(Ordering::Greater) | ||
} else { | ||
// 0 < +X | ||
Some(Ordering::Less) | ||
} | ||
} | ||
(PositVal::NonZero(s, _, _, _), PositVal::Zero) => { | ||
if *s { | ||
// -x < 0 | ||
Some(Ordering::Less) | ||
} else { | ||
// +x > 0 | ||
Some(Ordering::Greater) | ||
} | ||
} | ||
(PositVal::NonZero(_, _, _, _), PositVal::NonZero(_, _, _, _)) => { | ||
RFloat::from(self.clone()).partial_cmp(&RFloat::from(other.clone())) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl From<Posit> for RFloat { | ||
fn from(value: Posit) -> Self { | ||
match value.num { | ||
PositVal::Zero => RFloat::zero(), | ||
PositVal::NonZero(s, r, exp, c) => RFloat::Real(s, value.ctx.rscale() * r + exp, c), | ||
PositVal::Nar => RFloat::Nan, | ||
} | ||
} | ||
} |
Oops, something went wrong.