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 std::io;
use std::fmt;
pub type OResult = Result<usize, io::Error>;
@ -14,7 +15,6 @@ pub enum ErrType {
Failed(String),
}
pub fn fail<O>(input: &[u8], msg: String) -> IResult<O> {
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]) {
BigEndian::write_u16(buf, bitarray2int(bits))
BigEndian::write_u16(buf, bitarray2int(bits));
}
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) {
BigEndian::write_i32(buf, int)
BigEndian::write_i32(buf, int);
}
pub fn pack_real8(buf: &mut [u8], fnum: f64) {
BigEndian::write_u64(buf, encode_real8(fnum))
pub fn pack_real8(buf: &mut [u8], fnum: f64) -> Result<(), FloatTooBigError> {
BigEndian::write_u64(buf, encode_real8(fnum)?);
Ok(())
}
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.
pub fn encode_real8(fnum: f64) -> u64 {
pub fn encode_real8(fnum: f64) -> Result<u64, FloatTooBigError> {
// Split the ieee float bitfields
let ieee = fnum.to_bits();
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);
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)
@ -207,7 +218,7 @@ pub fn encode_real8(fnum: f64) -> u64 {
if gds_exp < -14 {
// number is too small
return 0
return Ok(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;
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 real8 = sign | gds_exp_bits | gds_mant;
real8
Ok(real8)
}
@ -281,7 +292,7 @@ mod tests {
#[should_panic]
fn test_encode_real8_panic() {
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];
for vv in REALS {
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];
let mut buf = [10; 8 * COUNT];
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() {
print!("{vv}\n");

View File

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