comparesf2/comparedf2: fix a signedness bug and add tests.
This commit is contained in:
parent
4cf6571362
commit
07b446a9ab
318
build.rs
318
build.rs
@ -89,6 +89,12 @@ mod tests {
|
||||
Adddf3,
|
||||
Addsf3,
|
||||
|
||||
// float/cmp.rs
|
||||
Gedf2,
|
||||
Gesf2,
|
||||
Ledf2,
|
||||
Lesf2,
|
||||
|
||||
// float/conv.rs
|
||||
Fixdfdi,
|
||||
Fixdfsi,
|
||||
@ -2529,6 +2535,318 @@ fn floatuntidf() {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
pub struct Gedf2 {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: i32,
|
||||
}
|
||||
|
||||
impl TestCase for Gedf2 {
|
||||
fn name() -> &'static str {
|
||||
"gedf2"
|
||||
}
|
||||
|
||||
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||
where
|
||||
R: Rng,
|
||||
Self: Sized,
|
||||
{
|
||||
let a = gen_f64(rng);
|
||||
let b = gen_f64(rng);
|
||||
// TODO accept NaNs. We don't do that right now because we can't check
|
||||
// for NaN-ness on the thumb targets (due to missing intrinsics)
|
||||
if a.is_nan() || b.is_nan() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let c;
|
||||
if a.is_nan() || b.is_nan() {
|
||||
c = -1;
|
||||
} else if a < b {
|
||||
c = -1;
|
||||
} else if a > b {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
|
||||
Some(Gedf2 { a: to_u64(a), b: to_u64(b), c })
|
||||
}
|
||||
|
||||
fn to_string(&self, buffer: &mut String) {
|
||||
writeln!(
|
||||
buffer,
|
||||
"(({a}, {b}), {c}),",
|
||||
a = self.a,
|
||||
b = self.b,
|
||||
c = self.c
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn prologue() -> &'static str {
|
||||
"
|
||||
use std::mem;
|
||||
use compiler_builtins::float::cmp::__gedf2;
|
||||
|
||||
fn to_f64(x: u64) -> f64 {
|
||||
unsafe { mem::transmute(x) }
|
||||
}
|
||||
|
||||
static TEST_CASES: &[((u64, u64), i32)] = &[
|
||||
"
|
||||
}
|
||||
|
||||
fn epilogue() -> &'static str {
|
||||
"
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn gedf2() {
|
||||
for &((a, b), c) in TEST_CASES {
|
||||
let c_ = __gedf2(to_f64(a), to_f64(b));
|
||||
assert_eq!(((a, b), c), ((a, b), c_));
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
pub struct Gesf2 {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: i32,
|
||||
}
|
||||
|
||||
impl TestCase for Gesf2 {
|
||||
fn name() -> &'static str {
|
||||
"gesf2"
|
||||
}
|
||||
|
||||
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||
where
|
||||
R: Rng,
|
||||
Self: Sized,
|
||||
{
|
||||
let a = gen_f32(rng);
|
||||
let b = gen_f32(rng);
|
||||
// TODO accept NaNs. We don't do that right now because we can't check
|
||||
// for NaN-ness on the thumb targets (due to missing intrinsics)
|
||||
if a.is_nan() || b.is_nan() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let c;
|
||||
if a.is_nan() || b.is_nan() {
|
||||
c = -1;
|
||||
} else if a < b {
|
||||
c = -1;
|
||||
} else if a > b {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
|
||||
Some(Gesf2 { a: to_u32(a), b: to_u32(b), c })
|
||||
}
|
||||
|
||||
fn to_string(&self, buffer: &mut String) {
|
||||
writeln!(
|
||||
buffer,
|
||||
"(({a}, {b}), {c}),",
|
||||
a = self.a,
|
||||
b = self.b,
|
||||
c = self.c
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn prologue() -> &'static str {
|
||||
"
|
||||
use std::mem;
|
||||
use compiler_builtins::float::cmp::__gesf2;
|
||||
|
||||
fn to_f32(x: u32) -> f32 {
|
||||
unsafe { mem::transmute(x) }
|
||||
}
|
||||
|
||||
static TEST_CASES: &[((u32, u32), i32)] = &[
|
||||
"
|
||||
}
|
||||
|
||||
fn epilogue() -> &'static str {
|
||||
"
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn gesf2() {
|
||||
for &((a, b), c) in TEST_CASES {
|
||||
let c_ = __gesf2(to_f32(a), to_f32(b));
|
||||
assert_eq!(((a, b), c), ((a, b), c_));
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
pub struct Ledf2 {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: i32,
|
||||
}
|
||||
|
||||
impl TestCase for Ledf2 {
|
||||
fn name() -> &'static str {
|
||||
"ledf2"
|
||||
}
|
||||
|
||||
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||
where
|
||||
R: Rng,
|
||||
Self: Sized,
|
||||
{
|
||||
let a = gen_f64(rng);
|
||||
let b = gen_f64(rng);
|
||||
// TODO accept NaNs. We don't do that right now because we can't check
|
||||
// for NaN-ness on the thumb targets (due to missing intrinsics)
|
||||
if a.is_nan() || b.is_nan() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let c;
|
||||
if a.is_nan() || b.is_nan() {
|
||||
c = 1;
|
||||
} else if a < b {
|
||||
c = -1;
|
||||
} else if a > b {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
|
||||
Some(Ledf2 { a: to_u64(a), b: to_u64(b), c })
|
||||
}
|
||||
|
||||
fn to_string(&self, buffer: &mut String) {
|
||||
writeln!(
|
||||
buffer,
|
||||
"(({a}, {b}), {c}),",
|
||||
a = self.a,
|
||||
b = self.b,
|
||||
c = self.c
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn prologue() -> &'static str {
|
||||
"
|
||||
use std::mem;
|
||||
use compiler_builtins::float::cmp::__ledf2;
|
||||
|
||||
fn to_f64(x: u64) -> f64 {
|
||||
unsafe { mem::transmute(x) }
|
||||
}
|
||||
|
||||
static TEST_CASES: &[((u64, u64), i32)] = &[
|
||||
"
|
||||
}
|
||||
|
||||
fn epilogue() -> &'static str {
|
||||
"
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn ledf2() {
|
||||
for &((a, b), c) in TEST_CASES {
|
||||
let c_ = __ledf2(to_f64(a), to_f64(b));
|
||||
assert_eq!(((a, b), c), ((a, b), c_));
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
pub struct Lesf2 {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: i32,
|
||||
}
|
||||
|
||||
impl TestCase for Lesf2 {
|
||||
fn name() -> &'static str {
|
||||
"lesf2"
|
||||
}
|
||||
|
||||
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||
where
|
||||
R: Rng,
|
||||
Self: Sized,
|
||||
{
|
||||
let a = gen_f32(rng);
|
||||
let b = gen_f32(rng);
|
||||
// TODO accept NaNs. We don't do that right now because we can't check
|
||||
// for NaN-ness on the thumb targets (due to missing intrinsics)
|
||||
if a.is_nan() || b.is_nan() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let c;
|
||||
if a.is_nan() || b.is_nan() {
|
||||
c = 1;
|
||||
} else if a < b {
|
||||
c = -1;
|
||||
} else if a > b {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
|
||||
Some(Lesf2 { a: to_u32(a), b: to_u32(b), c })
|
||||
}
|
||||
|
||||
fn to_string(&self, buffer: &mut String) {
|
||||
writeln!(
|
||||
buffer,
|
||||
"(({a}, {b}), {c}),",
|
||||
a = self.a,
|
||||
b = self.b,
|
||||
c = self.c
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn prologue() -> &'static str {
|
||||
"
|
||||
use std::mem;
|
||||
use compiler_builtins::float::cmp::__lesf2;
|
||||
|
||||
fn to_f32(x: u32) -> f32 {
|
||||
unsafe { mem::transmute(x) }
|
||||
}
|
||||
|
||||
static TEST_CASES: &[((u32, u32), i32)] = &[
|
||||
"
|
||||
}
|
||||
|
||||
fn epilogue() -> &'static str {
|
||||
"
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn lesf2() {
|
||||
for &((a, b), c) in TEST_CASES {
|
||||
let c_ = __lesf2(to_f32(a), to_f32(b));
|
||||
assert_eq!(((a, b), c), ((a, b), c_));
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
pub struct Moddi3 {
|
||||
a: i64,
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
use int::{Int, CastInto};
|
||||
use float::Float;
|
||||
|
||||
@ -35,18 +37,19 @@ fn cmp<F: Float>(a: F, b: F) -> Result where
|
||||
i32: CastInto<F::Int>,
|
||||
F::Int: CastInto<i32>,
|
||||
{
|
||||
let one = F::Int::ONE;
|
||||
let zero = F::Int::ZERO;
|
||||
let one = F::Int::ONE;
|
||||
let zero = F::Int::ZERO;
|
||||
let szero = F::SignedInt::ZERO;
|
||||
|
||||
let sign_bit = F::SIGN_MASK as F::Int;
|
||||
let abs_mask = sign_bit - one;
|
||||
let exponent_mask = F::EXPONENT_MASK;
|
||||
let inf_rep = exponent_mask;
|
||||
|
||||
let a_rep = a.repr();
|
||||
let b_rep = b.repr();
|
||||
let a_abs = a_rep & abs_mask;
|
||||
let b_abs = b_rep & abs_mask;
|
||||
let a_rep = a.repr();
|
||||
let b_rep = b.repr();
|
||||
let a_abs = a_rep & abs_mask;
|
||||
let b_abs = b_rep & abs_mask;
|
||||
|
||||
// If either a or b is NaN, they are unordered.
|
||||
if a_abs > inf_rep || b_abs > inf_rep {
|
||||
@ -58,12 +61,15 @@ fn cmp<F: Float>(a: F, b: F) -> Result where
|
||||
return Result::Equal
|
||||
}
|
||||
|
||||
let a_srep = a.signed_repr();
|
||||
let b_srep = b.signed_repr();
|
||||
|
||||
// If at least one of a and b is positive, we get the same result comparing
|
||||
// a and b as signed integers as we would with a fp_ting-point compare.
|
||||
if a_rep & b_rep >= zero {
|
||||
if a_rep < b_rep {
|
||||
if a_srep & b_srep >= szero {
|
||||
if a_srep < b_srep {
|
||||
return Result::Less
|
||||
} else if a_rep == b_rep {
|
||||
} else if a_srep == b_srep {
|
||||
return Result::Equal
|
||||
} else {
|
||||
return Result::Greater
|
||||
@ -75,9 +81,9 @@ fn cmp<F: Float>(a: F, b: F) -> Result where
|
||||
// complement integer representation; if integers are represented in a
|
||||
// sign-magnitude representation, then this flip is incorrect).
|
||||
else {
|
||||
if a_rep > b_rep {
|
||||
if a_srep > b_srep {
|
||||
return Result::Less
|
||||
} else if a_rep == b_rep {
|
||||
} else if a_srep == b_srep {
|
||||
return Result::Equal
|
||||
} else {
|
||||
return Result::Greater
|
||||
|
@ -26,6 +26,9 @@ pub trait Float:
|
||||
/// A uint of the same with as the float
|
||||
type Int: Int;
|
||||
|
||||
/// A int of the same with as the float
|
||||
type SignedInt: Int;
|
||||
|
||||
const ZERO: Self;
|
||||
const ONE: Self;
|
||||
|
||||
@ -59,6 +62,9 @@ pub trait Float:
|
||||
/// Returns `self` transmuted to `Self::Int`
|
||||
fn repr(self) -> Self::Int;
|
||||
|
||||
/// Returns `self` transmuted to `Self::SignedInt`
|
||||
fn signed_repr(self) -> Self::SignedInt;
|
||||
|
||||
#[cfg(test)]
|
||||
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
|
||||
/// represented in multiple different ways. This method returns `true` if two NaNs are
|
||||
@ -78,9 +84,10 @@ pub trait Float:
|
||||
// FIXME: Some of this can be removed if RFC Issue #1424 is resolved
|
||||
// https://github.com/rust-lang/rfcs/issues/1424
|
||||
macro_rules! float_impl {
|
||||
($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => {
|
||||
($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => {
|
||||
impl Float for $ty {
|
||||
type Int = $ity;
|
||||
type SignedInt = $sity;
|
||||
const ZERO: Self = 0.0;
|
||||
const ONE: Self = 1.0;
|
||||
|
||||
@ -95,6 +102,9 @@ macro_rules! float_impl {
|
||||
fn repr(self) -> Self::Int {
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
fn signed_repr(self) -> Self::SignedInt {
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
#[cfg(test)]
|
||||
fn eq_repr(self, rhs: Self) -> bool {
|
||||
if self.is_nan() && rhs.is_nan() {
|
||||
@ -120,5 +130,5 @@ macro_rules! float_impl {
|
||||
}
|
||||
}
|
||||
|
||||
float_impl!(f32, u32, 32, 23);
|
||||
float_impl!(f64, u64, 64, 52);
|
||||
float_impl!(f32, u32, i32, 32, 23);
|
||||
float_impl!(f64, u64, i64, 64, 52);
|
||||
|
7
tests/gedf2.rs
Normal file
7
tests/gedf2.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(compiler_builtins_lib)]
|
||||
#![feature(i128_type)]
|
||||
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||
target_os = "linux", test),
|
||||
no_std)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/gedf2.rs"));
|
7
tests/gesf2.rs
Normal file
7
tests/gesf2.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(compiler_builtins_lib)]
|
||||
#![feature(i128_type)]
|
||||
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||
target_os = "linux", test),
|
||||
no_std)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/gesf2.rs"));
|
7
tests/ledf2.rs
Normal file
7
tests/ledf2.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(compiler_builtins_lib)]
|
||||
#![feature(i128_type)]
|
||||
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||
target_os = "linux", test),
|
||||
no_std)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/ledf2.rs"));
|
7
tests/lesf2.rs
Normal file
7
tests/lesf2.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(compiler_builtins_lib)]
|
||||
#![feature(i128_type)]
|
||||
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||
target_os = "linux", test),
|
||||
no_std)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/lesf2.rs"));
|
Loading…
Reference in New Issue
Block a user