From fa1119b9a68e1d5dca22f8eed30101583ed4ac5c Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 20 Aug 2025 14:53:47 +0300 Subject: [PATCH] strconv: produce a maximum of 8 digits after the `.` for f32.str() (fix #25141) --- vlib/strconv/f32_f64_to_string_test.v | 20 ++++++++++++++++++++ vlib/strconv/ftoa.c.v | 8 ++------ vlib/strconv/utilities.c.v | 12 ++++++------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/vlib/strconv/f32_f64_to_string_test.v b/vlib/strconv/f32_f64_to_string_test.v index d73de5702e..5935acf636 100644 --- a/vlib/strconv/f32_f64_to_string_test.v +++ b/vlib/strconv/f32_f64_to_string_test.v @@ -172,3 +172,23 @@ fn test_float_to_str() { // assert ftoa.f64_to_str(0.3456789123456, 4)=="3.4568e-01" // assert ftoa.f32_to_str(0.345678, 3)=="3.457e-01" } + +fn test_issue_25141_1() { + assert strconv.ftoa_long_32(0.1234567901) == '0.12345679' +} + +fn test_issue_25141_2() { + assert strconv.f32_to_str_l(math.f32_from_bits(1055100472)) == '0.44444442' +} + +fn test_issue_25141_3() { + assert strconv.f32_to_str_l(math.f32_from_bits(1055100473)) == '0.44444445' +} + +fn test_issue_25141_4() { + assert strconv.f32_to_str_l(math.f32_from_bits(1055100474)) == '0.44444448' +} + +fn test_issue_25141_5() { + assert strconv.f32_to_str_l(math.f32_from_bits(1055100475)) == '0.4444445' +} diff --git a/vlib/strconv/ftoa.c.v b/vlib/strconv/ftoa.c.v index ef7f9490f8..ebf75725a4 100644 --- a/vlib/strconv/ftoa.c.v +++ b/vlib/strconv/ftoa.c.v @@ -19,7 +19,6 @@ https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea */ // ftoa_64 returns a string in scientific notation with max 17 digits after the dot. -// // Example: assert strconv.ftoa_64(123.1234567891011121) == '1.2312345678910111e+02' @[inline] pub fn ftoa_64(f f64) string { @@ -27,7 +26,6 @@ pub fn ftoa_64(f f64) string { } // ftoa_long_64 returns `f` as a `string` in decimal notation with a maximum of 17 digits after the dot. -// // Example: assert strconv.f64_to_str_l(123.1234567891011121) == '123.12345678910111' @[inline] pub fn ftoa_long_64(f f64) string { @@ -35,16 +33,14 @@ pub fn ftoa_long_64(f f64) string { } // ftoa_32 returns a `string` in scientific notation with max 8 digits after the dot. -// // Example: assert strconv.ftoa_32(34.1234567) == '3.4123455e+01' @[inline] pub fn ftoa_32(f f32) string { return f32_to_str(f, 8) } -// ftoa_long_32 returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot. -// -// Example: assert strconv.ftoa_long_32(34.1234567) == '34.12346' +// ftoa_long_32 returns `f` as a `string` in decimal notation with a maximum of 8 digits after the dot. +// Example: assert strconv.ftoa_long_32(0.1234567901) == '0.12345679' @[inline] pub fn ftoa_long_32(f f32) string { return f32_to_str_l(f) diff --git a/vlib/strconv/utilities.c.v b/vlib/strconv/utilities.c.v index 2b4a5a4748..23b82d7dd9 100644 --- a/vlib/strconv/utilities.c.v +++ b/vlib/strconv/utilities.c.v @@ -23,24 +23,24 @@ f64 to string with string format */ // TODO: Investigate precision issues -// f32_to_str_l returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot. -// -// Example: assert strconv.f32_to_str_l(34.1234567) == '34.12346' +// f32_to_str_l returns `f` as a `string` in decimal notation with a maximum of 8 digits after the dot. +// Example: assert strconv.f32_to_str_l(0.1234567891) == '0.12345679' +// Example: assert strconv.f32_to_str_l(34.1234567891) == '34.123455' @[manualfree] pub fn f32_to_str_l(f f32) string { - s := f32_to_str(f, 6) + s := f32_to_str(f, 8) res := fxx_to_str_l_parse(s) unsafe { s.free() } return res } -// f32_to_str_l_with_dot returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot. +// f32_to_str_l_with_dot returns `f` as a `string` in decimal notation with a maximum of 8 digits after the dot. // If the decimal digits after the dot are zero, a '.0' is appended for clarity. // // Example: assert strconv.f32_to_str_l_with_dot(34.) == '34.0' @[manualfree] pub fn f32_to_str_l_with_dot(f f32) string { - s := f32_to_str(f, 6) + s := f32_to_str(f, 8) res := fxx_to_str_l_parse_with_dot(s) unsafe { s.free() } return res