Skip to content
This repository has been archived by the owner on Jan 17, 2024. It is now read-only.

Commit

Permalink
Merge branch 'tune_to_float' into 'master'
Browse files Browse the repository at this point in the history
Optimize numeric to floating-point.

See merge request codbase/pgnumeric!1
  • Loading branch information
davidli2010 committed May 12, 2020
2 parents e6ad3d7 + f31f5d4 commit 74ffc9c
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ big-endian-varlen=[]
lazy_static = "1.4"
smallvec = "1.3"
cfg-if = "0.1"
strtod = "0.0.1"

[dev-dependencies]
criterion = "^0.3"
Expand Down
2 changes: 1 addition & 1 deletion benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn into_benchmark(c: &mut Criterion) {
c.bench_function("to_f64", |b| {
let val = parse("1.234567890123456789e10");
b.iter(|| {
let _n: f32 = into(black_box(&val));
let _n: f64 = into(black_box(&val));
})
});
}
Expand Down
28 changes: 23 additions & 5 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,23 @@ impl<'a> TryFrom<&NumericVar<'a>> for f32 {
#[inline]
fn try_from(value: &NumericVar<'a>) -> Result<Self, Self::Error> {
use std::fmt::Write;
if value.is_nan() {
return Ok(std::f32::NAN);
}
let mut buf = String::with_capacity(32);
buf.write_fmt(format_args!("{}", value))
.expect("returned an error unexpectedly");
let f = buf.parse::<f32>()?;
Ok(f)

match strtod::strtod(&buf) {
Some(val) => {
let f = val as f32;
if (f.is_infinite() && !val.is_infinite()) || (f == 0.0 && val != 0.0) {
return Err(NumericTryFromError::overflow());
}
Ok(f)
}
None => Err(NumericTryFromError::overflow()),
}
}
}

Expand All @@ -639,11 +651,17 @@ impl<'a> TryFrom<&NumericVar<'a>> for f64 {
#[inline]
fn try_from(value: &NumericVar<'a>) -> Result<Self, Self::Error> {
use std::fmt::Write;
if value.is_nan() {
return Ok(std::f64::NAN);
}
let mut buf = String::with_capacity(32);
buf.write_fmt(format_args!("{}", value))
.expect("returned an error unexpectedly");
let f = buf.parse::<f64>()?;
Ok(f)

match strtod::strtod(&buf) {
Some(f) => Ok(f),
None => Err(NumericTryFromError::overflow()),
}
}
}

Expand Down Expand Up @@ -1140,7 +1158,7 @@ mod tests {
assert_try_into("1.23456789e-10", 1.23456789e-10f32);
assert_try_into("3.40282347e+38", std::f32::MAX);
assert_try_into("-3.40282347e+38", std::f32::MIN);
assert_try_into("1e39", std::f32::INFINITY);
assert_try_into_overflow::<f32>("1e39");
assert_try_into("1.17549435e-38", std::f32::MIN_POSITIVE);
assert!(try_into::<&str, f32>("NaN").is_nan());
}
Expand Down
8 changes: 4 additions & 4 deletions src/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2102,17 +2102,17 @@ impl<'a> NumericVar<'a> {
/// `self` is displayed to the number of digits indicated by its dscale.
pub fn write<W: fmt::Write>(&self, f: &mut W) -> Result<(), fmt::Error> {
if self.is_nan() {
return write!(f, "NaN");
return f.write_str("NaN");
}

// Output a dash for negative values.
if self.sign == NUMERIC_NEG {
write!(f, "-")?;
f.write_char('-')?;
}

// Output all digits before the decimal point.
if self.weight < 0 {
write!(f, "0")?;
f.write_char('0')?;
} else {
let digits = self.digits();
debug_assert_eq!(digits.len(), self.ndigits as usize);
Expand All @@ -2137,7 +2137,7 @@ impl<'a> NumericVar<'a> {

// If requested, output a decimal point and all the digits that follow it.
if self.dscale > 0 {
write!(f, ".")?;
f.write_char('.')?;

let digits = self.digits();
debug_assert_eq!(digits.len(), self.ndigits as usize);
Expand Down

0 comments on commit 74ffc9c

Please sign in to comment.