Skip to content

Commit f31b606

Browse files
matticoMatthew Ickstadt
authored and
Matthew Ickstadt
committed
Add Quickcheck types for float tests
1 parent 3f254ca commit f31b606

File tree

3 files changed

+118
-121
lines changed

3 files changed

+118
-121
lines changed

src/float/add.rs

+9-103
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,12 @@ macro_rules! add {
8989
if a_exponent.0 == 0 {
9090
let (exponent, significand) = <$ty>::normalize(a_significand.0);
9191
a_exponent = Wrapping(exponent);
92-
a_significand = Wrapping(significand);
92+
a_significand = Wrapping(significand);
9393
}
9494
if b_exponent.0 == 0 {
9595
let (exponent, significand) = <$ty>::normalize(b_significand.0);
9696
b_exponent = Wrapping(exponent);
97-
b_significand = Wrapping(significand);
97+
b_significand = Wrapping(significand);
9898
}
9999

100100
// The sign of the result is the sign of the larger operand, a. If they
@@ -123,8 +123,8 @@ macro_rules! add {
123123
if subtraction {
124124
a_significand -= b_significand;
125125
// If a == -b, return +zero.
126-
if a_significand.0 == 0 {
127-
return (<$ty as Float>::from_repr(0));
126+
if a_significand.0 == 0 {
127+
return (<$ty as Float>::from_repr(0));
128128
}
129129

130130
// If partial cancellation occured, we need to left-shift the result
@@ -148,7 +148,7 @@ macro_rules! add {
148148
}
149149

150150
// If we have overflowed the type, return +/- infinity:
151-
if a_exponent >= Wrapping(max_exponent.0 as i32) {
151+
if a_exponent >= Wrapping(max_exponent.0 as i32) {
152152
return (<$ty>::from_repr((inf_rep | result_sign).0));
153153
}
154154

@@ -193,16 +193,9 @@ mod tests {
193193
use gcc_s;
194194
use rand;
195195

196-
// NOTE The tests below have special handing for NaN values.
197-
// Because NaN != NaN, the floating-point representations must be used
198-
// Because there are many diffferent values of NaN, and the implementation
199-
// doesn't care about calculating the 'correct' one, if both values are NaN
200-
// the values are considered equivalent.
201-
202-
// TODO: Add F32/F64 to qc so that they print the right values (at the very least)
203196
quickcheck! {
204-
fn addsf3(a: U32, b: U32) -> bool {
205-
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0));
197+
fn addsf3(a: F32, b: F32) -> bool {
198+
let (a, b) = (a.0, b.0);
206199
let x = super::__addsf3(a, b);
207200

208201
match gcc_s::addsf3() {
@@ -217,8 +210,8 @@ mod tests {
217210
}
218211
}
219212

220-
fn adddf3(a: U64, b: U64) -> bool {
221-
let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0));
213+
fn adddf3(a: F64, b: F64) -> bool {
214+
let (a, b) = (a.0, b.0);
222215
let x = super::__adddf3(a, b);
223216

224217
match gcc_s::adddf3() {
@@ -230,91 +223,4 @@ mod tests {
230223
}
231224
}
232225
}
233-
234-
// More tests for special float values
235-
236-
#[test]
237-
fn test_float_tiny_plus_tiny() {
238-
let tiny = f32::from_repr(1);
239-
let r = super::__addsf3(tiny, tiny);
240-
assert!(r.eq_repr(tiny + tiny));
241-
}
242-
243-
#[test]
244-
fn test_double_tiny_plus_tiny() {
245-
let tiny = f64::from_repr(1);
246-
let r = super::__adddf3(tiny, tiny);
247-
assert!(r.eq_repr(tiny + tiny));
248-
}
249-
250-
#[test]
251-
fn test_float_small_plus_small() {
252-
let a = f32::from_repr(327);
253-
let b = f32::from_repr(256);
254-
let r = super::__addsf3(a, b);
255-
assert!(r.eq_repr(a + b));
256-
}
257-
258-
#[test]
259-
fn test_double_small_plus_small() {
260-
let a = f64::from_repr(327);
261-
let b = f64::from_repr(256);
262-
let r = super::__adddf3(a, b);
263-
assert!(r.eq_repr(a + b));
264-
}
265-
266-
#[test]
267-
fn test_float_one_plus_one() {
268-
let r = super::__addsf3(1f32, 1f32);
269-
assert!(r.eq_repr(1f32 + 1f32));
270-
}
271-
272-
#[test]
273-
fn test_double_one_plus_one() {
274-
let r = super::__adddf3(1f64, 1f64);
275-
assert!(r.eq_repr(1f64 + 1f64));
276-
}
277-
278-
#[test]
279-
fn test_float_different_nan() {
280-
let a = f32::from_repr(1);
281-
let b = f32::from_repr(0b11111111100100010001001010101010);
282-
let x = super::__addsf3(a, b);
283-
let y = a + b;
284-
assert!(x.eq_repr(y));
285-
}
286-
287-
#[test]
288-
fn test_double_different_nan() {
289-
let a = f64::from_repr(1);
290-
let b = f64::from_repr(
291-
0b1111111111110010001000100101010101001000101010000110100011101011);
292-
let x = super::__adddf3(a, b);
293-
let y = a + b;
294-
assert!(x.eq_repr(y));
295-
}
296-
297-
#[test]
298-
fn test_float_nan() {
299-
let r = super::__addsf3(f32::NAN, 1.23);
300-
assert_eq!(r.repr(), f32::NAN.repr());
301-
}
302-
303-
#[test]
304-
fn test_double_nan() {
305-
let r = super::__adddf3(f64::NAN, 1.23);
306-
assert_eq!(r.repr(), f64::NAN.repr());
307-
}
308-
309-
#[test]
310-
fn test_float_inf() {
311-
let r = super::__addsf3(f32::INFINITY, -123.4);
312-
assert_eq!(r, f32::INFINITY);
313-
}
314-
315-
#[test]
316-
fn test_double_inf() {
317-
let r = super::__adddf3(f64::INFINITY, -123.4);
318-
assert_eq!(r, f64::INFINITY);
319-
}
320226
}

src/float/mod.rs

+57-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod add;
66
pub trait Float: Sized {
77
/// A uint of the same with as the float
88
type Int;
9-
9+
1010
/// Returns the bitwidth of the float type
1111
fn bits() -> u32;
1212

@@ -16,17 +16,14 @@ pub trait Float: Sized {
1616
/// Returns the bitwidth of the significand
1717
fn significand_bits() -> u32;
1818

19-
/// Returns `self` transmuted to `Self::Int`
20-
fn repr(self) -> Self::Int;
19+
/// Returns a mask for the sign bit of `self`
20+
fn sign_mask() -> Self::Int;
2121

22-
#[cfg(test)]
23-
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
24-
/// represented in multiple different ways. This methods returns `true` if two NaNs are
25-
/// compared.
26-
fn eq_repr(self, rhs: Self) -> bool;
22+
/// Returns a mask for the exponent portion of `self`
23+
fn exponent_mask() -> Self::Int;
2724

28-
/// Returns a `Self::Int` transmuted back to `Self`
29-
fn from_repr(a: Self::Int) -> Self;
25+
/// Returns a mask for the significand portion of `self`
26+
fn significand_mask() -> Self::Int;
3027

3128
/// Returns the sign bit of `self`
3229
fn sign(self) -> bool;
@@ -37,6 +34,21 @@ pub trait Float: Sized {
3734
/// Returns the significand portion of `self`
3835
fn significand(self) -> Self::Int;
3936

37+
/// Returns `self` transmuted to `Self::Int`
38+
fn repr(self) -> Self::Int;
39+
40+
#[cfg(test)]
41+
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
42+
/// represented in multiple different ways. This methods returns `true` if two NaNs are
43+
/// compared.
44+
fn eq_repr(self, rhs: Self) -> bool;
45+
46+
/// Returns a `Self::Int` transmuted back to `Self`
47+
fn from_repr(a: Self::Int) -> Self;
48+
49+
/// Constructs a `Self` from its parts
50+
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;
51+
4052
/// Returns (normalized exponent, normalized significand)
4153
fn normalize(significand: Self::Int) -> (i32, Self::Int);
4254
}
@@ -52,6 +64,15 @@ impl Float for f32 {
5264
fn significand_bits() -> u32 {
5365
23
5466
}
67+
fn sign_mask() -> Self::Int {
68+
1 << (Self::bits() - 1)
69+
}
70+
fn exponent_mask() -> Self::Int {
71+
((1 << Self::exponent_bits()) - 1) << Self::significand_bits()
72+
}
73+
fn significand_mask() -> Self::Int {
74+
(1 << Self::significand_bits()) - 1
75+
}
5576
fn repr(self) -> Self::Int {
5677
unsafe { mem::transmute(self) }
5778
}
@@ -66,15 +87,20 @@ impl Float for f32 {
6687
fn from_repr(a: Self::Int) -> Self {
6788
unsafe { mem::transmute(a) }
6889
}
90+
91+
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
92+
Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) |
93+
exponent & Self::exponent_mask() |
94+
significand & Self::significand_mask())
95+
}
6996
fn sign(self) -> bool {
70-
(self.repr() & 1 << Self::bits()) != 0
97+
(self.repr() & Self::sign_mask()) != 0
7198
}
7299
fn exponent(self) -> Self::Int {
73-
self.repr() >> Self::significand_bits()
74-
& ((1 << Self::exponent_bits()) - 1)
100+
self.repr() >> Self::significand_bits() & Self::exponent_mask()
75101
}
76102
fn significand(self) -> Self::Int {
77-
self.repr() & ((1 << Self::significand_bits()) - 1)
103+
self.repr() & Self::significand_mask()
78104
}
79105
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
80106
let shift = significand.leading_zeros()
@@ -93,6 +119,15 @@ impl Float for f64 {
93119
fn significand_bits() -> u32 {
94120
52
95121
}
122+
fn sign_mask() -> Self::Int {
123+
1 << (Self::bits() - 1)
124+
}
125+
fn exponent_mask() -> Self::Int {
126+
((1 << Self::exponent_bits()) - 1) << Self::significand_bits()
127+
}
128+
fn significand_mask() -> Self::Int {
129+
(1 << Self::significand_bits()) - 1
130+
}
96131
fn repr(self) -> Self::Int {
97132
unsafe { mem::transmute(self) }
98133
}
@@ -107,15 +142,19 @@ impl Float for f64 {
107142
fn from_repr(a: Self::Int) -> Self {
108143
unsafe { mem::transmute(a) }
109144
}
145+
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
146+
Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) |
147+
exponent & Self::exponent_mask() |
148+
significand & Self::significand_mask())
149+
}
110150
fn sign(self) -> bool {
111-
(self.repr() & 1 << Self::bits()) != 0
151+
(self.repr() & Self::sign_mask()) != 0
112152
}
113153
fn exponent(self) -> Self::Int {
114-
self.repr() >> Self::significand_bits()
115-
& ((1 << Self::exponent_bits()) - 1)
154+
self.repr() >> Self::significand_bits() & Self::exponent_mask()
116155
}
117156
fn significand(self) -> Self::Int {
118-
self.repr() & ((1 << Self::significand_bits()) - 1)
157+
self.repr() & Self::significand_mask()
119158
}
120159
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
121160
let shift = significand.leading_zeros()

src/qc.rs

+52
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
use std::boxed::Box;
77
use std::fmt;
8+
use core::{f32, f64};
89

910
use quickcheck::{Arbitrary, Gen};
1011

1112
use int::LargeInt;
13+
use float::Float;
1214

1315
// Generates values in the full range of the integer type
1416
macro_rules! arbitrary {
@@ -142,3 +144,53 @@ macro_rules! arbitrary_large {
142144

143145
arbitrary_large!(I64: i64);
144146
arbitrary_large!(U64: u64);
147+
148+
macro_rules! arbitrary_float {
149+
($TY:ident : $ty:ident) => {
150+
#[derive(Clone, Copy)]
151+
pub struct $TY(pub $ty);
152+
153+
impl Arbitrary for $TY {
154+
fn arbitrary<G>(g: &mut G) -> $TY
155+
where G: Gen
156+
{
157+
let special = [
158+
-0.0, 0.0, 1.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY
159+
];
160+
161+
if g.gen() { // Random special case
162+
let index: usize = g.gen();
163+
$TY(special[index % special.len()])
164+
} else if g.gen() { // Random anything
165+
let sign: bool = g.gen();
166+
let exponent: <$ty as Float>::Int = g.gen();
167+
let significand: <$ty as Float>::Int = g.gen();
168+
$TY($ty::from_parts(sign, exponent, significand))
169+
} else if g.gen() { // Denormalized
170+
let sign: bool = g.gen();
171+
let exponent: <$ty as Float>::Int = 0;
172+
let significand: <$ty as Float>::Int = g.gen();
173+
$TY($ty::from_parts(sign, exponent, significand))
174+
} else { // NaN variants
175+
let sign: bool = g.gen();
176+
let exponent: <$ty as Float>::Int = g.gen();
177+
let significand: <$ty as Float>::Int = 0;
178+
$TY($ty::from_parts(sign, exponent, significand))
179+
}
180+
}
181+
182+
fn shrink(&self) -> Box<Iterator<Item=$TY>> {
183+
::quickcheck::empty_shrinker()
184+
}
185+
}
186+
187+
impl fmt::Debug for $TY {
188+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189+
fmt::Debug::fmt(&self.0, f)
190+
}
191+
}
192+
}
193+
}
194+
195+
arbitrary_float!(F32: f32);
196+
arbitrary_float!(F64: f64);

0 commit comments

Comments
 (0)