base: fix parse_number_f64("0.000...0001e30001")
Updates PR #184
diff --git a/internal/cgen/base/floatconv-submodule-code.c b/internal/cgen/base/floatconv-submodule-code.c
index 4b293f3..b162fc4 100644
--- a/internal/cgen/base/floatconv-submodule-code.c
+++ b/internal/cgen/base/floatconv-submodule-code.c
@@ -422,9 +422,15 @@
p++;
}
+ // (1 << 24) is both smaller than ((INT32_MAX - 9) / 10) and larger than
+ // ((WUFFS_BASE__PARSE_NUMBER_XXX__SLICE_LEN_MAX_INCL * 10) + 9).
+ //
+ // dp's magnitude is at most s.len, and so at most
+ // WUFFS_BASE__PARSE_NUMBER_XXX__SLICE_LEN_MAX_INCL. Any exp outside
+ // ±exp_large gives the same (infinite or zero) result.
+ const int32_t exp_large = 1 << 24;
+
int32_t exp = 0;
- const int32_t exp_large = WUFFS_PRIVATE_IMPL__HPD__DECIMAL_POINT__RANGE +
- WUFFS_PRIVATE_IMPL__HPD__DIGITS_PRECISION;
bool saw_exp_digits = false;
for (; p < q; p++) {
if ((*p == '_') &&
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 71f03de..ad7e5f6 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -21832,9 +21832,15 @@
p++;
}
+ // (1 << 24) is both smaller than ((INT32_MAX - 9) / 10) and larger than
+ // ((WUFFS_BASE__PARSE_NUMBER_XXX__SLICE_LEN_MAX_INCL * 10) + 9).
+ //
+ // dp's magnitude is at most s.len, and so at most
+ // WUFFS_BASE__PARSE_NUMBER_XXX__SLICE_LEN_MAX_INCL. Any exp outside
+ // ±exp_large gives the same (infinite or zero) result.
+ const int32_t exp_large = 1 << 24;
+
int32_t exp = 0;
- const int32_t exp_large = WUFFS_PRIVATE_IMPL__HPD__DECIMAL_POINT__RANGE +
- WUFFS_PRIVATE_IMPL__HPD__DIGITS_PRECISION;
bool saw_exp_digits = false;
for (; p < q; p++) {
if ((*p == '_') &&
diff --git a/test/c/std/json.c b/test/c/std/json.c
index 58e8fbf..450ad73 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -1123,6 +1123,47 @@
}
}
+
+ // Test long inputs whose large exponent cancels out the decimal point.
+ {
+ // Initialize buf to "0.000...0001e30001" and "1000...000e-30000" with
+ // 30000 zeroes. Both are equal to 1.
+ static char buf[30016];
+ const char* names[2] = {"0.000...0001e30001", "1000...000e-30000"};
+ for (int j = 0; j < 2; j++) {
+ size_t n = 0;
+ if (j == 0) {
+ buf[n++] = '0';
+ buf[n++] = '.';
+ memset(buf + n, '0', 30000);
+ n += 30000;
+ memcpy(buf + n, "1e30001", 7);
+ n += 7;
+ } else {
+ buf[n++] = '1';
+ memset(buf + n, '0', 30000);
+ n += 30000;
+ memcpy(buf + n, "e-30000", 7);
+ n += 7;
+ }
+
+ wuffs_base__result_f64 r = wuffs_base__parse_number_f64(
+ wuffs_base__make_slice_u8((uint8_t*)(void*)buf, n),
+ WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS);
+ uint64_t have =
+ (r.status.repr == NULL)
+ ? wuffs_base__ieee_754_bit_representation__from_f64_to_u64(
+ r.value)
+ : fail;
+ uint64_t want = 0x3FF0000000000000;
+ if (have != want) {
+ RETURN_FAIL("\"%s\": have 0x%016" PRIX64 ", want 0x%016" PRIX64,
+ names[j], have, want);
+ }
+ }
+ }
+
+
return NULL;
}