From 066dbc2f0c705f963617f45c2e0b352ccf652c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 17 Aug 2021 11:43:11 +0200 Subject: String: Fix default decimals truncation in num and num_real Fixes undefined behavior, and fixes the logic for negative powers of ten. Fixes #51764. Adds tests to validate the changes and prevent regressions. Adds docs for `String.num`. --- core/string/ustring.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'core/string') diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 2fdf6e84e5..d2d563c5dc 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1396,7 +1396,13 @@ String String::num(double p_num, int p_decimals) { #ifndef NO_USE_STDLIB if (p_decimals < 0) { - p_decimals = 14 - (int)floor(log10(p_num)); + p_decimals = 14; + const double abs_num = ABS(p_num); + if (abs_num > 10) { + // We want to align the digits to the above sane default, so we only + // need to subtract log10 for numbers with a positive power of ten. + p_decimals -= (int)floor(log10(abs_num)); + } } if (p_decimals > MAX_DECIMALS) { p_decimals = MAX_DECIMALS; @@ -1625,24 +1631,31 @@ String String::num_real(double p_num, bool p_trailing) { String s; String sd; - /* integer part */ + + // Integer part. bool neg = p_num < 0; p_num = ABS(p_num); int intn = (int)p_num; - /* decimal part */ + // Decimal part. - if ((int)p_num != p_num) { - double dec = p_num - (double)((int)p_num); + if (intn != p_num) { + double dec = p_num - (double)(intn); int digit = 0; #if REAL_T_IS_DOUBLE - int decimals = 14 - (int)floor(log10(p_num)); + int decimals = 14; #else - int decimals = 6 - (int)floor(log10(p_num)); + int decimals = 6; #endif + // We want to align the digits to the above sane default, so we only + // need to subtract log10 for numbers with a positive power of ten. + if (p_num > 10) { + decimals -= (int)floor(log10(p_num)); + } + if (decimals > MAX_DECIMALS) { decimals = MAX_DECIMALS; } -- cgit v1.2.3