Merge pull request #12813 from Geotale/interpreter-subnormal-rounding

Proper Subnormal Rounding When Interpreting
This commit is contained in:
JosJuice 2024-09-08 14:22:02 +02:00 committed by GitHub
commit 4eec061824
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 27 additions and 1 deletions

View File

@ -92,7 +92,33 @@ inline double Force25Bit(double 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);
}
return std::bit_cast<double>(integral);
}