#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/"
)]
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(any(feature = "std", feature = "alloc")))]
compile_error!("either `std` or `alloc` feature is required");
extern crate core;
#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;
extern crate amplify_num;
#[macro_use]
extern crate bitflags;
#[cfg(not(feature = "std"))]
mod std {
pub use core::*;
#[cfg(feature = "alloc")]
pub use ::alloc::vec;
}
use core::cmp::Ordering;
use core::fmt::{self, Display, Formatter};
use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};
use core::str::FromStr;
use amplify_num::{i256, u256};
mod status {
#![allow(clippy::bad_bit_mask)]
bitflags! {
#[must_use]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Status: u8 {
const OK = 0x00;
const INVALID_OP = 0x01;
const DIV_BY_ZERO = 0x02;
const OVERFLOW = 0x04;
const UNDERFLOW = 0x08;
const INEXACT = 0x10;
}
}
}
pub use status::Status;
#[must_use]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct StatusAnd<T> {
pub status: Status,
pub value: T,
}
impl Status {
pub fn and<T>(self, value: T) -> StatusAnd<T> {
StatusAnd {
status: self,
value,
}
}
}
impl<T> StatusAnd<T> {
pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> {
StatusAnd {
status: self.status,
value: f(self.value),
}
}
}
#[macro_export]
macro_rules! unpack {
($status:ident |= , $e:expr) => {
match $e {
$crate::StatusAnd { status, value } => {
$status |= status;
value
}
}
};
($status:ident = , $e:expr) => {
match $e {
$crate::StatusAnd { status, value } => {
$status = status;
value
}
}
};
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
Infinity,
NaN,
Normal,
Zero,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Round {
NearestTiesToEven,
TowardPositive,
TowardNegative,
TowardZero,
NearestTiesToAway,
}
impl Neg for Round {
type Output = Round;
fn neg(self) -> Round {
match self {
Round::TowardPositive => Round::TowardNegative,
Round::TowardNegative => Round::TowardPositive,
Round::NearestTiesToEven | Round::TowardZero | Round::NearestTiesToAway => self,
}
}
}
pub type ExpInt = i32;
pub const IEK_INF: ExpInt = ExpInt::MAX;
pub const IEK_NAN: ExpInt = ExpInt::MIN;
pub const IEK_ZERO: ExpInt = ExpInt::MIN + 1;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ParseError(pub &'static str);
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str(self.0) }
}
pub trait Float:
Copy
+ Default
+ FromStr<Err = ParseError>
+ PartialOrd
+ fmt::Display
+ Neg<Output = Self>
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ RemAssign
+ Add<Output = StatusAnd<Self>>
+ Sub<Output = StatusAnd<Self>>
+ Mul<Output = StatusAnd<Self>>
+ Div<Output = StatusAnd<Self>>
+ Rem<Output = StatusAnd<Self>>
{
const BITS: usize;
const PRECISION: usize;
const MAX_EXP: ExpInt;
const MIN_EXP: ExpInt;
const ZERO: Self;
const INFINITY: Self;
const NAN: Self;
fn qnan(payload: Option<u256>) -> Self;
fn snan(payload: Option<u256>) -> Self;
fn largest() -> Self;
const SMALLEST: Self;
fn smallest_normalized() -> Self;
fn add_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
fn sub_r(self, rhs: Self, round: Round) -> StatusAnd<Self> { self.add_r(-rhs, round) }
fn mul_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self>;
fn mul_add(self, multiplicand: Self, addend: Self) -> StatusAnd<Self> {
self.mul_add_r(multiplicand, addend, Round::NearestTiesToEven)
}
fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
fn ieee_rem(self, rhs: Self) -> StatusAnd<Self> {
let mut v = self;
let status;
v = unpack!(status=, v / rhs);
if status == Status::DIV_BY_ZERO {
return status.and(self);
}
assert!(Self::PRECISION < 256);
let status;
let x = unpack!(status=, v.to_i256_r(256, Round::NearestTiesToEven, &mut false));
if status == Status::INVALID_OP {
return status.and(self);
}
let status;
let mut v = unpack!(status=, Self::from_i256(x));
assert_eq!(status, Status::OK);
let status;
v = unpack!(status=, v * rhs);
assert_eq!(status - Status::INEXACT, Status::OK);
let status;
v = unpack!(status=, self - v);
assert_eq!(status - Status::INEXACT, Status::OK);
if v.is_zero() {
status.and(v.copy_sign(self)) } else {
status.and(v)
}
}
fn c_fmod(self, rhs: Self) -> StatusAnd<Self>;
fn round_to_integral(self, round: Round) -> StatusAnd<Self>;
fn next_up(self) -> StatusAnd<Self>;
fn next_down(self) -> StatusAnd<Self> { (-self).next_up().map(|r| -r) }
fn abs(self) -> Self { if self.is_negative() { -self } else { self } }
fn copy_sign(self, rhs: Self) -> Self {
if self.is_negative() != rhs.is_negative() {
-self
} else {
self
}
}
fn from_bits(input: u256) -> Self;
fn from_i256_r(input: i256, round: Round) -> StatusAnd<Self> {
if input.is_negative() {
Self::from_u256_r(u256::from_inner(input.wrapping_neg().into_inner()), -round)
.map(|r| -r)
} else {
Self::from_u256_r(u256::from_inner(input.into_inner()), round)
}
}
fn from_i256(input: i256) -> StatusAnd<Self> {
Self::from_i256_r(input, Round::NearestTiesToEven)
}
fn from_u256_r(input: u256, round: Round) -> StatusAnd<Self>;
fn from_u256(input: u256) -> StatusAnd<Self> {
Self::from_u256_r(input, Round::NearestTiesToEven)
}
fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError>;
fn to_bits(self) -> u256;
fn to_i256_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i256> {
let status;
if self.is_negative() {
if self.is_zero() {
*is_exact = false;
}
let r = unpack!(status=, (-self).to_u256_r(width, -round, is_exact));
if r > (u256::ONE << (width - 1)) {
*is_exact = false;
Status::INVALID_OP.and(i256::from(-1) << (width - 1))
} else {
status.and(i256::from_inner(r.wrapping_neg().into_inner()))
}
} else {
self.to_u256_r(width - 1, round, is_exact)
.map(|r| i256::from_inner(r.into_inner()))
}
}
fn to_i256(self, width: usize) -> StatusAnd<i256> {
self.to_i256_r(width, Round::TowardZero, &mut true)
}
fn to_u256_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u256>;
fn to_u256(self, width: usize) -> StatusAnd<u256> {
self.to_u256_r(width, Round::TowardZero, &mut true)
}
fn cmp_abs_normal(self, rhs: Self) -> Ordering;
fn bitwise_eq(self, rhs: Self) -> bool;
fn min(self, other: Self) -> Self {
if self.is_nan() {
other
} else if other.is_nan() {
self
} else if other.partial_cmp(&self) == Some(Ordering::Less) {
other
} else {
self
}
}
fn max(self, other: Self) -> Self {
if self.is_nan() {
other
} else if other.is_nan() {
self
} else if self.partial_cmp(&other) == Some(Ordering::Less) {
other
} else {
self
}
}
fn is_negative(self) -> bool;
fn is_normal(self) -> bool { !self.is_denormal() && self.is_finite_non_zero() }
fn is_finite(self) -> bool { !self.is_nan() && !self.is_infinite() }
fn is_zero(self) -> bool { self.category() == Category::Zero }
fn is_denormal(self) -> bool;
fn is_infinite(self) -> bool { self.category() == Category::Infinity }
fn is_nan(self) -> bool { self.category() == Category::NaN }
fn is_signaling(self) -> bool;
fn category(self) -> Category;
fn is_non_zero(self) -> bool { !self.is_zero() }
fn is_finite_non_zero(self) -> bool { self.is_finite() && !self.is_zero() }
fn is_pos_zero(self) -> bool { self.is_zero() && !self.is_negative() }
fn is_neg_zero(self) -> bool { self.is_zero() && self.is_negative() }
fn is_smallest(self) -> bool { Self::SMALLEST.copy_sign(self).bitwise_eq(self) }
fn is_largest(self) -> bool { Self::largest().copy_sign(self).bitwise_eq(self) }
fn is_integer(self) -> bool {
if !self.is_finite() {
return false;
}
self.round_to_integral(Round::TowardZero)
.value
.bitwise_eq(self)
}
fn get_exact_inverse(self) -> Option<Self>;
fn ilogb(self) -> ExpInt;
fn scalbn_r(self, exp: ExpInt, round: Round) -> Self;
fn scalbn(self, exp: ExpInt) -> Self { self.scalbn_r(exp, Round::NearestTiesToEven) }
fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self;
fn frexp(self, exp: &mut ExpInt) -> Self { self.frexp_r(exp, Round::NearestTiesToEven) }
}
pub trait FloatConvert<T: Float>: Float {
fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<T>;
fn convert(self, loses_info: &mut bool) -> StatusAnd<T> {
self.convert_r(Round::NearestTiesToEven, loses_info)
}
}
macro_rules! float_common_impls {
($ty:ident < $t:tt >) => {
impl<$t> Default for $ty<$t>
where Self: Float
{
fn default() -> Self { Self::ZERO }
}
impl<$t> ::core::str::FromStr for $ty<$t>
where Self: Float
{
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, ParseError> {
Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value)
}
}
impl<$t> ::core::ops::Add for $ty<$t>
where Self: Float
{
type Output = StatusAnd<Self>;
fn add(self, rhs: Self) -> StatusAnd<Self> { self.add_r(rhs, Round::NearestTiesToEven) }
}
impl<$t> ::core::ops::Sub for $ty<$t>
where Self: Float
{
type Output = StatusAnd<Self>;
fn sub(self, rhs: Self) -> StatusAnd<Self> { self.sub_r(rhs, Round::NearestTiesToEven) }
}
impl<$t> ::core::ops::Mul for $ty<$t>
where Self: Float
{
type Output = StatusAnd<Self>;
fn mul(self, rhs: Self) -> StatusAnd<Self> { self.mul_r(rhs, Round::NearestTiesToEven) }
}
impl<$t> ::core::ops::Div for $ty<$t>
where Self: Float
{
type Output = StatusAnd<Self>;
fn div(self, rhs: Self) -> StatusAnd<Self> { self.div_r(rhs, Round::NearestTiesToEven) }
}
impl<$t> ::core::ops::Rem for $ty<$t>
where Self: Float
{
type Output = StatusAnd<Self>;
fn rem(self, rhs: Self) -> StatusAnd<Self> { self.c_fmod(rhs) }
}
impl<$t> ::core::ops::AddAssign for $ty<$t>
where Self: Float
{
fn add_assign(&mut self, rhs: Self) { *self = (*self + rhs).value; }
}
impl<$t> ::core::ops::SubAssign for $ty<$t>
where Self: Float
{
fn sub_assign(&mut self, rhs: Self) { *self = (*self - rhs).value; }
}
impl<$t> ::core::ops::MulAssign for $ty<$t>
where Self: Float
{
fn mul_assign(&mut self, rhs: Self) { *self = (*self * rhs).value; }
}
impl<$t> ::core::ops::DivAssign for $ty<$t>
where Self: Float
{
fn div_assign(&mut self, rhs: Self) { *self = (*self / rhs).value; }
}
impl<$t> ::core::ops::RemAssign for $ty<$t>
where Self: Float
{
fn rem_assign(&mut self, rhs: Self) { *self = (*self % rhs).value; }
}
};
}
pub mod ieee;
pub mod ppc;