use crate::all::Uncountable;
#[cfg(not(feature = "std"))]
use crate::number::real::float::fns::{abs32, abs64};
use crate::{
error::NumeraResult,
number::traits::{
Bound, ConstLowerBounded, ConstNegOne, ConstOne, ConstUpperBounded, ConstZero, Count,
Ident, LowerBounded, NegOne, Negative, Number, One, Positive, Sign, UpperBounded, Zero,
},
};
use core::fmt;
use decstr::{Bitstring128, Bitstring32, Bitstring64};
use devela::paste;
macro_rules! define_float_sized {
($name:ident, $abbr:ident, $pname:ident,
$doc_num:literal, $doc_type:literal, $doc_extra:literal,
$doc_sign:literal, $doc_lower:expr, $doc_upper:expr,
(
$doc_det:literal, $b:expr,
larger: $larger:literal, $larger_b:literal,
smaller: $smaller:literal, $smaller_b:literal
)
) => {
paste! {
#[doc = $doc_det " "$b "-bit " $doc_num $doc_type ","]
#[doc = "also known as [`" [<$abbr $b>] "`][super::super::" [<$abbr $b>] "]."]
#[doc = "\n\nThe range of valid numeric values is $\\lbrack"
$doc_sign "$[`" $doc_lower "`][" [<$name $b>] "::" $doc_lower "] $\\dots$ [`"
$doc_upper "`][" [<$name $b>] "::" $doc_upper "]$\\rbrack$."]
#[doc = $doc_extra ]
#[derive(Clone, Copy)] pub struct [<$name $b>](pub $pname);
impl fmt::Display for [<$name $b>] {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for [<$name $b>] {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({})", stringify!([<$abbr $b>]), self.0)
}
}
impl Default for [<$name $b>] {
fn default() -> Self {
Self::new_zero()
}
}
impl PartialEq for [<$name $b>] {
fn eq(&self, other: &Self) -> bool {
self.0.to_f64().eq(&other.0.to_f64())
}
}
impl PartialOrd for [<$name $b>] {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.0.to_f64().partial_cmp(&other.0.to_f64())
}
}
impl [<$name $b>] {
#[doc = "Returns a new `" [<$name $b>] "`."]
#[inline]
pub const fn new(value: $pname) -> Self { Self(value) }
}
impl Sign for [<$name $b>] {
#[inline]
fn can_negative(&self) -> bool { true }
#[inline]
fn can_positive(&self) -> bool { true }
#[inline]
fn is_negative(&self) -> bool { self.0.is_sign_negative() }
#[inline]
fn is_positive(&self) -> bool { !self.0.is_sign_negative() }
}
impl Positive for [<$name $b>] {}
impl Negative for [<$name $b>] {}
impl Bound for [<$name $b>] {
#[inline]
fn is_lower_bounded(&self) -> bool { true }
#[inline]
fn is_upper_bounded(&self) -> bool { true }
#[inline]
fn lower_bound(&self) -> Option<Self> { Some([<$name $b>]::new_min()) }
#[inline]
fn upper_bound(&self) -> Option<Self> { Some([<$name $b>]::new_max()) }
}
impl LowerBounded for [<$name $b>] {
#[inline]
fn new_min() -> Self { Self::MIN }
}
impl UpperBounded for [<$name $b>] {
#[inline]
fn new_max() -> Self { Self::MAX }
}
impl ConstLowerBounded for [<$name $b>] {
const MIN: Self = Self($pname::MIN);
}
impl ConstUpperBounded for [<$name $b>] {
const MAX: Self = Self($pname::MAX);
}
impl Count for [<$name $b>] {
#[inline]
fn is_countable(&self) -> bool { false }
}
impl Uncountable for [<$name $b>] {}
impl Ident for [<$name $b>] {
#[inline]
fn can_zero(&self) -> bool { true }
#[inline]
fn can_one(&self) -> bool { true }
#[inline]
fn can_neg_one(&self) -> bool { true }
#[inline]
fn is_zero(&self) -> bool {
[<approx_eq_$pname>](self.0, $pname::ZERO, $pname::EPSILON)
}
#[inline]
fn is_one(&self) -> bool {
[<approx_eq_$pname>](self.0, $pname::ONE, $pname::EPSILON)
}
#[inline]
fn is_neg_one(&self) -> bool {
[<approx_eq_$pname>](self.0, $pname::NEG_ONE, $pname::EPSILON)
}
}
impl ConstZero for [<$name $b>] { const ZERO: Self = Self($pname::ZERO); }
impl ConstOne for [<$name $b>] { const ONE: Self = Self($pname::ONE); }
impl ConstNegOne for [<$name $b>] { const NEG_ONE: Self = Self($pname::NEG_ONE); }
impl Zero for [<$name $b>] {
#[inline]
fn new_zero() -> Self { Self::ZERO }
}
impl One for [<$name $b>] {
#[inline]
fn new_one() -> Self { Self::ONE }
}
impl NegOne for [<$name $b>] {
#[inline]
fn new_neg_one() -> Self { Self::NEG_ONE }
}
impl Number for [<$name $b>] {
type InnerRepr = $pname;
type InnermostRepr = $pname;
#[doc = "Returns a new `" [<$name $b>] " from the inner representation`."]
#[inline]
fn from_inner_repr(value: Self::InnerRepr) -> NumeraResult<Self> { Ok(Self(value)) }
#[doc = "Returns a new `" [<$name $b>] "` from the inner representation`."]
#[inline]
#[cfg(not(feature = "safe"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
unsafe fn from_inner_repr_unchecked(value: Self::InnerRepr) -> Self { Self(value) }
#[doc = "Returns a new `" [<$name $b>] "` from the innermost representation."]
#[inline]
fn from_innermost_repr(value: Self::InnermostRepr) -> NumeraResult<Self> {
Ok(Self(value))
}
#[doc = "Returns a new `" [<$name $b>] "` from the innermost representation."]
#[inline]
#[cfg(not(feature = "safe"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
unsafe fn from_innermost_repr_unchecked(value: Self::InnermostRepr) -> Self {
Self(value)
}
#[inline]
fn into_inner_repr(self) -> Self::InnerRepr { self.0 }
#[inline]
fn into_innermost_repr(self) -> Self::InnermostRepr { self.0 }
}
}
};
}
#[inline]
#[allow(non_snake_case)]
pub(super) fn approx_eq_Bitstring32(a: Bitstring32, b: Bitstring32, epsilon: Bitstring32) -> bool {
if let Some(a) = a.to_f32() {
if let Some(b) = b.to_f32() {
if let Some(epsilon) = epsilon.to_f32() {
#[cfg(feature = "std")]
return (a - b).abs() <= epsilon;
#[cfg(not(feature = "std"))]
return abs32(a - b) <= epsilon;
}
}
}
false
}
#[inline]
#[allow(non_snake_case)]
pub(super) fn approx_eq_Bitstring64(a: Bitstring64, b: Bitstring64, epsilon: Bitstring64) -> bool {
if let Some(a) = a.to_f64() {
if let Some(b) = b.to_f64() {
if let Some(epsilon) = epsilon.to_f64() {
#[cfg(feature = "std")]
return (a - b).abs() <= epsilon;
#[cfg(not(feature = "std"))]
return abs64(a - b) <= epsilon;
}
}
}
false
}
#[inline]
#[allow(non_snake_case)]
pub(super) fn approx_eq_Bitstring128(
a: Bitstring128,
b: Bitstring128,
epsilon: Bitstring128,
) -> bool {
if let Some(a) = a.to_f64() {
if let Some(b) = b.to_f64() {
if let Some(epsilon) = epsilon.to_f64() {
#[cfg(feature = "std")]
return (a - b).abs() <= epsilon;
#[cfg(not(feature = "std"))]
return abs64(a - b) <= epsilon;
}
}
}
false
}
#[cfg(feature = "decstr")]
define_float_sized![DecFloat, Df, Bitstring32,
"ieee-754 single-precision *decimal* floating-point ([w][0w]) number", ",
from the set $\\R$",
"Supports 7 decimal digits of significand and a normalized exponent range of −101 to +90.
It doesn't implement any arithmetic operations and is mainly intended for storage and interchange.
[0w]: https://en.wikipedia.org/wiki/Decimal32_floating-point_format
",
"", MIN, MAX,
("A", 32, larger: true, 64, smaller: false, 32)
];
#[cfg(feature = "decstr")]
define_float_sized![DecFloat, Df, Bitstring64,
"ieee-754 double-precision *decimal* floating-point ([w][0w]) number",
", from the set $\\R$",
"Supports 16 decimal digits of significand and a normalized exponent range of −398 to +369.
It doesn't implement any arithmetic operations and is mainly intended for storage and interchange.
[0w]: https://en.wikipedia.org/wiki/Decimal64_floating-point_format
",
"", MIN, MAX,
("A", 64, larger: true, 128, smaller: true, 32)
];
#[cfg(feature = "decstr")]
define_float_sized![DecFloat, Df, Bitstring128,
"ieee-754 quadruple-precision *decimal* floating-point ([w][0w]) number",
", from the set $\\R$",
"Supports 34 decimal digits of significand and a normalized exponent range of −6176 to +6111.
It doesn't implement any arithmetic operations and is mainly intended for storage and interchange.
[0w]: https://en.wikipedia.org/wiki/Decimal128_floating-point_format
",
"", MIN, MAX,
("A", 128, larger: false, 128, smaller: true, 64)
];