f (int x) {return x == 0?0: 1;} в Java без условий - PullRequest
31 голосов
/ 08 июля 2011

Я хочу реализовать f(int x) { return x == 0 ? 0 : 1; } в Java.

В C я бы просто "return !!x;", но ! не работает так в Java.Есть ли способ сделать это без условий?Без чего-то глупого, как развернутая версия

int ret = 0;
for (int i = 0; i < 32; i++) {
    ret |= ((x & (1 << i)) >>> i);
}

или

try {
   return x/x;
} catch (ArithmeticException e) {
   return 0;
}

)

РЕДАКТИРОВАТЬ:

Итак,Я сделал микробенчмарк из трех разных решений:

  1. моего решения x / x catch для возврата,
  2. очевидного решения x == 0? 0: 1 и

Время для случайных входов int (всего диапазона int) было:

1. 0.268716  
2. 0.324449  
3. 0.347852  

Да,мое дурацкое х / х решение было быстрее с довольно большим запасом.Не очень удивительно, если учесть, что в нем очень мало нулей, и в подавляющем большинстве случаев используется быстрый путь.

Время для более интересного случая, когда 50% входных данных равно 0:

1. 1.256533  
2. 0.321485  
3. 0.348999  

Наивное решение x==0?0:1 оказалось на 5% быстрее, чем умное (на моей машине).Завтра я попытаюсь выполнить некоторую разборку, чтобы выяснить, почему.

EDIT2: Хорошо, поэтому разборка для условной версии (исключая бухгалтерию):

testl rsi,rsi
setnz rax
movzbl rax,rax

Разборка для (x | -x) >>> 31:

movl rax,rsi
negl rax
orl rax,rsi
sarl rax,#31

Я не думаю, что нужно что-то еще сказать.

Ответы [ 8 ]

42 голосов
/ 08 июля 2011

Хорошо, самое короткое решение без условного ответа, вероятно:

return (i|-i) >>> 31;
11 голосов
/ 08 июля 2011

Вот решение:

public static int compute(int i)
{
    return ((i | (~i + 1)) >> 31) & 1; // return ((i | -i) >> 31) & 1
}

РЕДАКТИРОВАТЬ:

или вы можете сделать его более простым:

public static int compute(int i)
{
    return -(-i >> 31); // return -i >>> 31
}

РЕДАКТИРОВАТЬ 2:

последнее решение не удается с отрицательными числами.Взгляните на решение @Ed Staub.

EDIT3:

@ Орион Адриан: ОК, вот общее решение:

public static int compute(int i)
{
    return (i|-i) >>> java.math.BigInteger.valueOf(Integer.MAX_VALUE).bitLength();
}
8 голосов
/ 08 июля 2011
int f(int x) {
    return Math.abs(Integer.signum(x));
}

Функция signum() возвращает знак числа как -1, 0 или 1. Так что все, что осталось, это превратить -1 в 1, что и делает abs.

7 голосов
/ 08 июля 2011

Кажется, что все эти решения страдают от недостатка усилий, чтобы понять. Это означает, что программисту, который должен позже прочитать и поддерживать этот код, придется тратить ненужные усилия. Это стоит денег.

Выражение

(x == 0)? 0:1

прост и понятен. Это действительно правильный способ сделать это. Использование исключения в обычном прогоне кода совершенно ужасно. Исключения - для обработки обстоятельств вне контроля программиста, а не для обычных рутинных операций.

7 голосов
/ 08 июля 2011

Функция signum реализует это таким образом

return (i >> 31) | (-i >>> 31);

Итак, просто добавьте еще одну побитовую операцию для возврата 0 или 1

return ((i >> 31) | (-i >>> 31)) & 1;
1 голос
/ 09 июля 2011

Интересно, во что это превратит компилятор ...

class kata {

    public static int f(int x){
     return -(Boolean.valueOf(x==0).compareTo(true));
    }

     public static void main(String[] args) {
         System.out.println(f(0));
         System.out.println(f(5));
         System.out.println(f(-1));

     }
}

http://ideone.com/ssAVo

0 голосов
/ 08 июля 2011

Если вы хотите логическое значение, я думаю:

return x == x >>> 1

Сделал бы это, потому что единственное число, чьи установленные биты не перемещаются при сдвиге, это одно без установленных бит.

Под капотом байт-код фактически использует 1 и 0 для true и false, но я не знаю ни одного способа превратить логическое значение языка Java в его соответствующее значение int без какого-либо условия.

0 голосов
/ 08 июля 2011

Этот вопрос сводится к следующему: «Есть ли способ отобразить логическое значение true, false и int 1,0 соответственно без записи условного выражения?»как 1.Наиболее близким является использование -1.Таким образом, как говорит @Ed, троичный оператор такой же краткий, как и вы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...