Skip to content

Trailing zeroes in printed numbers #114

@lpbak

Description

@lpbak
Contributor

While not required by JSON spec (I believe), it might be the desired behaviour for the following tests to pass:

 
#[test]
fn trailing_zeroes_int() {
    let n = Number::from_parts(true, 100, -1);
    assert_eq!(format!("{}", n), "10");
}

#[test]
fn trailing_zeroes_fp() {
    let n = Number::from_parts(true, 100, -3);
    assert_eq!(format!("{}", n), "0.1");
}

#[test]
fn trailing_zeroes_small_fp() {
    let n = Number::from_parts(true, 100, -302);
    assert_eq!(format!("{}", n), "1e-300");
}

Currently they fail with "10.0" != "10", "0.100" != "0.1", and "1.00e-300" != "1e-300" respectively.

Activity

lpbak

lpbak commented on Jul 1, 2017

@lpbak
ContributorAuthor

There is a simple solution:

--- a/src/util/print_dec.rs
+++ b/src/util/print_dec.rs
@@ -50,7 +50,7 @@ unsafe fn write_num(n: &mut u64, curr: &mut isize, buf_ptr: *mut u8, lut_ptr: *c
     }
 }
 
-pub unsafe fn write<W: io::Write>(wr: &mut W, positive: bool, mut n: u64, exponent: i16) -> io::Result<()> {
+pub unsafe fn write<W: io::Write>(wr: &mut W, positive: bool, mut n: u64, mut exponent: i16) -> io::Result<()> {
     if !positive {
         try!(wr.write_all(b"-"));
     }
@@ -59,6 +59,11 @@ pub unsafe fn write<W: io::Write>(wr: &mut W, positive: bool, mut n: u64, expone
         return wr.write_all(b"0");
     }
 
+    while exponent < 0 && n % 10 == 0 {
+        exponent += 1;
+        n /= 10;
+    }
+
     let mut buf: [u8; 30] = mem::uninitialized();
     let mut curr = buf.len() as isize;
     let buf_ptr = buf.as_mut_ptr();

but it unfortunately has a non-negligible impact on benchmarks. On my machine, the following benchmarks:

#[bench]
fn big(b: &mut test::Bencher) {
    b.iter(|| format!("{}", Number::from_parts(true, 1000000000000000, -10)))
}

#[bench]
fn small(b: &mut test::Bencher) {
    b.iter(|| format!("{}", Number::from_parts(true, 1000000000000000, -100)))
}

#[bench]
fn na(b: &mut test::Bencher) {
    b.iter(|| format!("{}", Number::from_parts(true, 1000000000000001, -10)))
}

go from


test big   ... bench:         135 ns/iter (+/- 20)
test na    ... bench:         135 ns/iter (+/- 7)
test small ... bench:         202 ns/iter (+/- 11)

to


test big   ... bench:         147 ns/iter (+/- 9)
test na    ... bench:         135 ns/iter (+/- 12)
test small ... bench:         262 ns/iter (+/- 36)

maciejhirsz

maciejhirsz commented on Jul 3, 2017

@maciejhirsz
Owner

I think a potential solution would be to change from_parts to always produce normalized numbers (so shifting the work from printing to constructing the type), and provide an unsafe variant of the function that doesn't do it, which could be used internally in the parser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @maciejhirsz@lpbak

        Issue actions

          Trailing zeroes in printed numbers · Issue #114 · maciejhirsz/json-rust