use core::{
cmp::Ordering,
fmt::Display,
ops::{Add, Div, Mul, Neg, Rem, Sub},
};
use alloc::{
boxed::Box,
string::{String, ToString},
};
use downcast_rs::{Downcast, impl_downcast};
use rustc_apfloat::ieee::{self, IeeeFloat, NonfiniteBehavior};
use thiserror::Error;
pub use rustc_apfloat::{
Category, ExpInt, Float, FloatConvert, Round, StatusAnd,
ieee::{BFloat, Double, Float8E4M3FN, Float8E5M2, Half, Quad, Single, X87DoubleExtended},
};
use crate::{
arg_error_noloc,
combine::{Parser, parser::char},
impl_printable_for_display, input_error,
location::Located,
parsable::{IntoParseResult, Parsable, ParseResult, StateStream, parser_combinator},
result::Result,
};
impl_printable_for_display!(BFloat);
impl_printable_for_display!(Double);
impl_printable_for_display!(Float8E4M3FN);
impl_printable_for_display!(Float8E5M2);
impl_printable_for_display!(Half);
impl_printable_for_display!(Quad);
impl_printable_for_display!(Single);
impl_printable_for_display!(X87DoubleExtended);
pub fn single_to_f32(value: Single) -> f32 {
f32::from_bits(value.to_bits().try_into().unwrap())
}
pub fn f32_to_single(value: f32) -> Single {
Single::from_bits(value.to_bits().into())
}
pub fn double_to_f64(value: Double) -> f64 {
f64::from_bits(value.to_bits().try_into().unwrap())
}
pub fn f64_to_double(value: f64) -> Double {
Double::from_bits(value.to_bits().into())
}
pub fn float_to_f64<T: FloatConvert<Double>>(value: T, loses_info: &mut bool) -> f64 {
double_to_f64(value.convert(loses_info).value)
}
pub fn f64_to_half(value: f64) -> Half {
Double::from_bits(value.to_bits().into())
.convert(&mut false)
.value
}
#[derive(Debug, Error)]
pub enum FloatErr {
#[error("Invalid float literal: {0}")]
InvalidFloatLiteral(String),
#[error("Failed to parse float from string {0}: {1}")]
ParseError(String, String),
}
pub fn float_parse<'a, T: Float>(
state_stream: &mut StateStream<'a>,
_arg: (),
) -> ParseResult<'a, T> {
let loc = state_stream.loc();
let mut allowed_chars = combine::many1::<String, _, _>(
char::letter()
.or(char::digit())
.or(char::char('+'))
.or(char::char('-'))
.or(char::char('.')),
);
let (f_str, _) = allowed_chars
.parse(state_stream)
.map_err(|e| input_error!(loc.clone(), FloatErr::InvalidFloatLiteral(e.to_string())))?;
T::from_str(&f_str)
.map_err(|e| input_error!(loc, FloatErr::ParseError(f_str, e.0.to_string())))
.into_parse_result()
}
pub fn float_parser<'a, T: Float + 'a>(_arg: ()) -> impl Parser<StateStream<'a>, Output = T> + 'a {
parser_combinator(float_parse, ())
}
impl Parsable for BFloat {
type Arg = ();
type Parsed = BFloat;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for Double {
type Arg = ();
type Parsed = Double;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for Float8E4M3FN {
type Arg = ();
type Parsed = Float8E4M3FN;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for Float8E5M2 {
type Arg = ();
type Parsed = Float8E5M2;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for Half {
type Arg = ();
type Parsed = Half;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for Quad {
type Arg = ();
type Parsed = Quad;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for Single {
type Arg = ();
type Parsed = Single;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
impl Parsable for X87DoubleExtended {
type Arg = ();
type Parsed = X87DoubleExtended;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
float_parse(state_stream, ())
}
}
pub struct Semantics {
pub bits: usize,
pub exp_bits: usize,
pub precision: usize,
pub nonfinite_behavior: NonfiniteBehavior,
pub max_exp: ExpInt,
pub ieee_max_exp: ExpInt,
pub min_exp: ExpInt,
pub ieee_min_exp: ExpInt,
pub nan_significand_base: u128,
pub nan_payload_mask: u128,
pub qnan_significand: u128,
}
pub trait GetSemantics {
fn get_semantics() -> Semantics
where
Self: Sized;
}
impl<S: ieee::Semantics> GetSemantics for IeeeFloat<S> {
fn get_semantics() -> Semantics {
Semantics {
bits: S::BITS,
exp_bits: S::EXP_BITS,
precision: S::PRECISION,
nonfinite_behavior: S::NONFINITE_BEHAVIOR,
max_exp: S::MAX_EXP,
ieee_max_exp: S::IEEE_MAX_EXP,
min_exp: S::MIN_EXP,
ieee_min_exp: S::IEEE_MIN_EXP,
nan_significand_base: S::NAN_SIGNIFICAND_BASE,
nan_payload_mask: S::NAN_PAYLOAD_MASK,
qnan_significand: S::QNAN_SIGNIFICAND,
}
}
}
pub trait DynFloat: Downcast + core::fmt::Debug {
fn build_qnan(&self, payload: Option<u128>) -> Box<dyn DynFloat>;
fn build_snan(&self, payload: Option<u128>) -> Box<dyn DynFloat>;
fn build_largest(&self) -> Box<dyn DynFloat>;
fn build_smallest_normalized(&self) -> Box<dyn DynFloat>;
fn build_from_bits(&self, bits: u128) -> Box<dyn DynFloat>;
fn build_from_u128_r(&self, value: u128, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn build_from_str_r(&self, s: &str, round: Round) -> Result<StatusAnd<Box<dyn DynFloat>>>;
fn build_from_i128_r(&self, value: i128, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn build_from_i128(&self, value: i128) -> StatusAnd<Box<dyn DynFloat>>;
fn build_from_u128(&self, value: u128) -> StatusAnd<Box<dyn DynFloat>>;
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
fn neg(&self) -> Box<dyn DynFloat>;
fn add(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn sub(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn mul(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn div(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn rem(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn add_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn mul_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn mul_add_r(
&self,
rhs: &dyn DynFloat,
addend: &dyn DynFloat,
round: Round,
) -> StatusAnd<Box<dyn DynFloat>>;
fn div_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn ieee_rem(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn c_fmod(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>>;
fn round_to_integral(&self, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn next_up(&self) -> StatusAnd<Box<dyn DynFloat>>;
fn to_bits(&self) -> u128;
fn to_u128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128>;
fn cmp_abs_normal(&self, other: &dyn DynFloat) -> Ordering;
fn bitwise_eq(&self, other: &dyn DynFloat) -> bool;
fn is_negative(&self) -> bool;
fn is_denormal(&self) -> bool;
fn is_signaling(&self) -> bool;
fn category(&self) -> Category;
fn get_exact_inverse(&self) -> Option<Box<dyn DynFloat>>;
fn ilogb(&self) -> ExpInt;
fn scalbn_r(&self, n: ExpInt, round: Round) -> Box<dyn DynFloat>;
fn frexp_r(&self, exp: &mut ExpInt, round: Round) -> Box<dyn DynFloat>;
fn sub_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>>;
fn mul_add(
&self,
multiplicand: &dyn DynFloat,
addend: &dyn DynFloat,
) -> StatusAnd<Box<dyn DynFloat>>;
fn next_down(&self) -> StatusAnd<Box<dyn DynFloat>>;
fn abs(&self) -> Box<dyn DynFloat>;
fn copy_sign(&self, other: &dyn DynFloat) -> Box<dyn DynFloat>;
fn to_i128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128>;
fn to_i128(&self, width: usize) -> StatusAnd<i128>;
fn to_u128(&self, width: usize) -> StatusAnd<u128>;
fn min(&self, other: &dyn DynFloat) -> Box<dyn DynFloat>;
fn max(&self, other: &dyn DynFloat) -> Box<dyn DynFloat>;
fn minimum(&self, other: &dyn DynFloat) -> Box<dyn DynFloat>;
fn maximum(&self, other: &dyn DynFloat) -> Box<dyn DynFloat>;
fn is_normal(&self) -> bool;
fn is_finite(&self) -> bool;
fn is_zero(&self) -> bool;
fn is_infinite(&self) -> bool;
fn is_nan(&self) -> bool;
fn is_non_zero(&self) -> bool;
fn is_finite_non_zero(&self) -> bool;
fn is_pos_zero(&self) -> bool;
fn is_neg_zero(&self) -> bool;
fn is_pos_infinity(&self) -> bool;
fn is_neg_infinity(&self) -> bool;
fn is_smallest(&self) -> bool;
fn is_smallest_normalized(&self) -> bool;
fn is_largest(&self) -> bool;
fn is_integer(&self) -> bool;
fn scalbn(&self, n: ExpInt) -> Box<dyn DynFloat>;
fn frexp(&self, exp: &mut ExpInt) -> Box<dyn DynFloat>;
fn semantics(&self) -> Semantics;
fn semantics_static() -> Semantics
where
Self: Sized;
}
impl_downcast!(DynFloat);
impl<T: Float + GetSemantics + core::fmt::Debug + 'static> DynFloat for T {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<Self as core::fmt::Display>::fmt(self, f)
}
fn neg(&self) -> Box<dyn DynFloat> {
Box::new(<Self as Neg>::neg(*self))
}
fn add(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::add");
<Self as Add>::add(*self, *rhs_float).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn sub(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::sub");
<Self as Sub>::sub(*self, *rhs_float).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn mul(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::mul");
<Self as Mul>::mul(*self, *rhs_float).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn div(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::div");
<Self as Div>::div(*self, *rhs_float).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn rem(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::rem");
<Self as Rem>::rem(*self, *rhs_float).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn build_qnan(&self, payload: Option<u128>) -> Box<dyn DynFloat> {
Box::new(<T as Float>::qnan(payload))
}
fn build_snan(&self, payload: Option<u128>) -> Box<dyn DynFloat> {
Box::new(<T as Float>::snan(payload))
}
fn build_largest(&self) -> Box<dyn DynFloat> {
Box::new(<T as Float>::largest())
}
fn build_smallest_normalized(&self) -> Box<dyn DynFloat> {
Box::new(<T as Float>::smallest_normalized())
}
fn add_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::add_r");
<Self as Float>::add_r(*self, *rhs_float, round)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn mul_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::mul_r");
<Self as Float>::mul_r(*self, *rhs_float, round)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn mul_add_r(
&self,
rhs: &dyn DynFloat,
addend: &dyn DynFloat,
round: Round,
) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::mul_add_r");
let addend_float = addend
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::mul_add_r");
<Self as Float>::mul_add_r(*self, *rhs_float, *addend_float, round)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn div_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::div_r");
<Self as Float>::div_r(*self, *rhs_float, round)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn ieee_rem(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::ieee_rem");
<Self as Float>::ieee_rem(*self, *rhs_float)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn c_fmod(&self, rhs: &dyn DynFloat) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::c_fmod");
<Self as Float>::c_fmod(*self, *rhs_float)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn round_to_integral(&self, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
<Self as Float>::round_to_integral(*self, round)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn next_up(&self) -> StatusAnd<Box<dyn DynFloat>> {
<Self as Float>::next_up(*self).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn build_from_bits(&self, bits: u128) -> Box<dyn DynFloat> {
let float_value = <T as Float>::from_bits(bits);
Box::new(float_value) as Box<dyn DynFloat>
}
fn build_from_u128_r(&self, value: u128, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
<T as Float>::from_u128_r(value, round).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn build_from_str_r(&self, s: &str, round: Round) -> Result<StatusAnd<Box<dyn DynFloat>>> {
<T as Float>::from_str_r(s, round)
.map_err(|e| {
arg_error_noloc!(FloatErr::ParseError(s.to_string(), e.0.to_string()))
})
.map(|status_and| status_and.map(|float| Box::new(float) as Box<dyn DynFloat>))
}
fn to_bits(&self) -> u128 {
<Self as Float>::to_bits(*self)
}
fn to_u128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
<Self as Float>::to_u128_r(*self, width, round, is_exact)
}
fn cmp_abs_normal(&self, other: &dyn DynFloat) -> Ordering {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::cmp_abs_normal");
<Self as Float>::cmp_abs_normal(*self, *other_float)
}
fn bitwise_eq(&self, other: &dyn DynFloat) -> bool {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::bitwise_eq");
<Self as Float>::bitwise_eq(*self, *other_float)
}
fn is_negative(&self) -> bool {
<Self as Float>::is_negative(*self)
}
fn is_denormal(&self) -> bool {
<Self as Float>::is_denormal(*self)
}
fn is_signaling(&self) -> bool {
<Self as Float>::is_signaling(*self)
}
fn category(&self) -> Category {
<Self as Float>::category(*self)
}
fn get_exact_inverse(&self) -> Option<Box<dyn DynFloat>> {
<Self as Float>::get_exact_inverse(*self)
.map(|inverse| Box::new(inverse) as Box<dyn DynFloat>)
}
fn ilogb(&self) -> ExpInt {
<Self as Float>::ilogb(*self)
}
fn scalbn_r(&self, n: ExpInt, round: Round) -> Box<dyn DynFloat> {
Box::new(<Self as Float>::scalbn_r(*self, n, round))
}
fn frexp_r(&self, exp: &mut ExpInt, round: Round) -> Box<dyn DynFloat> {
Box::new(<Self as Float>::frexp_r(*self, exp, round))
}
fn sub_r(&self, rhs: &dyn DynFloat, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
let rhs_float = rhs
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::sub_r");
<Self as Float>::sub_r(*self, *rhs_float, round)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn mul_add(
&self,
multiplicand: &dyn DynFloat,
addend: &dyn DynFloat,
) -> StatusAnd<Box<dyn DynFloat>> {
let multiplicand_float = multiplicand
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::mul_add");
let addend_float = addend
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::mul_add");
<Self as Float>::mul_add(*self, *multiplicand_float, *addend_float)
.map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn next_down(&self) -> StatusAnd<Box<dyn DynFloat>> {
<Self as Float>::next_down(*self).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn abs(&self) -> Box<dyn DynFloat> {
Box::new(<Self as Float>::abs(*self))
}
fn copy_sign(&self, other: &dyn DynFloat) -> Box<dyn DynFloat> {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::copy_sign");
Box::new(<Self as Float>::copy_sign(*self, *other_float))
}
fn build_from_i128_r(&self, value: i128, round: Round) -> StatusAnd<Box<dyn DynFloat>> {
<T as Float>::from_i128_r(value, round).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn build_from_i128(&self, value: i128) -> StatusAnd<Box<dyn DynFloat>> {
<T as Float>::from_i128(value).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn build_from_u128(&self, value: u128) -> StatusAnd<Box<dyn DynFloat>> {
<T as Float>::from_u128(value).map(|result| Box::new(result) as Box<dyn DynFloat>)
}
fn to_i128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
<Self as Float>::to_i128_r(*self, width, round, is_exact)
}
fn to_i128(&self, width: usize) -> StatusAnd<i128> {
<Self as Float>::to_i128(*self, width)
}
fn to_u128(&self, width: usize) -> StatusAnd<u128> {
<Self as Float>::to_u128(*self, width)
}
fn minimum(&self, other: &dyn DynFloat) -> Box<dyn DynFloat> {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::minimum");
Box::new(<Self as Float>::minimum(*self, *other_float))
}
fn maximum(&self, other: &dyn DynFloat) -> Box<dyn DynFloat> {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::maximum");
Box::new(<Self as Float>::maximum(*self, *other_float))
}
fn min(&self, other: &dyn DynFloat) -> Box<dyn DynFloat> {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::min");
Box::new(<Self as Float>::min(*self, *other_float))
}
fn max(&self, other: &dyn DynFloat) -> Box<dyn DynFloat> {
let other_float = other
.downcast_ref::<T>()
.expect("Type mismatch in DynFloat::max");
Box::new(<Self as Float>::max(*self, *other_float))
}
fn is_normal(&self) -> bool {
<Self as Float>::is_normal(*self)
}
fn is_finite(&self) -> bool {
<Self as Float>::is_finite(*self)
}
fn is_zero(&self) -> bool {
<Self as Float>::is_zero(*self)
}
fn is_infinite(&self) -> bool {
<Self as Float>::is_infinite(*self)
}
fn is_nan(&self) -> bool {
<Self as Float>::is_nan(*self)
}
fn is_non_zero(&self) -> bool {
<Self as Float>::is_non_zero(*self)
}
fn is_finite_non_zero(&self) -> bool {
<Self as Float>::is_finite_non_zero(*self)
}
fn is_pos_zero(&self) -> bool {
<Self as Float>::is_pos_zero(*self)
}
fn is_neg_zero(&self) -> bool {
<Self as Float>::is_neg_zero(*self)
}
fn is_pos_infinity(&self) -> bool {
<Self as Float>::is_pos_infinity(*self)
}
fn is_neg_infinity(&self) -> bool {
<Self as Float>::is_neg_infinity(*self)
}
fn is_smallest_normalized(&self) -> bool {
<Self as Float>::is_smallest_normalized(*self)
}
fn is_smallest(&self) -> bool {
<Self as Float>::is_smallest(*self)
}
fn is_largest(&self) -> bool {
<Self as Float>::is_largest(*self)
}
fn is_integer(&self) -> bool {
<Self as Float>::is_integer(*self)
}
fn scalbn(&self, n: ExpInt) -> Box<dyn DynFloat> {
Box::new(<Self as Float>::scalbn(*self, n))
}
fn frexp(&self, exp: &mut ExpInt) -> Box<dyn DynFloat> {
Box::new(<Self as Float>::frexp(*self, exp))
}
fn semantics(&self) -> Semantics {
Self::semantics_static()
}
fn semantics_static() -> Semantics
where
Self: Sized,
{
<Self as GetSemantics>::get_semantics()
}
}
impl Display for dyn DynFloat {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<Self as DynFloat>::fmt(self, f)
}
}
impl_printable_for_display!(dyn DynFloat);
impl<T: Float + GetSemantics + core::fmt::Debug + 'static> From<T> for Box<dyn DynFloat> {
fn from(value: T) -> Self {
Box::new(value)
}
}
#[cfg(test)]
mod tests {
use alloc::{str::FromStr, string::ToString};
use rustc_apfloat::ParseError;
use crate::{
context::Context,
parsable::parse_from_str,
printable::Printable,
result::ExpectOk,
utils::apfloat::{
double_to_f64, f32_to_single, f64_to_double, float_to_f64, single_to_f32,
},
};
use super::{
BFloat, Double, Float, Float8E4M3FN, Float8E5M2, Half, Parsable, Quad, Single,
X87DoubleExtended,
};
fn print_and_parse<T>(value: T, ctx: &mut Context)
where
T: Printable + Parsable<Arg = (), Parsed = T> + PartialEq,
{
let s = value.disp(ctx).to_string();
let parsed = parse_from_str(T::parser(()), ctx, &s).expect_ok(ctx);
assert!(value == parsed, "Failed for value: {}", value.disp(ctx));
}
#[test]
fn test_bfloat_print_parse() -> Result<(), ParseError> {
let values = [
BFloat::from_str("0.0")?,
BFloat::from_str("1.5")?,
BFloat::from_str("-2.25")?,
BFloat::from_str("12345.0")?,
BFloat::from_str("-0.0001")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_double_print_parse() -> Result<(), ParseError> {
let values = [
Double::from_str("0.0")?,
Double::from_str("1.5")?,
Double::from_str("-2.25")?,
Double::from_str("12345.0")?,
Double::from_str("-0.0001")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_float8e4m3fn_print_parse() -> Result<(), ParseError> {
let values = [
Float8E4M3FN::from_str("0.0")?,
Float8E4M3FN::from_str("1.5")?,
Float8E4M3FN::from_str("-2.25")?,
Float8E4M3FN::from_str("12.0")?,
Float8E4M3FN::from_str("-0.125")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_float8e5m2_print_parse() -> Result<(), ParseError> {
let values = [
Float8E5M2::from_str("0.0")?,
Float8E5M2::from_str("1.5")?,
Float8E5M2::from_str("-2.25")?,
Float8E5M2::from_str("12.0")?,
Float8E5M2::from_str("-0.125")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_half_print_parse() -> Result<(), ParseError> {
let values = [
Half::from_str("0.0")?,
Half::from_str("1.5")?,
Half::from_str("-2.25")?,
Half::from_str("12345.0")?,
Half::from_str("-0.0001")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_quad_print_parse() -> Result<(), ParseError> {
let values = [
Quad::from_str("0.0")?,
Quad::from_str("1.5")?,
Quad::from_str("-2.25")?,
Quad::from_str("12345.0")?,
Quad::from_str("-0.0001")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_single_print_parse() -> Result<(), ParseError> {
let values = [
Single::from_str("0.0")?,
Single::from_str("1.5")?,
Single::from_str("-2.25")?,
Single::from_str("12345.0")?,
Single::from_str("-0.0001")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_single_print_parse_infinity() -> Result<(), ParseError> {
let ctx = &mut Context::default();
print_and_parse(Single::from_str("+Inf")?, ctx);
print_and_parse(Single::from_str("-Inf")?, ctx);
Ok(())
}
#[test]
fn test_single_print_parse_nan() -> Result<(), ParseError> {
use rustc_apfloat::Float;
let ctx = &mut Context::default();
let nan = Single::from_str("NaN")?;
let s = nan.disp(ctx).to_string();
let parsed = parse_from_str(Single::parser(()), ctx, &s).expect_ok(ctx);
assert!(
parsed.is_nan(),
"Failed to round-trip NaN, got {}",
parsed.disp(ctx)
);
Ok(())
}
#[test]
fn test_x87doubleextended_print_parse() -> Result<(), ParseError> {
let values = [
X87DoubleExtended::from_str("0.0")?,
X87DoubleExtended::from_str("1.5")?,
X87DoubleExtended::from_str("-2.25")?,
X87DoubleExtended::from_str("12345.0")?,
X87DoubleExtended::from_str("-0.0001")?,
];
for v in values {
print_and_parse(v, &mut Context::default())
}
Ok(())
}
#[test]
fn test_single_to_f32_and_f32_to_single() {
let cases = [
0.0f32,
-0.0f32,
1.0f32,
-1.0f32,
f32::MIN,
f32::MAX,
f32::EPSILON,
f32::INFINITY,
f32::NEG_INFINITY,
f32::NAN,
];
for &val in &cases {
let single = f32_to_single(val);
let back = single_to_f32(single);
if val.is_nan() {
assert!(back.is_nan(), "Expected NaN for input {}", val);
} else {
assert_eq!(val, back, "Failed for value: {}", val);
}
}
}
#[test]
fn test_double_to_f64_and_f64_to_double() {
let cases = [
0.0f64,
-0.0f64,
1.0f64,
-1.0f64,
f64::MIN,
f64::MAX,
f64::EPSILON,
f64::INFINITY,
f64::NEG_INFINITY,
f64::NAN,
];
for &val in &cases {
let double = f64_to_double(val);
let back = double_to_f64(double);
if val.is_nan() {
assert!(back.is_nan(), "Expected NaN for input {}", val);
} else {
assert_eq!(val, back, "Failed for value: {}", val);
}
}
}
#[test]
fn test_single_to_f32_subnormals_and_extremes() {
let val = f32::from_bits(0x00000001);
let single = f32_to_single(val);
let back = single_to_f32(single);
assert_eq!(val, back);
let val = f32::from_bits(0x007FFFFF);
let single = f32_to_single(val);
let back = single_to_f32(single);
assert_eq!(val, back);
let val = f32::from_bits(0x00800000);
let single = f32_to_single(val);
let back = single_to_f32(single);
assert_eq!(val, back);
}
#[test]
fn test_double_to_f64_subnormals_and_extremes() {
let val = f64::from_bits(0x0000000000000001);
let double = f64_to_double(val);
let back = double_to_f64(double);
assert_eq!(val, back);
let val = f64::from_bits(0x000FFFFFFFFFFFFF);
let double = f64_to_double(val);
let back = double_to_f64(double);
assert_eq!(val, back);
let val = f64::from_bits(0x0010000000000000);
let double = f64_to_double(val);
let back = double_to_f64(double);
assert_eq!(val, back);
}
#[test]
fn test_float_to_f64() {
let cases: [(u128, f64); 8] = [
(0x0000, 0.0), (0x8000, -0.0), (0x3C00, 1.0), (0xC000, -2.0), (0x3555, 0.333251953125), (0x7BFF, 65504.0), (0x0001, 5.960464477539063e-8), (0x7C00, f64::INFINITY), ];
for (bits, expected) in cases {
let val = float_to_f64(Half::from_bits(bits), &mut false);
assert_eq!(val, expected, "Failed for Half with bits {:#x}", bits);
assert_eq!(
val.is_sign_negative(),
expected.is_sign_negative(),
"Sign mismatch for Half with bits {:#x}",
bits
);
}
assert!(float_to_f64(Half::NAN, &mut false).is_nan());
assert_eq!(
float_to_f64(f32_to_single(core::f32::consts::PI), &mut false),
core::f32::consts::PI as f64
);
assert_eq!(
float_to_f64(Quad::from_str("1.5").unwrap(), &mut false),
1.5
);
}
}