Все задачи

Из десятичной в двоичную систему

28 Oct 2013

Программист написал функцию для перевода чисел в двоичную систему счисления.

# принимает число, возвращает строку -- двоичное представление этого числа
sub dec2bin 
{ 
    my $dec = shift; 
    my $bin = ""; 
    while ($dec > 0){
        # Если очередной остаток от деления на 2 равен 1, приписываем к двоичной записи 1, иначе -- 0
        $dec % 2? $bin = 1 . $bin : $bin = 0 . $bin; 
        # делим исходное число на 2
        $dec >>= 1;
    } 
    return $bin;
};

Можно скачать код: здесь.

Однако работает функция как-то странно. Что с ней не так?

Подсказка

Показать

dec2bin(2) возвращает ‘00’, dec2bin(9) – ‘0000’, а dec2bin(2013) - ‘00000000000’.

Подсказка-2

Показать

Все-таки использовать оператор ?: вместо if – странноватая идея.

Разоблачение

Показать

Дело в том, что у тернарного оператора ?: приоритет выше, чем у присваивания. Поэтому выражение

$dec % 2? $bin = 1 . $bin : $bin = 0 . $bin;

вычисляется как

($dec % 2? $bin = 1 . $bin : $bin) = 0 . $bin;

Что интересно: в языке C приоритет ?: тоже выше, чем у присваивания. Однако в C выражение вида c ? i+=1 : i+=2 не пройдет компиляцию ( gcc выдает сообщение ‘lvalue required as left operand of assignment’), потому что выражение c ? i+=1 : i не может служить левой частью присваивания.

А вот в Perl результат выражения ($dec % 2? $bin = 1 . $bin : $bin) – корректное Л-значение, которое можно использовать в левой части присваивания. Получается так потому, и вторая и третья часть в ?: – Л-значения. $bin – переменная, а присваивание из второй части ($bin = 1) тоже возвращает Л-значение, переменную из своей левой части. См. также perldoc perlop.

Так что программисту стоило бы по крайней мере поставить скобки:

$dec % 2? ($bin = 1 . $bin) : ($bin = 0 . $bin);

А еще лучше – использовать обыкновенный if.

Из наших читателей наиболее точное описание проблемы прислал Тигран Оганесян. Здорово!