2017-01-24 27 views
2

В C, при реализации с поплавками IEEE-754, когда я сравниваю два числа с плавающей запятой, которые являются NaN, он возвращает 0 или «false». Но почему два числа с плавающей запятой, которые оба являются равными?C IEEE-Floats inf равно inf

В этой программе печатается «equal: ...» (по крайней мере, под Linux AMD64 с gcc), и, на мой взгляд, она должна печатать «разные: ...».

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
    { 
    volatile double a = 1e200; //use volatile to suppress compiler warnings 
    volatile double b = 3e200; 
    volatile double c = 1e200; 
    double resA = a * c; //resA and resB should by inf 
    double resB = b * c; 
    if (resA == resB) 
     { 
     printf("equal: %e * %e = %e = %e = %e * %e\n",a,c,resA,resB,b,c); 
     } 
    else 
     { 
     printf("different: %e * %e = %e != %e = %e * %e\n", a, c, resA, resB, b, c); 
     } 
    return EXIT_SUCCESS; 
    } 

Другой пример, почему я думаю, что инф не то же самое, как инф, является: число натуральных чисел и рациональных чисел, как бесконечны, но не то же самое.

Итак, почему inf == inf?

+1

Рассмотрите этот код, безусловно, не сравните 2 'double', которые оба являются' бесконечность'. Этот код сравнивает результаты двух операций для равенства. C позволяет выполнять промежуточные вычисления с использованием более широкого типа. В этом случае я ожидал бы, что 'a * c == b * c' будет ложным. Более прямой пример кода будет использовать объекты 'volatile double', которые являются бесконечными, а затем сравнивают их. – chux

+1

@chux Спасибо, я редактирую исходный код – 12431234123412341234123

ответ

5

Бесконечность сравнивается, потому что это то, что говорится в стандарте. Из раздела 5,11 Подробности предикатов сравнения:

Бесконечных операнды одного и тот же знака сравнит равно.

+0

Спасибо, но _why_ выполните стандарт, скажите, что? – 12431234123412341234123

+0

@ 12431234123412341234123 Это другой вопрос. – nwellnhof

+0

@nwellnof, но это было именно то, что я пытался спросить. – 12431234123412341234123

2

inf==inf по той же причине, что почти все числа с плавающей точкой сравнения равны себе: Потому что они равны. Они содержат один и тот же знак, экспоненту и мантиссу.

Возможно, вы думаете о том, как NaN != NaN. Но это относительно неважное следствие гораздо более важного инварианта: NaN != x для любойx. Как следует из названия, NaN - это , а не любое число и, следовательно, не может сравниться ни с чем, потому что рассматриваемое сравнение является числовым (отсюда и почему -0 == +0).

Было бы неплохо иметь inf сравнить неравные с другими inf, так как в математическом контексте они почти наверняка неравны. Но имейте в виду, что равенство с плавающей точкой - это не то же самое, что абсолютное математическое равенство; 0.1f * 10.0f != 1.0f, и 1e100f + 1.0f == 1e100f. Подобно тому, как числа с плавающей запятой постепенно перетекают в денормалы, не ставя под угрозу равноправное равенство, поэтому они переполняются в бесконечность без ущерба для как можно большего равенства.

Если вы хотите inf != inf, вы можете эмулировать: 1e400 == 3e400 истинно, но 1e400 - 3e400 == 0 оценивается как ложное, так как результат +inf + -inf является NaN. (Возможно вы могли бы сказать, что это должно вычисляться 0, но это будет служить ничьим интересам.)

+0

«Не любое число вообще» inf также не является числом. – 12431234123412341234123

+1

«Бесконечность» понятие не является числом в системе с реальными числами. Но 'inf' значение IEEE-754 действительно является номером в IEEE-754. – Sneftel

+1

FWIW, спецификация C использует _floating types_ ('float',' double', ...): _ нормированные числа с плавающей запятой_, _subnormal с плавающей запятой numbers_, _неопределенные числа с плавающей запятой_ и значения, которые не являются плавающей запятой чисел, таких как бесконечности и NaN. – chux

1

фон

В C, в соответствии с точкой стандарта двоичная с плавающей IEEE 754 (так, если вы используете float или double), вы получите точное значение, которое можно точно сравнить с другой переменной того же типа. Ну, это правда, если ваши вычисления не приведут к значению, которое находится вне диапазона целых чисел, которые могут быть представлены (то есть переполнения).

Почему бесконечность == бесконечность

resA и resB Стандарт IEEE-754 с учетом значений бесконечности и отрицательной бесконечности, чтобы быть больше или меньше, чем, соответственно, все другие значения, которые могут быть представлены (<= INFINITY == 0 11111111111 0000000000000000000000000000000000000000000000000000 и >= -INFINITY == 1 11111111111 0000000000000000000000000000000000000000000000000000), за исключением NaN, который не меньше, равен или больше любого значения с плавающей запятой (даже самого себя). Обратите внимание, что бесконечность и негатив имеют явные определения в их знаках, экспонентах и ​​битах мантиссы.

Таким образом, resA и resB являются бесконечными и поскольку бесконечность явно определена и воспроизводима, resA==resB. Я уверен, что это так, как реализовано isinf().

Почему NaN! = NaN

Однако, NaN не явно. Значение NaN имеет знаковый бит 0, биты экспоненты всех 1 s (как бесконечность и отрицательный), и любой набор ненулевых бит бит (Source). Итак, как бы вы сказали один NaN из другого, если их бит бит произвольно произволен? Ну, стандарт не предполагает этого и просто возвращает false, когда два значения с плавающей запятой этой структуры сравниваются друг с другом.

Подробнее Объяснение

Поскольку бесконечность явно заданное значение (Источник, GNU C Manual):

Бесконечности распространяться через вычислений, как можно было бы ожидать

2 + ∞ = ∞

4 & divide; ∞ = 0

arctan (∞) = π/2.

Однако NaN может распространяться или не распространяться путем распространения через вычисления. Когда это произойдет, это QNan (Quieting NaN, самый старший бит бит), и все вычисления приведут к NaN. Когда это не так, это SNan (Signaling NaN, старший бит бит не установлен), и все вычисления приведут к ошибке.

+1

'NAN = 0x7ff0000000000001' (а также другие значения) , но 'NAN! = NAN'. И '0x8000000000000000 == 0x0000000000000000' в контексте с плавающей запятой. Это не так просто, как сравнение бит (хотя это почти * почти так же просто). – Sneftel

+0

О, это не так. Я просто указывал, что равенство «специальных» значений, таких как 'inf' и' NaN' и '-0', сводится к индивидуальным решениям, принятым комитетом IEEE, а не к жестким математическим правилам. (Ну, кроме '-0 == 0', это очень важно, но существование -0 не является.) Если бы они пошли другим путем и сделали' inf! = Inf', ни один самолет не выпал неба. – Sneftel

+0

@Sneftel Это справедливый момент, просто хотелось убедиться, что я понял, откуда вы пришли. Что касается несоответствия между решениями комитета IEEE и жесткими математическими правилами, один из членов комитета выставил очень длинный пост об этом [здесь] (http://stackoverflow.com/a/1573715/5209610). –

0

Существует много арифметических систем. Некоторые из них, в том числе те, которые обычно охватываются математикой средней школы, такие как реальные цифры, не имеют бесконечности в виде числа. Другие имеют одну бесконечность, например projectively extended real line. Другие, такие как обсуждаемая арифметика IEEE с плавающей запятой и extended real line, имеют как положительную, так и отрицательную бесконечность.

Арифметика IEEE754 во многом отличается от арифметики реального числа, но является полезным приближением для многих целей.

Существует логика для различной обработки NaNs и бесконечностей. Весьма разумно сказать, что положительная бесконечность больше отрицательной бесконечности и любого конечного числа.Было бы неразумно говорить ничего подобного о квадратном корне от -1.

 Смежные вопросы

  • Нет связанных вопросов^_^