В другом вопросе обнаружилось, что деление нуля на переменную, содержащую вещественный ноль, в результате даёт значение -nan
#include
int main()
{
double zero = 0;
std::cout << 0/zero << "
";
}
Результат получается одинаковым для основных наиболее популярных компиляторов:
Clang
GCC
MSVC
Есть ли какой-то практический смысл в этом минусе, почему не просто nan?
Ответ
Получается это из-за того, что все вышеозначенные примеры были запущены на x86 архитектуре, а для FPU оной есть такое правило:
When neither of the source operands is a NaN, but the operation
generates a floating-point invalid-operation exception (see Tables
8-10 and 11-1), the result is commonly a QNaN FP Indefinite (Section
4.8.3.7).
Взятое из Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1: Basic Architecture параграфа 4.8.3.5.
Заглянув в таблицу, указанную в цитате выше, мы обнаружим там следующую операцию, которая даёт на выходе QNaN:
Division: ∞ by ∞ ; 0 by 0.
Т.е. как раз то, что у нас и есть в вопросе (там есть и другие операции). А если мы посмотрим на таблицу 4-3, из секции 4.2.2, то увидим, что у QNaN знаковый бит выставлен в 1, что объясняет появление отрицательного NaN в выводе.
А если посмотреть на это всё с точки зрения языка, то получается неопределённое поведение, поэтому видеть мы можем всё, что угодно.
C++14, [expr]p4:
If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable values for
its type, the behavior is undefined.
Ответ навеян замечательный постом от Реймонда Чена.
Комментариев нет:
Отправить комментарий