Случаи, где float == и!= Не являются прямыми противоположностями
В https://github.com/numpy/numpy/issues/6428 основной причиной ошибки является то, что в simd.inc.src:543
, компилятор оптимизирует !(tmp == 0.)
до tmp != 0.
.
Комментарий говорит, что это "совсем не то же самое". Но не уточняет никаких деталей. NaNs упоминаются далее, но тест показывает, что NaN сравнивается с 0.
ожидаемым способом.
Каковы случаи, когда ==
и !=
могут возвращать true/false?
Или расхождение находится в другом поле - например. возвращающие значения, которые имеют одинаковое значение истинности, но различаются как int (но тестирование показывает, что это даже не похоже) ?
Ответы
Ответ 1
В комментарии говорится, что это "совсем не то же самое". Но не уточняет никаких деталей. NaNs упоминаются далее, но тест показывает, что NaN сравнивается с 0. ожидаемым способом.
Каковы случаи, когда == и!= могут возвращать true/false?
В стандарте говорится:
Операторы ==
(равно) и !=
(не равные) аналогичны операторам отношения, за исключением их более низкого приоритета. [...] Для любой пары операндов истинно одно из отношений.
(C2011, 6.5.9/3, добавлено выделение)
Следовательно, для любых выражений X и Y, которые совместно разрешены в качестве операндов этих операторов, (X) != (Y)
должен оценивать тот же результат, что и !((X) == (Y))
. Если на практике они не обнаружены, то компилятор, который дал этот результат, не согласуется в этом отношении. Если это несоответствие непредсказуемо, то оно представляет собой ошибку в компиляторе.
Кроме того, я замечаю, что 6.5.9/3 применяет столько же к NaN, бесконечностям и субнормалам, как к любым другим операндам. NaNs являются особыми по отношению к этим операторам по другой причине: NaNs сравниваются неравномерно со всеми операндами, включая их (предполагая семантику IEEE).
Ответ 2
Из связанного сообщения:
charris прокомментировал 9 октября 2015 г.
Я собираюсь угадать, что !(tmp == 0.)
оптимизирован для tmp != 0.
, что не совсем то же самое.
Комментарий OP:
Автор говорит, что это предположение, но они вполне уверены, что !(tmp==0.)
и tmp!=0.
не являются эквивалентными и выражают это, как если бы это общее знание
Как мы смирим эти два?
Очевидно, что они эквивалентны логически. Но их реализация может быть не такой. Компилятор может реализовать !(a == b)
как тест a == b
, за которым следует отрицание. В качестве альтернативы он может оптимизировать выражение и непосредственно протестировать a != b
. В этих двух случаях может возникнуть другой код сборки. Тот же результат должен (должен) быть достигнут, но время выполнения может отличаться.
"не совсем то же самое" просто будет признанием того, что !(a == b)
и a != b
на самом деле представляют собой разные комбинации символов, и компилятор может сделать с ними что-то технически другое, что должно дать тот же результат. И если будут наблюдаться разные результаты, в компиляторе может существовать ошибка.