Подтвердить что ты не робот

F (int x) {return x == 0? 0: 1; } в Java без условных обозначений

Я хочу реализовать 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;
}

)

EDIT:

Итак, я сделал microbenchmark трех разных решений:

  • мое решение для возврата x/x,
  • очевидное решение x == 0? 0: 1 и
  • Решение Ed Staub: (x | -x) → > 31.

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

1. 0.268716  
2. 0.324449  
3. 0.347852  

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

Тайминги для более интересного случая, когда 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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Вот решение:

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

EDIT:

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

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

EDIT2:

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

EDIT3:

@Orion Adrian OK, вот общее решение:

public static int compute(int i)
{
    return (i|-i) >>> java.math.BigInteger.valueOf(Integer.MAX_VALUE).bitLength();
}

Ответ 3

int f(int x) {
    return Math.abs(Integer.signum(x));
}

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

Ответ 4

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

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

поэтому просто добавьте другую поразрядную операцию для возврата 0 или 1

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

Ответ 5

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

Выражение

(x == 0)? 0:1

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

Ответ 6

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

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

Ответ 7

Этот вопрос сводится к: "Есть ли способ сопоставить логическое значение true, false с int 1,0, не записывая условное выражение".

В Java нет стандартизированной обработки true как 1. Наиболее близким является использование -1. Так как @Ed говорит, тернарный оператор так же краток, как и вы.

Ответ 8

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

return x == x >>> 1

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

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