Skip to content

Commit fc9b234

Browse files
Add IEEE754 tests
1 parent 2287a88 commit fc9b234

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

library/core/tests/num/ieee754.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//! IEEE 754 floating point compliance tests
2+
//!
3+
//! To understand IEEE 754's requirements on a programming language, one must understand that the
4+
//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any
5+
//! one component. That means the hardware, language, and even libraries are considered part of
6+
//! conforming floating point support in a programming environment.
7+
//!
8+
//! A programming language's duty, accordingly, is:
9+
//! 1. offer access to the hardware where the hardware offers support
10+
//! 2. provide operations that fulfill the remaining requirements of the standard
11+
//! 3. provide the ability to write additional software that can fulfill those requirements
12+
//!
13+
//! This may be fulfilled in any combination that the language sees fit. However, to claim that
14+
//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without
15+
//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined
16+
//! as complete support for at least one specified floating point type as an "arithmetic" and
17+
//! "interchange" format, plus specified type conversions to "external character sequences" and
18+
//! integer types.
19+
//!
20+
//! For our purposes,
21+
//! "interchange format" => f32, f64
22+
//! "arithmetic format" => f32, f64, and any "soft floats"
23+
//! "external character sequence" => str from any float
24+
//! "integer format" => {i,u}{8,16,32,64,128}
25+
//!
26+
//! None of these tests are against Rust's own implementation. They are only tests against the
27+
//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests.
28+
//! Please consider this carefully when adding, removing, or reorganizing these tests. They are
29+
//! here so that it is clear what tests are required by the standard and what can be changed.
30+
use ::core::str::FromStr;
31+
32+
// IEEE 754 for many tests is applied to specific bit patterns.
33+
// These generally are not applicable to NaN, however.
34+
macro_rules! assert_biteq {
35+
($lhs:expr, $rhs:expr) => {
36+
assert_eq!($lhs.to_bits(), $rhs.to_bits())
37+
};
38+
}
39+
40+
// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
41+
// of the formatting infrastructure, which makes it ideal for testing here.
42+
#[allow(unused_macros)]
43+
macro_rules! roundtrip {
44+
($f:expr => $t:ty) => {
45+
($f).to_string().parse::<$t>().unwrap()
46+
};
47+
}
48+
49+
macro_rules! assert_floats_roundtrip {
50+
($f:ident) => {
51+
assert_biteq!(f32::$f, roundtrip!(f32::$f => f32));
52+
assert_biteq!(f64::$f, roundtrip!(f64::$f => f64));
53+
};
54+
($f:expr) => {
55+
assert_biteq!($f as f32, roundtrip!($f => f32));
56+
assert_biteq!($f as f64, roundtrip!($f => f64));
57+
}
58+
}
59+
60+
macro_rules! assert_floats_bitne {
61+
($lhs:ident, $rhs:ident) => {
62+
assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits());
63+
assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits());
64+
};
65+
($lhs:expr, $rhs:expr) => {
66+
assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs));
67+
assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs));
68+
};
69+
}
70+
71+
// We must preserve signs on all numbers. That includes zero.
72+
// -0 and 0 are == normally, so test bit equality.
73+
#[test]
74+
fn preserve_signed_zero() {
75+
assert_floats_roundtrip!(-0.0);
76+
assert_floats_roundtrip!(0.0);
77+
assert_floats_bitne!(0.0, -0.0);
78+
}
79+
80+
#[test]
81+
fn preserve_signed_infinity() {
82+
assert_floats_roundtrip!(INFINITY);
83+
assert_floats_roundtrip!(NEG_INFINITY);
84+
assert_floats_bitne!(INFINITY, NEG_INFINITY);
85+
}
86+
87+
#[test]
88+
fn infinity_to_str() {
89+
assert!(match f32::INFINITY.to_string().to_lowercase().as_str() {
90+
"+infinity" | "infinity" => true,
91+
"+inf" | "inf" => true,
92+
_ => false,
93+
});
94+
assert!(
95+
match f64::INFINITY.to_string().to_lowercase().as_str() {
96+
"+infinity" | "infinity" => true,
97+
"+inf" | "inf" => true,
98+
_ => false,
99+
},
100+
"Infinity must write to a string as some casing of inf or infinity, with an optional +."
101+
);
102+
}
103+
104+
#[test]
105+
fn neg_infinity_to_str() {
106+
assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() {
107+
"-infinity" | "-inf" => true,
108+
_ => false,
109+
});
110+
assert!(
111+
match f64::NEG_INFINITY.to_string().to_lowercase().as_str() {
112+
"-infinity" | "-inf" => true,
113+
_ => false,
114+
},
115+
"Negative Infinity must write to a string as some casing of -inf or -infinity"
116+
)
117+
}
118+
119+
#[test]
120+
fn nan_to_str() {
121+
assert!(
122+
match f32::NAN.to_string().to_lowercase().as_str() {
123+
"nan" | "+nan" | "-nan" => true,
124+
_ => false,
125+
},
126+
"NaNs must write to a string as some casing of nan."
127+
)
128+
}
129+
130+
// "+"?("inf"|"infinity") in any case => Infinity
131+
#[test]
132+
fn infinity_from_str() {
133+
assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap());
134+
assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap());
135+
assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap());
136+
assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap());
137+
// yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd
138+
assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap());
139+
}
140+
141+
// "-inf"|"-infinity" in any case => Negative Infinity
142+
#[test]
143+
fn neg_infinity_from_str() {
144+
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap());
145+
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap());
146+
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap());
147+
assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap());
148+
}
149+
150+
// ("+"|"-"")?"s"?"nan" in any case => qNaN
151+
#[test]
152+
fn qnan_from_str() {
153+
assert!("nan".parse::<f32>().unwrap().is_nan());
154+
assert!("-nan".parse::<f32>().unwrap().is_nan());
155+
assert!("+nan".parse::<f32>().unwrap().is_nan());
156+
assert!("+NAN".parse::<f32>().unwrap().is_nan());
157+
assert!("-NaN".parse::<f32>().unwrap().is_nan());
158+
}

library/core/tests/num/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod flt2dec;
3232
mod ops;
3333
mod wrapping;
3434

35+
mod ieee754;
3536
mod nan;
3637

3738
/// Adds the attribute to all items in the block.

0 commit comments

Comments
 (0)