Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if a number is positive or negative?

Tags:

java

numbers

The integer cases are easy. The double case is trickier, until you remember about infinities.

Note: If you consider the double constants "part of the api", you can replace them with overflowing expressions like 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");
}

The following is a terrible approach that would get you fired at any job...

It depends on you getting a Stack Overflow Exception [or whatever Java calls it]... And it would only work for positive numbers that don't deviate from 0 like crazy.

Negative numbers are fine, since you would overflow to positive, and then get a stack overflow exception eventually [which would return false, or "yes, it is negative"]

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

This will only works for everything except [0..2]

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

You can make a better solution like this (works except for [0..1])

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

You can get better precision by changing the 0.5 part with something like 2^m (m integer):

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

You can do something like this:

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

The main idea here is that we cast to a long and check the value of the most significant bit. As a double/float between -1 and 0 will round to zero when cast to a long, we multiply by large doubles so that a negative float/double will be less than -1. Two multiplications are required because of the existence of subnormals (it doesn't really need to be that big though).


What about this?

return ((num + "").charAt(0) == '-');

// Returns 0 if positive, nonzero if negative
public long sign(long value) {
    return value & 0x8000000000000000L;
}

Call like:

long val1 = ...;
double val2 = ...;
float val3 = ...;
int val4 = ...;

sign((long) valN);

Casting from double / float / integer to long should preserve the sign, if not the actual value...


You say

we should not use conditional operators

But this is a trick requirement, because == is also a conditional operator. There is also one built into ? :, while, and for loops. So nearly everyone has failed to provide an answer meeting all the requirements.

The only way to build a solution without a conditional operator is to use lookup table vs one of a few other people's solutions that can be boiled down to 0/1 or a character, before a conditional is met.

Here are the answers that I think might work vs a lookup table:

  • Nabb
  • Steven Schlansker
  • Dennis Cheung
  • Gary Rowe