diff --git a/Cargo.lock b/Cargo.lock index 0a8b0fe86..c06c977f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] diff --git a/src/od/Cargo.toml b/src/od/Cargo.toml index c6b86e354..a500caecc 100644 --- a/src/od/Cargo.toml +++ b/src/od/Cargo.toml @@ -11,6 +11,7 @@ path = "od.rs" getopts = "*" libc = "*" byteorder = "*" +half = "*" uucore = { path="../uucore" } [[bin]] diff --git a/src/od/inputdecoder.rs b/src/od/inputdecoder.rs index 01143d24b..97106fa2e 100644 --- a/src/od/inputdecoder.rs +++ b/src/od/inputdecoder.rs @@ -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), diff --git a/src/od/od.rs b/src/od/od.rs index a20856ba0..93e7c028d 100644 --- a/src/od/od.rs +++ b/src/od/od.rs @@ -11,6 +11,7 @@ extern crate getopts; extern crate byteorder; +extern crate half; #[macro_use] extern crate uucore; diff --git a/src/od/parse_formats.rs b/src/od/parse_formats.rs index db4b20daa..5f719deba 100644 --- a/src/od/parse_formats.rs +++ b/src/od/parse_formats.rs @@ -73,6 +73,7 @@ fn od_format_type(type_char: FormatType, byte_size: u8) -> Option 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] diff --git a/src/od/prn_float.rs b/src/od/prn_float.rs index 22918ccb4..bf6403bbd 100644 --- a/src/od/prn_float.rs +++ b/src/od/prn_float.rs @@ -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"); +} diff --git a/tests/test_od.rs b/tests/test_od.rs index 92828012f..1446f53e3 100644 --- a/tests/test_od.rs +++ b/tests/test_od.rs @@ -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(){