strconv: fix e/g format (fix #22424) (#22430)

This commit is contained in:
kbkpbot 2024-10-07 13:43:04 +08:00 committed by GitHub
parent 502442ad00
commit 309c8d3778
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 11 deletions

View file

@ -512,6 +512,9 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) {
f.free() f.free()
return 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) mut f := strconv.format_es(data.d.d_f32, bf)
if upper_case { if upper_case {
tmp := f tmp := f
@ -582,6 +585,9 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) {
f.free() f.free()
return 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) mut f := strconv.format_es(data.d.d_f64, bf)
if upper_case { if upper_case {
tmp := f tmp := f
@ -595,7 +601,6 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) {
.si_e32 { .si_e32 {
$if !nofloat ? { $if !nofloat ? {
// println("HERE: e32") // println("HERE: e32")
bf.len1 = 6
if use_default_str { if use_default_str {
mut f := data.d.d_f32.str() mut f := data.d.d_f32.str()
if upper_case { if upper_case {
@ -623,7 +628,6 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) {
.si_e64 { .si_e64 {
$if !nofloat ? { $if !nofloat ? {
// println("HERE: e64") // println("HERE: e64")
bf.len1 = 6
if use_default_str { if use_default_str {
mut f := data.d.d_f64.str() mut f := data.d.d_f64.str()
if upper_case { if upper_case {

View file

@ -22,7 +22,7 @@ https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
@[direct_array_access] @[direct_array_access]
fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { 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 pad_digit := i_pad_digit + 1
mut out := d.m mut out := d.m
mut d_exp := d.e 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 - 1] * 5 // round to up
out /= ten_pow_table_64[out_len - n_digit] out /= ten_pow_table_64[out_len - n_digit]
// println("out1:[$out] ${d.m / 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++ d_exp++
n_digit++ n_digit++
} }
@ -74,13 +77,14 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string {
x++ x++
} }
// fix issue #22424
// no decimal digits needed, end here // no decimal digits needed, end here
if i_n_digit == 0 { // if i_n_digit == 0 {
unsafe { // unsafe {
buf[i] = 0 // buf[i] = 0
return tos(&u8(&buf[0]), i) // return tos(&u8(&buf[0]), i)
} // }
} //}
if out_len >= 1 { if out_len >= 1 {
buf[y - x] = `.` buf[y - x] = `.`
@ -365,7 +369,7 @@ pub fn f64_to_str_pad(f f64, n_digit int) string {
neg := (u >> (mantbits64 + expbits64)) != 0 neg := (u >> (mantbits64 + expbits64)) != 0
mant := u & ((u64(1) << mantbits64) - u64(1)) mant := u & ((u64(1) << mantbits64) - u64(1))
exp := (u >> mantbits64) & ((u64(1) << expbits64) - 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. // Exit early for easy cases.
if exp == maxexp64 || (exp == 0 && mant == 0) { if exp == maxexp64 || (exp == 0 && mant == 0) {

View file

@ -126,3 +126,22 @@ fn test_remove_tail_zeros() {
assert strconv.remove_tail_zeros('1234') == '1234' assert strconv.remove_tail_zeros('1234') == '1234'
assert strconv.remove_tail_zeros('1.00000000007') == '1.00000000007' 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
}