od: implement 16-bit floating point type

This commit is contained in:
Wim Hueskes 2016-09-03 21:47:36 +02:00
parent fd5879dcf2
commit 99f70ba648
7 changed files with 76 additions and 1 deletions

6
Cargo.lock generated
View file

@ -392,6 +392,11 @@ dependencies = [
"uucore 0.0.1",
]
[[package]]
name = "half"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hashsum"
version = "0.0.1"
@ -665,6 +670,7 @@ version = "0.0.1"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"half 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.1",
]

View file

@ -11,6 +11,7 @@ path = "od.rs"
getopts = "*"
libc = "*"
byteorder = "*"
half = "*"
uucore = { path="../uucore" }
[[bin]]

View file

@ -2,6 +2,7 @@ use std::io;
use byteorder_io::ByteOrder;
use multifilereader::HasError;
use peekreader::PeekRead;
use half::f16;
/// Processes an input and provides access to the data read in various formats
///
@ -128,6 +129,7 @@ impl<'a> MemoryDecoder<'a> {
/// Returns a f32/f64 from the internal buffer at position `start`.
pub fn read_float(&self, start: usize, byte_size: usize) -> f64 {
match byte_size {
2 => f64::from(f16::from_bits(self.byte_order.read_u16(&self.data[start..start + 2]))),
4 => self.byte_order.read_f32(&self.data[start..start + 4]) as f64,
8 => self.byte_order.read_f64(&self.data[start..start + 8]),
_ => panic!("Invalid byte_size: {}", byte_size),

View file

@ -11,6 +11,7 @@
extern crate getopts;
extern crate byteorder;
extern crate half;
#[macro_use]
extern crate uucore;

View file

@ -73,6 +73,7 @@ fn od_format_type(type_char: FormatType, byte_size: u8) -> Option<FormatterItemI
(FormatType::HexadecimalInt, 4) => Some(FORMAT_ITEM_HEX32),
(FormatType::HexadecimalInt, 8) => Some(FORMAT_ITEM_HEX64),
(FormatType::Float, 2) => Some(FORMAT_ITEM_F16),
(FormatType::Float, 0) |
(FormatType::Float, 4) => Some(FORMAT_ITEM_F32),
(FormatType::Float, 8) => Some(FORMAT_ITEM_F64),
@ -402,7 +403,7 @@ fn test_invalid_long_format() {
parse_format_flags_str(&vec!("od", "--format=c1")).unwrap_err();
parse_format_flags_str(&vec!("od", "--format=x256")).unwrap_err();
parse_format_flags_str(&vec!("od", "--format=d5")).unwrap_err();
parse_format_flags_str(&vec!("od", "--format=f2")).unwrap_err();
parse_format_flags_str(&vec!("od", "--format=f1")).unwrap_err();
}
#[test]

View file

@ -1,8 +1,15 @@
use std::num::FpCategory;
use half::f16;
use std::f32;
use std::f64;
use formatteriteminfo::*;
pub static FORMAT_ITEM_F16: FormatterItemInfo = FormatterItemInfo {
byte_size: 2,
print_width: 10,
formatter: FormatWriter::FloatWriter(format_item_flo16),
};
pub static FORMAT_ITEM_F32: FormatterItemInfo = FormatterItemInfo {
byte_size: 4,
print_width: 15,
@ -15,6 +22,9 @@ pub static FORMAT_ITEM_F64: FormatterItemInfo = FormatterItemInfo {
formatter: FormatWriter::FloatWriter(format_item_flo64),
};
pub fn format_item_flo16(f: f64) -> String {
format!(" {}", format_flo16(f16::from_f64(f)))
}
pub fn format_item_flo32(f: f64) -> String {
format!(" {}", format_flo32(f as f32))
@ -24,6 +34,10 @@ pub fn format_item_flo64(f: f64) -> String {
format!(" {}", format_flo64(f))
}
fn format_flo16(f: f16) -> String {
format_float(f64::from(f), 9, 4)
}
// formats float with 8 significant digits, eg 12345678 or -1.2345678e+12
// always retuns a string of 14 characters
fn format_flo32(f: f32) -> String {
@ -171,3 +185,30 @@ fn test_format_flo64() {
assert_eq!(format_flo64(-0.0), " -0");
assert_eq!(format_flo64(0.0), " 0");
}
#[test]
fn test_format_flo16() {
use half::consts::*;
assert_eq!(format_flo16(f16::from_bits(0x8400u16)), "-6.104e-5");
assert_eq!(format_flo16(f16::from_bits(0x8401u16)), "-6.109e-5");
assert_eq!(format_flo16(f16::from_bits(0x8402u16)), "-6.115e-5");
assert_eq!(format_flo16(f16::from_bits(0x8403u16)), "-6.121e-5");
assert_eq!(format_flo16(f16::from_f32(1.0)), " 1.000");
assert_eq!(format_flo16(f16::from_f32(10.0)), " 10.00");
assert_eq!(format_flo16(f16::from_f32(100.0)), " 100.0");
assert_eq!(format_flo16(f16::from_f32(1000.0)), " 1000");
assert_eq!(format_flo16(f16::from_f32(10000.0)), " 1.000e4");
assert_eq!(format_flo16(f16::from_f32(-0.2)), " -0.2000");
assert_eq!(format_flo16(f16::from_f32(-0.02)), "-2.000e-2");
assert_eq!(format_flo16(MIN_POSITIVE_SUBNORMAL), " 5.966e-8");
assert_eq!(format_flo16(MIN), " -6.550e4");
assert_eq!(format_flo16(NAN), " NaN");
assert_eq!(format_flo16(INFINITY), " inf");
assert_eq!(format_flo16(NEG_INFINITY), " -inf");
assert_eq!(format_flo16(NEG_ZERO), " -0");
assert_eq!(format_flo16(ZERO), " 0");
}

View file

@ -198,6 +198,29 @@ fn test_hex32(){
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_f16(){
let input : [u8; 14] = [
0x00, 0x3c, // 0x3C00 1.0
0x00, 0x00, // 0x0000 0.0
0x00, 0x80, // 0x8000 -0.0
0x00, 0x7c, // 0x7C00 Inf
0x00, 0xfc, // 0xFC00 -Inf
0x00, 0xfe, // 0xFE00 NaN
0x00, 0x84];// 0x8400 -6.104e-5
let expected_output = unindent("
0000000 1.000 0 -0 inf
0000010 -inf NaN -6.104e-5
0000016
");
let result = new_ucmd!().arg("--endian=little").arg("-tf2").arg("-w8").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_f32(){