> The formula was probably `return new_maxhp * (old_hp / old_maxhp);` ...
> Due to floating point rounding errors, convert_hp(1, 55, 55) equals 0.999999940395355224609375, which is less than 1, which means the unit dies.
Ahh. The old "Multiplying and dividing is associative... for the set of reals, not for the subset that you can actually afford to compute with." So it should have been `(new_maxhp * old_hp) / old_maxhp`. ffmpeg has a whole AVRational class for the same type of problem when converting timestamps accurately between 2 timebases.
Reminds me of the TF2 ammo boxes that give 40 metal on Linux and 41 on Windows https://www.youtube.com/watch?v=QzZoo1yAQag&pp=ygUfdGYyIGhlY...
Apparently the compiler used on Linux chose a less-accurate multiply instruction for 0.2 * 200.
Two wrongs make a right - After being less accurate but rounding up where you don't need to, the Linux binary correctly arrives at 40, and the Windows binary arrives at 41.
For percents (and dollars) I always do everything in cents and divide by 100 at the very end. "20 * 200 / 100" can be done with pure ints, and f32 can represent i16 exactly.
> Due to floating point rounding errors, convert_hp(1, 55, 55) equals 0.999999940395355224609375, which is less than 1, which means the unit dies.
Ahh. The old "Multiplying and dividing is associative... for the set of reals, not for the subset that you can actually afford to compute with." So it should have been `(new_maxhp * old_hp) / old_maxhp`. ffmpeg has a whole AVRational class for the same type of problem when converting timestamps accurately between 2 timebases.
Reminds me of the TF2 ammo boxes that give 40 metal on Linux and 41 on Windows https://www.youtube.com/watch?v=QzZoo1yAQag&pp=ygUfdGYyIGhlY...
Apparently the compiler used on Linux chose a less-accurate multiply instruction for 0.2 * 200.
Two wrongs make a right - After being less accurate but rounding up where you don't need to, the Linux binary correctly arrives at 40, and the Windows binary arrives at 41.
For percents (and dollars) I always do everything in cents and divide by 100 at the very end. "20 * 200 / 100" can be done with pure ints, and f32 can represent i16 exactly.