Merge pull request #12813 from Geotale/interpreter-subnormal-rounding
Proper Subnormal Rounding When Interpreting
This commit is contained in:
commit
4eec061824
|
@ -92,7 +92,33 @@ inline double Force25Bit(double d)
|
||||||
{
|
{
|
||||||
u64 integral = std::bit_cast<u64>(d);
|
u64 integral = std::bit_cast<u64>(d);
|
||||||
|
|
||||||
|
u64 exponent = integral & Common::DOUBLE_EXP;
|
||||||
|
u64 fraction = integral & Common::DOUBLE_FRAC;
|
||||||
|
|
||||||
|
if (exponent == 0 && fraction != 0)
|
||||||
|
{
|
||||||
|
// Subnormals get "normalized" before they're rounded
|
||||||
|
// In the end, this practically just means that the rounding is
|
||||||
|
// at a different bit
|
||||||
|
|
||||||
|
s64 keep_mask = 0xFFFFFFFFF8000000LL;
|
||||||
|
u64 round = 0x8000000;
|
||||||
|
|
||||||
|
// Shift the mask and rounding bit to the right until
|
||||||
|
// the fraction is "normal"
|
||||||
|
// That is to say shifting it until the MSB of the fraction
|
||||||
|
// would escape into the exponent
|
||||||
|
u32 shift = std::countl_zero(fraction) - (63 - Common::DOUBLE_FRAC_WIDTH);
|
||||||
|
keep_mask >>= shift;
|
||||||
|
round >>= shift;
|
||||||
|
|
||||||
|
// Round using these shifted values
|
||||||
|
integral = (integral & keep_mask) + (integral & round);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
integral = (integral & 0xFFFFFFFFF8000000ULL) + (integral & 0x8000000);
|
integral = (integral & 0xFFFFFFFFF8000000ULL) + (integral & 0x8000000);
|
||||||
|
}
|
||||||
|
|
||||||
return std::bit_cast<double>(integral);
|
return std::bit_cast<double>(integral);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue