在java中不使用条件语句检查肯定或否定

在java中不使用条件语句检查肯定或否定,java,Java,上周有人问我一个面试问题: 我需要一个函数来打印出一个数字是正数还是负数,而不使用条件语句,如if else,而用于开关>31)将最高位复制到每一位(因此负数变成11111111111111111111111111,正数/零数变成00000000000000000000000000)&1将除最低位以外的所有位设置为0。组合(i>>31)&1仅有效读取i的最高位。我之所以做出这个新答案,是因为我使用了布尔的compareTo方法,该方法使用三元运算符将布尔表达式转换为二进制 这是我的新答案,更难理

上周有人问我一个面试问题:

我需要一个函数来打印出一个数字是正数还是负数,而不使用条件语句,如
if else
,而
用于
开关
等。我该怎么做呢

我告诉面试官这是不可能的,因为这个问题本质上是“有条件的”。他告诉我这是可能的,但没有告诉我怎么做。我找了不少,但没有找到好的答案

一种可能的解决方案:

String[] responses = {"Positive", "Negative"};
System.out.println(responses[(i >> 31) & 1]);
boolean isPositive(int n) {
  return n > ((n + 1) % n);
}
这也将零计为正数

因为Java中的整数需要存储在(或表现为)中,所以任何负数的最高位都是1,而任何其他数字的最高位都是0
(i>>31)
将最高位复制到每一位(因此负数变成
11111111111111111111111111
,正数/零数变成
00000000000000000000000000
)<代码>&1
将除最低位以外的所有位设置为0。组合
(i>>31)&1
仅有效读取
i
的最高位。我之所以做出这个新答案,是因为我使用了布尔的
compareTo
方法,该方法使用三元运算符将布尔表达式转换为二进制

这是我的新答案,更难理解

public static String positiveOrNegative(int n) {

    ArrayList<String> responses = new ArrayList<String>();
    // first element should be "Zero", so if n is 0, the response is "Zero"
    responses.add("Zero");

    // this populates the ArrayList with elements "Positive" for n elements
    // so that if n is positive, n will be an index in the ArrayList
    // and the return will be "Positive"
    // but still if n is negative, it will never be an index in the ArrayList
    for (int i = 0; i < n; i++) {
        responses.add("Positive");
    }

    String response = "";
    try {
        // try to get a response from the ArrayList
        response = responses.get(n);
    } catch (Exception e) {
         // index is out of bounds, so it must have been negative
        response = "Negative";
    }

    return response;
}

public static void main(String[] args) {
    System.out.println(positiveOrNegative(4)); // Positive
    System.out.println(positiveOrNegative(1)); // Positive
    System.out.println(positiveOrNegative(0)); // Zero
    System.out.println(positiveOrNegative(-1)); // Negative
    System.out.println(positiveOrNegative(-4)); // Negative
}
公共静态字符串正或负(int n){
ArrayList responses=新的ArrayList();
//第一个元素应该是“零”,所以如果n是0,响应是“零”
答复。添加(“零”);
//这将使用n个元素的“正”元素填充ArrayList
//因此,如果n为正,则n将是ArrayList中的索引
//回报将是“积极的”
//但是,如果n为负,它将永远不会是ArrayList中的索引
对于(int i=0;i
另一种可能的解决方案:

String[] responses = {"Positive", "Negative"};
System.out.println(responses[(i >> 31) & 1]);
boolean isPositive(int n) {
  return n > ((n + 1) % n);
}
但它不适用于
0

----编辑-----

新算法:

String isPositive(int n) {
  String[] results = {"-", "", "+"};
  return results[1+(1+((n+1)%n)*((n-1)%n))/n];
}

它仍然不适用于
0

这里有一个变化,说明了零既不是正的也不是负的事实:

    int x = (int)Math.sqrt(Math.pow(n, 2));
    try {
        x = n / x;
    }
    catch (ArithmeticException e) {
        x = 0;
    }

    String[] result = {"negative", "zero", "positive"};
    System.out.println(result[x + 1]);

只是想详细说明一下immibis的回答:

int index(int i) {
    return 1 + (i>>31) - (-i>>31);
}

String[] text = {"negative", "zero", "positive"};

private String text(int i) {
    return text[index(i)];
}
有符号移位
i>>31
将每个负数转换为
-1
,将每个负数转换为
0
。计算
-i>>31
可以区分正数和非正数。现在看一下计算的
索引:

positive: 1 +    0 - (-1) = 2
zero:     1 +    0 -    0 = 1
negative: 1 + (-1) -    0 = 0

超级简单的解决方案滥用阵列不能为负的大小这一事实:

void printPositive(int i) {
    try { new int[i]; System.out.println("positive"); } 
    catch( NegativeArraySizeException e) { System.out.println("negative"); }
}

好的,如果
i
为正,那么这个答案可能会分配一个巨大的数组,并且VM在评估
new int[i]
时可能会使用条件,但至少它会向面试官展示某种创造力。此外,这可能会向面试官表明,你可以跳出框框思考(因为他可能预期你会像大多数其他答案一样做一些魔术),并做一些完全不同的事情。

伙计们,这并不难,不需要变换位或做奇怪的调用,只要在数学课上使用signum方法就行了;p

http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#signum%28float%29

正确答案-“这不重要,因为这个问题很愚蠢。任何在生产代码中使用技巧而不是使用if语句的人都应该被解雇。”在采访中提出这样的问题有什么意义?我怀疑雇主是否能找到这样的最佳人选。当然,思考很长,但解决方案的可读性较差。我希望这是针对接近位或硬件的工作。@Gabeschen这是否是一个好主意取决于代码的性质。这些技巧在高性能代码中很有用。在加密代码中,它们对于避免旁道攻击至关重要。许多现代加密库都要求不能有依赖于秘密数据的分支。所以我强烈反对你这种笼统的说法。
a?b:c
不是条件语句,它是条件表达式。事实上,作为一个表达式,而不是一个语句,首先是条件运算符存在的全部理由!因此,这个问题是错误的;-)(嘿,如果你想和你的面试者玩把戏,把你该死的问题问对!)是的。但是我的解释可能会让人困惑。如果我们要计算跳转表,你可以说
switch(i/i){case-1:…;break;case-1:…;break;}
,希望编译器同意你的说法,把它变成一个跳转表。问题不是只指定整数。你可以通过铸造
i/abs(i)来解决这个问题
int32
,然后再执行上述操作。@ebarr您可以使用
Double.Double到longbits
Float.floatToIntBits
然后同样的事情-Float和Double也使用最高位作为符号。向右移动31位将“符号位”移动到最低顺序位;'与1相加将产生1或0。现在您有了字符串数组的索引。我认为>>>会在不扩展符号位的情况下对其进行移位,并消除对and的需要,因此另一个答案是使用
响应[I>>>31)]
。如果(isPositive)打印“positive”
这并不是问题的真正含义。您也可以这样做:
return