如何确定一个数字是正数还是负数?

我在接受采访时被问到如何判断一个数字是正数还是负数。 规则是我们不应该使用诸如<>类的条件运算符,构build在Java函数中(比如substringindexOfcharAtstartsWith ),没有正则expression式或API。

我做了一些这方面的功课,代码如下,但它只适用于整数types。 但是他们要求我编写一个适用于floatdoublelong的generics代码。

  // This might not be better way!! SOP ((( number >> 31 ) & 1) == 1 ? "- ve number " : "+ve number ); 

任何想法从你身边?

整数情况很容易。 这个双重情况是棘手的,直到你记得有关infinities。

注意:如果你认为双常数是“api的一部分”,你可以用1E308 * 2这样的溢出expression式replace它们。

 int sign(int i) { if (i == 0) return 0; if (i >> 31 != 0) return -1; return +1; } int sign(long i) { if (i == 0) return 0; if (i >> 63 != 0) return -1; return +1; } int sign(double f) { if (f != f) throw new IllegalArgumentException("NaN"); if (f == 0) return 0; f *= Double.POSITIVE_INFINITY; if (f == Double.POSITIVE_INFINITY) return +1; if (f == Double.NEGATIVE_INFINITY) return -1; //this should never be reached, but I've been wrong before... throw new IllegalArgumentException("Unfathomed double"); } 

以下是一个可怕的方法,会让你在任何工作中被解雇。

这取决于你得到一个堆栈溢出exception[或任何Java调用它] …而且它只会正常的数字,不会像疯了一样偏离0。

负数是好的,因为你会溢出到正面,然后得到一个堆栈溢出exception最终[这将返回false,或“是的,这是负面的”]

 Boolean isPositive<T>(T a) { if(a == 0) return true; else { try { return isPositive(a-1); }catch(StackOverflowException e) { return false; //It went way down there and eventually went kaboom } } } 

这只适用于除[0..2]之外的所有内容

 boolean isPositive = (n % (n - 1)) * n == n; 

你可以像这样做一个更好的解决scheme(除了[0..1])

 boolean isPositive = ((n % (n - 0.5)) * n) / 0.5 == n; 

用2 ^ m(m整数)改变0.5部分可以得到更好的精度:

 boolean isPositive = ((n % (n - 0.03125)) * n) / 0.03125 == n; 

你可以做这样的事情:

 ((long) (num * 1E308 * 1E308) >> 63) == 0 ? "+ve" : "-ve" 

这里的主要思想是我们投入很长时间,并检查最重要的位的价值。 由于-1和0之间的双/浮点数将在投射到一个长整数时舍入到零,所以我们乘以大双数,因此负浮点/双将小于-1。 由于存在次正常情况,需要进行两次乘法运算(虽然并不需要那么大)。

那这个呢?

 return ((num + "").charAt(0) == '-'); 
 // Returns 0 if positive, nonzero if negative public long sign(long value) { return value & 0x8000000000000000L; } 

打电话:

 long val1 = ...; double val2 = ...; float val3 = ...; int val4 = ...; sign((long) valN); 

从double / float / integer转换为long应该保留符号,如果不是实际值…

你说

我们不应该使用条件运算符

但这是一个技巧要求,因为==也是一个条件运算符。 还有一个内置的? : ? :whilefor循环。 所以几乎每个人都没有提供满足所有要求的答案。

在没有条件运算符的情况下构build解决scheme的唯一方法是使用查找表与其他几个人的解决scheme中的一个解决scheme,可以在满足条件之前将其parsing为0/1或一个字符。

以下是我认为可能对查找表起作用的答案:

  • Nabb
  • 史蒂芬Schlansker
  • Dennis Cheung
  • 加里·罗(Gary Rowe)

该解决scheme使用模数。 是的,它也适用于0.5 (testing在主要方法下面)。

 public class Num { public static int sign(long x) { if (x == 0L || x == 1L) return (int) x; return x == Long.MIN_VALUE || x % (x - 1L) == x ? -1 : 1; } public static int sign(double x) { if (x != x) throw new IllegalArgumentException("NaN"); if (x == 0.d || x == 1.d) return (int) x; if (x == Double.POSITIVE_INFINITY) return 1; if (x == Double.NEGATIVE_INFINITY) return -1; return x % (x - 1.d) == x ? -1 : 1; } public static int sign(int x) { return Num.sign((long)x); } public static int sign(float x) { return Num.sign((double)x); } public static void main(String args[]) { System.out.println(Num.sign(Integer.MAX_VALUE)); // 1 System.out.println(Num.sign(1)); // 1 System.out.println(Num.sign(0)); // 0 System.out.println(Num.sign(-1)); // -1 System.out.println(Num.sign(Integer.MIN_VALUE)); // -1 System.out.println(Num.sign(Long.MAX_VALUE)); // 1 System.out.println(Num.sign(1L)); // 1 System.out.println(Num.sign(0L)); // 0 System.out.println(Num.sign(-1L)); // -1 System.out.println(Num.sign(Long.MIN_VALUE)); // -1 System.out.println(Num.sign(Double.POSITIVE_INFINITY)); // 1 System.out.println(Num.sign(Double.MAX_VALUE)); // 1 System.out.println(Num.sign(0.5d)); // 1 System.out.println(Num.sign(0.d)); // 0 System.out.println(Num.sign(-0.5d)); // -1 System.out.println(Num.sign(Double.MIN_VALUE)); // -1 System.out.println(Num.sign(Double.NEGATIVE_INFINITY)); // -1 System.out.println(Num.sign(Float.POSITIVE_INFINITY)); // 1 System.out.println(Num.sign(Float.MAX_VALUE)); // 1 System.out.println(Num.sign(0.5f)); // 1 System.out.println(Num.sign(0.f)); // 0 System.out.println(Num.sign(-0.5f)); // -1 System.out.println(Num.sign(Float.MIN_VALUE)); // -1 System.out.println(Num.sign(Float.NEGATIVE_INFINITY)); // -1 System.out.println(Num.sign(Float.NaN)); // Throws an exception } } 

这段代码涵盖了所有的案例和types:

 public static boolean isNegative(Number number) { return (Double.doubleToLongBits(number.doubleValue()) & Long.MIN_VALUE) == Long.MIN_VALUE; } 

此方法接受任何包装类( IntegerLongFloatDouble ),并感谢自动装箱的任何基本数字types( intlongfloatdouble ),并简单地检查它的高位,在所有types是符号位,被设置。

它通过以下任何一个返回true

  • 任何负int / Integer
  • 任何负long / Long
  • 任何负的float / Float
  • 任何负double / Double
  • Double.NEGATIVE_INFINITY
  • Float.NEGATIVE_INFINITY

否则为false

未经testing,但说明了我的想法:

 boolean IsNegative<T>(T v) { return (v & ((T)-1)); } 

对我来说这似乎是任意的,因为我不知道你会如何得到这个号码,但是检查Abs(number)!= number是什么? 也许&&数字!= 0

整数是微不足道的; 这你已经知道了。 深层次的问题是如何处理浮点值。 在这一点上,您必须更多地了解浮点值实际上是如何工作的。

关键是Double.doubleToLongBits() ,它可以让你获得数字的IEEE表示。 (这个方法实际上是一个直接的投射,有一些处理NaN值的魔法)。一旦double被转换为long,你可以使用0x8000000000000000L作为掩码来select符号位; 如果为零,则该值为正值,如果为零,则为负值。

如果这是一个有效的答案

 boolean IsNegative(char[] v) throws NullPointerException, ArrayIndexOutOfBoundException { return v[0]=='-'; } 

还有一个select我可以想到

 private static boolean isPositive(Object numberObject) { Long number = Long.valueOf(numberObject.toString()); return Math.sqrt((number * number)) != number; } private static boolean isPositive(Object numberObject) { Long number = Long.valueOf(numberObject.toString()); long signedLeftShifteredNumber = number << 1; // Signed left shift long unsignedRightShifterNumber = signedLeftShifteredNumber >>> 1; // Unsigned right shift return unsignedRightShifterNumber == number; } 

这个大概是基于ItzWarty的答案,但它运行在logn时间! 警告:只适用于整数。

 Boolean isPositive(int a) { if(a == -1) return false; if(a == 0) return false; if(a == 1) return true; return isPositive(a/2); } 

我觉得有一个非常简单的解决scheme:

 public boolean isPositive(int|float|double|long i){ return (((ii)==0)? true : false); } 

告诉我,如果我错了!

尝试这个没有代码: (x-SQRT(x^2))/(2*x)

用条件写它然后看看生成的汇编代码。

为什么不能得到数字的平方根? 如果它的负面 – java会抛出一个错误,我们将处理它。

  try { d = Math.sqrt(THE_NUMBER); } catch ( ArithmeticException e ) { console.putln("Number is negative."); } 

我不知道Java是如何强制数值的,但是如果用伪代码(我把细节留给你),答案很简单:

 sign(x) := (x == 0) ? 0 : (x/x) 

如果允许像“==”一样使用,那么可以这样做,就是利用如果数组索引超出范围就会引发exception的情况。 代码是双重的,但你可以将任何数字types转换为双精度(这里最终的精度损失根本就不重要)。

我已经添加了注释来解释这个过程(带来的价值)-2.0; -1.0] union [1.0; 2.0 [)和一个小testing驱动程序以及。

 class T { public static boolean positive(double f) { final boolean pos0[] = {true}; final boolean posn[] = {false, true}; if (f == 0.0) return true; while (true) { // If f is in ]-1.0; 1.0[, multiply it by 2 and restart. try { if (pos0[(int) f]) { f *= 2.0; continue; } } catch (Exception e) { } // If f is in ]-2.0; -1.0] U [1.0; 2.0[, return the proper answer. try { return posn[(int) ((f+1.5)/2)]; } catch (Exception e) { } // f is outside ]-2.0; 2.0[, divide by 2 and restart. f /= 2.0; } } static void check(double f) { System.out.println(f + " -> " + positive(f)); } public static void main(String args[]) { for (double i = -10.0; i <= 10.0; i++) check(i); check(-1e24); check(-1e-24); check(1e-24); check(1e24); } 

输出是:

 -10.0 -> false -9.0 -> false -8.0 -> false -7.0 -> false -6.0 -> false -5.0 -> false -4.0 -> false -3.0 -> false -2.0 -> false -1.0 -> false 0.0 -> true 1.0 -> true 2.0 -> true 3.0 -> true 4.0 -> true 5.0 -> true 6.0 -> true 7.0 -> true 8.0 -> true 9.0 -> true 10.0 -> true -1.0E24 -> false -1.0E-24 -> false 1.0E-24 -> true 1.0E24 -> true 

效率不高,但我想在这里并不重要(我也对Java有些生疏,我希望这个语法或多或less是正确的)。

 boolean isPositive = false; int n = (int)(x * x); while (n-- != 0) { if ((int)(--x) == 0) { isPositive = true; break; } } 

这应该起作用,因为x最多会减lessx * x次(总是一个正数),如果x永远不等于0,那么它一定是负的开始。 另一方面,如果x在某个点上等于0,它肯定是正面的。

请注意,这将导致isPositive为0为false

PS:无可否认,这将不会用于非常大的数字,因为(int)(x * x)会溢出。

那么,利用铸造(因为我们不在乎实际的价值是什么)或许下面的工作。 请记住,实际的实现不违反API规则。 我已经编辑了这个方法,使得方法名更加明显,并且根据@chris关于{-1,+ 1}问题域的评论。 从本质上讲,这个问题在浮点或双精度浮点数和双精度浮点数的本地位结构的引用下不会求解。

正如大家所说:愚蠢的面试问题。 格儿。

 public class SignDemo { public static boolean isNegative(byte x) { return (( x >> 7 ) & 1) == 1; } public static boolean isNegative(short x) { return (( x >> 15 ) & 1) == 1; } public static boolean isNegative(int x) { return (( x >> 31 ) & 1) == 1; } public static boolean isNegative(long x) { return (( x >> 63 ) & 1) == 1; } public static boolean isNegative(float x) { return isNegative((int)x); } public static boolean isNegative(double x) { return isNegative((long)x); } public static void main(String[] args) { // byte System.out.printf("Byte %b%n",isNegative((byte)1)); System.out.printf("Byte %b%n",isNegative((byte)-1)); // short System.out.printf("Short %b%n",isNegative((short)1)); System.out.printf("Short %b%n",isNegative((short)-1)); // int System.out.printf("Int %b%n",isNegative(1)); System.out.printf("Int %b%n",isNegative(-1)); // long System.out.printf("Long %b%n",isNegative(1L)); System.out.printf("Long %b%n",isNegative(-1L)); // float System.out.printf("Float %b%n",isNegative(Float.MAX_VALUE)); System.out.printf("Float %b%n",isNegative(Float.NEGATIVE_INFINITY)); // double System.out.printf("Double %b%n",isNegative(Double.MAX_VALUE)); System.out.printf("Double %b%n",isNegative(Double.NEGATIVE_INFINITY)); // interesting cases // This will fail because we can't get to the float bits without an API and // casting will round to zero System.out.printf("{-1,1} (fail) %b%n",isNegative(-0.5f)); } } 

这个解决scheme不使用条件运算符,而是依赖于捕获两个奇异点。

划分错误等同于原本为“负面”的数字。 或者,这个数字最终会从这个星球上掉下来,如果它是肯定的,就抛出一个StackOverFlowexception。

 public static boolean isPositive( f) { int x; try { x = 1/((int)f + 1); return isPositive(x+1); } catch (StackOverFlow Error e) { return true; } catch (Zero Division Error e) { return false; } } 

那么下面呢?

 T sign(T x) { if(x==0) return 0; return x/Math.abs(x); } 

应该为每一种types工作…

或者,可以将abs(x)定义为Math.sqrt(x * x),如果这也是作弊,请实现您自己的平方根函数…

 if (((Double)calcYourDouble()).toString().contains("-")) doThis(); else doThat(); 

结合generics与双API。 猜猜这有点作弊,但至less我们只需要编写一个方法:

 static <T extends Number> boolean isNegative(T number) { return ((number.doubleValue() * Double.POSITIVE_INFINITY) == Double.NEGATIVE_INFINITY); } 

两个简单的scheme。 适用于infinities和数字-1 <= r <= 1将返回NaN的“正面”。

 String positiveOrNegative(double number){ return (((int)(number/0.0))>>31 == 0)? "positive" : "negative"; } String positiveOrNegative(double number){ return (number==0 || ((int)(number-1.0))>>31==0)? "positive" : "negative"; } 

这很容易做到这一点

 private static boolean isNeg(T l) { return (Math.abs(l-1)>Math.abs(l)); }