-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix potentially incorrect floating-point arithmetic on MinGW #50426
Conversation
447b9a8
to
bb8db75
Compare
Expected output for the first two assertions:
|
Different rounding (again!)? |
Yes it seems to be a rounding problem:
45000 * 1.01 should be 45450 but was 45449 in MinGW workflow . |
Setting rounding mode to nearest representable value doesn't help. std::fesetround( FE_TONEAREST ); |
Stamina test is fixed by |
Now throwing test is failing:
Expected numbers should be:
|
The plain static_cast<int>() gives a different rounding result on MinGW cross compile test workflow on GitHub Actions.
02e6bd9
to
5833666
Compare
@@ -91,7 +91,7 @@ static int actual_burn_rate( Character &dummy, const move_mode_id &move_mode ) | |||
static void burden_player( Character &dummy, float burden_proportion ) | |||
{ | |||
units::mass capacity = dummy.weight_capacity(); | |||
int units = static_cast<int>( capacity * burden_proportion / 1_gram ); | |||
int units = static_cast<int>( std::round( capacity * burden_proportion / 1_gram ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very concerned that this leaves the door open for other errors to persist in the codebase that aren't calling std::round(), this behavior needs to be the same in both builds (though if this is an incremental step to getting things unblocked disregard).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even with fpreset this test is still failing, so I'm adding rounding at the moment.
Summary
Bugfixes "Fix potentially incorrect floating-point arithmetic on MinGW"
Purpose of change
The following three tests are failing on MinGW cross-compile test workflow:
stamina burn for movement
player_morale_decay
throwing_skill_impact_test
The symptom is that floating point arithmetic in these three failing tests is producing different numeric results to that on other platforms.
Describe the solution
player_morale_decay
andthrowing_skill_impact_test
succeeds if I reset x87 FPU and SSE states at the beginning ofmain
function. This seems to be a MinGW bug where floating point math package states are not properly initialised on a Windows thread: https://blog.zaita.com/mingw64-compiler-bug/stamina burn for movement
failure is solved by addingstd::round()
to round adouble
number toint
inburden_player
, without which on MinGW 45000 * 1.01 => 45449.Describe alternatives you've considered
I've tried to call standard library function
std::fesetround( FE_TONEAREST )
to set floating point rounding mode to round to nearest representable value, but this does not actually solve the problem, the tests were still failing.Compiling with
-msse -mfpmath=sse -march=pentium4
mentioned by lemire in his blog https://lemire.me/blog/2020/06/26/gcc-not-nearest/ might help, but I haven't tried yet.Testing
Expect to see MinGW cross-compile test workflow to pass.
Additional context