1#![no_std]
22#![cfg_attr(feature = "f16", feature(f16))]
23#![cfg_attr(feature = "f128", feature(f128))]
24#![allow(missing_docs)]
25
26#[macro_use]
27mod macros;
28
29mod helpers;
30
31define! {
32 #[doc = "A newtype containing the raw bits of a Google BFloat16 floating point number."]
33 #[doc = ""]
34 #[doc = "Values of this type are hashable and have a well-defined total order: the one given "]
35 #[doc = "by [`Self::total_cmp`]. As a consequence, `+0.0` is not equal to `-0.0`, and NaN "]
36 #[doc = "compares equal to NaN if both NaN values have exactly the same bit pattern."]
37 pub struct BF16;
38 size 16 bits;
39 exp 8 bits;
40 repr u16 / i16;
41}
42
43define! {
44 #[doc = "A newtype containing the raw bits of an IEEE 754 binary16 floating point number."]
45 #[doc = ""]
46 #[doc = "Values of this type are hashable and have a well-defined total order: the one given "]
47 #[doc = "by [`Self::total_cmp`]. As a consequence, `+0.0` is not equal to `-0.0`, and NaN "]
48 #[doc = "compares equal to NaN if both NaN values have exactly the same bit pattern."]
49 #[doc = ""]
50 #[doc = "# Features"]
51 #[doc = ""]
52 #[doc = "Crate feature `f16` enables use of the Rust [`f16`] primitive type, which is a"]
53 #[doc = "nightly-only language feature that's only functional on certain architectures."]
54 pub struct F16;
55 size 16 bits;
56 exp 5 bits;
57 repr u16 / i16;
58 float f16 with feature "f16";
59}
60
61define! {
62 #[doc = "A newtype containing the raw bits of an IEEE 754 binary32 floating point number."]
63 #[doc = ""]
64 #[doc = "Values of this type are hashable and have a well-defined total order: the one given "]
65 #[doc = "by [`Self::total_cmp`]. As a consequence, `+0.0` is not equal to `-0.0`, and NaN "]
66 #[doc = "compares equal to NaN if both NaN values have exactly the same bit pattern."]
67 pub struct F32;
68 size 32 bits;
69 exp 8 bits;
70 repr u32 / i32;
71 float f32;
72}
73
74define! {
75 #[doc = "A newtype containing the raw bits of an IEEE 754 binary64 floating point number."]
76 #[doc = ""]
77 #[doc = "Values of this type are hashable and have a well-defined total order: the one given "]
78 #[doc = "by [`Self::total_cmp`]. As a consequence, `+0.0` is not equal to `-0.0`, and NaN "]
79 #[doc = "compares equal to NaN if both NaN values have exactly the same bit pattern."]
80 pub struct F64;
81 size 64 bits;
82 exp 11 bits;
83 repr u64 / i64;
84 float f64;
85}
86
87define! {
88 #[doc = "A newtype containing the raw bits of an IEEE 754 binary128 floating point number."]
89 #[doc = ""]
90 #[doc = "Values of this type are hashable and have a well-defined total order: the one given "]
91 #[doc = "by [`Self::total_cmp`]. As a consequence, `+0.0` is not equal to `-0.0`, and NaN "]
92 #[doc = "compares equal to NaN if both NaN values have exactly the same bit pattern."]
93 #[doc = ""]
94 #[doc = "# Features"]
95 #[doc = ""]
96 #[doc = "Crate feature `f128` enables use of the Rust [`f128`] primitive type, which is a"]
97 #[doc = "nightly-only language feature that's only functional on certain architectures."]
98 pub struct F128;
99 size 128 bits;
100 exp 15 bits;
101 repr u128 / i128;
102 float f128 with feature "f128";
103}
104
105impl core::fmt::Display for F64 {
106 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107 let val = self.to_float();
108 core::fmt::Display::fmt(&val, f)
109 }
110}
111
112impl core::str::FromStr for F64 {
113 type Err = core::num::ParseFloatError;
114 fn from_str(s: &str) -> Result<Self, Self::Err> {
115 Ok(Self::from_float(s.parse()?))
116 }
117}
118
119impl core::fmt::Display for F32 {
120 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 let val = self.to_float();
122 core::fmt::Display::fmt(&val, f)
123 }
124}
125
126impl core::str::FromStr for F32 {
127 type Err = core::num::ParseFloatError;
128 fn from_str(s: &str) -> Result<Self, Self::Err> {
129 Ok(Self::from_float(s.parse()?))
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use core::num::FpCategory;
136
137 use super::*;
138 use crate::helpers::{C_INF, C_NAN, C_NORM, C_ZERO};
139
140 #[test]
141 fn f32_smoke_test() {
142 const P_ZERO: F32 = F32::ZERO;
143 const N_ZERO: F32 = F32::NEG_ZERO;
144 const P_TINY: F32 = F32::MIN_POSITIVE;
145 const N_TINY: F32 = F32::MAX_NEGATIVE;
146 const P_ONE: F32 = F32::ONE;
147 const N_ONE: F32 = F32::NEG_ONE;
148 const P_MAX: F32 = F32::MAX;
149 const N_MAX: F32 = F32::MIN;
150 const P_INF: F32 = F32::INFINITY;
151 const N_INF: F32 = F32::NEG_INFINITY;
152 const P_QNAN: F32 = F32::QNAN;
153 const P_SNAN: F32 = F32::SNAN;
154 const N_QNAN: F32 = F32::NEG_QNAN;
155 const N_SNAN: F32 = F32::NEG_SNAN;
156
157 type Row = (u32, FpCategory, bool, F32, f32);
158 const ROWS: [Row; 14] = [
159 (0x00000000, C_ZERO, false, P_ZERO, 0.0),
160 (0x80000000, C_ZERO, true, N_ZERO, -0.0),
161 (0x00800000, C_NORM, false, P_TINY, f32::MIN_POSITIVE),
162 (0x80800000, C_NORM, true, N_TINY, -f32::MIN_POSITIVE),
163 (0x3f800000, C_NORM, false, P_ONE, 1.0),
164 (0xbf800000, C_NORM, true, N_ONE, -1.0),
165 (0x7f7fffff, C_NORM, false, P_MAX, f32::MAX),
166 (0xff7fffff, C_NORM, true, N_MAX, -f32::MAX),
167 (0x7f800000, C_INF, false, P_INF, f32::INFINITY),
168 (0xff800000, C_INF, true, N_INF, f32::NEG_INFINITY),
169 (0x7f800001, C_NAN, false, P_SNAN, f32::NAN),
170 (0x7fc00001, C_NAN, false, P_QNAN, f32::NAN),
171 (0xff800001, C_NAN, true, N_SNAN, f32::NAN),
172 (0xffc00001, C_NAN, true, N_QNAN, f32::NAN),
173 ];
174 for (bits, class, neg, val, float) in ROWS {
175 assert_eq!(neg, val.is_sign_negative());
176 assert_eq!(class, val.classify());
177 assert_eq!(float.is_nan(), val.is_nan());
178 if !val.is_nan() {
179 assert_eq!(float, val.to_float());
180 }
181 assert_eq!(bits, val.to_bits());
182 }
183 }
184
185 #[test]
186 fn f64_smoke_test() {
187 const P_ZERO: F64 = F64::ZERO;
188 const N_ZERO: F64 = F64::NEG_ZERO;
189 const P_TINY: F64 = F64::MIN_POSITIVE;
190 const N_TINY: F64 = F64::MAX_NEGATIVE;
191 const P_ONE: F64 = F64::ONE;
192 const N_ONE: F64 = F64::NEG_ONE;
193 const P_MAX: F64 = F64::MAX;
194 const N_MAX: F64 = F64::MIN;
195 const P_INF: F64 = F64::INFINITY;
196 const N_INF: F64 = F64::NEG_INFINITY;
197 const P_QNAN: F64 = F64::QNAN;
198 const P_SNAN: F64 = F64::SNAN;
199 const N_QNAN: F64 = F64::NEG_QNAN;
200 const N_SNAN: F64 = F64::NEG_SNAN;
201
202 type Row = (u64, FpCategory, bool, F64, f64);
203 const ROWS: [Row; 14] = [
204 (0x0000000000000000, C_ZERO, false, P_ZERO, 0.0),
205 (0x8000000000000000, C_ZERO, true, N_ZERO, -0.0),
206 (0x0010000000000000, C_NORM, false, P_TINY, f64::MIN_POSITIVE),
207 (0x8010000000000000, C_NORM, true, N_TINY, -f64::MIN_POSITIVE),
208 (0x3ff0000000000000, C_NORM, false, P_ONE, 1.0),
209 (0xbff0000000000000, C_NORM, true, N_ONE, -1.0),
210 (0x7fefffffffffffff, C_NORM, false, P_MAX, f64::MAX),
211 (0xffefffffffffffff, C_NORM, true, N_MAX, -f64::MAX),
212 (0x7ff0000000000000, C_INF, false, P_INF, f64::INFINITY),
213 (0xfff0000000000000, C_INF, true, N_INF, f64::NEG_INFINITY),
214 (0x7ff0000000000001, C_NAN, false, P_SNAN, f64::NAN),
215 (0x7ff8000000000001, C_NAN, false, P_QNAN, f64::NAN),
216 (0xfff0000000000001, C_NAN, true, N_SNAN, f64::NAN),
217 (0xfff8000000000001, C_NAN, true, N_QNAN, f64::NAN),
218 ];
219 for (bits, class, neg, val, float) in ROWS {
220 assert_eq!(neg, val.is_sign_negative());
221 assert_eq!(class, val.classify());
222 assert_eq!(float.is_nan(), val.is_nan());
223 if !val.is_nan() {
224 assert_eq!(float, val.to_float());
225 }
226 assert_eq!(bits, val.to_bits());
227 }
228 }
229}