1#![doc = include_str!("../README.md")]
2#![doc = include_str!("doc/encoded_reserved.doc")]
4#![doc = include_str!("doc/vax_ieee_754_diffs.doc")]
6
7#![forbid(future_incompatible)]
8#![warn(missing_docs, missing_debug_implementations, bare_trait_objects)]
9
10use forward_ref::{
11 forward_ref_binop,
12 forward_ref_op_assign,
13 forward_ref_unop,
14};
15use std::{
16 cmp::Ordering,
17 fmt::{self, Debug, Display, Formatter, LowerExp, UpperExp},
18 hash::{Hash, Hasher},
19 ops::{
20 Add,
21 AddAssign,
22 Div,
23 DivAssign,
24 Mul,
25 MulAssign,
26 Sub,
27 SubAssign,
28 Neg,
29 Shl,
30 ShlAssign,
31 Shr,
32 ShrAssign,
33 },
34 str::FromStr,
35};
36
37pub mod error;
38pub mod arithmetic;
39#[cfg(any(test, feature = "proptest"))]
40pub mod proptest;
41
42pub use crate::{
43 error::{Error, Result},
44 arithmetic::{Fault, Sign, VaxFloatingPoint},
45};
46
47macro_rules! swap_words_impl {
49 (u32) => {
50 const fn swap_words(value: u32) -> u32 {
52 value.rotate_right(16)
53 }
54 };
55 (u64) => {
56 const fn swap_words(value: u64) -> u64 {
58 let low = value as u32;
59 let low = low.rotate_right(16) as u64;
60 let high = (value >> 32) as u32;
61 let high = high.rotate_right(16) as u64;
62 (low << 32) | high
63 }
64 };
65 (u128) => {
66 const fn swap_words(value: u128) -> u128 {
68 let low_low = value as u32;
69 let low_low = low_low.rotate_right(16) as u128;
70 let low_high = (value >> 32) as u32;
71 let low_high = low_high.rotate_right(16) as u128;
72 let high_low = (value >> 64) as u32;
73 let high_low = high_low.rotate_right(16) as u128;
74 let high_high = (value >> 96) as u32;
75 let high_high = high_high.rotate_right(16) as u128;
76 (low_low << 96) | (low_high << 64) | (high_low << 32) | high_high
77 }
78 };
79}
80
81macro_rules! zero_ext_hex {
83 (FFloating) => {"{:#010X}"};
84 (DFloating) => {"{:#018X}"};
85 (GFloating) => {"{:#018X}"};
86 (HFloating) => {"{:#034X}"};
87}
88
89macro_rules! vax_fp_bits {
91 (FFloating, 1.5) => {"0x000040C0"};
92 (DFloating, 1.5) => {"0x00000000000040C0"};
93 (GFloating, 1.5) => {"0x0000000000004018"};
94 (HFloating, 1.5) => {"0x0000000000000000000000000080004001"};
95 (FFloating, 12.5) => {"0x00004248"};
96 (DFloating, 12.5) => {"0x0000000000004248"};
97 (GFloating, 12.5) => {"0x0000000000004049"};
98 (HFloating, 12.5) => {"0x0000000000000000000000000090004004"};
99 (FFloating, 10.0) => {"0x00004220"};
100 (DFloating, 10.0) => {"0x0000000000004220"};
101 (GFloating, 10.0) => {"0x0000000000004044"};
102 (HFloating, 10.0) => {"0x00000000000000000000000040004004"};
103 (FFloating, -10.0) => {"0x0000C220"};
104 (DFloating, -10.0) => {"0x000000000000C220"};
105 (GFloating, -10.0) => {"0x000000000000C044"};
106 (HFloating, -10.0) => {"0x0000000000000000000000004000C004"};
107}
108
109macro_rules! to_from_rust_fp_impl {
121 (u32, $SelfT: ident) => {
122 to_from_rust_fp_impl!(u32, $SelfT, f32, to_f32, from_f32);
123 };
124 ($ux: ident, $SelfT: ident) => {
125 to_from_rust_fp_impl!($ux, $SelfT, f32, to_f32, from_f32);
126 to_from_rust_fp_impl!($ux, $SelfT, f64, to_f64, from_f64);
127 };
128 (From, u32, $SelfT: ident) => {
129 to_from_rust_fp_impl!(From, u32, $SelfT, f32, to_f32, from_f32);
130 };
131 (From, $ux: ident, $SelfT: ident) => {
132 to_from_rust_fp_impl!(From, $ux, $SelfT, f32, to_f32, from_f32);
133 to_from_rust_fp_impl!(From, $ux, $SelfT, f64, to_f64, from_f64);
134 };
135 ($ux: ident, $SelfT: ident, $fx: ident, $to_func: ident, $from_func: ident) => {
136 #[doc = concat!("Convert from [`", stringify!($fx), "`] to a `", stringify!($SelfT), "`.")]
137 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
144 #[doc = concat!("const ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT), "::",
145 stringify!($from_func), "(0_", stringify!($fx), ");")]
146 #[doc = concat!("const THREE_HALVES: ", stringify!($SelfT), " = ", stringify!($SelfT),
147 "::", stringify!($from_func), "(1.5);")]
148 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0), ZERO);")]
149 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(", vax_fp_bits!($SelfT, 1.5), "), THREE_HALVES);")]
150 #[doc = concat!("`From<", stringify!($fx), ">` cannot be used to define constants.")]
153 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
156 #[doc = concat!("const ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
157 "::from(0_", stringify!($fx), ");")]
158 pub const fn $from_func(src: $fx) -> Self {
160 Self::from_fp(VaxFloatingPoint::<$ux>::$from_func(src))
161 }
162
163 #[doc = concat!("Convert from a `", stringify!($SelfT), "` to [`", stringify!($fx), "`].")]
164 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
171 #[doc = concat!("const ZERO: ", stringify!($fx), " = ", stringify!($SelfT),
172 "::from_bits(0).", stringify!($to_func), "();")]
173 #[doc = concat!("const THREE_HALVES: ", stringify!($fx), " = ", stringify!($SelfT),
174 "::from_bits(", vax_fp_bits!($SelfT, 1.5), ").", stringify!($to_func), "();")]
175 #[doc = concat!("assert_eq!(ZERO, 0.0_", stringify!($fx), ");")]
176 #[doc = concat!("assert_eq!(THREE_HALVES, 1.5_", stringify!($fx), ");")]
177 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(",
178 vax_fp_bits!($SelfT, 1.5), ").", stringify!($to_func), "(), 1.5_",
179 stringify!($fx), ");")]
180 #[doc = concat!("`From<", stringify!($SelfT), ">` cannot be used to define constants.")]
183 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
186 #[doc = concat!("const ZERO: ", stringify!($fx), " = ", stringify!($fx),
187 "::from(", stringify!($SelfT), "::from_bits(0));")]
188 pub const fn $to_func(&self) -> $fx {
190 self.to_fp().$to_func()
191 }
192 };
193 (From, $ux: ident, $SelfT: ident, $fx: ident, $to_func: ident, $from_func: ident) => {
194 impl From<&$fx> for $SelfT {
195 fn from(src: &$fx) -> Self {
196 Self::$from_func(*src)
197 }
198 }
199
200 impl From<$fx> for $SelfT {
201 fn from(src: $fx) -> Self {
202 Self::$from_func(src)
203 }
204 }
205
206 impl From<&$SelfT> for $fx {
207 fn from(src: &$SelfT) -> Self {
208 src.$to_func()
209 }
210 }
211
212 impl From<$SelfT> for $fx {
213 fn from(src: $SelfT) -> Self {
214 src.$to_func()
215 }
216 }
217 };
218}
219
220macro_rules! vax_float_use_line {
221 (FFloating, FFloating) => {
222 "# use vax_floating::FFloating;"
223 };
224 (DFloating, DFloating) => {
225 "# use vax_floating::DFloating;"
226 };
227 (GFloating, GFloating) => {
228 "# use vax_floating::GFloating;"
229 };
230 (HFloating, HFloating) => {
231 "# use vax_floating::HFloating;"
232 };
233 ($SelfT: ident, $ToSelfT: ident) => {
234 concat!("# use vax_floating::{", stringify!($SelfT), ", ", stringify!($ToSelfT), "};")
235 };
236}
237
238macro_rules! to_from_vax_float_impl {
250 (From, FFloating) => {
251 to_from_vax_float_impl!(From, FFloating, DFloating, to_f_floating, to_d_floating);
252 to_from_vax_float_impl!(From, FFloating, GFloating, to_f_floating, to_g_floating);
253 to_from_vax_float_impl!(From, FFloating, HFloating, to_f_floating, to_h_floating);
254 };
255 (From, DFloating) => {
256 to_from_vax_float_impl!(From, DFloating, GFloating, to_d_floating, to_g_floating);
257 to_from_vax_float_impl!(From, DFloating, HFloating, to_d_floating, to_h_floating);
258 };
259 (From, GFloating) => {
260 to_from_vax_float_impl!(From, GFloating, HFloating, to_g_floating, to_h_floating);
261 };
262 (From, HFloating) => {};
263 ($ux: ident, $SelfT: ident) => {
264 to_from_vax_float_impl!($ux, $SelfT, FFloating, to_f_floating, to_vfp_32, from_f_floating, from_vfp_32);
265 to_from_vax_float_impl!($ux, $SelfT, DFloating, to_d_floating, to_vfp_64, from_d_floating, from_vfp_64);
266 to_from_vax_float_impl!($ux, $SelfT, GFloating, to_g_floating, to_vfp_64, from_g_floating, from_vfp_64);
267 to_from_vax_float_impl!($ux, $SelfT, HFloating, to_h_floating, to_vfp_128, from_h_floating, from_vfp_128);
268 };
269 ($ux: ident, $SelfT: ident, $ToSelfT: ident, $to_fp_func: ident, $to_vfp: ident, $from_fp_func: ident, $from_vfp: ident) => {
270 #[doc = concat!("Convert from [`", stringify!($ToSelfT), "`] to a `", stringify!($SelfT), "`.")]
271 #[doc = vax_float_use_line!($SelfT, $ToSelfT)]
278 #[doc = concat!("const FROM_ZERO: ", stringify!($ToSelfT), " = ", stringify!($ToSelfT),
279 "::from_bits(0);")]
280 #[doc = concat!("const FROM_THREE_HALVES: ", stringify!($ToSelfT), " = ",
281 stringify!($ToSelfT), "::from_f32(1.5);")]
282 #[doc = concat!("const ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT), "::",
283 stringify!($from_fp_func), "(FROM_ZERO);")]
284 #[doc = concat!("const THREE_HALVES: ", stringify!($SelfT), " = ", stringify!($SelfT), "::",
285 stringify!($from_fp_func), "(FROM_THREE_HALVES);")]
286 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0), ZERO);")]
287 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(", vax_fp_bits!($SelfT, 1.5), "), THREE_HALVES);")]
288 #[doc = concat!("`From<", stringify!($ToSelfT), ">` cannot be used to define constants.")]
291 #[doc = vax_float_use_line!($SelfT, $ToSelfT)]
294 #[doc = concat!("const FROM_ZERO: ", stringify!($ToSelfT), " = ", stringify!($ToSelfT),
295 "::from_bits(0);")]
296 #[doc = concat!("const ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
297 "::from(FROM_ZERO);")]
298 pub const fn $from_fp_func(src: $ToSelfT) -> Self {
300 Self::from_fp(VaxFloatingPoint::<$ux>::$from_vfp(src.to_fp()))
301 }
302
303 #[doc = concat!("Convert from a `", stringify!($SelfT), "` to [`",
304 stringify!($ToSelfT), "`].")]
305 #[doc = vax_float_use_line!($SelfT, $ToSelfT)]
312 #[doc = concat!("const FROM_ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
313 "::from_bits(0);")]
314 #[doc = concat!("const FROM_THREE_HALVES: ", stringify!($SelfT), " = ",
315 stringify!($SelfT), "::from_bits(", vax_fp_bits!($SelfT, 1.5), ");")]
316 #[doc = concat!("const ZERO: ", stringify!($ToSelfT), " = FROM_ZERO.",
317 stringify!($to_fp_func), "();")]
318 #[doc = concat!("const THREE_HALVES: ", stringify!($ToSelfT), " = FROM_THREE_HALVES.",
319 stringify!($to_fp_func), "();")]
320 #[doc = concat!("assert_eq!(ZERO, ", stringify!($ToSelfT), "::from_bits(0));")]
321 #[doc = concat!("assert_eq!(THREE_HALVES, ", stringify!($ToSelfT), "::from_f32(1.5));")]
322 #[doc = concat!("`From<", stringify!($SelfT), ">` cannot be used to define constants.")]
325 #[doc = vax_float_use_line!($SelfT, $ToSelfT)]
328 #[doc = concat!("const FROM_ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
329 "::from_bits(0);")]
330 #[doc = concat!("const ZERO: ", stringify!($ToSelfT), " = ", stringify!($ToSelfT),
331 "::from(FROM_ZERO);")]
332 pub const fn $to_fp_func(&self) -> $ToSelfT {
334 $ToSelfT::from_fp(self.to_fp().$to_vfp())
335 }
336 };
337 (From, $SelfT: ident, $OtherT: ident, $to_self: ident, $to_other: ident) => {
338 impl From<&$OtherT> for $SelfT {
339 fn from(src: &$OtherT) -> Self {
340 src.$to_self()
341 }
342 }
343
344 impl From<$OtherT> for $SelfT {
345 fn from(src: $OtherT) -> Self {
346 src.$to_self()
347 }
348 }
349
350 impl From<&$SelfT> for $OtherT {
351 fn from(src: &$SelfT) -> Self {
352 src.$to_other()
353 }
354 }
355
356 impl From<$SelfT> for $OtherT {
357 fn from(src: $SelfT) -> Self {
358 src.$to_other()
359 }
360 }
361 };
362}
363
364macro_rules! from_int_lossy_doc {
367 ($SelfT: ident) => {
368 concat!("**Note**: Only the most significant set bits that fit into the number of [`",
369 stringify!($SelfT), "::MANTISSA_DIGITS`] will be preserved. This will result in a loss
370 of precision.")
371 };
372}
373
374macro_rules! from_rust_int_impl {
385 (u32, $SelfT: ident) => {
386 from_rust_int_impl!(to_u32, u32, $SelfT);
387 from_rust_int_impl!(lossy_u64, u32, $SelfT);
388 from_rust_int_impl!(lossy_u128, u32, $SelfT);
389 };
390 (u64, $SelfT: ident) => {
391 from_rust_int_impl!(to_u32, u64, $SelfT);
392 from_rust_int_impl!(to_u64, u64, $SelfT);
393 from_rust_int_impl!(lossy_u128, u64, $SelfT);
394 };
395 (u128, $SelfT: ident) => {
396 from_rust_int_impl!(to_u32, u128, $SelfT);
397 from_rust_int_impl!(to_u64, u128, $SelfT);
398 from_rust_int_impl!(to_u128, u128, $SelfT);
399 };
400 (From, u32, $SelfT: ident) => {
401 from_rust_int_impl!(From, to_u32, u32, $SelfT);
402 from_rust_int_impl!(From, lossy_u64, u32, $SelfT);
403 from_rust_int_impl!(From, lossy_u128, u32, $SelfT);
404 };
405 (From, u64, $SelfT: ident) => {
406 from_rust_int_impl!(From, to_u32, u64, $SelfT);
407 from_rust_int_impl!(From, to_u64, u64, $SelfT);
408 from_rust_int_impl!(From, lossy_u128, u64, $SelfT);
409 };
410 (From, u128, $SelfT: ident) => {
411 from_rust_int_impl!(From, to_u32, u128, $SelfT);
412 from_rust_int_impl!(From, to_u64, u128, $SelfT);
413 from_rust_int_impl!(From, to_u128, u128, $SelfT);
414 };
415 (to_u32, $ux: ident, $SelfT: ident) => {
416 from_rust_int_impl!($ux, $SelfT, u8, from_u8, "");
417 from_rust_int_impl!($ux, $SelfT, i8, from_i8, "");
418 from_rust_int_impl!($ux, $SelfT, u16, from_u16, "");
419 from_rust_int_impl!($ux, $SelfT, i16, from_i16, "");
420 };
421 (to_u64, $ux: ident, $SelfT: ident) => {
422 from_rust_int_impl!($ux, $SelfT, u32, from_u32, "");
423 from_rust_int_impl!($ux, $SelfT, i32, from_i32, "");
424 };
425 (to_u128, $ux: ident, $SelfT: ident) => {
426 from_rust_int_impl!($ux, $SelfT, u64, from_u64, "");
427 from_rust_int_impl!($ux, $SelfT, i64, from_i64, "");
428 from_rust_int_impl!($ux, $SelfT, usize, from_usize, "");
429 from_rust_int_impl!($ux, $SelfT, isize, from_isize, "");
430 from_rust_int_impl!($ux, $SelfT, u128, from_u128, from_int_lossy_doc!($SelfT));
431 from_rust_int_impl!($ux, $SelfT, i128, from_i128, from_int_lossy_doc!($SelfT));
432 };
433 (lossy_u64, $ux: ident, $SelfT: ident) => {
434 from_rust_int_impl!($ux, $SelfT, u32, from_u32, from_int_lossy_doc!($SelfT));
435 from_rust_int_impl!($ux, $SelfT, i32, from_i32, from_int_lossy_doc!($SelfT));
436 };
437 (lossy_u128, $ux: ident, $SelfT: ident) => {
438 from_rust_int_impl!($ux, $SelfT, u64, from_u64, from_int_lossy_doc!($SelfT));
439 from_rust_int_impl!($ux, $SelfT, i64, from_i64, from_int_lossy_doc!($SelfT));
440 from_rust_int_impl!($ux, $SelfT, usize, from_usize, from_int_lossy_doc!($SelfT));
441 from_rust_int_impl!($ux, $SelfT, isize, from_isize, from_int_lossy_doc!($SelfT));
442 from_rust_int_impl!($ux, $SelfT, u128, from_u128, from_int_lossy_doc!($SelfT));
443 from_rust_int_impl!($ux, $SelfT, i128, from_i128, from_int_lossy_doc!($SelfT));
444 };
445 (From, to_u32, $ux: ident, $SelfT: ident) => {
446 from_rust_int_impl!(From, $ux, $SelfT, u8, from_u8, "");
447 from_rust_int_impl!(From, $ux, $SelfT, i8, from_i8, "");
448 from_rust_int_impl!(From, $ux, $SelfT, u16, from_u16, "");
449 from_rust_int_impl!(From, $ux, $SelfT, i16, from_i16, "");
450 };
451 (From, to_u64, $ux: ident, $SelfT: ident) => {
452 from_rust_int_impl!(From, $ux, $SelfT, u32, from_u32, "");
453 from_rust_int_impl!(From, $ux, $SelfT, i32, from_i32, "");
454 };
455 (From, to_u128, $ux: ident, $SelfT: ident) => {
456 from_rust_int_impl!(From, $ux, $SelfT, u64, from_u64, "");
457 from_rust_int_impl!(From, $ux, $SelfT, i64, from_i64, "");
458 from_rust_int_impl!(From, $ux, $SelfT, usize, from_usize, "");
459 from_rust_int_impl!(From, $ux, $SelfT, isize, from_isize, "");
460 from_rust_int_impl!(From, $ux, $SelfT, u128, from_u128, from_int_lossy_doc!($SelfT));
461 from_rust_int_impl!(From, $ux, $SelfT, i128, from_i128, from_int_lossy_doc!($SelfT));
462 };
463 (From, lossy_u64, $ux: ident, $SelfT: ident) => {
464 from_rust_int_impl!(From, $ux, $SelfT, u32, from_u32, from_int_lossy_doc!($SelfT));
465 from_rust_int_impl!(From, $ux, $SelfT, i32, from_i32, from_int_lossy_doc!($SelfT));
466 };
467 (From, lossy_u128, $ux: ident, $SelfT: ident) => {
468 from_rust_int_impl!(From, $ux, $SelfT, u64, from_u64, from_int_lossy_doc!($SelfT));
469 from_rust_int_impl!(From, $ux, $SelfT, i64, from_i64, from_int_lossy_doc!($SelfT));
470 from_rust_int_impl!(From, $ux, $SelfT, usize, from_usize, from_int_lossy_doc!($SelfT));
471 from_rust_int_impl!(From, $ux, $SelfT, isize, from_isize, from_int_lossy_doc!($SelfT));
472 from_rust_int_impl!(From, $ux, $SelfT, u128, from_u128, from_int_lossy_doc!($SelfT));
473 from_rust_int_impl!(From, $ux, $SelfT, i128, from_i128, from_int_lossy_doc!($SelfT));
474 };
475 ($ux: ident, $SelfT: ident, $uy: ident, $from_func: ident, $lossy_doc: expr) => {
476 #[doc = concat!("Convert from [`", stringify!($uy), "`] to a `", stringify!($SelfT), "`.")]
477 #[doc = $lossy_doc]
481 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
486 #[doc = concat!("const ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT), "::",
487 stringify!($from_func), "(0_", stringify!($uy), ");")]
488 #[doc = concat!("const TEN: ", stringify!($SelfT), " = ", stringify!($SelfT),
489 "::", stringify!($from_func), "(10);")]
490 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0), ZERO);")]
491 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(", vax_fp_bits!($SelfT, 10.0), "), TEN);")]
492 #[doc = concat!("`From<", stringify!($uy), ">` cannot be used to define constants.")]
495 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
498 #[doc = concat!("const ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
499 "::from(0_", stringify!($uy), ");")]
500 pub const fn $from_func(src: $uy) -> Self {
502 Self::from_fp(VaxFloatingPoint::<$ux>::$from_func(src))
503 }
504 };
505 (From, $ux: ident, $SelfT: ident, $fx: ident, $from_func: ident, $lossy_doc: expr) => {
506 impl From<&$fx> for $SelfT {
507 #[doc = $lossy_doc]
510 fn from(src: &$fx) -> Self {
511 Self::$from_func(*src)
512 }
513 }
514
515 impl From<$fx> for $SelfT {
516 #[doc = $lossy_doc]
519 fn from(src: $fx) -> Self {
520 Self::$from_func(src)
521 }
522 }
523 };
524}
525
526macro_rules! sh_impl {
528 ($t: ident) => {
529 sh_impl! { $t, u32, i32 }
530 };
531 ($t: ident, $uf: ident, $if: ident) => {
532 impl Shl<$uf> for $t {
533 type Output = $t;
534
535 #[inline]
536 fn shl(self, other: $uf) -> $t {
537 Self::from_fp(self.to_fp().shift_left_unsigned(other))
538 }
539 }
540 forward_ref_binop! { impl Shl, shl for $t, $uf }
541
542 impl Shr<$uf> for $t {
543 type Output = $t;
544
545 #[inline]
546 fn shr(self, other: $uf) -> $t {
547 Self::from_fp(self.to_fp().shift_right_unsigned(other))
548 }
549 }
550 forward_ref_binop! { impl Shr, shr for $t, $uf }
551
552 impl ShlAssign<$uf> for $t {
553 #[inline]
554 fn shl_assign(&mut self, other: $uf) {
555 *self = *self << other;
556 }
557 }
558 forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $uf }
559
560 impl ShrAssign<$uf> for $t {
561 #[inline]
562 fn shr_assign(&mut self, other: $uf) {
563 *self = *self >> other;
564 }
565 }
566 forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $uf }
567
568 impl Shl<$if> for $t {
569 type Output = $t;
570
571 #[inline]
572 fn shl(self, other: $if) -> $t {
573 Self::from_fp(self.to_fp().shift_left(other))
574 }
575 }
576 forward_ref_binop! { impl Shl, shl for $t, $if }
577
578 impl Shr<$if> for $t {
579 type Output = $t;
580
581 #[inline]
582 fn shr(self, other: $if) -> $t {
583 Self::from_fp(self.to_fp().shift_right(other))
584 }
585 }
586 forward_ref_binop! { impl Shr, shr for $t, $if }
587 };
588}
589
590macro_rules! floating_impl {
605 (
606 Self = $SelfT: ident,
607 ActualT = $ux: ident,
608 ExpBits = $exp: literal,
609 VaxName = $VaxName: literal,
610 swapped = $swapped: literal,
611 le_bytes = $le_bytes: literal,
612 be_bytes = $be_bytes: literal,
613 ) => {
614 #[doc = concat!("# The VAX ", $VaxName, " type.")]
615 #[doc = concat!($VaxName, " floating-point type.")]
621 #[doc = include_str!(concat!("doc/", stringify!($SelfT), "_vax.doc"))]
623 #[derive(Copy, Clone, Default, Eq)]
624 pub struct $SelfT($ux);
625
626 impl $SelfT {
627 #[doc = concat!("The radix or base of the internal representation of `", stringify!($SelfT), "`.")]
628 pub const RADIX: u32 = 2;
629
630 pub const MANTISSA_DIGITS: u32 = <$ux>::BITS - $exp;
632
633 #[doc = concat!("The mask used by `from_ascii()` to determine when new digits won't ",
634 "change the `", stringify!($SelfT), "` fraction value.")]
635 const DIV_PRECISION: u32 = Self::MANTISSA_DIGITS + 2;
636
637 pub const DIGITS: u32 = {
639 let value: $ux = 1 << Self::MANTISSA_DIGITS;
640 value.ilog10()
663 };
664
665 #[doc = concat!("[Machine epsilon] value for `", stringify!($SelfT), "`.")]
666 pub const EPSILON: $SelfT = $SelfT::from_parts(Sign::Positive, Self::EXP_BIAS + 1 - (Self::MANTISSA_DIGITS as i32), 0);
671
672 #[doc = concat!("Smallest finite `", stringify!($SelfT), "` value.")]
673 pub const MIN: $SelfT =
674 $SelfT::from_parts(Sign::Negative, Self::MAX_EXP, (1 << Self::MANTISSA_DIGITS) - 1);
675 #[doc = concat!("Smallest positive normal `", stringify!($SelfT), "` value.")]
676 pub const MIN_POSITIVE: $SelfT =
677 $SelfT::from_parts(Sign::Positive, Self::MIN_EXP, 0);
678 #[doc = concat!("Largest finite `", stringify!($SelfT), "` value.")]
679 pub const MAX: $SelfT =
680 $SelfT::from_parts(Sign::Positive, Self::MAX_EXP, (1 << Self::MANTISSA_DIGITS) - 1);
681
682 pub const MIN_EXP: i32 = 1 - (Self::EXP_BIAS);
684 pub const MAX_EXP: i32 = (Self::EXP_BIAS) - 1;
686
687 pub const MIN_10_EXP: i32 = {
689 const TEN: VaxFloatingPoint::<$ux> = VaxFloatingPoint::<$ux>::from_f32(10.0);
690 let mut temp = Self::MIN_POSITIVE.to_fp();
691 let mut tens = 1;
692 while temp.exponent() <= 0 {
693 temp = temp.multiply_by(TEN);
694 tens -= 1;
695 }
696 tens
697 };
698 pub const MAX_10_EXP: i32 = {
700 const TENTH: VaxFloatingPoint::<$ux> = VaxFloatingPoint::<$ux>::from_f32(1.0)
701 .divide_by(VaxFloatingPoint::<$ux>::from_f32(10.0), <$ux>::BITS);
702 let mut temp = Self::MAX.to_fp();
703 let mut tens = -1;
704 while temp.exponent() > 0 {
705 temp = temp.multiply_by(TENTH);
706 tens += 1;
707 }
708 tens
709 };
710
711 #[doc = concat!("The size of the VAX `", $VaxName, "` type in bits.")]
712 pub const BITS: u32 = <$ux>::BITS;
713
714 #[doc = concat!("[Exponent bias] of the `", stringify!($SelfT), "` type.")]
715 const EXP_BIAS: i32 = 1 << ($exp - 1);
720
721 #[doc = concat!("The size of the exponent in the VAX `", $VaxName, "` type in bits.")]
722 const EXP_BITS: u32 = $exp;
723
724 #[doc = concat!("The number of bits the exponent of the VAX `", $VaxName,
725 "` type is shifted.")]
726 const EXP_SHIFT: u32 = 15 - Self::EXP_BITS;
730
731 #[doc = concat!("The mask for the exponent of the VAX `", $VaxName, "` type.")]
732 const EXP_MASK: $ux = ((1 << Self::EXP_BITS) - 1) << Self::EXP_SHIFT;
736
737 #[doc = concat!("The sign mask for the VAX `", $VaxName, "` type.")]
738 const SIGN: $ux = 1 << 15;
742
743 #[doc = concat!("The fraction mask for the VAX `", $VaxName, "` type.")]
744 const FRAC_MASK: $ux = !(Self::EXP_MASK | Self::SIGN);
745
746 #[doc = concat!("Number of bits to shift when converting from the word swapped `",
747 stringify!($SelfT), "` to `VaxFloatingPoint<", stringify!($ux),
748 ">` fraction value.")]
749 const FP_FRAC_SHIFT: u32 = $exp;
750
751 #[doc = concat!("The rounding bit mask added to the fraction of `VaxFloatingPoint<",
752 stringify!($ux), "> when converting back to `", stringify!($SelfT), "`.")]
753 const FP_FRAC_ROUND: $ux = 1 << (Self::FP_FRAC_SHIFT - 1);
754
755 #[doc = concat!(
756 "The mask used by `from_ascii()` to determine when new digits won't change the `",
757 stringify!($SelfT), "` fraction value.")]
758 const ASCII_MASK: $ux = ((1 << (Self::MANTISSA_DIGITS + 1)) - 1) << Self::FP_FRAC_SHIFT;
759
760 const RESERVED_SHIFT: u32 = if 14 > Self::EXP_BITS {
762 13_u32.wrapping_sub(Self::EXP_BITS)
771 }
772 else {
773 30
775 };
776 const RESERVED_OVER_UNDER_SHIFT: u32 = if 14 > Self::EXP_BITS { 16 } else { 32 };
779
780 swap_words_impl!($ux);
782
783 #[doc = concat!("Raw transmutation from the `", stringify!($SelfT), "` type to `",
784 stringify!($ux), "`.")]
785 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
790 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(0_f32).to_bits(), 0_",
791 stringify!($ux), ");")]
792 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(1.5).to_bits(), ",
793 vax_fp_bits!($SelfT, 1.5), "_", stringify!($ux), ");")]
794 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5).to_bits(), ",
795 vax_fp_bits!($SelfT, 12.5), "_", stringify!($ux), ");")]
796 #[inline]
798 pub const fn to_bits(self) -> $ux { self.0 }
799
800 #[doc = concat!("Raw transmutation from a `", stringify!($ux), "` the `",
801 stringify!($SelfT), "` type.")]
802 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
807 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0), ",
808 stringify!($SelfT), "::from_f32(0_f32));")]
809 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(",
810 vax_fp_bits!($SelfT, 1.5), "), ", stringify!($SelfT), "::from_f32(1.5));")]
811 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(",
812 vax_fp_bits!($SelfT, 12.5), "), ", stringify!($SelfT), "::from_f32(12.5));")]
813 #[inline]
815 pub const fn from_bits(bits: $ux) -> Self { Self(bits) }
816
817 #[doc = concat!("Return the memory representation of the `", stringify!($SelfT),
818 "` type as a byte array in little-endian byte order.")]
819 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
824 #[doc = concat!("let bytes = ", stringify!($SelfT), "::from_f32(12.5).to_le_bytes();")]
825 #[doc = concat!("assert_eq!(bytes, ", $le_bytes, ");")]
826 #[inline]
828 pub const fn to_le_bytes(&self) -> [u8; std::mem::size_of::<$ux>()] { self.0.to_le_bytes() }
829
830 #[doc = concat!("Return the memory representation of the `", stringify!($SelfT),
831 "` type as a byte array in big-endian (network) byte order.")]
832 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
837 #[doc = concat!("let bytes = ", stringify!($SelfT), "::from_f32(12.5).to_be_bytes();")]
838 #[doc = concat!("assert_eq!(bytes, ", $be_bytes, ");")]
839 #[inline]
841 pub const fn to_be_bytes(&self) -> [u8; std::mem::size_of::<$ux>()] { self.0.to_be_bytes() }
842
843 #[doc = concat!("Return the memory representation of the `", stringify!($SelfT),
844 "` type as a byte array in native byte order.")]
845 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
850 #[doc = concat!("let bytes = ", stringify!($SelfT), "::from_f32(12.5).to_ne_bytes();")]
851 #[doc = concat!(" ", $be_bytes)]
855 #[doc = concat!(" ", $le_bytes)]
857 #[inline]
861 pub const fn to_ne_bytes(&self) -> [u8; std::mem::size_of::<$ux>()] { self.0.to_ne_bytes() }
862
863 #[doc = concat!("Create a `", stringify!($SelfT),
864 "` type from its representation as a byte array in little endian.")]
865 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
870 #[doc = concat!("let float = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, ");")]
871 #[doc = concat!("assert_eq!(float, ", stringify!($SelfT), "::from_f32(12.5));")]
872 #[inline]
874 pub const fn from_le_bytes(bytes: [u8; std::mem::size_of::<$ux>()]) -> Self {
875 Self(<$ux>::from_le_bytes(bytes))
876 }
877
878 #[doc = concat!("Create a `", stringify!($SelfT),
879 "` type from its representation as a byte array in big endian.")]
880 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
885 #[doc = concat!("let float = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, ");")]
886 #[doc = concat!("assert_eq!(float, ", stringify!($SelfT), "::from_f32(12.5));")]
887 #[inline]
889 pub const fn from_be_bytes(bytes: [u8; std::mem::size_of::<$ux>()]) -> Self {
890 Self(<$ux>::from_be_bytes(bytes))
891 }
892
893 #[doc = concat!("Create a `", stringify!($SelfT),
894 "` type from its representation as a byte array in native endianness.")]
895 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
900 #[doc = concat!("let float = ", stringify!($SelfT), "::from_ne_bytes(")]
901 #[doc = concat!(" ", $be_bytes)]
903 #[doc = concat!(" ", $le_bytes)]
905 #[doc = concat!("assert_eq!(float, ", stringify!($SelfT), "::from_f32(12.5));")]
908 #[inline]
910 pub const fn from_ne_bytes(bytes: [u8; std::mem::size_of::<$ux>()]) -> Self {
911 Self(<$ux>::from_ne_bytes(bytes))
912 }
913
914 #[doc = concat!("Reverses the (16-bit) word order of the raw transmutation of a `",
915 stringify!($ux), "` into the `", stringify!($SelfT), "` type.")]
916 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
921 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(",
922 vax_fp_bits!($SelfT, 12.5), ").to_swapped(), ", $swapped, "_", stringify!($ux), ");")]
923 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5).to_swapped(), ",
924 $swapped, "_", stringify!($ux), ");")]
925 #[inline]
927 pub const fn to_swapped(self) -> $ux {
928 Self::swap_words(self.0)
929 }
930
931 #[doc = concat!("Reverses the (16-bit) word order of the raw transmutation of the `",
932 stringify!($SelfT), "` type into a `", stringify!($ux), "`.")]
933 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
938 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_swapped(", $swapped, "), ",
939 stringify!($SelfT), "::from_f32(12.5));")]
940 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_swapped(", $swapped, "), ",
941 stringify!($SelfT), "::from_bits(", vax_fp_bits!($SelfT, 12.5), "));")]
942 #[inline]
944 pub const fn from_swapped(swapped: $ux) -> Self {
945 Self(Self::swap_words(swapped))
946 }
947
948 #[doc = concat!("Create a `", stringify!($SelfT),
949 "` type from the sign, (base 2) exponent, and fraction value.")]
950 #[inline]
951 const fn from_parts(sign: Sign, exp: i32, frac: $ux) -> Self {
952 Self((Self::swap_words(frac) & Self::FRAC_MASK) |
953 ((((exp + Self::EXP_BIAS) as $ux) << Self::EXP_SHIFT) & Self::EXP_MASK) |
954 if sign.is_negative() { Self::SIGN } else { 0 })
955 }
956
957 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
966 #[doc = concat!("const ONE: ", stringify!($SelfT), " = ", stringify!($SelfT),
967 "::from_i8(1);")]
968 #[doc = concat!("const NEG: ", stringify!($SelfT), " = ", stringify!($SelfT),
969 "::from_i8(-1);")]
970 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0).signum(), ONE);")]
971 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN_POSITIVE.signum(), ONE);")]
972 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.signum(), ONE);")]
973 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.signum(), NEG);")]
974 #[doc = concat!("assert!(", stringify!($SelfT),
975 "::from_bits(0x8000).signum().is_reserved());")]
976 #[inline]
978 pub const fn signum(self) -> Self {
979 if self.is_reserved() { self }
980 else {
981 Self((self.0 & Self::SIGN) |
982 (((Self::EXP_BIAS as $ux) + 1) << Self::EXP_SHIFT))
983 }
984 }
985
986 #[doc = concat!("Return `true` if the `", stringify!($SelfT), "` is zero.")]
987 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
992 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0).is_zero(), true);")]
993 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN_POSITIVE.is_zero(), false);")]
994 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.is_zero(), false);")]
995 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.is_zero(), false);")]
996 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0xFFFF0000_",
998 stringify!($ux), ").is_zero(), true);")]
999 #[inline]
1001 pub const fn is_zero(&self) -> bool { 0 == (self.0 & (Self::SIGN | Self::EXP_MASK)) }
1002
1003 #[doc = concat!("Return `true` if the `", stringify!($SelfT), "` is negative.")]
1004 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1009 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0).is_negative(), false);")]
1010 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN_POSITIVE.is_negative(), false);")]
1011 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.is_negative(), false);")]
1012 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.is_negative(), true);")]
1013 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0x8000_",
1015 stringify!($ux), ").is_negative(), false);")]
1016 #[inline]
1018 pub const fn is_negative(&self) -> bool {
1019 0 != ((self.0 & Self::SIGN)) && (0 != (self.0 & Self::EXP_MASK))
1020 }
1021
1022 #[doc = concat!("Return `true` if the `", stringify!($SelfT), "` is reserved.")]
1023 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1028 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0).is_reserved(), false);")]
1029 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN_POSITIVE.is_reserved(), false);")]
1030 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.is_reserved(), false);")]
1031 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.is_reserved(), false);")]
1032 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0x8000_",
1034 stringify!($ux), ").is_reserved(), true);")]
1035 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0xFFFF8000_",
1036 stringify!($ux), ").is_reserved(), true);")]
1037 #[inline]
1039 pub const fn is_reserved(&self) -> bool { Self::SIGN == (self.0 & (Self::SIGN | Self::EXP_MASK)) }
1040
1041 #[doc = concat!("Force the sign of the `", stringify!($SelfT), "` to positive.")]
1042 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1047 #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_f32(*case).abs(), ", stringify!($SelfT), "::from_f32(*abs));")]
1054 #[inline]
1057 pub const fn abs(self) -> Self { Self(self.0 & !Self::SIGN) }
1058
1059 #[doc = concat!("Negate the sign of the `", stringify!($SelfT), "` value.")]
1060 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1065 #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_f32(*case).negate(), ", stringify!($SelfT), "::from_f32(*neg));")]
1071 pub const fn negate(self) -> Self {
1074 if 0 != (self.0 & Self::EXP_MASK) { Self(self.0 ^ Self::SIGN) }
1075 else { self }
1076 }
1077
1078 #[doc = concat!("Return the sign of the `", stringify!($SelfT), "` value.")]
1079 #[doc = concat!("# use vax_floating::{", stringify!($SelfT), ", arithmetic::Sign};")]
1084 #[doc = concat!(" assert_eq!(", stringify!($SelfT), "::from_f32(*case).sign(), *sign);")]
1090 pub const fn sign(&self) -> Sign {
1093 if 0 == (self.0 & Self::SIGN) {
1094 Sign::Positive
1095 }
1096 else {
1097 Sign::Negative
1098 }
1099 }
1100
1101 #[doc = concat!("Add a `", stringify!($SelfT), "` to another `",
1102 stringify!($SelfT), "`.")]
1103 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1108 #[doc = concat!("const NINETEEN_POINT_FIVE: ", stringify!($SelfT), " = ",
1109 stringify!($SelfT), "::from_u8(17).add_to(", stringify!($SelfT),
1110 "::from_f32(2.5));")]
1111 #[doc = concat!("let seventeen = ", stringify!($SelfT), "::from_u8(17);")]
1112 #[doc = concat!("let two_point_five = ", stringify!($SelfT), "::from_f32(2.5);")]
1113 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1121 #[doc = concat!("const NINETEEN_POINT_FIVE: ", stringify!($SelfT), " = ",
1122 stringify!($SelfT), "::from_u8(17) + ", stringify!($SelfT), "::from_f32(2.5);")]
1123 pub const fn add_to(self, other: Self) -> Self {
1125 Self::from_fp(self.to_fp().add_to(other.to_fp(), false))
1126 }
1127
1128 #[doc = concat!("Subtract a `", stringify!($SelfT), "` from another `",
1129 stringify!($SelfT), "`.")]
1130 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1135 #[doc = concat!("const FOURTEEN_POINT_FIVE: ", stringify!($SelfT), " = ",
1136 stringify!($SelfT), "::from_u8(17).subtract_by(", stringify!($SelfT),
1137 "::from_f32(2.5));")]
1138 #[doc = concat!("let seventeen = ", stringify!($SelfT), "::from_u8(17);")]
1139 #[doc = concat!("let two_point_five = ", stringify!($SelfT), "::from_f32(2.5);")]
1140 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1148 #[doc = concat!("const FOURTEEN_POINT_FIVE: ", stringify!($SelfT), " = ",
1149 stringify!($SelfT), "::from_u8(17) - ", stringify!($SelfT), "::from_f32(2.5);")]
1150 pub const fn subtract_by(self, other: Self) -> Self {
1152 Self::from_fp(self.to_fp().add_to(other.to_fp(), true))
1153 }
1154
1155 #[doc = concat!("Multiply a `", stringify!($SelfT), "` by another `",
1156 stringify!($SelfT), "`.")]
1157 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1162 #[doc = concat!("const SEVENTEEN_TIMES_TWENTY_THREE: ", stringify!($SelfT), " = ",
1163 stringify!($SelfT), "::from_u8(17).multiply_by(", stringify!($SelfT),
1164 "::from_u8(23));")]
1165 #[doc = concat!("let seventeen = ", stringify!($SelfT), "::from_u8(17);")]
1166 #[doc = concat!("let twenty_three = ", stringify!($SelfT), "::from_u8(23);")]
1167 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1175 #[doc = concat!("const SEVENTEEN_TIMES_TWENTY_THREE: ", stringify!($SelfT), " = ",
1176 stringify!($SelfT), "::from_u8(17) * ", stringify!($SelfT), "::from_u8(23);")]
1177 pub const fn multiply_by(self, multiplier: Self) -> Self {
1179 Self::from_fp(self.to_fp().multiply_by(multiplier.to_fp()))
1180 }
1181
1182 #[doc = concat!("Divide a `", stringify!($SelfT), "` by another `",
1183 stringify!($SelfT), "`.")]
1184 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1189 #[doc = concat!("const TWENTY_TWO_SEVENTHS: ", stringify!($SelfT), " = ",
1190 stringify!($SelfT), "::from_u8(22).divide_by(", stringify!($SelfT),
1191 "::from_u8(7));")]
1192 #[doc = concat!("let twenty_two = ", stringify!($SelfT), "::from_u8(22);")]
1193 #[doc = concat!("let seven = ", stringify!($SelfT), "::from_u8(7);")]
1194 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1202 #[doc = concat!("const TWENTY_TWO_SEVENTHS: ", stringify!($SelfT), " = ", stringify!($SelfT),
1203 "::from_u8(22) / ", stringify!($SelfT), "::from_u8(7);")]
1204 pub const fn divide_by(self, divisor: Self) -> Self {
1206 Self::from_fp(self.to_fp().divide_by(divisor.to_fp(), Self::DIV_PRECISION))
1207 }
1208
1209 #[doc = concat!("Convert from a `", stringify!($SelfT), "` to a `VaxFloatingPoint<", stringify!($ux), ">`.")]
1210 #[doc = concat!("the `VaxFloatingPoint<", stringify!($ux),
1213 ">` type has more precision (it uses the entire", stringify!($ux), ")")]
1214 #[doc = concat!(stringify!($SelfT), "(", $VaxName, ")")]
1216 #[doc = concat!("# use vax_floating::{", stringify!($SelfT), ", VaxFloatingPoint};")]
1222 #[doc = concat!("const TWO: VaxFloatingPoint<", stringify!($ux), "> = ", stringify!($SelfT),
1223 "::from_ascii(\"2\").to_fp();")]
1224 #[doc = concat!("const THREE: VaxFloatingPoint<", stringify!($ux),
1225 "> = VaxFloatingPoint::<", stringify!($ux), ">::from_u8(3);")]
1226 #[doc = concat!("const TWO_THIRDS_MAX: ", stringify!($SelfT), " = ",
1227 stringify!($SelfT), "::MAX.divide_by(", stringify!($SelfT),
1228 "::from_u8(3)).multiply_by(", stringify!($SelfT), "::from_u8(2));")]
1229 #[doc = concat!("let fp = ", stringify!($SelfT), "::MAX.to_fp();")]
1230 #[doc = concat!("assert_eq!(", stringify!($SelfT),
1233 "::from_fp(two_thirds), TWO_THIRDS_MAX);")]
1234 #[doc = concat!("assert!(", stringify!($SelfT), "::from_fp(invalid).is_reserved());")]
1235 pub const fn to_fp(&self) -> VaxFloatingPoint<$ux> {
1237 match (self.0 & Self::EXP_MASK) >> Self::EXP_SHIFT {
1238 0 => match self.to_fault() {
1239 None => VaxFloatingPoint::<$ux>::ZERO,
1240 Some(fault) => VaxFloatingPoint::<$ux>::from_fault(fault),
1241 }
1242 exp => unsafe { VaxFloatingPoint::<$ux>::new_unchecked(
1243 self.sign(),
1244 (exp as i32) - Self::EXP_BIAS,
1245 Self::swap_words(self.0 & Self::FRAC_MASK) << Self::FP_FRAC_SHIFT |
1246 (1 << (<$ux>::BITS - 1)),
1247 ) },
1248 }
1249 }
1250
1251 #[doc = concat!("Convert from a `VaxFloatingPoint<", stringify!($ux), ">` to a `",
1252 stringify!($SelfT), "`.")]
1253 #[doc = concat!("the `VaxFloatingPoint<", stringify!($ux),
1256 ">` type has more precision (it uses the entire", stringify!($ux), ")")]
1257 #[doc = concat!(stringify!($SelfT), "(", $VaxName, ")")]
1259 #[doc = concat!("# use vax_floating::{", stringify!($SelfT), ", VaxFloatingPoint};")]
1265 #[doc = concat!("const TWO: VaxFloatingPoint<", stringify!($ux), "> = ", stringify!($SelfT),
1266 "::from_ascii(\"2\").to_fp();")]
1267 #[doc = concat!("const THREE: VaxFloatingPoint<", stringify!($ux),
1268 "> = VaxFloatingPoint::<", stringify!($ux), ">::from_u8(3);")]
1269 #[doc = concat!("const TWO_THIRDS_MAX: ", stringify!($SelfT), " = ",
1270 stringify!($SelfT), "::MAX.divide_by(", stringify!($SelfT),
1271 "::from_u8(3)).multiply_by(", stringify!($SelfT), "::from_u8(2));")]
1272 #[doc = concat!("let fp = ", stringify!($SelfT), "::MAX.to_fp();")]
1273 #[doc = concat!("assert_eq!(", stringify!($SelfT),
1276 "::from_fp(two_thirds), TWO_THIRDS_MAX);")]
1277 #[doc = concat!("assert!(", stringify!($SelfT), "::from_fp(invalid).is_reserved());")]
1278 pub const fn from_fp(fp: VaxFloatingPoint<$ux>) -> Self {
1280 if let Some(fault) = fp.fault() { Self::from_fault(fault) }
1281 else if fp.is_zero() { Self(0) }
1282 else {
1283 let fp = fp.round_fraction(Self::FP_FRAC_ROUND);
1284 let exp = ((fp.exponent() + Self::EXP_BIAS) << Self::EXP_SHIFT) as $ux;
1285 if 0 == (exp & Self::EXP_MASK) || 0 != (exp & !Self::EXP_MASK) {
1286 if 0 >= (fp.exponent() + Self::EXP_BIAS) {
1287 Self::from_underflow(Some(fp.exponent()))
1288 }
1289 else {
1290 Self::from_overflow(Some(fp.exponent()))
1291 }
1292 }
1293 else {
1294 Self((Self::swap_words(fp.fraction() >> Self::FP_FRAC_SHIFT) & Self::FRAC_MASK) |
1295 exp | if fp.sign().is_negative() { Self::SIGN } else { 0 })
1296 }
1297 }
1298 }
1299
1300 #[doc = concat!("Parse a string slice into a `", stringify!($SelfT), "`.")]
1301 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1310 #[doc = concat!("const TWELVE_DOT_FIVE: ", stringify!($SelfT), " = ", stringify!($SelfT),
1311 "::from_ascii(\"12.5\");")]
1312 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5), TWELVE_DOT_FIVE);")]
1313 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1319 #[doc = concat!("const TWO_DECIMAL_POINTS: ", stringify!($SelfT), " = ", stringify!($SelfT),
1320 "::from_ascii(\"..\");")]
1321 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1327 #[doc = concat!("const TWELVE_DOT_FIVE: ", stringify!($SelfT), " = ", stringify!($SelfT),
1329 "::from_str(\"12.5\").unwrap();")]
1330 pub const fn from_ascii(text: &str) -> $SelfT {
1332 match Self::from_ascii_inner(text) {
1333 Ok(me) => me,
1334 Err(_) => { panic!("Failed to parse input string within from_ascii()"); }
1335 }
1336 }
1337
1338 #[doc = concat!("Internal function that Parses a string slice into a `",
1339 stringify!($SelfT), "`.")]
1340 const fn from_ascii_inner(text: &str) -> std::result::Result<$SelfT, &str> {
1341 match VaxFloatingPoint::<$ux>::from_ascii(text, Self::ASCII_MASK) {
1342 Ok(vfp) => Ok(Self::from_fp(vfp)),
1343 Err(s) => Err(s),
1344 }
1345 }
1346
1347 #[doc = concat!("Convert an [`Error::Underflow`] to the corresponding reserved value of a `",
1348 stringify!($SelfT), "`.")]
1349 const fn from_underflow(exp: Option<i32>) -> $SelfT {
1350 const UNDERFLOW: $ux = $SelfT::SIGN | (0b01 << $SelfT::RESERVED_SHIFT);
1351 match exp {
1352 None => Self(UNDERFLOW),
1353 Some(exp) => Self(UNDERFLOW | if exp < (i16::MIN as i32) {
1354 0
1355 }
1356 else {
1357 ((exp as $ux) & 0xFFFF) << Self::RESERVED_OVER_UNDER_SHIFT
1358 }),
1359 }
1360 }
1361
1362 #[doc = concat!("Convert an [`Error::Overflow`] to the corresponding reserved value of a `",
1363 stringify!($SelfT), "`.")]
1364 const fn from_overflow(exp: Option<i32>) -> $SelfT {
1365 const OVERFLOW: $ux = $SelfT::SIGN | (0b10 << $SelfT::RESERVED_SHIFT);
1366 match exp {
1367 None => Self(OVERFLOW),
1368 Some(exp) => Self(OVERFLOW | if exp > (u16::MAX as i32) {
1369 0
1370 }
1371 else {
1372 ((exp as $ux) & 0xFFFF) << Self::RESERVED_OVER_UNDER_SHIFT
1373 }),
1374 }
1375 }
1376
1377 #[doc = concat!("Convert an [`Error`] to the corresponding reserved value of a `",
1378 stringify!($SelfT), "`.")]
1379 const fn from_error(err: &Error) -> $SelfT {
1380 const DIV_BY_ZERO: $ux = $SelfT::SIGN;
1381 const RESERVED: $ux = $SelfT::SIGN | (0b11 << $SelfT::RESERVED_SHIFT);
1382 match err {
1383 Error::DivByZero => $SelfT(DIV_BY_ZERO),
1384 Error::Underflow(exp) => $SelfT::from_underflow(*exp),
1385 Error::Overflow(exp) => $SelfT::from_overflow(*exp),
1386 Error::Reserved | Error::InvalidStr(_) => $SelfT(RESERVED),
1387 }
1388 }
1389
1390 #[doc = concat!("Convert a [`Fault`] to the corresponding reserved value of a `",
1391 stringify!($SelfT), "`.")]
1392 const fn from_fault(fault: Fault) -> $SelfT {
1393 const DIV_BY_ZERO: $ux = $SelfT::SIGN;
1394 const UNDERFLOW: $ux = $SelfT::SIGN | (0b01 << $SelfT::RESERVED_SHIFT);
1395 const OVERFLOW: $ux = $SelfT::SIGN | (0b10 << $SelfT::RESERVED_SHIFT);
1396 const RESERVED: $ux = $SelfT::SIGN | (0b11 << $SelfT::RESERVED_SHIFT);
1397 match fault {
1398 Fault::DivByZero => $SelfT(DIV_BY_ZERO),
1399 Fault::Underflow => $SelfT(UNDERFLOW),
1400 Fault::Overflow => $SelfT(OVERFLOW),
1401 Fault::Reserved => $SelfT(RESERVED),
1402 }
1403 }
1404
1405 #[doc = concat!("Convert a `", stringify!($SelfT), "` to a [`Result`].")]
1406 const fn to_result(self) -> Result<$SelfT> {
1410 if self.is_reserved() {
1411 match (self.0 >> $SelfT::RESERVED_SHIFT) & 3 {
1412 0b00 => Err(Error::DivByZero),
1413 0b01 => Err(Error::Underflow(
1414 match (self.0 >> $SelfT::RESERVED_OVER_UNDER_SHIFT) & 0xFFFF {
1415 0 => None,
1416 value => Some((value | 0xFFFF0000) as i32),
1417 })),
1418 0b10 => Err(Error::Overflow(
1419 match (self.0 >> $SelfT::RESERVED_OVER_UNDER_SHIFT) & 0xFFFF {
1420 0 => None,
1421 value => Some(value as i32),
1422 })),
1423 0b11 => Err(Error::Reserved),
1424 _ => unreachable!(),
1425 }
1426 }
1427 else {
1428 Ok(self)
1429 }
1430 }
1431
1432 #[doc = concat!("Convert a [`Fault`] to the corresponding reserved value of a `",
1433 stringify!($SelfT), "`.")]
1434 const fn to_fault(self) -> Option<Fault> {
1435 if self.is_reserved() {
1436 match (self.0 >> $SelfT::RESERVED_SHIFT) & 3 {
1437 0b00 => Some(Fault::DivByZero),
1438 0b01 => Some(Fault::Underflow),
1439 0b10 => Some(Fault::Overflow),
1440 0b11 => Some(Fault::Reserved),
1441 _ => unreachable!(),
1442 }
1443 }
1444 else {
1445 None
1446 }
1447 }
1448
1449 #[doc = concat!("Panic if the `",
1450 stringify!($SelfT), "` is not a valid value (i.e. reserved).")]
1451 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1462 #[doc = concat!("const TWELVE_DOT_FIVE: ", stringify!($SelfT), " = ", stringify!($SelfT),
1463 "::from_f32(12.5).unwrap();")]
1464 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5), TWELVE_DOT_FIVE);")]
1465 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1469 #[doc = concat!("const OVERFLOW: ", stringify!($SelfT), " = ", stringify!($SelfT),
1470 "::MAX.add_to(", stringify!($SelfT), "::MAX).unwrap();")]
1471 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1475 #[doc = concat!("const DIV_BY_ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
1476 "::MAX.divide_by(", stringify!($SelfT), "::from_bits(0));")]
1477 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(0x8000), DIV_BY_ZERO);")]
1479 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1483 #[doc = concat!("const DIV_BY_ZERO: ", stringify!($SelfT), " = ", stringify!($SelfT),
1484 "::MAX.divide_by(", stringify!($SelfT), "::from_bits(0)).unwrap();")]
1485 pub const fn unwrap(self) -> Self {
1487 if self.is_reserved() {
1488 match (self.0 >> $SelfT::RESERVED_SHIFT) & 3 {
1489 0b00 => { panic!("Divide by zero error"); }
1490 0b01 => { panic!("Underflow error"); }
1491 0b10 => { panic!("Overflow error"); }
1492 0b11 => { panic!("Reserved operand fault"); }
1493 _ => unreachable!(),
1494 }
1495 }
1496 else {
1497 self
1498 }
1499 }
1500
1501 #[doc = concat!("Return the defualt value if the `",
1502 stringify!($SelfT), "` is not valid (i.e. reserved).")]
1503 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1508 #[doc = concat!("const TWELVE_DOT_FIVE: ", stringify!($SelfT), " = ", stringify!($SelfT),
1509 "::from_f32(12.5).unwrap_or_default();")]
1510 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5), TWELVE_DOT_FIVE);")]
1511 #[doc = concat!("const OVERFLOW: ", stringify!($SelfT), " = ", stringify!($SelfT),
1513 "::MAX.add_to(", stringify!($SelfT), "::MAX).unwrap_or_default();")]
1514 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::default(), OVERFLOW);")]
1515 pub const fn unwrap_or_default(self) -> Self {
1517 if self.is_reserved() {
1518 Self::from_bits(0)
1521 }
1522 else {
1523 self
1524 }
1525 }
1526
1527 #[doc = concat!("Return an alternate value if the `",
1528 stringify!($SelfT), "` is not valid (i.e. reserved).")]
1529 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1534 #[doc = concat!("const TWELVE_DOT_FIVE: ", stringify!($SelfT), " = ", stringify!($SelfT),
1535 "::from_f32(12.5).unwrap_or(", stringify!($SelfT), "::MAX);")]
1536 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5), TWELVE_DOT_FIVE);")]
1537 #[doc = concat!("const OVERFLOW: ", stringify!($SelfT), " = ", stringify!($SelfT),
1539 "::MAX.add_to(", stringify!($SelfT), "::MAX).unwrap_or(", stringify!($SelfT), "::MAX);")]
1540 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, OVERFLOW);")]
1541 pub const fn unwrap_or(self, default: Self) -> Self {
1543 if self.is_reserved() {
1544 default
1545 }
1546 else {
1547 self
1548 }
1549 }
1550
1551 #[doc = concat!("Returns the result from a closure if the `",
1552 stringify!($SelfT), "` is not valid (i.e. reserved).")]
1553 #[doc = concat!("# use vax_floating::", stringify!($SelfT), ";")]
1561 #[doc = concat!("fn saturate_float(float: ", stringify!($SelfT), ") -> ",
1563 stringify!($SelfT), " {")]
1564 #[doc = concat!(" match <Result<", stringify!($SelfT), ">>::from(float) {")]
1566 #[doc = concat!(" Err(Overflow(_)) | Err(DivByZero) => ", stringify!($SelfT), "::MAX,")]
1568 #[doc = concat!(" Err(Underflow(_)) => ", stringify!($SelfT), "::MIN_POSITIVE,")]
1569 #[doc = concat!(" Err(_) => ", stringify!($SelfT), "::MIN,")]
1570 #[doc = concat!("let twelve_dot_five: ", stringify!($SelfT), " = ", stringify!($SelfT),
1574 "::from_f32(12.5).unwrap_or_else(saturate_float);")]
1575 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_f32(12.5), twelve_dot_five);")]
1576 #[doc = concat!("let overflow: ", stringify!($SelfT), " = ", stringify!($SelfT),
1578 "::MAX.add_to(", stringify!($SelfT), "::MAX).unwrap_or_else(saturate_float);")]
1579 #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, overflow);")]
1580 pub fn unwrap_or_else<F: FnOnce(Self) -> Self>(self, op: F) -> Self {
1582 if self.is_reserved() {
1583 op(self)
1584 }
1585 else {
1586 self
1587 }
1588 }
1589
1590 from_rust_int_impl!($ux, $SelfT);
1591
1592 to_from_rust_fp_impl!($ux, $SelfT);
1593
1594 to_from_vax_float_impl!($ux, $SelfT);
1595 }
1596
1597 from_rust_int_impl!(From, $ux, $SelfT);
1598
1599 to_from_rust_fp_impl!(From, $ux, $SelfT);
1600
1601 to_from_vax_float_impl!(From, $SelfT);
1602
1603 impl From<$SelfT> for Result<$SelfT> {
1604 fn from(float: $SelfT) -> Result<$SelfT> {
1605 float.to_result()
1606 }
1607 }
1608
1609 impl From<Result<$SelfT>> for $SelfT {
1610 fn from(result: Result<$SelfT>) -> $SelfT {
1611 match result {
1612 Ok(float) => float,
1613 Err(err) => $SelfT::from_error(&err),
1614 }
1615 }
1616 }
1617
1618 impl Hash for $SelfT {
1619 fn hash<H: Hasher>(&self, state: &mut H) {
1620 const ZERO: $ux = 0;
1621 if self.is_zero() { ZERO.hash(state); }
1622 else { self.0.hash(state) }
1623 }
1624 }
1625
1626 impl PartialEq for $SelfT {
1627 fn eq(&self, other: &Self) -> bool {
1628 if self.is_zero() && other.is_zero() { true }
1630 else { self.0 == other.0 }
1631 }
1632 }
1633
1634 impl PartialOrd for $SelfT {
1635 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1636 use Ordering::*;
1637 if self.is_reserved() || other.is_reserved() {
1638 if self.0 == other.0 { return Some(Equal); }
1639 return None;
1640 }
1641 match (self.is_zero(), other.is_zero()) {
1642 (true, true) => Some(Equal),
1643 (false, true) => match 0 == (self.0 & Self::SIGN) {
1644 true => Some(Greater),
1645 false => Some(Less),
1646 }
1647 (true, false) => match 0 == (other.0 & Self::SIGN) {
1648 true => Some(Less),
1649 false => Some(Greater),
1650 }
1651 (false, false) => {
1652 if (0 != (self.0 & Self::SIGN)) ^ (0 != (other.0 & Self::SIGN)) {
1653 match (0 != (self.0 & Self::SIGN)) {
1654 false => Some(Greater),
1655 true => Some(Less),
1656 }
1657 }
1658 else {
1659 match 0 != (self.0 & Self::SIGN) {
1660 false => {
1661 Self::swap_words(self.0 & !Self::SIGN)
1662 .partial_cmp(&Self::swap_words(other.0 & !Self::SIGN))
1663 }
1664 true => {
1665 Self::swap_words(other.0 & !Self::SIGN)
1666 .partial_cmp(&Self::swap_words(self.0 & !Self::SIGN))
1667 }
1668 }
1669 }
1670 }
1671 }
1672 }
1673 }
1674
1675 impl Add for $SelfT {
1676 type Output = $SelfT;
1677
1678 fn add(self, rhs: Self) -> Self::Output {
1679 Self::from_fp(self.to_fp().add_to(rhs.to_fp(), false))
1680 }
1681 }
1682 forward_ref_binop!(impl Add, add for $SelfT, $SelfT);
1683
1684 impl AddAssign for $SelfT {
1685 #[inline]
1686 fn add_assign(&mut self, other: $SelfT) {
1687 *self = *self / other;
1688 }
1689 }
1690 forward_ref_op_assign! { impl AddAssign, add_assign for $SelfT, $SelfT }
1691
1692 impl Sub for $SelfT {
1693 type Output = $SelfT;
1694
1695 fn sub(self, rhs: Self) -> Self::Output {
1696 Self::from_fp(self.to_fp().add_to(rhs.to_fp(), true))
1697 }
1698 }
1699 forward_ref_binop!(impl Sub, sub for $SelfT, $SelfT);
1700
1701 impl SubAssign for $SelfT {
1702 #[inline]
1703 fn sub_assign(&mut self, other: $SelfT) {
1704 *self = *self / other;
1705 }
1706 }
1707 forward_ref_op_assign! { impl SubAssign, sub_assign for $SelfT, $SelfT }
1708
1709 impl Div for $SelfT {
1710 type Output = $SelfT;
1711
1712 fn div(self, rhs: Self) -> Self::Output {
1713 Self::from_fp(self.to_fp().divide_by(rhs.to_fp(), Self::DIV_PRECISION))
1714 }
1715 }
1716 forward_ref_binop!(impl Div, div for $SelfT, $SelfT);
1717
1718 impl DivAssign for $SelfT {
1719 #[inline]
1720 fn div_assign(&mut self, other: $SelfT) {
1721 *self = *self / other;
1722 }
1723 }
1724 forward_ref_op_assign! { impl DivAssign, div_assign for $SelfT, $SelfT }
1725
1726 impl Mul for $SelfT {
1727 type Output = $SelfT;
1728
1729 fn mul(self, rhs: Self) -> Self::Output {
1730 Self::from_fp(self.to_fp().multiply_by(rhs.to_fp()))
1731 }
1732 }
1733 forward_ref_binop!(impl Mul, mul for $SelfT, $SelfT);
1734
1735 impl MulAssign for $SelfT {
1736 #[inline]
1737 fn mul_assign(&mut self, other: $SelfT) {
1738 *self = *self * other;
1739 }
1740 }
1741 forward_ref_op_assign! { impl MulAssign, mul_assign for $SelfT, $SelfT }
1742
1743 sh_impl!($SelfT);
1744
1745 impl Neg for $SelfT {
1746 type Output = $SelfT;
1747
1748 #[inline]
1749 fn neg(self) -> Self::Output
1750 {
1751 self.negate()
1752 }
1753 }
1754 forward_ref_unop! { impl Neg, neg for $SelfT }
1755
1756 impl FromStr for $SelfT {
1757 type Err = Error;
1758
1759 fn from_str(s: &str) -> Result<$SelfT> {
1760 Ok($SelfT::from_ascii_inner(s)?)
1761 }
1762 }
1763
1764 impl Debug for $SelfT {
1765 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1766 let fp = self.to_fp();
1767 fmt.debug_struct(stringify!($SelfT))
1768 .field("bits", &format_args!(zero_ext_hex!($SelfT), self.clone().to_bits()))
1769 .field("sign", &format_args!("{:?}", fp.sign()))
1770 .field("exponent", &format_args!("{0}", fp.exponent()))
1771 .field("frac", &format_args!("{:#X}", fp.fraction()))
1772 .finish()
1773 }
1774 }
1775
1776 impl Display for $SelfT {
1777 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1778 self.to_fp().float_to_decimal_display(fmt, Self::MANTISSA_DIGITS)
1779 }
1780 }
1781
1782 impl LowerExp for $SelfT {
1783 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1784 self.to_fp().float_to_exponential_common(fmt, Self::MANTISSA_DIGITS, false)
1785 }
1786 }
1787
1788 impl UpperExp for $SelfT {
1789 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1790 self.to_fp().float_to_exponential_common(fmt, Self::MANTISSA_DIGITS, true)
1791 }
1792 }
1793 };
1794}
1795
1796floating_impl!{
1797 Self = FFloating,
1798 ActualT = u32,
1799 ExpBits = 8,
1800 VaxName = "F_floating",
1801 swapped = "0x42480000",
1802 le_bytes = "[0x48, 0x42, 0x00, 0x00]",
1803 be_bytes = "[0x00, 0x00, 0x42, 0x48]",
1804}
1805
1806floating_impl!{
1807 Self = DFloating,
1808 ActualT = u64,
1809 ExpBits = 8,
1810 VaxName = "D_floating",
1811 swapped = "0x4248000000000000",
1812 le_bytes = "[0x48, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]",
1813 be_bytes = "[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x48]",
1814}
1815
1816floating_impl!{
1817 Self = GFloating,
1818 ActualT = u64,
1819 ExpBits = 11,
1820 VaxName = "G_floating",
1821 swapped = "0x4049000000000000",
1822 le_bytes = "[0x49, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]",
1823 be_bytes = "[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49]",
1824}
1825
1826floating_impl!{
1827 Self = HFloating,
1828 ActualT = u128,
1829 ExpBits = 15,
1830 VaxName = "H_floating",
1831 swapped = "0x40049000000000000000000000000000",
1832 le_bytes = "[0x04, 0x40, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, \
1833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]",
1834 be_bytes = "[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
1835 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x40, 0x04]",
1836}
1837
1838#[cfg(test)]
1839mod tests {
1840 use super::{
1841 FFloating,
1842 DFloating,
1843 GFloating,
1844 HFloating,
1845 Sign,
1846 Error,
1847 };
1848 use proptest::prelude::*;
1849 use std::{
1850 cmp::{min, max},
1851 collections::hash_map::DefaultHasher,
1852 hash::{Hash, Hasher},
1853 str::FromStr,
1854 };
1855
1856 fn pi_str(size: usize) -> &'static str {
1857 static PI_STR: &'static str = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989";
1858 if 0 == size { &PI_STR[..=0] }
1859 else if size < (PI_STR.len()-2) { &PI_STR[..(size+2)] }
1860 else { PI_STR }
1861 }
1862
1863 macro_rules! create_pi_test {
1864 ($name: ident, $floating: ident, $start: expr) => {
1865 #[test]
1866 fn $name() {
1867 let expected_pi = $floating::from_str(pi_str($start as usize)).unwrap();
1868 for i in (($start+1) as usize)..1000 {
1869 let pi = $floating::from_str(pi_str(i)).unwrap();
1870 assert_eq!(pi, expected_pi);
1871 }
1872 }
1873 };
1874 }
1875
1876 create_pi_test!(f_floating_pi_test, FFloating, FFloating::DIGITS+1);
1877 create_pi_test!(d_floating_pi_test, DFloating, DFloating::DIGITS+1);
1878 create_pi_test!(g_floating_pi_test, GFloating, GFloating::DIGITS);
1879 create_pi_test!(h_floating_pi_test, HFloating, HFloating::DIGITS);
1880
1881 const MAX_FFLOATING: f32 = unsafe { std::mem::transmute::<u32, f32>(0x7EFFFFFF) };
1882 const MIN_FFLOATING: f32 = unsafe { std::mem::transmute::<u32, f32>(0xFEFFFFFF) };
1883
1884 prop_compose! {
1885 fn ffloating_f32_range(min: f32, max: f32)(float in min..=max) -> f32 {
1886 float
1887 }
1888 }
1889
1890 prop_compose! {
1891 fn ffloating_range(min: f32, max: f32)(float in ffloating_f32_range(min, max)) -> FFloating {
1892 FFloating::from_f32(float)
1893 }
1894 }
1895
1896 prop_compose! {
1897 fn ffloating_f32()(float in ffloating_f32_range(MIN_FFLOATING, MAX_FFLOATING)) -> f32 {
1898 float
1899 }
1900 }
1901
1902 prop_compose! {
1903 fn ffloating()(float in ffloating_f32_range(MAX_FFLOATING, MIN_FFLOATING)) -> FFloating {
1904 FFloating::from_f32(float)
1905 }
1906 }
1907
1908 macro_rules! to_from_test {
1909 ($float: ident, $floating: ident) => {
1910 let floating = $floating::from_f32($float);
1911 let to_f32 = floating.to_f32();
1912 assert_eq!($float, to_f32, "{:?}, float bits = {:#X}, to_from bits = {:#X}", floating,
1913 $float.to_bits(), to_f32.to_bits());
1914 };
1915 }
1916
1917 proptest! {
1918 #[test]
1919 fn to_from_f32(float in ffloating_f32()) {
1920 to_from_test!(float, FFloating);
1921 to_from_test!(float, DFloating);
1922 to_from_test!(float, GFloating);
1923 to_from_test!(float, HFloating);
1924 }
1925 }
1926
1927 #[test]
1928 fn verify_float_defaults() {
1929 assert_eq!(FFloating::default(), FFloating::from_bits(0));
1930 assert_eq!(DFloating::default(), DFloating::from_bits(0));
1931 assert_eq!(GFloating::default(), GFloating::from_bits(0));
1932 assert_eq!(HFloating::default(), HFloating::from_bits(0));
1933 }
1934
1935 macro_rules! swap_words_test {
1936 ($ux: ident, $bytes: literal, $vax_type: ident, $start: ident, $swapped: ident) => {
1937 let mut start = [0_u8; $bytes];
1938 start.copy_from_slice(&$start[0..$bytes]);
1939 let start = $ux::from_ne_bytes(start);
1940 let mut swapped = [0_u8; $bytes];
1941 swapped.copy_from_slice(&$swapped[(16-$bytes)..16]);
1942 let swapped = $ux::from_ne_bytes(swapped);
1943 assert_eq!($vax_type::swap_words(start), swapped)};
1946 }
1947
1948 proptest! {
1949 #[test]
1950 fn swap_words(words in proptest::collection::vec(u16::MIN..=u16::MAX, 8..=8)) {
1951 let start_bytes: Vec<u8> = words.iter().map(|w| w.to_ne_bytes()).flatten().collect();
1952 let swapped_bytes: Vec<u8> = words.iter().rev().map(|w| w.to_ne_bytes()).flatten().collect();
1953 swap_words_test!(u128, 16, HFloating, start_bytes, swapped_bytes);
1954 swap_words_test!(u64, 8, GFloating, start_bytes, swapped_bytes);
1955 swap_words_test!(u64, 8, DFloating, start_bytes, swapped_bytes);
1956 swap_words_test!(u32, 4, FFloating, start_bytes, swapped_bytes);
1957 }
1958 }
1959
1960 fn calculate_hash<T: Hash>(t: &T) -> u64 {
1961 let mut s = DefaultHasher::new();
1962 t.hash(&mut s);
1963 s.finish()
1964 }
1965
1966 macro_rules! create_hash_eq_test {
1967 ($name: ident, $floating: ident, $ux: ident) => {
1968 proptest! {
1969 #[test]
1970 fn $name(bits1 in <$ux>::MIN..=<$ux>::MAX, bits2 in <$ux>::MIN..=<$ux>::MAX) {
1971 let zero1 = bits1 & $floating::FRAC_MASK;
1972 let zero2 = bits2 & $floating::FRAC_MASK;
1973 let float1 = $floating::from_bits(bits1);
1974 let float2 = $floating::from_bits(bits2);
1975 let float_zero1 = $floating::from_bits(zero1);
1976 let float_zero2 = $floating::from_bits(zero2);
1977 if zero1 != bits1 {
1978 assert_ne!(float1, float_zero1, "float1 should not be equal to float_zero1");
1979 }
1980 if zero2 != bits2 {
1981 assert_ne!(float2, float_zero2, "float2 should not be equal to float_zero2");
1982 }
1983 if bits1 != bits2 {
1984 assert_ne!(float1, float2, "float1 should not be equal to float2");
1985 }
1986 else {
1987 assert_eq!(float1, float2, "float1 should be equal to float2");
1988 assert_eq!(calculate_hash(&float1), calculate_hash(&float2),
1989 "float1 hash should be equal to float2 hash");
1990 }
1991 assert_eq!(float_zero1, float_zero2, "float_zero1 should be equal to float_zero2");
1993 assert_eq!(calculate_hash(&float_zero1), calculate_hash(&float_zero2),
1994 "float_zero1 hash should be equal to float_zero2 hash");
1995 }
1996 }
1997 };
1998 }
1999
2000 create_hash_eq_test!(test_f_floating_hash_eq, FFloating, u32);
2001 create_hash_eq_test!(test_d_floating_hash_eq, DFloating, u64);
2002 create_hash_eq_test!(test_g_floating_hash_eq, GFloating, u64);
2003 create_hash_eq_test!(test_h_floating_hash_eq, HFloating, u128);
2004
2005 macro_rules! create_ordering_test {
2006 ($name: ident, $floating: ident, $ux: ident) => {
2007 #[test]
2008 fn $name() {
2009 use Sign::*;
2010 const MAX_FRAC: $ux = (1 << $floating::MANTISSA_DIGITS) - 1;
2011 static ORDERED_LIST: &'static [$floating] = &[
2012 $floating::from_parts(Negative, $floating::MAX_EXP, MAX_FRAC), $floating::from_parts(Negative, $floating::MAX_EXP, 0),
2014 $floating::from_parts(Negative, 0, MAX_FRAC), $floating::from_parts(Negative, 0, 0), $floating::from_parts(Negative, $floating::MIN_EXP, MAX_FRAC),
2017 $floating::from_parts(Negative, $floating::MIN_EXP, 0), $floating(0), $floating::from_parts(Positive, $floating::MIN_EXP, 0), $floating::from_parts(Positive, $floating::MIN_EXP, MAX_FRAC),
2021 $floating::from_parts(Positive, 0, 0), $floating::from_parts(Positive, 0, MAX_FRAC), $floating::from_parts(Positive, $floating::MAX_EXP, 0),
2024 $floating::from_parts(Positive, $floating::MAX_EXP, MAX_FRAC), ];
2026 for i in 0..ORDERED_LIST.len() {
2027 let leq = ORDERED_LIST[i];
2028 for j in i..ORDERED_LIST.len() {
2029 let geq = ORDERED_LIST[j];
2030 assert!(leq <= geq,
2031 "Comparison failed: {:X?} should be less than {:X?}, but it wasn't",
2032 leq, geq);
2033 assert!(geq >= leq,
2034 "Comparison failed: {:X?} should be less than {:X?}, but it wasn't",
2035 leq, geq);
2036 }
2037 }
2038 }
2039 };
2040 }
2041
2042 create_ordering_test!(test_f_floating_ordering, FFloating, u32);
2043 create_ordering_test!(test_d_floating_ordering, DFloating, u64);
2044 create_ordering_test!(test_g_floating_ordering, GFloating, u64);
2045 create_ordering_test!(test_h_floating_ordering, HFloating, u128);
2046
2047 macro_rules! create_convert_test {
2048 ($name: ident, $floating: ident, $ux: ident) => {
2049 proptest! {
2050 #[test]
2051 fn $name(
2052 frac in 0..((1 as $ux) << ($floating::MANTISSA_DIGITS)),
2053 sign in 0..=1,
2054 ) {
2055 let sign = if sign == 0 { '+' } else { '-' };
2056 let int_text = format!("{}{}", sign, frac);
2057 let float_text = format!("{}{}.0", sign, frac);
2058 let exp_text = {
2059 let (before, after) = int_text.split_at(2);
2060 format!("{}.{}e{}", before, after, after.len())
2061 };
2062 let from_int_text = $floating::from_str(&int_text).unwrap();
2063 let from_float_text = $floating::from_str(&float_text).unwrap();
2064 let from_exp_text = $floating::from_str(&exp_text).unwrap();
2065 let mut from_frac = $floating::from(frac);
2066 if '-' == sign { from_frac = -from_frac; }
2067 prop_assert_eq!(from_int_text, from_float_text);
2068 prop_assert_eq!(from_int_text, from_exp_text);
2069 prop_assert_eq!(from_int_text, from_frac);
2070 }
2071 }
2072 };
2073 }
2074
2075 create_convert_test!(convert_to_f_floating, FFloating, u32);
2076 create_convert_test!(convert_to_d_floating, DFloating, u64);
2077 create_convert_test!(convert_to_g_floating, GFloating, u64);
2078 create_convert_test!(convert_to_h_floating, HFloating, u128);
2079
2080 pub fn display_close_enough(disp1: &str, disp2: &str, ok_diff: usize, fail_msg: &str) -> u128 {
2085 if disp1 != disp2 {
2086 close_enough_inner(disp1.to_string(), disp2.to_string(), disp1, disp2, ok_diff, fail_msg)
2087 }
2088 else { 0 }
2089 }
2090
2091 pub fn close_enough_inner(
2098 mut disp1: String,
2099 mut disp2: String,
2100 orig1: &str,
2101 orig2: &str,
2102 ok_diff: usize,
2103 fail_msg: &str,
2104 ) -> u128 {
2105 match disp1.get(0..=0) {
2107 Some("+") => if disp1.get(0..=0) == Some("+") {
2108 disp1.remove(0);
2109 disp2.remove(0);
2110 }
2111 else {
2112 panic!("Signs don't match don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2113 }
2114 Some("-") => if disp1.get(0..=0) == Some("-") {
2115 disp1.remove(0);
2116 disp2.remove(0);
2117 }
2118 else {
2119 panic!("Signs don't match don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2120 }
2121 _ => {}
2122 }
2123 if disp1.contains(['e', 'E']) {
2125 let (rem1, exp1) = disp1.rsplit_once(['e', 'E']).unwrap_or((&disp1, ""));
2126 let (rem2, exp2) = disp2.rsplit_once(['e', 'E']).unwrap_or((&disp2, ""));
2127 if exp1 != exp2 {
2128 panic!("Exponents don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2129 }
2130 disp1.truncate(rem1.len());
2131 disp2.truncate(rem2.len());
2132 }
2133 match(disp1.find('.'), disp2.find('.')) {
2135 (Some(p1), Some(p2)) => {
2136 if p1 != p2 {
2137 panic!("Decimal points don't line up: {}\n left: {:?}\nright: {:?}", fail_msg,
2138 orig1, orig2);
2139 }
2140 disp1.remove(p1);
2141 disp2.remove(p2);
2142 }
2143 (None, Some(p2)) => {
2144 if disp1.len() != p2 {
2145 panic!("Decimal points don't line up: {}\n left: {:?}\nright: {:?}", fail_msg,
2146 orig1, orig2);
2147 }
2148 disp2.remove(p2);
2149 }
2150 (Some(p1), None) => {
2151 if p1 != disp2.len() {
2152 panic!("Decimal points don't line up: {}\n left: {:?}\nright: {:?}", fail_msg,
2153 orig1, orig2);
2154 }
2155 disp1.remove(p1);
2156 }
2157 (None, None) => {}
2158 }
2159 let no_lead1 = disp1.trim_start_matches('0');
2161 let no_lead2 = disp2.trim_start_matches('0');
2162 if 1 < (disp1.len() - no_lead1.len()).abs_diff(disp2.len() - no_lead2.len()) {
2163 panic!("Leading zeroes don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2164 }
2165 let no_tail1 = disp1.trim_end_matches('0');
2167 let no_tail2 = disp2.trim_end_matches('0');
2168 let remove_tail = min(disp1.len() - no_tail1.len(), disp2.len() - no_tail2.len());
2169 disp1.truncate(disp1.len() - remove_tail);
2170 disp2.truncate(disp2.len() - remove_tail);
2171 if disp1.len() > disp2.len() {
2172 for _ in 0..(disp1.len()-disp2.len()) {
2173 disp2.push('0');
2174 }
2175 }
2176 else if disp1.len() < disp2.len() {
2177 for _ in 0..(disp2.len()-disp1.len()) {
2178 disp1.push('0');
2179 }
2180 }
2181 let val1 = i128::from_str_radix(&disp1, 10)
2182 .expect(&format!("Failed to convert string to number ({:?}): {}\n left: {:?}\nright: {:?}",
2183 &disp1, fail_msg, orig1, orig2));
2184 let val2 = i128::from_str_radix(&disp2, 10)
2185 .expect(&format!("Failed to convert string to number ({:?}): {}\n left: {:?}\nright: {:?}",
2186 &disp2, fail_msg, orig1, orig2));
2187 let diff = val1.abs_diff(val2);
2188 if diff > (ok_diff as u128) {
2189 panic!("Values are too far apart ({}): {}\n left: {:?}\nright: {:?}", diff, fail_msg,
2190 orig1, orig2);
2191 }
2192 diff
2193 }
2194
2195 pub fn display_close_enough_2(disp1: &str, disp2: &str, digits: usize, precision: bool, fail_msg: &str) -> u128 {
2200 if disp1 != disp2 {
2201 close_enough_inner_2(disp1.to_string(), disp2.to_string(), disp1, disp2, digits, precision, fail_msg)
2202 }
2203 else { 0 }
2204 }
2205
2206 pub fn close_enough_inner_2(
2223 mut disp1: String,
2224 mut disp2: String,
2225 orig1: &str,
2226 orig2: &str,
2227 digits: usize,
2228 precision: bool,
2229 fail_msg: &str,
2230 ) -> u128 {
2231 match disp1.get(0..=0) {
2233 Some("+") => if disp1.get(0..=0) == Some("+") {
2234 disp1.remove(0);
2235 disp2.remove(0);
2236 }
2237 else {
2238 panic!("Signs don't match don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2239 }
2240 Some("-") => if disp1.get(0..=0) == Some("-") {
2241 disp1.remove(0);
2242 disp2.remove(0);
2243 }
2244 else {
2245 panic!("Signs don't match don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2246 }
2247 _ => {}
2248 }
2249 if disp1.contains(['e', 'E']) {
2251 let (rem1, exp1) = disp1.rsplit_once(['e', 'E']).unwrap_or((&disp1, ""));
2252 let (rem2, exp2) = disp2.rsplit_once(['e', 'E']).unwrap_or((&disp2, ""));
2253 if exp1 != exp2 {
2254 panic!("Exponents don't match: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2255 }
2256 disp1.truncate(rem1.len());
2257 disp2.truncate(rem2.len());
2258 }
2259 let fp1 = match disp1.find('.') {
2261 None => disp1.len(),
2262 Some(fp1) => {
2263 disp1.remove(fp1);
2264 fp1
2265 }
2266 };
2267 let fp2 = match disp2.find('.') {
2268 None => disp2.len(),
2269 Some(fp2) => {
2270 disp2.remove(fp2);
2271 fp2
2272 }
2273 };
2274 if precision {
2275 if (disp1.len() - fp1) != (disp2.len() - fp2) {
2276 panic!("Precision mismatch: {}\n left: {:?}\nright: {:?}", fail_msg, orig1, orig2);
2277 }
2278 }
2279 let (val1, val2) = match (disp1.find(|c: char| ('1' <= c) && ('9' >= c)),
2280 disp2.find(|c: char| ('1' <= c) && ('9' >= c)))
2281 {
2282 (None, None) => (0, 0),
2283 (Some(digit1), None) => (
2284 u128::from_str_radix(&disp1[digit1..min(digit1+digits, disp1.len())], 10)
2285 .expect(&format!("Failed to convert string to number ({:?}): {}\n left: {:?}\nright: {:?}",
2286 &disp1, fail_msg, orig1, orig2)),
2287 0),
2288 (None, Some(digit2)) => (0,
2289 u128::from_str_radix(&disp2[digit2..min(digit2+digits, disp2.len())], 10)
2290 .expect(&format!("Failed to convert string to number ({:?}): {}\n left: {:?}\nright: {:?}",
2291 &disp2, fail_msg, orig1, orig2))),
2292 (Some(digit1), Some(digit2)) => {
2293 let offset = min((digit1 as isize)-(fp1 as isize), (digit2 as isize)-(fp2 as isize));
2294 let start1 = if 0 > ((fp1 as isize)+offset) {
2295 for _ in 0..((fp1 as isize)+offset).unsigned_abs() {
2296 disp1.insert(0, '0');
2297 }
2298 0
2299 }
2300 else {
2301 ((fp1 as isize)+offset) as usize
2302 };
2303 let start2 = if 0 > ((fp2 as isize)+offset) {
2304 for _ in 0..((fp2 as isize)+offset).unsigned_abs() {
2305 disp2.insert(0, '0');
2306 }
2307 0
2308 }
2309 else {
2310 ((fp2 as isize)+offset) as usize
2311 };
2312 let mut target_len = max(disp1.len()-start1, disp2.len()-start2);
2313 if target_len > digits { target_len = digits; }
2314 if disp1.len()-start1 > target_len {
2315 disp1.truncate(start1 + target_len);
2316 }
2317 else if disp1.len()-start1 < target_len {
2318 for _ in 0..(target_len+start1-disp1.len()) {
2319 disp1.push('0');
2320 }
2321 }
2322 if disp2.len()-start2 > target_len {
2323 disp2.truncate(start2 + target_len);
2324 }
2325 else if disp2.len()-start2 < target_len {
2326 for _ in 0..(target_len+start2-disp2.len()) {
2327 disp2.push('0');
2328 }
2329 }
2330 (
2331 u128::from_str_radix(&disp1[start1..], 10)
2332 .expect(&format!("Failed to convert string to number ({:?}): {}\n left: {:?}\nright: {:?}",
2333 &disp1, fail_msg, orig1, orig2)),
2334 u128::from_str_radix(&disp2[start2..], 10)
2335 .expect(&format!("Failed to convert string to number ({:?}): {}\n left: {:?}\nright: {:?}",
2336 &disp1, fail_msg, orig1, orig2))
2337 )
2338 }
2339 };
2340 let diff = val1.abs_diff(val2);
2341 if diff > (1 as u128) {
2342 panic!("Values are too far apart ({}): {}\n left: {:?}\nright: {:?}", diff, fail_msg,
2343 orig1, orig2);
2344 }
2345 diff
2346 }
2347
2348 macro_rules! display_case {
2349 ($fmt: literal, $floating: ident, $fx: ident, $text: ident) => {
2350 let vax_float = format!($fmt, $floating);
2351 let rust_float = format!($fmt, $fx);
2352 dbg!(&$text);
2353 display_close_enough(&vax_float, &rust_float, 2, &format!("input string = {:?}", $text));
2354 };
2355 }
2356
2357 macro_rules! create_display_test {
2358 ($name: ident, $floating: ident, $ux: ident, $fx: ident) => {
2359 create_display_test!($name, $floating, $ux, $fx, {
2360 "{}",
2361 "{:e}",
2362 "{:E}",
2363 "{:.0e}",
2364 "{:.0E}",
2365 "{:.1e}",
2366 "{:.1E}",
2367 "{:.2e}",
2368 "{:.2E}",
2369 "{:.3e}",
2370 "{:.3E}",
2371 "{:.4e}",
2372 "{:.4E}",
2373 "{:.5e}",
2374 "{:.5E}",
2375 "{:.6e}",
2376 "{:.6E}"
2377 });
2378 };
2379 ($name: ident, $floating: ident, $ux: ident, $fx: ident, $fmts: tt) => {
2380 create_display_test!($name, $floating, $ux, $fx, $fmts, $floating::MIN_10_EXP+1, $floating::MAX_10_EXP);
2381 };
2382 (
2383 $name: ident,
2384 $floating: ident,
2385 $ux: ident,
2386 $fx: ident,
2387 {$($fmt: literal),+},
2388 $min_exp: expr,
2389 $max_exp: expr
2390 ) => {
2391 proptest! {
2392 #[test]
2393 fn $name(
2394 frac in 9..((1 as $ux) << ($floating::MANTISSA_DIGITS)),
2395 exp in $min_exp..$max_exp,
2396 sign in 0..=1,
2397 ) {
2398 let sign = if sign == 0 { '+' } else { '-' };
2399 let int_text = if 9 == frac { "0".to_string() } else { format!("{}", frac) };
2400 let exp_text = {
2401 let (before, mut after) = int_text.split_at(1);
2402 if "" == after { after = "0"; }
2403 format!("{}{}.{}e{}", sign, before, after, exp)
2404 };
2405 let mut rust_float = $fx::from_str(&exp_text).unwrap();
2406 if rust_float == -0.0 { rust_float = 0.0; }
2407 let vax_float = $floating::from_str(&exp_text).unwrap();
2408 $(
2409 display_case!($fmt, vax_float, rust_float, exp_text);
2410 )+
2411 }
2412 }
2413 };
2414 ($name: ident, $floating: ident, $ux: ident) => {
2415 create_display_test!($name, $floating, $ux, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2416 13, 14, 15, 16, 17});
2417 };
2418 ($name: ident, $floating: ident, $ux: ident, $fmts: tt) => {
2419 create_display_test!($name, $floating, $ux, $fmts, $floating::MIN_10_EXP+1, $floating::MAX_10_EXP);
2420 };
2421 (
2422 $name: ident,
2423 $floating: ident,
2424 $ux: ident,
2425 {$($prec: literal),+},
2426 $min_exp: expr,
2427 $max_exp: expr
2428 ) => {
2429 proptest! {
2430 #[test]
2431 fn $name(
2432 frac in 9..((1 as $ux) << ($floating::MANTISSA_DIGITS)),
2433 exp in $min_exp..$max_exp,
2434 sign in 0..=1,
2435 ) {
2436 let mut sign = if sign == 0 { "" } else { "-" };
2437 let int_text = if 9 == frac {
2438 sign = "";
2439 "0".to_string()
2440 } else { format!("{}", frac) };
2441 let exp_text = {
2442 let (before, mut after) = int_text.split_at(1);
2443 if "" == after { after = "0"; }
2444 format!("{}{}.{}e{}", sign, before, after, exp)
2445 };
2446 let vax_float = $floating::from_str(&exp_text).unwrap();
2447 $(
2448 {
2449 let mut expected = if 0 > exp {
2450 let leading_zeroes = (exp.unsigned_abs() - 1) as usize;
2451 format!("{0}0.{3:0>1$}{2}", sign, leading_zeroes, int_text, "")
2452 }
2453 else {
2454 let insert = (exp as usize) + 1;
2455 if insert > int_text.len() {
2456 let trailing_zeroes = if "0" == int_text { 0 } else {
2457 insert - int_text.len()
2458 };
2459 format!("{0}{1}{3:0>2$}.0", sign, int_text, trailing_zeroes, "")
2460 }
2461 else {
2462 let (before, after) = int_text.split_at(insert);
2463 format!("{0}{1}.{2}", sign, before, after)
2464 }
2465 };
2466 let end = expected.find('.').unwrap_or(expected.len()) + $prec + 1;
2467 if 0 == $prec { expected.truncate(end - 1); }
2468 else if end < expected.len() { expected.truncate(end); }
2469 else if end > expected.len() {
2470 for _ in expected.len()..end {
2471 expected.push('0');
2472 }
2473 }
2474 let vax_float = format!("{0:.1$}", vax_float, $prec);
2475 display_close_enough_2(&vax_float, &expected, $floating::DIGITS as usize, true, &format!("input string = {:?}", &exp_text));
2476 }
2477 )+
2478 }
2479 }
2480 };
2481 }
2482
2483 create_display_test!(display_f_floating, FFloating, u32, f32);
2484 create_display_test!(display_g_floating, GFloating, u64, f64);
2485 create_display_test!(display_g_floating_extra, GFloating, u64, f64, {
2486 "{:.7e}",
2487 "{:.7E}",
2488 "{:.8e}",
2489 "{:.8E}",
2490 "{:.9e}",
2491 "{:.9E}",
2492 "{:.10e}",
2493 "{:.10E}",
2494 "{:.11e}",
2495 "{:.11E}",
2496 "{:.12e}",
2497 "{:.12E}",
2498 "{:.13e}",
2499 "{:.13E}",
2500 "{:.14e}",
2501 "{:.14E}",
2502 "{:.15e}",
2503 "{:.15E}"
2504 });
2505 create_display_test!(display_d_floating, DFloating, u64, f64, {
2506 "{:.0e}",
2507 "{:.0E}",
2508 "{:.1e}",
2509 "{:.1E}",
2510 "{:.2e}",
2511 "{:.2E}",
2512 "{:.3e}",
2513 "{:.3E}",
2514 "{:.4e}",
2515 "{:.4E}",
2516 "{:.5e}",
2517 "{:.5E}",
2518 "{:.6e}",
2519 "{:.6E}",
2520 "{:.7e}",
2521 "{:.7E}",
2522 "{:.8e}",
2523 "{:.8E}",
2524 "{:.9e}",
2525 "{:.9E}",
2526 "{:.10e}",
2527 "{:.10E}",
2528 "{:.11e}",
2529 "{:.11E}",
2530 "{:.12e}",
2531 "{:.12E}",
2532 "{:.13e}",
2533 "{:.13E}",
2534 "{:.14e}",
2535 "{:.14E}",
2536 "{:.15e}",
2537 "{:.15E}"
2538 });
2539 create_display_test!(display_h_floating, HFloating, u128, f64, {
2540 "{:.0e}",
2541 "{:.0E}",
2542 "{:.1e}",
2543 "{:.1E}",
2544 "{:.2e}",
2545 "{:.2E}",
2546 "{:.3e}",
2547 "{:.3E}",
2548 "{:.4e}",
2549 "{:.4E}",
2550 "{:.5e}",
2551 "{:.5E}",
2552 "{:.6e}",
2553 "{:.6E}",
2554 "{:.7e}",
2555 "{:.7E}",
2556 "{:.8e}",
2557 "{:.8E}",
2558 "{:.9e}",
2559 "{:.9E}",
2560 "{:.10e}",
2561 "{:.10E}",
2562 "{:.11e}",
2563 "{:.11E}",
2564 "{:.12e}",
2565 "{:.12E}",
2566 "{:.13e}",
2567 "{:.13E}",
2568 "{:.14e}",
2569 "{:.14E}",
2570 "{:.15e}",
2571 "{:.15E}"
2572 }, f64::MIN_10_EXP+1, f64::MAX_10_EXP);
2573 create_display_test!(display_f_floating_precision, FFloating, u32);
2577 create_display_test!(display_d_floating_precision, DFloating, u64);
2578 create_display_test!(display_g_floating_precision, GFloating, u64);
2579 create_display_test!(display_h_floating_precision, HFloating, u128);
2580
2581 #[test]
2582 fn vax_reserved_and_results() {
2583 assert_eq!(FFloating::from_bits(0x8000).to_result(), Err(Error::DivByZero));
2584 assert_eq!(DFloating::from_bits(0x8000).to_result(), Err(Error::DivByZero));
2585 assert_eq!(GFloating::from_bits(0x8000).to_result(), Err(Error::DivByZero));
2586 assert_eq!(HFloating::from_bits(0x8000).to_result(), Err(Error::DivByZero));
2587 assert_eq!(FFloating::from_bits(0x8060).to_result(), Err(Error::Reserved));
2588 assert_eq!(DFloating::from_bits(0x8060).to_result(), Err(Error::Reserved));
2589 assert_eq!(GFloating::from_bits(0x800C).to_result(), Err(Error::Reserved));
2590 assert_eq!(HFloating::from_bits(0xC0008000).to_result(), Err(Error::Reserved));
2591 assert_eq!(FFloating::from_bits(0x8040).to_result(), Err(Error::Overflow(None)));
2592 assert_eq!(DFloating::from_bits(0x8040).to_result(), Err(Error::Overflow(None)));
2593 assert_eq!(GFloating::from_bits(0x8008).to_result(), Err(Error::Overflow(None)));
2594 assert_eq!(HFloating::from_bits(0x80008000).to_result(), Err(Error::Overflow(None)));
2595 assert_eq!(FFloating::from_bits(0x8020).to_result(), Err(Error::Underflow(None)));
2596 assert_eq!(DFloating::from_bits(0x8020).to_result(), Err(Error::Underflow(None)));
2597 assert_eq!(GFloating::from_bits(0x8004).to_result(), Err(Error::Underflow(None)));
2598 assert_eq!(HFloating::from_bits(0x40008000).to_result(), Err(Error::Underflow(None)));
2599 assert_eq!(FFloating::from_bits(0xFFFF8040).to_result(), Err(Error::Overflow(Some(65535))));
2600 assert_eq!(DFloating::from_bits(0xFFFF8040).to_result(), Err(Error::Overflow(Some(65535))));
2601 assert_eq!(GFloating::from_bits(0xFFFF8008).to_result(), Err(Error::Overflow(Some(65535))));
2602 assert_eq!(HFloating::from_bits(0xFFFF80008000).to_result(), Err(Error::Overflow(Some(65535))));
2603 assert_eq!(FFloating::from_bits(0x80008020).to_result(), Err(Error::Underflow(Some(-32768))));
2604 assert_eq!(DFloating::from_bits(0x80008020).to_result(), Err(Error::Underflow(Some(-32768))));
2605 assert_eq!(GFloating::from_bits(0x80008004).to_result(), Err(Error::Underflow(Some(-32768))));
2606 assert_eq!(HFloating::from_bits(0x800040008000).to_result(), Err(Error::Underflow(Some(-32768))));
2607 }
2608
2609 macro_rules! ilog10_test {
2610 ($ux: ty) => {
2611 let mut value: $ux = <$ux>::MAX;
2612 let ilog = value.ilog10();
2613 let display = format!("{}", value).len() - 1;
2614 let mut slow = 0_u32;
2615 while 10 <= value {
2616 slow += 1;
2617 value /= 10;
2618 }
2619 assert_eq!(ilog, slow);
2620 assert_eq!(ilog, display as u32);
2621 };
2622 ($ux: ty, $floating: ident) => {
2623 let mut value: $ux = 1 << $floating::MANTISSA_DIGITS;
2624 let ilog = value.ilog10();
2625 let display = format!("{}", value).len() - 1;
2626 let mut slow = 0_u32;
2627 while 10 <= value {
2628 slow += 1;
2629 value /= 10;
2630 }
2631 assert_eq!(ilog, slow);
2632 assert_eq!(ilog, display as u32);
2633 };
2634 }
2635
2636 #[test]
2637 fn alternate_ilog10() {
2638 ilog10_test!(u32, FFloating);
2639 ilog10_test!(u64, DFloating);
2640 ilog10_test!(u64, GFloating);
2641 ilog10_test!(u128, HFloating);
2642 ilog10_test!(u32);
2643 ilog10_test!(u64);
2644 ilog10_test!(u128);
2645 }
2646
2647 #[test]
2648 #[ignore]
2649 fn minor_display_bug_1() {
2650 const TENTH: DFloating = DFloating::from_ascii("0.1");
2651 const ONE_HUNDRED: FFloating = FFloating::from_u8(100);
2652 const MANY_ZEROES: HFloating = HFloating::from_u128(
2653 100_000_000_000_000_000_000_000_000_000_000u128);
2654 assert_eq!(&format!("{:e}", TENTH), "1e-1");
2655 assert_eq!(&format!("{:e}", ONE_HUNDRED), "1e2"); assert_eq!(&format!("{:E}", MANY_ZEROES), "1E32"); }
2658
2659 proptest! {
2660 fn from_h_floating_tests(
2661 h_floating in any::<HFloating>(),
2662 ) {
2663 let float_as_text = h_floating.to_string();
2664 let f_float = h_floating.to_f_floating();
2665 let d_float = h_floating.to_d_floating();
2666 let g_float = h_floating.to_g_floating();
2667 assert_eq!(f_float, FFloating::from_str(&float_as_text).unwrap());
2668 assert_eq!(d_float, DFloating::from_str(&float_as_text).unwrap());
2669 assert_eq!(g_float, GFloating::from_str(&float_as_text).unwrap());
2670 }
2671 }
2672
2673 proptest! {
2674 fn from_g_floating_tests(
2675 g_floating in any::<GFloating>(),
2676 ) {
2677 let float_as_text = g_floating.to_string();
2678 let f_float = g_floating.to_f_floating();
2679 let d_float = g_floating.to_d_floating();
2680 let h_float = g_floating.to_h_floating();
2681 assert_eq!(f_float, FFloating::from_str(&float_as_text).unwrap());
2682 assert_eq!(d_float, DFloating::from_str(&float_as_text).unwrap());
2683 assert_eq!(h_float, HFloating::from_str(&float_as_text).unwrap());
2684 }
2685 }
2686
2687 proptest! {
2688 fn from_d_floating_tests(
2689 d_floating in any::<DFloating>(),
2690 ) {
2691 let float_as_text = d_floating.to_string();
2692 let f_float = d_floating.to_f_floating();
2693 let g_float = d_floating.to_g_floating();
2694 let h_float = d_floating.to_h_floating();
2695 assert_eq!(f_float, FFloating::from_str(&float_as_text).unwrap());
2696 assert_eq!(g_float, GFloating::from_str(&float_as_text).unwrap());
2697 assert_eq!(h_float, HFloating::from_str(&float_as_text).unwrap());
2698 }
2699 }
2700
2701 proptest! {
2702 fn from_f_floating_tests(
2703 f_floating in any::<FFloating>(),
2704 ) {
2705 let float_as_text = f_floating.to_string();
2706 let d_float = f_floating.to_d_floating();
2707 let g_float = f_floating.to_g_floating();
2708 let h_float = f_floating.to_h_floating();
2709 assert_eq!(d_float, DFloating::from_str(&float_as_text).unwrap());
2710 assert_eq!(g_float, GFloating::from_str(&float_as_text).unwrap());
2711 assert_eq!(h_float, HFloating::from_str(&float_as_text).unwrap());
2712 }
2713 }
2714}