From 8de027c4b4b7bc7b4472a2509ca90e701e972f55 Mon Sep 17 00:00:00 2001 From: penguindark <57967770+penguindark@users.noreply.github.com> Date: Thu, 26 Mar 2020 22:39:46 +0100 Subject: [PATCH] strconv: fix on ftoa string decimal aproximation, 'nan' string fix --- vlib/strconv/ftoa/f32_f64_to_string_test.v | 4 ++ vlib/strconv/ftoa/f32_str.v | 39 ++++++++++++--- vlib/strconv/ftoa/f64_str.v | 57 +++++++++++++++------- vlib/strconv/ftoa/utilities.v | 2 +- 4 files changed, 75 insertions(+), 27 deletions(-) diff --git a/vlib/strconv/ftoa/f32_f64_to_string_test.v b/vlib/strconv/ftoa/f32_f64_to_string_test.v index 42528bdb86..6bf862ed9d 100644 --- a/vlib/strconv/ftoa/f32_f64_to_string_test.v +++ b/vlib/strconv/ftoa/f32_f64_to_string_test.v @@ -165,4 +165,8 @@ fn test_float_to_str(){ //println(b) assert b.len == exp + 2 } + + // test rounding str conversion + assert f64_to_str(0.3456789123456, 4)=="3.4568e-01" + assert f32_to_str(0.345678, 3)=="3.457e-01" } diff --git a/vlib/strconv/ftoa/f32_str.v b/vlib/strconv/ftoa/f32_str.v index 5ea6002a53..0905f35230 100644 --- a/vlib/strconv/ftoa/f32_str.v +++ b/vlib/strconv/ftoa/f32_str.v @@ -33,6 +33,24 @@ mut: u u32 } +// pow of ten table used by n_digit reduction +const( + ten_pow_table_32 = [ + u32(1), + u32(10), + u32(100), + u32(1000), + u32(10000), + u32(100000), + u32(1000000), + u32(10000000), + u32(100000000), + u32(1000000000), + u32(10000000000), + u32(100000000000), + ] +) + /****************************************************************************** * * Conversion Functions @@ -47,17 +65,15 @@ const( // max 46 char // -3.40282346638528859811704183484516925440e+38 -fn (d Dec32) get_string_32(neg bool, n_digit int) string { - mut out := d.m - mut out_len := decimal_len_32(out) +fn (d Dec32) get_string_32(neg bool, i_n_digit int) string { + n_digit := i_n_digit + 1 + mut out := d.m + mut out_len := decimal_len_32(out) + out_len_original := out_len mut buf := [byte(0)].repeat(out_len + 5 + 1 +1) // sign + mant_len + . + e + e_sign + exp_len(2) + \0 mut i := 0 - if n_digit > 0 && out_len > n_digit { - out_len = n_digit+1 - } - if neg { buf[i]=`-` i++ @@ -68,6 +84,13 @@ fn (d Dec32) get_string_32(neg bool, n_digit int) string { disp = 1 } + if n_digit < out_len { + //println("orig: ${out_len_original}") + out += ten_pow_table_32[out_len - n_digit] + 1 // round to up + out /= ten_pow_table_32[out_len - n_digit] + out_len = n_digit + } + y := i + out_len mut x := 0 for x < (out_len-disp-1) { @@ -100,7 +123,7 @@ fn (d Dec32) get_string_32(neg bool, n_digit int) string { buf[i]=`e` i++ - mut exp := d.e + out_len - 1 + mut exp := d.e + out_len_original - 1 if exp < 0 { buf[i]=`-` i++ diff --git a/vlib/strconv/ftoa/f64_str.v b/vlib/strconv/ftoa/f64_str.v index e7ffd5f7f5..05902b3825 100644 --- a/vlib/strconv/ftoa/f64_str.v +++ b/vlib/strconv/ftoa/f64_str.v @@ -39,6 +39,32 @@ mut: u u64 } +// pow of ten table used by n_digit reduction +const( + ten_pow_table_64 = [ + u64(1), + u64(10), + u64(100), + u64(1000), + u64(10000), + u64(100000), + u64(1000000), + u64(10000000), + u64(100000000), + u64(1000000000), + u64(10000000000), + u64(100000000000), + u64(1000000000000), + u64(10000000000000), + u64(100000000000000), + u64(1000000000000000), + u64(10000000000000000), + u64(100000000000000000), + u64(1000000000000000000), + u64(10000000000000000000), + ] +) + /****************************************************************************** * * Conversion Functions @@ -51,17 +77,15 @@ const( maxexp64 = 2047 ) -fn (d Dec64) get_string_64(neg bool, n_digit int) string { - mut out := d.m - mut out_len := decimal_len_64(out) +fn (d Dec64) get_string_64(neg bool, i_n_digit int) string { + n_digit := i_n_digit + 1 + mut out := d.m + mut out_len := decimal_len_64(out) + out_len_original := out_len mut buf := [byte(0)].repeat(out_len + 6 + 1 +1) // sign + mant_len + . + e + e_sign + exp_len(2) + \0 mut i := 0 - if n_digit > 0 && out_len > n_digit { - out_len = n_digit+1 - } - if neg { buf[i]=`-` i++ @@ -72,6 +96,13 @@ fn (d Dec64) get_string_64(neg bool, n_digit int) string { disp = 1 } + if n_digit < out_len { + //println("orig: ${out_len_original}") + out += ten_pow_table_64[out_len - n_digit] + 1 // round to up + out /= ten_pow_table_64[out_len - n_digit] + out_len = n_digit + } + y := i + out_len mut x := 0 for x < (out_len-disp-1) { @@ -104,7 +135,7 @@ fn (d Dec64) get_string_64(neg bool, n_digit int) string { buf[i]=`e` i++ - mut exp := d.e + out_len - 1 + mut exp := d.e + out_len_original - 1 if exp < 0 { buf[i]=`-` i++ @@ -114,16 +145,6 @@ fn (d Dec64) get_string_64(neg bool, n_digit int) string { i++ } - // Always print two digits to match strconv's formatting. -/* d1 := exp % 10 - d0 := exp / 10 - buf[i]=`0` + byte(d0) - i++ - buf[i]=`0` + byte(d1) - i++ - buf[i]=0 -*/ - // Always print at least two digits to match strconv's formatting. d2 := exp % 10 exp /= 10 diff --git a/vlib/strconv/ftoa/utilities.v b/vlib/strconv/ftoa/utilities.v index 0fcbc8f5d9..98e093f491 100644 --- a/vlib/strconv/ftoa/utilities.v +++ b/vlib/strconv/ftoa/utilities.v @@ -233,7 +233,7 @@ pub fn f64_to_str_l(f f64) string { s := f64_to_str(f,18) // check for +inf -inf Nan - if s.len > 2 && (s[0] == `N` || s[1] == `i`) { + if s.len > 2 && (s[0] == `n` || s[1] == `i`) { return s }