Я смущен поведением числа с плавающей запятой, увидев результат следующего фрагмента кода.
float var1 = 5.4f;
float var2 = 5.5f;
if(var1 == 5.4)
System.out.println("Matched");
else
System.out.println("Oops!!");
if(var2 == 5.5)
System.out.println("Matched");
else
System.out.println("Oops!!");
Вывод:
Oops!!
Matched
Это из-за того, что десятичное число не может быть точно представлено в двоичном формате с основанием 2? ИЛИ Это из-за точности, поскольку я сравниваю переменную типа float с типом double? Если да, то почему он отлично работает для следующей переменной?
Ответ 1 · рейтинг 16 · Jon Skeet
Это из-за того, что десятичное число не может быть точно представлено в двоичном формате с основанием 2?
да. По сути, 5.4f и 5.4d не одинаковы, потому что ни один из них не является точным представлением 5.4.
5.5f и 5.5d одинаковы, потому что они оба являются точным представлением 5.5.
Обратите внимание, что 5.4 неявно совпадает с 5.4d - типом по умолчанию для литерала с плавающей запятой является double. Любое использование бинарного оператора с операндами float и double повысит float до double и выполнит операцию с двумя значениями double.
Это может упростить представление об этом в терминах десятичных типов. Предположим, у нас есть два типа, Decimal5 и Decimal10, которые представляют собой десятичные числа с 5 или 10 значащими цифрами. Затем рассмотрим "треть" и "четверть":
A third:
Decimal5: 0.33333
Decimal10: 0.3333333333
A quarter (showing trailing zeroes just for clarity):
Decimal5: 0.25000
Decimal10: 0.2500000000
При сравнении значения Decimal5, ближайшего к третьему, со значением Decimal10, значение Decimal5 будет преобразовано в значение Decimal10, равное 0,3333300000, что не равно 0,3333333333. Это похоже на ваш первый пример.
Однако при сравнении значений для квартала значение Decimal5 0,25000 преобразуется в 0,2500000000, что совпадает со значением Decimal10, которое мы имеем для квартала. Это похоже на ваш второй пример.
Конечно, двоичные типы с плавающей запятой немного сложнее, чем это, с нормализацией, субнормальными числами и т.д., но для целей вашего примера эта аналогия достаточно близка.
Ответ 3 · рейтинг 3 · anubhava
Замените условие if на:
if(var1 == 5.4f)
System.out.println("Matched");
else
System.out.println("Oops!!");
if(var2 == 5.5f)
System.out.println("Matched");
else
System.out.println("Oops!!");
Затем он будет печатать Matched оба раза. Причина в том, что без квалификатора f в конце Java обрабатывает 5.4 как double, что не может быть представлено точно по сравнению с 5.5.