#![no_std]
#![deny(warnings)]
#![forbid(unsafe_code)]
#[macro_use]
extern crate bitflags;
extern crate alloc;
use core::cmp::Ordering;
use core::fmt;
use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
use core::str::FromStr;
bitflags! {
#[must_use]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, 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;
}
}
#[must_use]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, 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),
}
}
}
impl<T: core::fmt::Debug> StatusAnd<T> {
pub fn unwrap(self) -> T {
assert_eq!(self.status, Status::OK, "called `StatusAnd::unwrap()` on an error value. Value: {:?}", self.value);
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;
#[inline]
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_value();
pub const IEK_NAN: ExpInt = ExpInt::min_value();
pub const IEK_ZERO: ExpInt = ExpInt::min_value() + 1;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ParseError(pub &'static str);
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<u128>) -> Self;
fn snan(payload: Option<u128>) -> 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>;
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: u128) -> Self;
fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> {
if input < 0 {
Self::from_u128_r(input.wrapping_neg() as u128, -round).map(|r| -r)
} else {
Self::from_u128_r(input as u128, round)
}
}
fn from_i128(input: i128) -> StatusAnd<Self> {
Self::from_i128_r(input, Round::NearestTiesToEven)
}
fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self>;
fn from_u128(input: u128) -> StatusAnd<Self> {
Self::from_u128_r(input, Round::NearestTiesToEven)
}
fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError>;
fn to_bits(self) -> u128;
fn to_i128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
let status;
if self.is_negative() {
if self.is_zero() {
*is_exact = false;
}
let r = unpack!(status=, (-self).to_u128_r(width, -round, is_exact));
if r > (1 << (width - 1)) {
*is_exact = false;
Status::INVALID_OP.and(-1 << (width - 1))
} else {
status.and(r.wrapping_neg() as i128)
}
} else {
self.to_u128_r(width - 1, round, is_exact).map(|r| r as i128)
}
}
fn to_i128(self, width: usize) -> StatusAnd<i128> {
self.to_i128_r(width, Round::TowardZero, &mut true)
}
fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128>;
fn to_u128(self, width: usize) -> StatusAnd<u128> {
self.to_u128_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 < self {
other
} else {
self
}
}
fn max(self, other: Self) -> Self {
if self.is_nan() {
other
} else if other.is_nan() {
self
} else if self < other {
other
} else {
self
}
}
fn minimum(self, other: Self) -> Self {
if self.is_nan() {
self
} else if other.is_nan() {
other
} else if self.is_zero() && other.is_zero() && self.is_negative() != other.is_negative() {
if self.is_negative() {
self
} else {
other
}
} else if other < self {
other
} else {
self
}
}
fn maximum(self, other: Self) -> Self {
if self.is_nan() {
self
} else if other.is_nan() {
other
} else if self.is_zero() && other.is_zero() && self.is_negative() != other.is_negative() {
if self.is_negative() {
other
} else {
self
}
} else if self < other {
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_pos_infinity(self) -> bool {
self.is_infinite() && !self.is_negative()
}
fn is_neg_infinity(self) -> bool {
self.is_infinite() && self.is_negative()
}
fn is_smallest(self) -> bool {
Self::SMALLEST.copy_sign(self).bitwise_eq(self)
}
fn is_smallest_normalized(self) -> bool {
Self::smallest_normalized().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,
{
#[inline]
fn default() -> Self {
Self::ZERO
}
}
impl<$t> ::core::str::FromStr for $ty<$t>
where
Self: Float,
{
type Err = ParseError;
#[inline]
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>;
#[inline]
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>;
#[inline]
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>;
#[inline]
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>;
#[inline]
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>;
#[inline]
fn rem(self, rhs: Self) -> StatusAnd<Self> {
self.c_fmod(rhs)
}
}
impl<$t> ::core::ops::AddAssign for $ty<$t>
where
Self: Float,
{
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = (*self + rhs).value;
}
}
impl<$t> ::core::ops::SubAssign for $ty<$t>
where
Self: Float,
{
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = (*self - rhs).value;
}
}
impl<$t> ::core::ops::MulAssign for $ty<$t>
where
Self: Float,
{
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = (*self * rhs).value;
}
}
impl<$t> ::core::ops::DivAssign for $ty<$t>
where
Self: Float,
{
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = (*self / rhs).value;
}
}
impl<$t> ::core::ops::RemAssign for $ty<$t>
where
Self: Float,
{
#[inline]
fn rem_assign(&mut self, rhs: Self) {
*self = (*self % rhs).value;
}
}
};
}
pub mod ieee;
pub mod ppc;