diff options
| author | Eduard Burtescu <edy.burt@gmail.com> | 2016-06-01 12:22:07 +0300 |
|---|---|---|
| committer | Eduard Burtescu <edy.burt@gmail.com> | 2016-06-05 19:18:28 +0300 |
| commit | c77166c68547863db87f38e6a47c33f343980ee8 (patch) | |
| tree | e9664bdbc44440b48c302e0faaab82fcd3fc044b /src/librustc_const_math/float.rs | |
| parent | 27673610a60c4aa538a92647ec9125b04f653fe4 (diff) | |
| download | rust-c77166c68547863db87f38e6a47c33f343980ee8.tar.gz rust-c77166c68547863db87f38e6a47c33f343980ee8.zip | |
rustc_const_eval: work around double rounding.
Diffstat (limited to 'src/librustc_const_math/float.rs')
| -rw-r--r-- | src/librustc_const_math/float.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs new file mode 100644 index 00000000000..4610c183e1b --- /dev/null +++ b/src/librustc_const_math/float.rs @@ -0,0 +1,173 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp::Ordering; +use std::hash; +use std::mem::transmute; + +use super::err::*; + +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum ConstFloat { + F32(f32), + F64(f64), + + // When the type isn't known, we have to operate on both possibilities. + FInfer { + f32: f32, + f64: f64 + } +} +pub use self::ConstFloat::*; + +impl ConstFloat { + /// Description of the type, not the value + pub fn description(&self) -> &'static str { + match *self { + FInfer {..} => "float", + F32(_) => "f32", + F64(_) => "f64", + } + } + + pub fn is_nan(&self) -> bool { + match *self { + F32(f) => f.is_nan(), + F64(f) => f.is_nan(), + FInfer { f32, f64 } => f32.is_nan() || f64.is_nan() + } + } + + /// Compares the values if they are of the same type + pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> { + match (self, rhs) { + (F64(a), F64(b)) | + (F64(a), FInfer { f64: b, .. }) | + (FInfer { f64: a, .. }, F64(b)) | + (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => { + // This is pretty bad but it is the existing behavior. + Ok(if a == b { + Ordering::Equal + } else if a < b { + Ordering::Less + } else { + Ordering::Greater + }) + } + + (F32(a), F32(b)) | + (F32(a), FInfer { f32: b, .. }) | + (FInfer { f32: a, .. }, F32(b)) => { + Ok(if a == b { + Ordering::Equal + } else if a < b { + Ordering::Less + } else { + Ordering::Greater + }) + } + + _ => Err(CmpBetweenUnequalTypes), + } + } +} + +/// Note that equality for `ConstFloat` means that the it is the same +/// constant, not that the rust values are equal. In particular, `NaN +/// == NaN` (at least if it's the same NaN; distinct encodings for NaN +/// are considering unequal). +impl PartialEq for ConstFloat { + fn eq(&self, other: &Self) -> bool { + match (*self, *other) { + (F64(a), F64(b)) | + (F64(a), FInfer { f64: b, .. }) | + (FInfer { f64: a, .. }, F64(b)) | + (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => { + unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)} + } + (F32(a), F32(b)) => { + unsafe{transmute::<_,u32>(a) == transmute::<_,u32>(b)} + } + _ => false + } + } +} + +impl Eq for ConstFloat {} + +impl hash::Hash for ConstFloat { + fn hash<H: hash::Hasher>(&self, state: &mut H) { + match *self { + F64(a) | FInfer { f64: a, .. } => { + unsafe { transmute::<_,u64>(a) }.hash(state) + } + F32(a) => { + unsafe { transmute::<_,u32>(a) }.hash(state) + } + } + } +} + +impl ::std::fmt::Display for ConstFloat { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + match *self { + FInfer { f64, .. } => write!(fmt, "{}", f64), + F32(f) => write!(fmt, "{}f32", f), + F64(f) => write!(fmt, "{}f64", f), + } + } +} + +macro_rules! derive_binop { + ($op:ident, $func:ident) => { + impl ::std::ops::$op for ConstFloat { + type Output = Result<Self, ConstMathErr>; + fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> { + match (self, rhs) { + (F32(a), F32(b)) | + (F32(a), FInfer { f32: b, .. }) | + (FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))), + + (F64(a), F64(b)) | + (FInfer { f64: a, .. }, F64(b)) | + (F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))), + + (FInfer { f32: a32, f64: a64 }, + FInfer { f32: b32, f64: b64 }) => Ok(FInfer { + f32: a32.$func(b32), + f64: a64.$func(b64) + }), + + _ => Err(UnequalTypes(Op::$op)), + } + } + } + } +} + +derive_binop!(Add, add); +derive_binop!(Sub, sub); +derive_binop!(Mul, mul); +derive_binop!(Div, div); +derive_binop!(Rem, rem); + +impl ::std::ops::Neg for ConstFloat { + type Output = Self; + fn neg(self) -> Self { + match self { + F32(f) => F32(-f), + F64(f) => F64(-f), + FInfer { f32, f64 } => FInfer { + f32: -f32, + f64: -f64 + } + } + } +} |
