Doug Semler - 2017-07-12

The runtime can't "just use" the glibc implementation because of licensing. In the versions (6.3 and 7.1) I have tested, the problem exists at point nextafter (0.5, 0) for all versions of float, double, and long double.

Anyway, the reason for the bug is the (res - x) computation...non constant floating point operations take the rounding mode into account. So you end up with internal calculation of 1.0 - 0.4999999999997 in the FPU, which depending on the rounding mode can get you exactly 0.50000000000000 (round down, nearest, and towards zero). This is also why other "trivial" solutions such as trunc(x + 0.5) doesn't work for all positive values, etc. It's the MATH operation that screws things up with its rounding mode if the result happens to round differently in the least significant bit of the converted value.

Isn't floating point fun?

Sandboxing without looking at the glibc, it seems to me that the mingw runtime needs to avoid doing math operations for all the floating point functions that do rounding, and look at the various bits of the floating point value to get the sign, exponent, mantissa, etc and mask/bit-bang things to be correct across all values. Otherwise, floating point values one epsilon away from midpoints may violate IEEE and std rounding.