Что такое -1.#IND и -1.#J?

http://blogs.msdn.com/b/oldnewthing/archive/2013/02/21/10395734.aspx
  • Перевод

Любой опытный программист знает, что стандарт представления значений с плавающей точкой (IEEE 754) оставляет несколько зарезервированных значений, соответствующих не-числам (NaN, not-a-number). Стандартная библиотека Visual C печатает не-числа следующим образом:
Печатается Означает
1.#INF Положительная бесконечность
-1.#INF Отрицательная бесконечность
1.#SNAN Положительное сигнальное не-число (signaling NaN)
-1.#SNAN Отрицательное сигнальное не-число (signaling NaN)
1.#QNAN Положительное несигнальное не-число (quiet NaN)
-1.#QNAN Отрицательное несигнальное не-число (quiet NaN)
1.#IND Положительная неопределённость
-1.#IND Отрицательная неопределённость
Положительная и отрицательная бесконечности могут получаться при переполнении в результате арифметического действия — например, при делении на ноль, или при взятии логарифма от положительного нуля. (По стандарту IEEE, любое значение с плавающей точкой имеет определённый знак — не только не-числа существуют в положительном и отрицательном вариантах, но и нулей тоже два.)

Сигнальные и несигнальные не-числа, как правило, получаются не в результате вычислений, а генерируются программой намеренно — например, в C++ их можно получить, вызвав методы signaling_NaN() или quiet_NaN() класса std::numeric_limits. Скажем, воображаемая программа электронных таблиц могла бы использовать их для обозначения высокоуровневых ошибок при вычислении ячейки -- "циклическая ссылка", "неизвестная функция" и т.п. Любая операция с использованием не-числа даёт в результате не-число, т.е. приложению достаточно проверить только окончательный результат вычисления, чтобы убедиться в корректности всех этапов.

Сигнальных и несигнальных не-чисел зарезервировано много, но runtime-библиотека Visual C при печати различает их только по знаку, и игнорирует присвоенное приложением значение. Исключениями являются две неопределённости, которые могут получаться при вычислении, не имеющем ни конечного, ни бесконечного результата: например, сумма 1.#INF
и -1.#INF, логарифм или квадратный корень отрицательного числа. В стандарте прописано, что неопределённость должна представляться несигнальным не-числом, но каким именно -- не определено. В разных процессорах значения получаются разными, так что разработчикам стандартных библиотек приходится экспериментировать. В x86 неопределённость получается отрицательным несигнальным не-числом с нулевым значением, но в других процессорах неопределённость может оказаться положительной.

(Прим. перев.: я не поленился и проверил, на x86 логарифм отрицательного нуля всё равно -1.#INF, как и у положительного -- а не -1.#IND)

Комментаторы Чена обратили внимание, что не-числа могут печататься и иначе.
Например, нижеследующий код напечатает 1.#J:
   double z = 0;
   printf("%.2f", 1/z);

В результате деления на ноль получается 1.#INF, и затем runtime-библиотека должна округлить это не-число до двух знаков после запятой. Вероятно, именно поэтому все не-числа начинаются с "1." -- чтобы при округлении можно было найти запятую, и отсчитывать от неё знаки. Отсчитываем два, получаем "#I", и следующая "цифра" -- "N" -- больше 5, так что мы округляем предыдущую "цифру" вверх до "J".

Графически это даже кажется понятным -- что такое J, как не I, закруглённая вверх?

Вряд ли такая печать не-чисел была заложена в спецификации; но после того, как библиотека выпущена, менять алгоритм уже нельзя -- одному богу известно, сколько существующих приложений полагаются на то, что получат именно 1.#J.

С другой стороны Реймонд замечает, что фонетическое округление (огубление) I давало бы Ü. Вот если бы округление 1.#INF до двух знаков печатало 1.#Ü, это было бы über-гикство.
  • +28
  • 28,5k
  • 5
Поделиться публикацией

Похожие публикации

Комментарии 5
    0
    Вот крутой баг!

    А printf("%.3f", 1/z), наверно, должен дать 1.#IO?
      0
      Так и есть. А printf("%.1f", 1/z) выдаст 1.$
        0
        А точно 1.$, а не 1."?
        Да, ошибаюсь. Именно 1.$
      –8
      Oppan PHP style!
        0
        Интересно одно — заминусовали за oppan или за PHP style?

        Да, история интересная, да, в разработке языков такое случается… особенно в разработке PHP )))

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое