Skip to content

Commit 07b446a

Browse files
committed
comparesf2/comparedf2: fix a signedness bug and add tests.
1 parent 4cf6571 commit 07b446a

File tree

7 files changed

+376
-14
lines changed

7 files changed

+376
-14
lines changed

build.rs

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ mod tests {
8989
Adddf3,
9090
Addsf3,
9191

92+
// float/cmp.rs
93+
Gedf2,
94+
Gesf2,
95+
Ledf2,
96+
Lesf2,
97+
9298
// float/conv.rs
9399
Fixdfdi,
94100
Fixdfsi,
@@ -2529,6 +2535,318 @@ fn floatuntidf() {
25292535
}
25302536
}
25312537

2538+
#[derive(Eq, Hash, PartialEq)]
2539+
pub struct Gedf2 {
2540+
a: u64,
2541+
b: u64,
2542+
c: i32,
2543+
}
2544+
2545+
impl TestCase for Gedf2 {
2546+
fn name() -> &'static str {
2547+
"gedf2"
2548+
}
2549+
2550+
fn generate<R>(rng: &mut R) -> Option<Self>
2551+
where
2552+
R: Rng,
2553+
Self: Sized,
2554+
{
2555+
let a = gen_f64(rng);
2556+
let b = gen_f64(rng);
2557+
// TODO accept NaNs. We don't do that right now because we can't check
2558+
// for NaN-ness on the thumb targets (due to missing intrinsics)
2559+
if a.is_nan() || b.is_nan() {
2560+
return None;
2561+
}
2562+
2563+
let c;
2564+
if a.is_nan() || b.is_nan() {
2565+
c = -1;
2566+
} else if a < b {
2567+
c = -1;
2568+
} else if a > b {
2569+
c = 1;
2570+
} else {
2571+
c = 0;
2572+
}
2573+
2574+
Some(Gedf2 { a: to_u64(a), b: to_u64(b), c })
2575+
}
2576+
2577+
fn to_string(&self, buffer: &mut String) {
2578+
writeln!(
2579+
buffer,
2580+
"(({a}, {b}), {c}),",
2581+
a = self.a,
2582+
b = self.b,
2583+
c = self.c
2584+
)
2585+
.unwrap();
2586+
}
2587+
2588+
fn prologue() -> &'static str {
2589+
"
2590+
use std::mem;
2591+
use compiler_builtins::float::cmp::__gedf2;
2592+
2593+
fn to_f64(x: u64) -> f64 {
2594+
unsafe { mem::transmute(x) }
2595+
}
2596+
2597+
static TEST_CASES: &[((u64, u64), i32)] = &[
2598+
"
2599+
}
2600+
2601+
fn epilogue() -> &'static str {
2602+
"
2603+
];
2604+
2605+
#[test]
2606+
fn gedf2() {
2607+
for &((a, b), c) in TEST_CASES {
2608+
let c_ = __gedf2(to_f64(a), to_f64(b));
2609+
assert_eq!(((a, b), c), ((a, b), c_));
2610+
}
2611+
}
2612+
"
2613+
}
2614+
}
2615+
2616+
#[derive(Eq, Hash, PartialEq)]
2617+
pub struct Gesf2 {
2618+
a: u32,
2619+
b: u32,
2620+
c: i32,
2621+
}
2622+
2623+
impl TestCase for Gesf2 {
2624+
fn name() -> &'static str {
2625+
"gesf2"
2626+
}
2627+
2628+
fn generate<R>(rng: &mut R) -> Option<Self>
2629+
where
2630+
R: Rng,
2631+
Self: Sized,
2632+
{
2633+
let a = gen_f32(rng);
2634+
let b = gen_f32(rng);
2635+
// TODO accept NaNs. We don't do that right now because we can't check
2636+
// for NaN-ness on the thumb targets (due to missing intrinsics)
2637+
if a.is_nan() || b.is_nan() {
2638+
return None;
2639+
}
2640+
2641+
let c;
2642+
if a.is_nan() || b.is_nan() {
2643+
c = -1;
2644+
} else if a < b {
2645+
c = -1;
2646+
} else if a > b {
2647+
c = 1;
2648+
} else {
2649+
c = 0;
2650+
}
2651+
2652+
Some(Gesf2 { a: to_u32(a), b: to_u32(b), c })
2653+
}
2654+
2655+
fn to_string(&self, buffer: &mut String) {
2656+
writeln!(
2657+
buffer,
2658+
"(({a}, {b}), {c}),",
2659+
a = self.a,
2660+
b = self.b,
2661+
c = self.c
2662+
)
2663+
.unwrap();
2664+
}
2665+
2666+
fn prologue() -> &'static str {
2667+
"
2668+
use std::mem;
2669+
use compiler_builtins::float::cmp::__gesf2;
2670+
2671+
fn to_f32(x: u32) -> f32 {
2672+
unsafe { mem::transmute(x) }
2673+
}
2674+
2675+
static TEST_CASES: &[((u32, u32), i32)] = &[
2676+
"
2677+
}
2678+
2679+
fn epilogue() -> &'static str {
2680+
"
2681+
];
2682+
2683+
#[test]
2684+
fn gesf2() {
2685+
for &((a, b), c) in TEST_CASES {
2686+
let c_ = __gesf2(to_f32(a), to_f32(b));
2687+
assert_eq!(((a, b), c), ((a, b), c_));
2688+
}
2689+
}
2690+
"
2691+
}
2692+
}
2693+
2694+
#[derive(Eq, Hash, PartialEq)]
2695+
pub struct Ledf2 {
2696+
a: u64,
2697+
b: u64,
2698+
c: i32,
2699+
}
2700+
2701+
impl TestCase for Ledf2 {
2702+
fn name() -> &'static str {
2703+
"ledf2"
2704+
}
2705+
2706+
fn generate<R>(rng: &mut R) -> Option<Self>
2707+
where
2708+
R: Rng,
2709+
Self: Sized,
2710+
{
2711+
let a = gen_f64(rng);
2712+
let b = gen_f64(rng);
2713+
// TODO accept NaNs. We don't do that right now because we can't check
2714+
// for NaN-ness on the thumb targets (due to missing intrinsics)
2715+
if a.is_nan() || b.is_nan() {
2716+
return None;
2717+
}
2718+
2719+
let c;
2720+
if a.is_nan() || b.is_nan() {
2721+
c = 1;
2722+
} else if a < b {
2723+
c = -1;
2724+
} else if a > b {
2725+
c = 1;
2726+
} else {
2727+
c = 0;
2728+
}
2729+
2730+
Some(Ledf2 { a: to_u64(a), b: to_u64(b), c })
2731+
}
2732+
2733+
fn to_string(&self, buffer: &mut String) {
2734+
writeln!(
2735+
buffer,
2736+
"(({a}, {b}), {c}),",
2737+
a = self.a,
2738+
b = self.b,
2739+
c = self.c
2740+
)
2741+
.unwrap();
2742+
}
2743+
2744+
fn prologue() -> &'static str {
2745+
"
2746+
use std::mem;
2747+
use compiler_builtins::float::cmp::__ledf2;
2748+
2749+
fn to_f64(x: u64) -> f64 {
2750+
unsafe { mem::transmute(x) }
2751+
}
2752+
2753+
static TEST_CASES: &[((u64, u64), i32)] = &[
2754+
"
2755+
}
2756+
2757+
fn epilogue() -> &'static str {
2758+
"
2759+
];
2760+
2761+
#[test]
2762+
fn ledf2() {
2763+
for &((a, b), c) in TEST_CASES {
2764+
let c_ = __ledf2(to_f64(a), to_f64(b));
2765+
assert_eq!(((a, b), c), ((a, b), c_));
2766+
}
2767+
}
2768+
"
2769+
}
2770+
}
2771+
2772+
#[derive(Eq, Hash, PartialEq)]
2773+
pub struct Lesf2 {
2774+
a: u32,
2775+
b: u32,
2776+
c: i32,
2777+
}
2778+
2779+
impl TestCase for Lesf2 {
2780+
fn name() -> &'static str {
2781+
"lesf2"
2782+
}
2783+
2784+
fn generate<R>(rng: &mut R) -> Option<Self>
2785+
where
2786+
R: Rng,
2787+
Self: Sized,
2788+
{
2789+
let a = gen_f32(rng);
2790+
let b = gen_f32(rng);
2791+
// TODO accept NaNs. We don't do that right now because we can't check
2792+
// for NaN-ness on the thumb targets (due to missing intrinsics)
2793+
if a.is_nan() || b.is_nan() {
2794+
return None;
2795+
}
2796+
2797+
let c;
2798+
if a.is_nan() || b.is_nan() {
2799+
c = 1;
2800+
} else if a < b {
2801+
c = -1;
2802+
} else if a > b {
2803+
c = 1;
2804+
} else {
2805+
c = 0;
2806+
}
2807+
2808+
Some(Lesf2 { a: to_u32(a), b: to_u32(b), c })
2809+
}
2810+
2811+
fn to_string(&self, buffer: &mut String) {
2812+
writeln!(
2813+
buffer,
2814+
"(({a}, {b}), {c}),",
2815+
a = self.a,
2816+
b = self.b,
2817+
c = self.c
2818+
)
2819+
.unwrap();
2820+
}
2821+
2822+
fn prologue() -> &'static str {
2823+
"
2824+
use std::mem;
2825+
use compiler_builtins::float::cmp::__lesf2;
2826+
2827+
fn to_f32(x: u32) -> f32 {
2828+
unsafe { mem::transmute(x) }
2829+
}
2830+
2831+
static TEST_CASES: &[((u32, u32), i32)] = &[
2832+
"
2833+
}
2834+
2835+
fn epilogue() -> &'static str {
2836+
"
2837+
];
2838+
2839+
#[test]
2840+
fn lesf2() {
2841+
for &((a, b), c) in TEST_CASES {
2842+
let c_ = __lesf2(to_f32(a), to_f32(b));
2843+
assert_eq!(((a, b), c), ((a, b), c_));
2844+
}
2845+
}
2846+
"
2847+
}
2848+
}
2849+
25322850
#[derive(Eq, Hash, PartialEq)]
25332851
pub struct Moddi3 {
25342852
a: i64,

src/float/cmp.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(unreachable_code)]
2+
13
use int::{Int, CastInto};
24
use float::Float;
35

@@ -35,18 +37,19 @@ fn cmp<F: Float>(a: F, b: F) -> Result where
3537
i32: CastInto<F::Int>,
3638
F::Int: CastInto<i32>,
3739
{
38-
let one = F::Int::ONE;
39-
let zero = F::Int::ZERO;
40+
let one = F::Int::ONE;
41+
let zero = F::Int::ZERO;
42+
let szero = F::SignedInt::ZERO;
4043

4144
let sign_bit = F::SIGN_MASK as F::Int;
4245
let abs_mask = sign_bit - one;
4346
let exponent_mask = F::EXPONENT_MASK;
4447
let inf_rep = exponent_mask;
4548

46-
let a_rep = a.repr();
47-
let b_rep = b.repr();
48-
let a_abs = a_rep & abs_mask;
49-
let b_abs = b_rep & abs_mask;
49+
let a_rep = a.repr();
50+
let b_rep = b.repr();
51+
let a_abs = a_rep & abs_mask;
52+
let b_abs = b_rep & abs_mask;
5053

5154
// If either a or b is NaN, they are unordered.
5255
if a_abs > inf_rep || b_abs > inf_rep {
@@ -58,12 +61,15 @@ fn cmp<F: Float>(a: F, b: F) -> Result where
5861
return Result::Equal
5962
}
6063

64+
let a_srep = a.signed_repr();
65+
let b_srep = b.signed_repr();
66+
6167
// If at least one of a and b is positive, we get the same result comparing
6268
// a and b as signed integers as we would with a fp_ting-point compare.
63-
if a_rep & b_rep >= zero {
64-
if a_rep < b_rep {
69+
if a_srep & b_srep >= szero {
70+
if a_srep < b_srep {
6571
return Result::Less
66-
} else if a_rep == b_rep {
72+
} else if a_srep == b_srep {
6773
return Result::Equal
6874
} else {
6975
return Result::Greater
@@ -75,9 +81,9 @@ fn cmp<F: Float>(a: F, b: F) -> Result where
7581
// complement integer representation; if integers are represented in a
7682
// sign-magnitude representation, then this flip is incorrect).
7783
else {
78-
if a_rep > b_rep {
84+
if a_srep > b_srep {
7985
return Result::Less
80-
} else if a_rep == b_rep {
86+
} else if a_srep == b_srep {
8187
return Result::Equal
8288
} else {
8389
return Result::Greater

0 commit comments

Comments
 (0)