Ответ 1
Из apidoc, Float.compare
:
Сравнивает два указанных значения float. Знак возвращаемого целочисленного значения совпадает с признаком целого числа, которое будет возвращено вызовом:
new Float (f1).compareTo(новый Float (f2))
Сравнивает два объекта Float численно. Существует два способа сравнения сравнений, выполненных этим методом, от тех, которые выполняются операторами численного сравнения языка Java (<, < =, ==, >= > ) при применении к значениям примитивного значения float:
- Float.NaN считается этим методом равным себе и больше всех других значений float (включая Float.POSITIVE_INFINITY).
- 0.0f считается этим методом больше -0.0f.
Это гарантирует, что естественный порядок объектов Float, налагаемых этим методом, согласуется с равными.
Рассмотрим следующий код:
System.out.println(-0.0f == 0.0f); //true
System.out.println(Float.compare(-0.0f, 0.0f) == 0 ? true : false); //false
System.out.println(Float.NaN == Float.NaN);//false
System.out.println(Float.compare(Float.NaN, Float.NaN) == 0 ? true : false); //true
System.out.println(-0.0d == 0.0d); //true
System.out.println(Double.compare(-0.0d, 0.0d) == 0 ? true : false);//false
System.out.println(Double.NaN == Double.NaN);//false
System.out.println(Double.compare(Double.NaN, Double.NaN) == 0 ? true : false);//true
Вывод неправильный, поскольку то, что не является числом, просто не является числом и должно рассматриваться как равное с точки зрения сравнения чисел. Ясно также, что 0=-0
.
Посмотрим, что делает Float.compare
:
public static int compare(float f1, float f2) {
if (f1 < f2)
return -1; // Neither val is NaN, thisVal is smaller
if (f1 > f2)
return 1; // Neither val is NaN, thisVal is larger
int thisBits = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
Возвращает представление указанного значения с плавающей запятой в соответствии с форматом бит IEEE 754 с плавающей запятой "одиночный формат".Бит 31 (бит, выбранный маской 0x80000000) представляет знак числа с плавающей запятой. Показатели экспоненты представляют собой биты 30-23 (биты, выбранные маской 0x7f800000). Биты 22-0 (биты, которые выбираются маской 0x007fffff) представляют значимые (иногда называемые мантиссой) числа с плавающей запятой.
Если аргумент является положительной бесконечностью, результат равен 0x7f800000.
Если аргумент отрицательной бесконечности, результат равен 0xff800000.
Если аргументом является NaN, результат равен 0x7fc00000.
Во всех случаях результат представляет собой целое число, которое при задании методу intBitsToFloat (int) создает значение с плавающей запятой, такое же как и аргумент floatToIntBits (, за исключением того, что все значения NaN сворачиваются в одиночное "каноническое" значение NaN).
Из JLS 15.20.1. Операторы численного сравнения <, < =, > и > =
Результатом сравнения с плавающей запятой, определяемого спецификацией стандарта IEEE 754, является:
Если любой из операндов равен NaN, тогда результат будет ложным.
Все значения, отличные от NaN, упорядочены, с отрицательной бесконечностью меньше всех конечных значений, а положительная бесконечность больше всех конечных значений.
Положительный нуль и отрицательный нуль считаются равными. Например, -0.0 < 0.0 - false, но -0.0 <= 0.0 истинно.
Обратите внимание, однако, что методы Math.min и Math.max обрабатывают отрицательный ноль как строго меньший положительного нуля.
Для строгих сравнений, где операнды являются положительными и отрицательными, результат будет неправильным.
Из JLS 15.21.1. Операторы числового равенства == и!=:
Результатом сравнения с плавающей запятой, определяемого спецификацией стандарта IEEE 754, является:
Тестирование равенства с плавающей точкой выполняется в соответствии с правилами стандарта IEEE 754:
Если либо операнд NaN, то результат == является ложным, но результат!= - true. Действительно, тест x!= X истинен тогда и только тогда, когда значение x равно NaN. Методы Float.isNaN и Double.isNaN также могут использоваться для проверки того, является ли значение NaN.
Положительный нуль и отрицательный нуль считаются равными. Например, -0.0 == 0.0 истинно.
В противном случае два разных значения с плавающей запятой считаются неравными операторами равенства. В частности, существует одно значение, представляющее положительную бесконечность, а одно значение представляет отрицательную бесконечность; каждый сравнивает равный только с самим собой, и каждый сравнивает неравные со всеми другими значениями.
Для сравнений равенств, где оба операнда NaN, результат будет неправильным.
Поскольку общее упорядочение (=
, <
, >
, <=
, >=
)используется многими важными алгоритмами (см. все классы, реализующие интерфейс Comparable), лучше использовать метод сравнения, потому что это даст более последовательное поведение.
Следствием полного упорядочения в контексте стандарта IEEE-754 является разница между положительным и отрицательным нулями.
Например, если вы используете оператор равенства вместо метода сравнения и имеете некоторый набор значений, а ваша логика кода принимает некоторые решения, основанные на упорядочении элементов, и вы как-то начинаете получать излишки значений NaN, они все будут рассматриваться как разные значения, а не как те же значения.
Это может привести к ошибке в поведении программы, пропорциональной количеству/скорости значений NaN. И если у вас много положительных и отрицательных нулей, то только одна пара влияет на вашу логику с ошибкой.
Float использует 32-битный формат IEEE-754 и Double использует 64-битный формат IEEE-754.