add FloatTooBigError

This commit is contained in:
jan 2024-12-18 17:27:10 -08:00
parent babd7f1402
commit e42ac03c95
2 changed files with 28 additions and 17 deletions

View File

@ -3,6 +3,7 @@
/// ///
use byteorder::{ByteOrder, BigEndian}; use byteorder::{ByteOrder, BigEndian};
use std::io; use std::io;
use std::fmt;
pub type OResult = Result<usize, io::Error>; pub type OResult = Result<usize, io::Error>;
@ -14,7 +15,6 @@ pub enum ErrType {
Failed(String), Failed(String),
} }
pub fn fail<O>(input: &[u8], msg: String) -> IResult<O> { pub fn fail<O>(input: &[u8], msg: String) -> IResult<O> {
Err((input, ErrType::Failed(msg))) Err((input, ErrType::Failed(msg)))
} }
@ -118,20 +118,21 @@ pub fn bitarray2int(bits: &[bool; 16]) -> u16 {
} }
pub fn pack_bitarray(buf: &mut [u8], bits: &[bool; 16]) { pub fn pack_bitarray(buf: &mut [u8], bits: &[bool; 16]) {
BigEndian::write_u16(buf, bitarray2int(bits)) BigEndian::write_u16(buf, bitarray2int(bits));
} }
pub fn pack_int2(buf: &mut [u8], int: i16) { pub fn pack_int2(buf: &mut [u8], int: i16) {
BigEndian::write_i16(buf, int) BigEndian::write_i16(buf, int);
} }
pub fn pack_int4(buf: &mut [u8], int: i32) { pub fn pack_int4(buf: &mut [u8], int: i32) {
BigEndian::write_i32(buf, int) BigEndian::write_i32(buf, int);
} }
pub fn pack_real8(buf: &mut [u8], fnum: f64) { pub fn pack_real8(buf: &mut [u8], fnum: f64) -> Result<(), FloatTooBigError> {
BigEndian::write_u64(buf, encode_real8(fnum)) BigEndian::write_u64(buf, encode_real8(fnum)?);
Ok(())
} }
pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize { pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize {
@ -156,8 +157,18 @@ pub fn pack_datetime(buf: &mut [u8], date: &[i16; 6]) {
} }
#[derive(Debug, Clone)]
pub struct FloatTooBigError {
float_value: f64,
}
impl fmt::Display for FloatTooBigError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Float {0} is too large for Real8", self.float_value)
}
}
/// Convert from float64 to GDS REAL8 representation. /// Convert from float64 to GDS REAL8 representation.
pub fn encode_real8(fnum: f64) -> u64 { pub fn encode_real8(fnum: f64) -> Result<u64, FloatTooBigError> {
// Split the ieee float bitfields // Split the ieee float bitfields
let ieee = fnum.to_bits(); let ieee = fnum.to_bits();
let sign = ieee & 0x8000_0000_0000_0000; let sign = ieee & 0x8000_0000_0000_0000;
@ -166,7 +177,7 @@ pub fn encode_real8(fnum: f64) -> u64 {
let subnorm = (ieee_exp == 0) & (ieee_mant != 0); let subnorm = (ieee_exp == 0) & (ieee_mant != 0);
if (ieee_exp == 0) & (ieee_mant == 0) { if (ieee_exp == 0) & (ieee_mant == 0) {
return 0 return Ok(0)
} }
// IEEE normal double is (1 + ieee_mant / 2^52) * 2^(ieee_exp - 1023) // IEEE normal double is (1 + ieee_mant / 2^52) * 2^(ieee_exp - 1023)
@ -207,7 +218,7 @@ pub fn encode_real8(fnum: f64) -> u64 {
if gds_exp < -14 { if gds_exp < -14 {
// number is too small // number is too small
return 0 return Ok(0)
} }
let neg_biased = gds_exp < 0; let neg_biased = gds_exp < 0;
@ -218,13 +229,13 @@ pub fn encode_real8(fnum: f64) -> u64 {
let too_big = (gds_exp > 0x7f) & !subnorm; let too_big = (gds_exp > 0x7f) & !subnorm;
if too_big { if too_big {
panic!("Number too big for real8 format"); //TODO error handling return Err(FloatTooBigError{float_value: fnum});
} }
let gds_exp_bits = (gds_exp as u64) << 56; let gds_exp_bits = (gds_exp as u64) << 56;
let real8 = sign | gds_exp_bits | gds_mant; let real8 = sign | gds_exp_bits | gds_mant;
real8 Ok(real8)
} }
@ -281,7 +292,7 @@ mod tests {
#[should_panic] #[should_panic]
fn test_encode_real8_panic() { fn test_encode_real8_panic() {
use crate::basic::encode_real8; use crate::basic::encode_real8;
encode_real8(1e80); encode_real8(1e80).unwrap();
} }
@ -348,7 +359,7 @@ mod tests {
const REALS: [f64; 5] = [1.0, -2.0, 1e-9, 1e-3, 1e-12]; const REALS: [f64; 5] = [1.0, -2.0, 1e-9, 1e-3, 1e-12];
for vv in REALS { for vv in REALS {
print!("{vv}\n"); print!("{vv}\n");
assert!((decode_real8(encode_real8(vv)) - vv).abs() < f64::EPSILON); assert!((decode_real8(encode_real8(vv).unwrap()) - vv).abs() < f64::EPSILON);
} }
} }
@ -359,7 +370,7 @@ mod tests {
const REALS: [f64; COUNT] = [0.0, 1.0, -1.0, 0.5, 1e-9, 1e-3, 1e-12]; const REALS: [f64; COUNT] = [0.0, 1.0, -1.0, 0.5, 1e-9, 1e-3, 1e-12];
let mut buf = [10; 8 * COUNT]; let mut buf = [10; 8 * COUNT];
for (ii, &vv) in REALS.iter().enumerate() { for (ii, &vv) in REALS.iter().enumerate() {
pack_real8(&mut buf[ii * 8..], vv); pack_real8(&mut buf[ii * 8..], vv).unwrap();
} }
for (ii, &vv) in REALS.iter().enumerate() { for (ii, &vv) in REALS.iter().enumerate() {
print!("{vv}\n"); print!("{vv}\n");

View File

@ -279,7 +279,7 @@ impl RecordData for Real8 {
} }
fn pack_into(buf: &mut [u8], data: &Self::InData) { fn pack_into(buf: &mut [u8], data: &Self::InData) {
pack_real8(buf, *data) pack_real8(buf, *data).expect(&format!("Float {0} too big for Real8", data))
} }
fn pack(data: &Self::InData) -> Self::ByteData { fn pack(data: &Self::InData) -> Self::ByteData {
@ -303,8 +303,8 @@ impl RecordData for Real8Pair {
} }
fn pack_into(buf: &mut [u8], data: &Self::InData) { fn pack_into(buf: &mut [u8], data: &Self::InData) {
pack_real8(&mut buf[8 * 0..], data.0); pack_real8(&mut buf[8 * 0..], data.0).expect(&format!("Float.0 {0} too big for Real8", data.0));
pack_real8(&mut buf[8 * 1..], data.1); pack_real8(&mut buf[8 * 1..], data.1).expect(&format!("Float.1 {0} too big for Real8", data.1));
} }
fn pack(data: &Self::InData) -> Self::ByteData { fn pack(data: &Self::InData) -> Self::ByteData {