From 309c8d3778c1453b0fd1cef28531de106ab6f215 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Mon, 7 Oct 2024 13:43:04 +0800 Subject: [PATCH] strconv: fix e/g format (fix #22424) (#22430) --- vlib/builtin/string_interpolation.v | 8 ++++++-- vlib/strconv/f64_str.c.v | 22 +++++++++++++--------- vlib/strconv/format_test.v | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/vlib/builtin/string_interpolation.v b/vlib/builtin/string_interpolation.v index 4d990a0f008b28..0357f9ecbd4935 100644 --- a/vlib/builtin/string_interpolation.v +++ b/vlib/builtin/string_interpolation.v @@ -512,6 +512,9 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) { f.free() return } + // NOTE: For 'g' and 'G' bf.len1 is the maximum number of significant digits. + // Not like 'e' or 'E', which is the number of digits after the decimal point. + bf.len1-- mut f := strconv.format_es(data.d.d_f32, bf) if upper_case { tmp := f @@ -582,6 +585,9 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) { f.free() return } + // NOTE: For 'g' and 'G' bf.len1 is the maximum number of significant digits + // Not like 'e' or 'E', which is the number of digits after the decimal point. + bf.len1-- mut f := strconv.format_es(data.d.d_f64, bf) if upper_case { tmp := f @@ -595,7 +601,6 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) { .si_e32 { $if !nofloat ? { // println("HERE: e32") - bf.len1 = 6 if use_default_str { mut f := data.d.d_f32.str() if upper_case { @@ -623,7 +628,6 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) { .si_e64 { $if !nofloat ? { // println("HERE: e64") - bf.len1 = 6 if use_default_str { mut f := data.d.d_f64.str() if upper_case { diff --git a/vlib/strconv/f64_str.c.v b/vlib/strconv/f64_str.c.v index 5adab6e11b2464..66140356cad37e 100644 --- a/vlib/strconv/f64_str.c.v +++ b/vlib/strconv/f64_str.c.v @@ -22,7 +22,7 @@ https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea @[direct_array_access] fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { - mut n_digit := i_n_digit + 1 + mut n_digit := if i_n_digit < 1 { 1 } else { i_n_digit + 1 } pad_digit := i_pad_digit + 1 mut out := d.m mut d_exp := d.e @@ -54,7 +54,10 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { out += ten_pow_table_64[out_len - n_digit - 1] * 5 // round to up out /= ten_pow_table_64[out_len - n_digit] // println("out1:[$out] ${d.m / ten_pow_table_64[out_len - n_digit ]}") - if d.m / ten_pow_table_64[out_len - n_digit] < out { + // fix issue #22424 + out_div := d.m / ten_pow_table_64[out_len - n_digit] + if out_div < out && dec_digits(out_div) < dec_digits(out) { + // from `99` to `100`, will need d_exp+1 d_exp++ n_digit++ } @@ -74,13 +77,14 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { x++ } + // fix issue #22424 // no decimal digits needed, end here - if i_n_digit == 0 { - unsafe { - buf[i] = 0 - return tos(&u8(&buf[0]), i) - } - } + // if i_n_digit == 0 { + // unsafe { + // buf[i] = 0 + // return tos(&u8(&buf[0]), i) + // } + //} if out_len >= 1 { buf[y - x] = `.` @@ -365,7 +369,7 @@ pub fn f64_to_str_pad(f f64, n_digit int) string { neg := (u >> (mantbits64 + expbits64)) != 0 mant := u & ((u64(1) << mantbits64) - u64(1)) exp := (u >> mantbits64) & ((u64(1) << expbits64) - u64(1)) - // println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016lx}") + // unsafe { println("s:${neg} mant:${mant} exp:${exp} float:${f} byte:${u1.u:016x}") } // Exit early for easy cases. if exp == maxexp64 || (exp == 0 && mant == 0) { diff --git a/vlib/strconv/format_test.v b/vlib/strconv/format_test.v index ffd469a90ab38f..d42eaf1774c920 100644 --- a/vlib/strconv/format_test.v +++ b/vlib/strconv/format_test.v @@ -126,3 +126,22 @@ fn test_remove_tail_zeros() { assert strconv.remove_tail_zeros('1234') == '1234' assert strconv.remove_tail_zeros('1.00000000007') == '1.00000000007' } + +fn test_g_format() { + a := 1234.56789000e10 + assert '${a:1.0g}' == '1e+13' + assert '${a:1.1g}' == '1e+13' + assert '${a:1.2g}' == '1.2e+13' + assert '${a:1.3g}' == '1.23e+13' + assert '${a:1.4g}' == '1.235e+13' + assert '${a:1.5g}' == '1.2346e+13' + assert '${a:1.6g}' == '1.23457e+13' + assert '${a:1.7g}' == '1.234568e+13' + assert '${a:1.8g}' == '1.2345679e+13' + assert '${a:1.9g}' == '1.23456789e+13' + assert '${a:1.10g}' == '1.23456789e+13' + assert '${a:1.11g}' == '1.23456789e+13' + assert '${a:1.12g}' == '1.23456789e+13' + + // TODO: e format not support due to issue #22429 +}