diff --git a/source/mir/parse.d b/source/mir/parse.d index b870c213..022c052e 100644 --- a/source/mir/parse.d +++ b/source/mir/parse.d @@ -209,7 +209,46 @@ version(mir_bignum_test) else { str.fromString!float.should == str._stdc_parse!float; - str.fromString!double.should == str._stdc_parse!double; + auto mirStrValue = str.fromString!double; + auto crtStrValue = str._stdc_parse!double; + + version(CRuntime_Microsoft) { + // Some Windows CRTs clamp extreme underflow to min-subnormal instead of 0. + // Accept both behaviors *only* at the very bottom of the subnormal range. + bool equalOrTinyUnderflow(double a, double b) + { + import core.stdc.math: fpclassify, FP_SUBNORMAL; + import mir.math.common: fabs; + import mir.math.ieee: signbit; + import std.math.operations: nextafter; + + if (a == b) return true; + if (signbit(a) != signbit(b)) return false; + + enum double minSub = nextafter(0.0, 1.0); // smallest positive subnormal + + const aa = fabs(a); + const bb = fabs(b); + + // 0 <-> min-subnormal (or similar one-ULP-at-zero behavior) + if (aa == 0.0 && bb > 0.0) + return fpclassify(b) == FP_SUBNORMAL && bb <= minSub; + if (bb == 0.0 && aa > 0.0) + return fpclassify(a) == FP_SUBNORMAL && aa <= minSub; + + // If both are subnormal, permit differences only if both are at the very bottom. + if (fpclassify(a) == FP_SUBNORMAL && fpclassify(b) == FP_SUBNORMAL) + return aa <= minSub && bb <= minSub; + + return false; + } + if (!equalOrTinyUnderflow(mirStrValue, crtStrValue)) { + mirStrValue.should == crtStrValue; + } + } else { + mirStrValue.should == crtStrValue; + } + version (Windows) // No precise real parsing on windows { }