Гарантируется ли для любого конечного значения с плавающей точкой x - x == 0? - PullRequest
8 голосов
/ 30 августа 2010

Значения с плавающей точкой являются неточными, поэтому мы редко должны использовать строгое числовое равенство в сравнениях.Например, в Java это печатает false ( как видно на ideone.com ):

System.out.println(.1 + .2 == .3);
// false

Обычно правильный способ сравнения результатов вычислений с плавающей запятой состоит в том, чтобы увидеть,абсолютная разница относительно некоторого ожидаемого значения меньше, чем допустимая epsilon .

System.out.println(Math.abs(.1 + .2 - .3) < .00000000000001);
// true

Вопрос заключается в том, могут ли некоторые операции дать точный результат.Мы знаем, что для любого неконечного значения с плавающей запятой x (то есть либо NaN или бесконечности), x - x равно ВСЕГДА NaN.

Но если x конечно, гарантируется ли что-нибудь из этого?

  1. x * -1 == -x
  2. x - x == 0

(В частности, меня больше всего интересует поведение Java, но обсуждения для других языков также приветствуются.)


Я думаю, что это того стоит (и я могуздесь не так) ответ ДА! Я думаю, что все сводится к тому, является ли для любого конечного IEEE-754 значение с плавающей запятой, его аддитивная обратная равнойвсегда вычислимо точно.Так как, например, float и double имеет один выделенный бит только для знака , это, похоже, имеет место, поскольку для нахождения аддитивного инвертирования нужно только перевернуть знаковый бит (то есть * 1054)* Значение и следует оставить без изменений).

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

Ответы [ 2 ]

3 голосов
/ 30 августа 2010

Оба равенства гарантируются с плавающей точкой IEEE 754, потому что результаты как x-x, так и x * -1 представляются точно в виде чисел с плавающей запятой с той же точностью, что и x.В этом случае, независимо от режима округления, точные значения должны быть возвращены совместимой реализацией.

РЕДАКТИРОВАТЬ: По сравнению с примером .1 + .2.

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

Тот факт, что ваш компилятор позволяетВы пишете 0.1 как сокращение для другого, представимого числа без предупреждения, ортогонального определению этих операций.Например, когда вы пишете - (0.1), - является точным: он возвращает в точности противоположность своего аргумента.С другой стороны, его аргумент не 0.1, а double, который ваш компилятор использует вместо него.

Короче говоря, другая часть причины, почему операция x * (-1) является точной, заключается в том, что-1 можно представить как double.

2 голосов
/ 30 августа 2010

Хотя x - x может дать вам -0 вместо истинного 0, -0 сравнивается как равное 0, так что вы будете в безопасности, предполагая, что любое конечное число минус само будет сравниваться равным нулю .

См. Существует ли значение x с плавающей запятой, для которого x-x == 0 равно false? для получения более подробной информации.

...