1 //! IEEE 754 floating point compliance tests
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.
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
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
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}
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;
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())
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()
49 macro_rules! assert_floats_roundtrip {
51 assert_biteq!(f32::$f, roundtrip!(f32::$f => f32));
52 assert_biteq!(f64::$f, roundtrip!(f64::$f => f64));
55 assert_biteq!($f as f32, roundtrip!($f => f32));
56 assert_biteq!($f as f64, roundtrip!($f => f64));
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());
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));
71 // We must preserve signs on all numbers. That includes zero.
72 // -0 and 0 are == normally, so test bit equality.
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);
81 fn preserve_signed_infinity() {
82 assert_floats_roundtrip!(INFINITY);
83 assert_floats_roundtrip!(NEG_INFINITY);
84 assert_floats_bitne!(INFINITY, NEG_INFINITY);
88 fn infinity_to_str() {
89 assert!(match f32::INFINITY.to_string().to_lowercase().as_str() {
90 "+infinity" | "infinity" => true,
91 "+inf" | "inf" => true,
95 match f64::INFINITY.to_string().to_lowercase().as_str() {
96 "+infinity" | "infinity" => true,
97 "+inf" | "inf" => true,
100 "Infinity must write to a string as some casing of inf or infinity, with an optional +."
105 fn neg_infinity_to_str() {
106 assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() {
107 "-infinity" | "-inf" => true,
111 match f64::NEG_INFINITY.to_string().to_lowercase().as_str() {
112 "-infinity" | "-inf" => true,
115 "Negative Infinity must write to a string as some casing of -inf or -infinity"
122 match f32::NAN.to_string().to_lowercase().as_str() {
123 "nan" | "+nan" | "-nan" => true,
126 "NaNs must write to a string as some casing of nan."
130 // "+"?("inf"|"infinity") in any case => Infinity
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());
141 // "-inf"|"-infinity" in any case => Negative Infinity
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());
150 // ("+"|"-"")?"s"?"nan" in any case => qNaN
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());