Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion source/mir/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,43 @@ version(mir_bignum_test)
else
{
str.fromString!float.should == str._stdc_parse!float;
str.fromString!double.should == str._stdc_parse!double;

// 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;
}

auto mirv = str.fromString!double;
auto crtv = str._stdc_parse!double;
if (!equalOrTinyUnderflow(mirv, crtv)) {
mirv.should == crtv;
}

version (Windows) // No precise real parsing on windows
{
}
Expand Down
Loading