Merge pull request #51864 from aaronfranke/test-string-double

Fix String::num_real and test cases when compiling with doubles
This commit is contained in:
Rémi Verschelde 2021-09-15 21:28:54 +02:00 committed by GitHub
commit 5179124fd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 10 deletions

View file

@ -1551,19 +1551,21 @@ String String::num_real(double p_num, bool p_trailing) {
bool neg = p_num < 0; bool neg = p_num < 0;
p_num = ABS(p_num); p_num = ABS(p_num);
int intn = (int)p_num; int64_t intn = (int64_t)p_num;
// Decimal part. // Decimal part.
if (intn != p_num) { if (intn != p_num) {
double dec = p_num - (double)(intn); double dec = p_num - (double)intn;
int digit = 0; int digit = 0;
#if REAL_T_IS_DOUBLE #ifdef REAL_T_IS_DOUBLE
int decimals = 14; int decimals = 14;
double tolerance = 1e-14;
#else #else
int decimals = 6; int decimals = 6;
double tolerance = 1e-6;
#endif #endif
// We want to align the digits to the above sane default, so we only // 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. // need to subtract log10 for numbers with a positive power of ten.
@ -1575,16 +1577,21 @@ String String::num_real(double p_num, bool p_trailing) {
decimals = MAX_DECIMALS; decimals = MAX_DECIMALS;
} }
int dec_int = 0; // In case the value ends up ending in "99999", we want to add a
int dec_max = 0; // tiny bit to the value we're checking when deciding when to stop,
// so we multiply by slightly above 1 (1 + 1e-7 or 1e-15).
double check_multiplier = 1 + tolerance / 10;
int64_t dec_int = 0;
int64_t dec_max = 0;
while (true) { while (true) {
dec *= 10.0; dec *= 10.0;
dec_int = dec_int * 10 + (int)dec % 10; dec_int = dec_int * 10 + (int64_t)dec % 10;
dec_max = dec_max * 10 + 9; dec_max = dec_max * 10 + 9;
digit++; digit++;
if ((dec - (double)((int)dec)) < 1e-6) { if ((dec - (double)(int64_t)(dec * check_multiplier)) < tolerance) {
break; break;
} }
@ -1594,7 +1601,7 @@ String String::num_real(double p_num, bool p_trailing) {
} }
dec *= 10; dec *= 10;
int last = (int)dec % 10; int last = (int64_t)dec % 10;
if (last > 5) { if (last > 5) {
if (dec_int == dec_max) { if (dec_int == dec_max) {
@ -3555,7 +3562,7 @@ String String::strip_edges(bool left, bool right) const {
} }
if (right) { if (right) {
for (int i = (int)(len - 1); i >= 0; i--) { for (int i = len - 1; i >= 0; i--) {
if (operator[](i) <= 32) { if (operator[](i) <= 32) {
end--; end--;
} else { } else {

View file

@ -355,13 +355,23 @@ TEST_CASE("[String] Number to string") {
CHECK(String::num(-0.0) == "-0"); // Includes sign even for zero. CHECK(String::num(-0.0) == "-0"); // Includes sign even for zero.
CHECK(String::num(3.141593) == "3.141593"); CHECK(String::num(3.141593) == "3.141593");
CHECK(String::num(3.141593, 3) == "3.142"); CHECK(String::num(3.141593, 3) == "3.142");
CHECK(String::num_real(3.141593) == "3.141593");
CHECK(String::num_scientific(30000000) == "3e+07"); CHECK(String::num_scientific(30000000) == "3e+07");
CHECK(String::num_int64(3141593) == "3141593"); CHECK(String::num_int64(3141593) == "3141593");
CHECK(String::num_int64(0xA141593, 16) == "a141593"); CHECK(String::num_int64(0xA141593, 16) == "a141593");
CHECK(String::num_int64(0xA141593, 16, true) == "A141593"); CHECK(String::num_int64(0xA141593, 16, true) == "A141593");
CHECK(String::num(42.100023, 4) == "42.1"); // No trailing zeros. CHECK(String::num(42.100023, 4) == "42.1"); // No trailing zeros.
// String::num_real tests.
CHECK(String::num_real(3.141593) == "3.141593");
CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros.
#ifdef REAL_T_IS_DOUBLE
CHECK_MESSAGE(String::num_real(Math_PI) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.14149999618530", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double).");
#else
CHECK_MESSAGE(String::num_real(Math_PI) == "3.141593", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float.");
#endif // REAL_T_IS_DOUBLE
// Checks doubles with many decimal places. // Checks doubles with many decimal places.
CHECK(String::num(0.0000012345432123454321, -1) == "0.00000123454321"); // -1 uses 14 as sane default. CHECK(String::num(0.0000012345432123454321, -1) == "0.00000123454321"); // -1 uses 14 as sane default.
CHECK(String::num(0.0000012345432123454321) == "0.00000123454321"); // -1 is the default value. CHECK(String::num(0.0000012345432123454321) == "0.00000123454321"); // -1 is the default value.