Для любого конечного значения с плавающей запятой гарантируется, что x - x == 0?
Значения с плавающей точкой неточны, поэтому мы редко должны использовать строгое числовое равенство в сравнениях. Например, в Java это печатает false
( как видно на ideone.com):
System.out.println(.1 + .2 == .3);
// false
Обычно правильный способ сравнения результатов вычислений с плавающей запятой состоит в том, чтобы увидеть, меньше ли абсолютная разница относительно некоторого ожидаемого значения, чем допустимый эпсилон.
System.out.println(Math.abs(.1 + .2 - .3) < .00000000000001);
// true
Вопрос в том, могут ли некоторые операции дать точный результат. Мы знаем, что для любого неконечного значения с плавающей запятой x
(т.е. либо NaN
или бесконечность), x - x
ВСЕГДАNaN
,
Но если x
конечно, это гарантировано?
x * -1 == -x
x - x == 0
(В частности, меня больше всего интересует поведение Java, но также приветствуются обсуждения для других языков.)
Для чего это стоит, я думаю (и я могу ошибаться здесь) ответ ДА! Я думаю, что это сводится к тому, что для любого конечного значения с плавающей запятой IEEE-754 его аддитивная обратная всегда всегда вычислима точно. Так как например float
а также double
имеет один выделенный бит только для знака, это, похоже, имеет место, поскольку для нахождения аддитивного обратного нужно только перевернуть бит знака (т. е. значение и следует оставить без изменений).
Смежные вопросы
2 ответа
Хотя x - x
может дать вам -0
а не правда 0
, -0
сравнивается как равный 0
, так что вы будете в безопасности, предполагая, что любое конечное число минус само по себе будет сравниваться равным нулю.
См. Есть ли значение x с плавающей запятой, для которого xx == 0 является ложным? Больше подробностей.
Оба равенства гарантируются с плавающей точкой 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
,