Процедура cos (x) == cos (x), сгенерированная в режиме разблокировки:
00DB101A call _CIcos (0DB1870h)
00DB101F fld st(0)
00DB1021 fucompp
Значение вычисляется один раз, затем клонируется, затем сравнивается с самим собой - результат будет в порядке
То же самое в режиме отладки:
00A51405 sub esp,8
00A51408 fld qword ptr [x]
00A5140B fstp qword ptr [esp]
00A5140E call @ILT+270(_cos) (0A51113h)
00A51413 fld qword ptr [x]
00A51416 fstp qword ptr [esp]
00A51419 fstp qword ptr [ebp-0D8h]
00A5141F call @ILT+270(_cos) (0A51113h)
00A51424 add esp,8
00A51427 fld qword ptr [ebp-0D8h]
00A5142D fucompp
Теперь происходят странные вещи.
1. X загружен в fstack (X, 0)
2. Х хранится в обычном стеке (усечение)
3. Косинус вычисляется, результат на стеке с плавающей точкой
4. Х загружается снова
5. X хранится в обычном стеке (усечение, так как на данный момент мы «симметричны»)
6. Результат 1-го косинуса, который был в стеке, сохраняется в памяти, теперь происходит еще одно усечение для 1-го значения
7. Косинус вычисляется, 2-й результат, если он находится в стеке float, но это значение было усечено только один раз
8. 1-е значение загружается в fstack, но это значение было усечено дважды (один раз до вычисления косинуса, один раз после)
9. Эти два значения сравниваются - мы получаем ошибки округления.