]> git.lizzy.rs Git - rust.git/blob - library/core/tests/num/ieee754.rs
Auto merge of #106827 - alexcrichton:update-llvm-to-15.0.7, r=cuviper
[rust.git] / library / core / tests / num / ieee754.rs
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 }