繁体   English   中英

如何判断一个数是正数还是负数?

[英]How to determine if a number is positive or negative?

我在一次采访中被问到,如何确定一个数字是正数还是负数。 规则是我们不应使用诸如<>类的关系运算符、内置 java 函数(如substringindexOfcharAtstartsWith )、不使用正则表达式或 API。

我对此做了一些功课,代码如下,但它仅适用于整数类型。 但是他们要求我编写一个适用于floatdoublelong的通用代码。

 // This might not be better way!!

 S.O.P ((( number >> 31 ) & 1) == 1 ? "- ve number " : "+ve number );

你有什么想法吗?

整数情况很容易。 双重情况更棘手,直到您记住无穷大。

注意:如果您将双常量视为“api 的一部分”,则可以将它们替换为溢出表达式,例如1E308 * 2

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");
}

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

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

负数很好,因为你会溢出到正数,然后最终得到一个堆栈溢出异常 [这将返回 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;

您可以像这样制定更好的解决方案(除 [0..1] 外有效)

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

您可以通过将 0.5 部分更改为 2^m(m 整数)之类的内容来获得更好的精度:

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

你可以这样做:

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

这里的主要思想是我们转换为 long 并检查最高有效位的值。 当转换为 long 时,-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循环。 因此,几乎每个人都未能提供满足所有要求的答案。

在满足条件之前,构建没有条件运算符的解决方案的唯一方法是使用查找表与其他一些人的解决方案之一,这些解决方案可以归结为 0/1 或一个字符。

以下是我认为与查找表相比可能有效的答案:

  • 纳布
  • 史蒂文·施兰斯克
  • 丹尼斯·张
  • 加里·罗

此代码涵盖所有情况和类型:

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

此方法接受任何包装类( IntegerLongFloatDouble ),并且由于自动装箱任何原始数字类型( intlongfloatdouble )并简单地检查它的高位,在所有类型中是符号位,被设置。

当通过以下任何一项时,它返回true

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

否则为false

此解决方案使用模数。 是的,它也适用于0.5 (测试如下,在主要方法中)。

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

    }
}

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

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

对我来说这似乎是任意的,因为我不知道您将如何获得任何类型的数字,但是如何检查 Abs(number) != number? 也许&& number != 0

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

关键是Double.doubleToLongBits() ,它可以让您获得数字的 IEEE 表示。 (该方法实际上是在幕后直接转换,在处理 NaN 值时有点魔法。)一旦 double 被转换为 long,您就可以使用 0x8000000000000000L 作为掩码来选择符号位; 如果为零,则值为正,如果为一,则为负。

我能想到的另一种选择

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;
}

如果这是一个有效的答案

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

这个大致基于 ItzWarty 的回答,但它在登录时间运行! 警告:仅适用于整数。

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

我认为有一个非常简单的解决方案:

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

告诉我如果我错了!

不用代码试试这个: (x-SQRT(x^2))/(2*x)

结合了双 API 的泛型。 估计有点作弊,不过至少我们只需要写一个方法:

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

两个简单的解决方案。 也适用于无穷大和数字 -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));
 }

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

为什么不求这个数的平方根? 如果它是负数 - java 将抛出一个错误,我们将处理它。

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

好吧,利用强制转换(因为我们不关心实际值是什么)也许下面的方法会起作用。 请记住,实际实现不会违反 API 规则。 根据@chris 关于 {-1,+1} 问题域的评论,我对其进行了编辑,以使方法名称更加明显。 从本质上讲,如果不求助于 Float 或 Double 中引用 float 和 double 原语的本机位结构的 API 方法,这个问题似乎无法解决。

正如其他人所说:愚蠢的面试问题。 咕噜噜

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));

  }

}

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

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

如果您被允许使用“==”,就像这样,您可以利用以下事实:如果数组索引超出范围,则会引发异常。 该代码适用于双精度型,但您可以将任何数字类型转换为双精度型(此处精度的最终损失根本不重要)。

我添加了注释来解释这个过程(将值带入 ]-2.0; -1.0] union [1.0; 2.0[] 和一个小的测试驱动程序。

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也有点生疏,我希望这或多或少是正确的语法。)

boolean isPositive = false;

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

这应该有效,因为x将最多减少x * x次(总是一个正数),如果x永远不等于0,那么它必须是负数才能开始。 另一方面,如果x在某个时刻等于0,那么它必须是正定的。

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

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

此解决方案不使用条件运算符,而是依赖于捕获两个异常。

除法错误等同于最初为“负”的数字。 或者,如果该数字为正数,该数字最终将脱离地球并引发 StackOverFlow 异常。

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);
}

应该适用于每种类型的 T...

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

if (((Double)calcYourDouble()).toString().contains("-"))
        doThis();
else doThat();
static boolean isNegative(double v) {
  return new Double(v).toString().startsWith("-");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM