пятница, августа 28, 2009

WTF

Скажите, что должен чувствовать программист, когда вот для примерно такого кода:


float speed = Float.NaN;
if (speed == Float.NaN)
Dialog.alert("Not a number");
else
Dialog.alert("Shit happens...");



он видит на экране "Shit happens..."?
Ага, такое дерьмо приключилось вчера со мной, когда я ковырялся в реализации J2ME от одного вполне уважаемого вендора. Убив на проблему около часа, я совсем было отчаялся, решил что я уже слишком стар для таких приколов, и пора мне завязывать с программированием. Однако, неожиданно, замена (speed == Float.NaN) на (Float.isNaN(speed)) решила проблему. Дерьмо исчезло.
Но запах остался...
Продолжаю программировать.

14 комментариев:

Илья Казначеев комментирует...

А чего ты ожидал-то?

Можно ещё в SQL набрать WHERE column = NULL, и честно смотреть интерпретатору в глаза.

NaN затем и специально, что не равно ни одному числу, в том числе себе.

Idsa комментирует...

Это действительно код из реального проекта?! В голову не идет, зачем он такой нужен.

Sergey Rozovik комментирует...

Нет, конечно.
Этот код иллюстрирует ситуацию из реального проекта, когда мы имеем переменную, проинициализированную значением NaN, изатем проверяем ее на это значение.

Анонимный комментирует...

мдя.
и давно вы программируете?
Поведение кода абсолютно правильное.

Sergey Rozovik комментирует...

> и давно вы программируете?
на J2ME - неделю. Собираю грабли :)

Rusted комментирует...

Как сказано в документации проверку на NaN нужно делать так Float.isNaN(speed) и никак иначе.

Sergey Rozovik комментирует...

В документации уважаемого вендора ничего не сказано на этот счет. Там сказано буквально:
NaN
public static final float NaN
The Not-a-Number (NaN) value of type float. It is equal to the value returned by Float.intBitsToFloat(0x7fc00000).

Меня вобщем-то это и сбило с понталыку.
Короче, собираю грабли, как уже сказал.

Анонимный комментирует...

в .NET NaN (float, double) тоже так себя ведет. так што серега, это не вендор а ты типо облажался :(

Анонимный комментирует...

:) волшебный флоат :) помниться тоже оторопел когда однажды получил что-то типо 2+2 != 4

phis комментирует...

Вполне ожидаемое поведение.

Алексей комментирует...

Вики говорит:
NaN не равен ни одному другому значению (даже самому себе); соответственно, самый простой метод проверки результата на NaN — это сравнение полученной величины с самой собой.

Rageous комментирует...

Документация-документация... зачем вообще связываться с программированием, если лениться изучить основы?

С NaN нельзя сравнивать не потому что "нельзя, ибо в доке написано", а потому что число вариантов записи NaN в бинарном виде равно 2 в степени разрядности дробной части числа с плавающей точкой. Потому, чтобы избежать проблем, сравнение на равенство даже одного и того же бинарного NaN флоата даст false.

За более подробной информацией рекомендую уделить час времени непосредственно IEEE 754, а не докам писанным для java-monkeys.

Анонимный комментирует...

Не такой простой это вопрос.
Вот, например, такой код:

if (speed != Float.NaN)
Dialog.alert("Shit happens...");
else
Dialog.alert("Not a number");

тоже выдаст "Shit happens". А его эквивалент в SQL выдал бы "Not a number".
Так что аналогия с SQL здесь не совсем полная (там используется троичная логика, а в Java двоичная).

Анонимный комментирует...

Не такой простой это вопрос.
Вот, например, такой код:

if (speed != Float.NaN)
Dialog.alert("Shit happens...");
else
Dialog.alert("Not a number");

тоже выдаст "Shit happens". А его эквивалент в SQL выдал бы "Not a number".
Так что аналогия с SQL здесь не совсем полная (там используется троичная логика, а в Java двоичная).