2 releases
0.1.1 | Jan 19, 2020 |
---|---|
0.1.0 | Jan 19, 2020 |
#931 in Algorithms
1,458 downloads per month
Used in 3 crates
(via giga-segy-core)
57KB
1K
SLoC
ibmfloat
A Rust library for IBM floating point numbers, specifically focused on converting them to IEEE-754 floating point values.
This crate has no Rust dependencies, no C dependencies, and no unsafe
code. Its std
feature is enabled by default,
and it can be disabled to support #![no_std]
environments.
The conversion processes and much of the test suite are derived from the
Python ibm2ieee
library.
Performance
Representative results from a laptop:
F32 to f32 time: [6.7092 ns 6.7734 ns 6.8454 ns]
F32 to f64 time: [2.4642 ns 2.4965 ns 2.5326 ns]
F64 to f32 time: [7.2500 ns 7.3315 ns 7.4169 ns]
F64 to f64 time: [2.7761 ns 2.8028 ns 2.8342 ns]
Conversions to f32
are more expensive than conversions to f64
.
Usage
32-bit floats
ibmfloat::F32
represents a 32-bit IBM floating point number. It supports the conversions:
- Transmuting to/from a
u32
viafrom_bits()
,to_bits()
- Transmuting to/from a big-endian
[u8; 4]
viafrom_be_bytes()
/to_be_bytes()
- Lossily converting to an
f32
viaFrom
/Into
- Losslessly converting to an
f64
viaFrom
/Into
IBM F32
floats have slightly less precision than IEEE-754 f32
floats, but it covers a slightly larger domain. F32
s
of typical magnitude can be converted to f32
without rounding or other loss of precision. Converting F32
s of large
magnitude to f32
will cause rounding; F32
s of extreme magnitude can also cause overflow and underflow to occur.
Every F32
can be precisely represented as an f64
, without rounding, overflow, or underflow. Those seeking a lossless
path to IEEE-754 should convert F32
to f64
.
// Use the example -118.625:
// https://en.wikipedia.org/wiki/IBM_hexadecimal_floating_point#Example
let foreign_float = ibmfloat::F32::from_bits(0b1_1000010_0111_0110_1010_0000_0000_0000);
let native_float = f32::from(foreign_float);
assert_eq!(native_float, -118.625f32);
let native_float: f32 = foreign_float.into();
assert_eq!(native_float, -118.625f32);
64-bit floats
ibmfloat::64
represents a 64-bit IBM floating point number. It supports the conversions:
- Transmuting to/from a
u64
viafrom_bits()
,to_bits()
- Transmuting to/from a big-endian
[u8; 8]
viafrom_be_bytes()
/to_be_bytes()
- Lossily converting to an
f32
viaFrom
/Into
- Lossily converting to an
f64
viaFrom
/Into
IBM F64
floats have slightly more precision than IEEE-754 f64
floats, but they cover a slightly smaller domain. Most
conversions will require rounding, but there is no risk of overflow or underflow.
let foreign_float = ibmfloat::F64::from_bits(0x4110000000000000);
let native_float = f64::from(foreign_float);
assert_eq!(native_float, 1.0f64);
let native_float: f64 = foreign_float.into();
assert_eq!(native_float, 1.0f64);
Development
Please use cargo test
, cargo clippy
, and cargo fmt
as you go. Please also cargo test --no-default-features
to
prevent accidental breakage for #![no_std]
users. GitHub Actions runs each of these commands on push.
ibm2ieee-sys/
contains a crate wrapping ibm2ieee.c
, tests which compare ibm2ieee.c
's conversion to ibmfloat
's
conversions over random values, and benchmarks of both libraries.
$ cd ibm2ieee-sys/
$ cargo test
$ cargo bench
cargo fuzz
covers each of the four IBM to IEEE conversion paths, comparing
them to ibm2ieee-sys
. Please run them as needed if you tinker with that logic.
$ cargo +nightly fuzz run ibm32ieee32
$ cargo +nightly fuzz run ibm32ieee64
$ cargo +nightly fuzz run ibm64ieee32
$ cargo +nightly fuzz run ibm64ieee64
Additional references:
- ESA/390 Enhanced Floating Point Support: An Overview is an excellent introduction
- Hercules implements IBM floating point hardware in C