From: Francis De Brabandere <francisdb@gmail.com> Literals such as 1e-309 were rounded to zero because pow(10, 309) overflows to infinity, making `d / pow(10, -exp)` equal to d / inf = 0. Split the multiplication so the intermediate value stays in the representable range, which lets the final product reach the IEEE 754 subnormal range like native. --- dlls/vbscript/lex.c | 8 +++++++- dlls/vbscript/tests/lang.vbs | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 81cc67e037b..3ccbd0a3730 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -346,7 +346,13 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) return tInt; } - r = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp); + if(exp >= -308) { + r = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp); + }else { + /* Subnormal range: pow(10, -exp) would overflow, so split into two + * multiplications that each stay within the representable range. */ + r = (d * pow(10, -308)) * pow(10, exp + 308); + } if(isinf(r)) { return lex_error(ctx, MAKE_VBSERROR(VBSE_INVALID_NUMBER)); } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index f6361eaec0f..12d8ba5d45c 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -412,9 +412,9 @@ Call ok(getVT(1e0) = "VT_R8", "getVT(1e0) is not VT_R8") Call ok(getVT(0.1e2) = "VT_R8", "getVT(0.1e2) is not VT_R8") ' Subnormal doubles: literals smaller than DBL_MIN (~1e-308) parse as positive ' subnormals down to ~5e-324; anything smaller rounds to zero. -todo_wine_ok 1e-309 > 0, "1e-309 should be subnormal positive, got " & 1e-309 -todo_wine_ok 1e-320 > 0, "1e-320 should be subnormal positive, got " & 1e-320 -todo_wine_ok 5e-324 > 0, "5e-324 should be subnormal positive, got " & 5e-324 +Call ok(1e-309 > 0, "1e-309 should be subnormal positive, got " & 1e-309) +Call ok(1e-320 > 0, "1e-320 should be subnormal positive, got " & 1e-320) +Call ok(5e-324 > 0, "5e-324 should be subnormal positive, got " & 5e-324) Call ok(1e-400 = 0, "1e-400 should round to 0, got " & 1e-400) Call ok(getVT(1 & 100000) = "VT_BSTR", "getVT(1 & 100000) is not VT_BSTR") Call ok(getVT(-empty) = "VT_I2", "getVT(-empty) = " & getVT(-empty)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10898