section: Move properties into Row
This commit is contained in:
141
src/float_ord.rs
Normal file
141
src/float_ord.rs
Normal file
@ -0,0 +1,141 @@
|
||||
//! Order floating point numbers, into this ordering:
|
||||
//!
|
||||
//! NaN | -Infinity | x < 0 | -0 | +0 | x > 0 | +Infinity | NaN
|
||||
|
||||
/* Adapted from https://github.com/notriddle/rust-float-ord revision e995165f
|
||||
* maintained by Michael Howell <michael@notriddle.com>
|
||||
* licensed under MIT / Apache-2.0 licenses
|
||||
*/
|
||||
|
||||
extern crate core;
|
||||
|
||||
use ::float_ord::core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
||||
use ::float_ord::core::hash::{Hash, Hasher};
|
||||
use ::float_ord::core::mem::transmute;
|
||||
|
||||
/// A wrapper for floats, that implements total equality and ordering
|
||||
/// and hashing.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FloatOrd<T>(pub T);
|
||||
|
||||
macro_rules! float_ord_impl {
|
||||
($f:ident, $i:ident, $n:expr) => {
|
||||
impl FloatOrd<$f> {
|
||||
fn convert(self) -> $i {
|
||||
let u = unsafe { transmute::<$f, $i>(self.0) };
|
||||
let bit = 1 << ($n - 1);
|
||||
if u & bit == 0 {
|
||||
u | bit
|
||||
} else {
|
||||
!u
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PartialEq for FloatOrd<$f> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.convert() == other.convert()
|
||||
}
|
||||
}
|
||||
impl Eq for FloatOrd<$f> {}
|
||||
impl PartialOrd for FloatOrd<$f> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.convert().partial_cmp(&other.convert())
|
||||
}
|
||||
}
|
||||
impl Ord for FloatOrd<$f> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.convert().cmp(&other.convert())
|
||||
}
|
||||
}
|
||||
impl Hash for FloatOrd<$f> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.convert().hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_ord_impl!(f32, u32, 32);
|
||||
float_ord_impl!(f64, u64, 64);
|
||||
|
||||
/// Sort a slice of floats.
|
||||
///
|
||||
/// # Allocation behavior
|
||||
///
|
||||
/// This routine uses a quicksort implementation that does not heap allocate.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// let mut v = [-5.0, 4.0, 1.0, -3.0, 2.0];
|
||||
///
|
||||
/// float_ord::sort(&mut v);
|
||||
/// assert!(v == [-5.0, -3.0, 1.0, 2.0, 4.0]);
|
||||
/// ```
|
||||
#[allow(dead_code)]
|
||||
pub fn sort<T>(v: &mut [T]) where FloatOrd<T>: Ord {
|
||||
let v_: &mut [FloatOrd<T>] = unsafe { transmute(v) };
|
||||
v_.sort_unstable();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate std;
|
||||
|
||||
use self::std::collections::hash_map::DefaultHasher;
|
||||
use self::std::hash::{Hash, Hasher};
|
||||
use super::FloatOrd;
|
||||
|
||||
#[test]
|
||||
fn test_ord() {
|
||||
assert!(FloatOrd(1.0f64) < FloatOrd(2.0f64));
|
||||
assert!(FloatOrd(2.0f32) > FloatOrd(1.0f32));
|
||||
assert!(FloatOrd(1.0f64) == FloatOrd(1.0f64));
|
||||
assert!(FloatOrd(1.0f32) == FloatOrd(1.0f32));
|
||||
assert!(FloatOrd(0.0f64) > FloatOrd(-0.0f64));
|
||||
assert!(FloatOrd(0.0f32) > FloatOrd(-0.0f32));
|
||||
assert!(FloatOrd(::float_ord::core::f64::NAN) == FloatOrd(::float_ord::core::f64::NAN));
|
||||
assert!(FloatOrd(::float_ord::core::f32::NAN) == FloatOrd(::float_ord::core::f32::NAN));
|
||||
assert!(FloatOrd(-::float_ord::core::f64::NAN) < FloatOrd(::float_ord::core::f64::NAN));
|
||||
assert!(FloatOrd(-::float_ord::core::f32::NAN) < FloatOrd(::float_ord::core::f32::NAN));
|
||||
assert!(FloatOrd(-::float_ord::core::f64::INFINITY) < FloatOrd(::float_ord::core::f64::INFINITY));
|
||||
assert!(FloatOrd(-::float_ord::core::f32::INFINITY) < FloatOrd(::float_ord::core::f32::INFINITY));
|
||||
assert!(FloatOrd(::float_ord::core::f64::INFINITY) < FloatOrd(::float_ord::core::f64::NAN));
|
||||
assert!(FloatOrd(::float_ord::core::f32::INFINITY) < FloatOrd(::float_ord::core::f32::NAN));
|
||||
assert!(FloatOrd(-::float_ord::core::f64::NAN) < FloatOrd(::float_ord::core::f64::INFINITY));
|
||||
assert!(FloatOrd(-::float_ord::core::f32::NAN) < FloatOrd(::float_ord::core::f32::INFINITY));
|
||||
}
|
||||
|
||||
fn hash<F: Hash>(f: F) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
f.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
assert_ne!(hash(FloatOrd(0.0f64)), hash(FloatOrd(-0.0f64)));
|
||||
assert_ne!(hash(FloatOrd(0.0f32)), hash(FloatOrd(-0.0f32)));
|
||||
assert_eq!(hash(FloatOrd(-0.0f64)), hash(FloatOrd(-0.0f64)));
|
||||
assert_eq!(hash(FloatOrd(0.0f32)), hash(FloatOrd(0.0f32)));
|
||||
assert_ne!(hash(FloatOrd(::float_ord::core::f64::NAN)), hash(FloatOrd(-::float_ord::core::f64::NAN)));
|
||||
assert_ne!(hash(FloatOrd(::float_ord::core::f32::NAN)), hash(FloatOrd(-::float_ord::core::f32::NAN)));
|
||||
assert_eq!(hash(FloatOrd(::float_ord::core::f64::NAN)), hash(FloatOrd(::float_ord::core::f64::NAN)));
|
||||
assert_eq!(hash(FloatOrd(-::float_ord::core::f32::NAN)), hash(FloatOrd(-::float_ord::core::f32::NAN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_nan() {
|
||||
let nan = ::float_ord::core::f64::NAN;
|
||||
let mut v = [-1.0, 5.0, 0.0, -0.0, nan, 1.5, nan, 3.7];
|
||||
super::sort(&mut v);
|
||||
assert!(v[0] == -1.0);
|
||||
assert!(v[1] == 0.0 && v[1].is_sign_negative());
|
||||
assert!(v[2] == 0.0 && !v[2].is_sign_negative());
|
||||
assert!(v[3] == 1.5);
|
||||
assert!(v[4] == 3.7);
|
||||
assert!(v[5] == 5.0);
|
||||
assert!(v[6].is_nan());
|
||||
assert!(v[7].is_nan());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user