Skip to content

Commit 8b135b3

Browse files
committed
Add Quickcheck types for float tests
1 parent 5bf28a0 commit 8b135b3

File tree

3 files changed

+114
-117
lines changed

3 files changed

+114
-117
lines changed

src/float/add.rs

+11-104
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ macro_rules! add {
8787
if a_exponent.0 == 0 {
8888
let (exponent, significand) = <$ty>::normalize(a_significand.0);
8989
a_exponent = Wrapping(exponent);
90-
a_significand = Wrapping(significand);
90+
a_significand = Wrapping(significand);
9191
}
9292
if b_exponent.0 == 0 {
9393
let (exponent, significand) = <$ty>::normalize(b_significand.0);
9494
b_exponent = Wrapping(exponent);
95-
b_significand = Wrapping(significand);
95+
b_significand = Wrapping(significand);
9696
}
9797

9898
// The sign of the result is the sign of the larger operand, a. If they
@@ -121,8 +121,8 @@ macro_rules! add {
121121
if subtraction {
122122
a_significand -= b_significand;
123123
// If a == -b, return +zero.
124-
if a_significand.0 == 0 {
125-
return (<$ty as Float>::from_repr(0));
124+
if a_significand.0 == 0 {
125+
return (<$ty as Float>::from_repr(0));
126126
}
127127

128128
// If partial cancellation occured, we need to left-shift the result
@@ -146,7 +146,7 @@ macro_rules! add {
146146
}
147147

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

@@ -196,20 +196,18 @@ pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 {
196196

197197
#[cfg(test)]
198198
mod tests {
199-
use core::{f32, f64};
200-
use qc::{U32, U64};
201199
use float::Float;
200+
use qc::{F32, F64};
202201

203202
// NOTE The tests below have special handing for NaN values.
204-
// Because NaN != NaN, the floating-point representations must be used
203+
// Because NaN != NaN, the representations are compared
205204
// Because there are many diffferent values of NaN, and the implementation
206205
// doesn't care about calculating the 'correct' one, if both values are NaN
207206
// the values are considered equivalent.
208207

209-
// TODO: Add F32/F64 to qc so that they print the right values (at the very least)
210208
quickcheck! {
211-
fn addsf3(a: U32, b: U32) -> bool {
212-
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0));
209+
fn addsf3(a: F32, b: F32) -> bool {
210+
let (a, b) = (a.0, b.0);
213211
let x = super::__addsf3(a, b);
214212
let y = a + b;
215213
if !(x.is_nan() && y.is_nan()) {
@@ -219,8 +217,8 @@ mod tests {
219217
}
220218
}
221219

222-
fn adddf3(a: U64, b: U64) -> bool {
223-
let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0));
220+
fn adddf3(a: F64, b: F64) -> bool {
221+
let (a, b) = (a.0, b.0);
224222
let x = super::__adddf3(a, b);
225223
let y = a + b;
226224
if !(x.is_nan() && y.is_nan()) {
@@ -230,95 +228,4 @@ mod tests {
230228
}
231229
}
232230
}
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_eq!(r, 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_eq!(r, 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_eq!(r, 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_eq!(r, a + b);
264-
}
265-
266-
#[test]
267-
fn test_float_one_plus_one() {
268-
let r = super::__addsf3(1f32, 1f32);
269-
assert_eq!(r, 1f32 + 1f32);
270-
}
271-
272-
#[test]
273-
fn test_double_one_plus_one() {
274-
let r = super::__adddf3(1f64, 1f64);
275-
assert_eq!(r, 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-
if !(x.is_nan() && y.is_nan()) {
285-
assert_eq!(x.repr(), y.repr());
286-
}
287-
}
288-
289-
#[test]
290-
fn test_double_different_nan() {
291-
let a = f64::from_repr(1);
292-
let b = f64::from_repr(
293-
0b1111111111110010001000100101010101001000101010000110100011101011);
294-
let x = super::__adddf3(a, b);
295-
let y = a + b;
296-
if !(x.is_nan() && y.is_nan()) {
297-
assert_eq!(x.repr(), y.repr());
298-
}
299-
}
300-
301-
#[test]
302-
fn test_float_nan() {
303-
let r = super::__addsf3(f32::NAN, 1.23);
304-
assert_eq!(r.repr(), f32::NAN.repr());
305-
}
306-
307-
#[test]
308-
fn test_double_nan() {
309-
let r = super::__adddf3(f64::NAN, 1.23);
310-
assert_eq!(r.repr(), f64::NAN.repr());
311-
}
312-
313-
#[test]
314-
fn test_float_inf() {
315-
let r = super::__addsf3(f32::INFINITY, -123.4);
316-
assert_eq!(r, f32::INFINITY);
317-
}
318-
319-
#[test]
320-
fn test_double_inf() {
321-
let r = super::__adddf3(f64::INFINITY, -123.4);
322-
assert_eq!(r, f64::INFINITY);
323-
}
324231
}

src/float/mod.rs

+51-13
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,11 +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-
/// Returns a `Self::Int` transmuted back to `Self`
23-
fn from_repr(a: Self::Int) -> Self;
22+
/// Returns a mask for the exponent portion of `self`
23+
fn exponent_mask() -> Self::Int;
24+
25+
/// Returns a mask for the significand portion of `self`
26+
fn significand_mask() -> Self::Int;
2427

2528
/// Returns the sign bit of `self`
2629
fn sign(self) -> bool;
@@ -31,6 +34,15 @@ pub trait Float: Sized {
3134
/// Returns the significand portion of `self`
3235
fn significand(self) -> Self::Int;
3336

37+
/// Returns `self` transmuted to `Self::Int`
38+
fn repr(self) -> Self::Int;
39+
40+
/// Returns a `Self::Int` transmuted back to `Self`
41+
fn from_repr(a: Self::Int) -> Self;
42+
43+
/// Constructs a `Self` from its parts
44+
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;
45+
3446
/// Returns (normalized exponent, normalized significand)
3547
fn normalize(significand: Self::Int) -> (i32, Self::Int);
3648
}
@@ -46,21 +58,34 @@ impl Float for f32 {
4658
fn significand_bits() -> u32 {
4759
23
4860
}
61+
fn sign_mask() -> Self::Int {
62+
1 << (Self::bits() - 1)
63+
}
64+
fn exponent_mask() -> Self::Int {
65+
((1 << Self::exponent_bits()) - 1) << Self::significand_bits()
66+
}
67+
fn significand_mask() -> Self::Int {
68+
(1 << Self::significand_bits()) - 1
69+
}
4970
fn repr(self) -> Self::Int {
5071
unsafe { mem::transmute(self) }
5172
}
5273
fn from_repr(a: Self::Int) -> Self {
5374
unsafe { mem::transmute(a) }
5475
}
76+
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
77+
Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) |
78+
exponent & Self::exponent_mask() |
79+
significand & Self::significand_mask())
80+
}
5581
fn sign(self) -> bool {
56-
(self.repr() & 1 << Self::bits()) != 0
82+
(self.repr() & Self::sign_mask()) != 0
5783
}
5884
fn exponent(self) -> Self::Int {
59-
self.repr() >> Self::significand_bits()
60-
& ((1 << Self::exponent_bits()) - 1)
85+
self.repr() >> Self::significand_bits() & Self::exponent_mask()
6186
}
6287
fn significand(self) -> Self::Int {
63-
self.repr() & ((1 << Self::significand_bits()) - 1)
88+
self.repr() & Self::significand_mask()
6489
}
6590
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
6691
let shift = significand.leading_zeros()
@@ -79,21 +104,34 @@ impl Float for f64 {
79104
fn significand_bits() -> u32 {
80105
52
81106
}
107+
fn sign_mask() -> Self::Int {
108+
1 << (Self::bits() - 1)
109+
}
110+
fn exponent_mask() -> Self::Int {
111+
((1 << Self::exponent_bits()) - 1) << Self::significand_bits()
112+
}
113+
fn significand_mask() -> Self::Int {
114+
(1 << Self::significand_bits()) - 1
115+
}
82116
fn repr(self) -> Self::Int {
83117
unsafe { mem::transmute(self) }
84118
}
85119
fn from_repr(a: Self::Int) -> Self {
86120
unsafe { mem::transmute(a) }
87121
}
122+
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
123+
Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) |
124+
exponent & Self::exponent_mask() |
125+
significand & Self::significand_mask())
126+
}
88127
fn sign(self) -> bool {
89-
(self.repr() & 1 << Self::bits()) != 0
128+
(self.repr() & Self::sign_mask()) != 0
90129
}
91130
fn exponent(self) -> Self::Int {
92-
self.repr() >> Self::significand_bits()
93-
& ((1 << Self::exponent_bits()) - 1)
131+
self.repr() >> Self::significand_bits() & Self::exponent_mask()
94132
}
95133
fn significand(self) -> Self::Int {
96-
self.repr() & ((1 << Self::significand_bits()) - 1)
134+
self.repr() & Self::significand_mask()
97135
}
98136
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
99137
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 {
@@ -121,3 +123,53 @@ macro_rules! arbitrary_large {
121123

122124
arbitrary_large!(I64: i64);
123125
arbitrary_large!(U64: u64);
126+
127+
macro_rules! arbitrary_float {
128+
($TY:ident : $ty:ident) => {
129+
#[derive(Clone, Copy)]
130+
pub struct $TY(pub $ty);
131+
132+
impl Arbitrary for $TY {
133+
fn arbitrary<G>(g: &mut G) -> $TY
134+
where G: Gen
135+
{
136+
let special = [
137+
-0.0, 0.0, 1.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY
138+
];
139+
140+
if g.gen() { // Random special case
141+
let index: usize = g.gen();
142+
$TY(special[index % special.len()])
143+
} else if g.gen() { // Random anything
144+
let sign: bool = g.gen();
145+
let exponent: <$ty as Float>::Int = g.gen();
146+
let significand: <$ty as Float>::Int = g.gen();
147+
$TY($ty::from_parts(sign, exponent, significand))
148+
} else if g.gen() { // Denormalized
149+
let sign: bool = g.gen();
150+
let exponent: <$ty as Float>::Int = 0;
151+
let significand: <$ty as Float>::Int = g.gen();
152+
$TY($ty::from_parts(sign, exponent, significand))
153+
} else { // NaN variants
154+
let sign: bool = g.gen();
155+
let exponent: <$ty as Float>::Int = g.gen();
156+
let significand: <$ty as Float>::Int = 0;
157+
$TY($ty::from_parts(sign, exponent, significand))
158+
}
159+
}
160+
161+
fn shrink(&self) -> Box<Iterator<Item=$TY>> {
162+
::quickcheck::empty_shrinker()
163+
}
164+
}
165+
166+
impl fmt::Debug for $TY {
167+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168+
fmt::Debug::fmt(&self.0, f)
169+
}
170+
}
171+
}
172+
}
173+
174+
arbitrary_float!(F32: f32);
175+
arbitrary_float!(F64: f64);

0 commit comments

Comments
 (0)