views:

2008

answers:

24

I was asked this question in Amazon Chennai(India) interview , to determine whether an number is positive or negative. The rules are that , we should not use conditional operators such as <, and >, built in java functions (like substring, indexOf, charAt, and startsWith), no regex, or API's. I did some homework on this and the code is given below, but it only works for integer type. But they asked me to write a generic code that works for float, double, and long.

 // This might not be better way!!

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

any ideas from your side.Thanks.

Updates:

OMG!!! looking at the answers, i think the interviewer thought me i was upto something.

Thank you all for providing an excellent answers(Especially Nanda,Itzwarky,Nabb and Strilanc) and spending your precious time of yours.

A: 

Write it using the conditional then take a look at the assembly code generated.

jeffo
@jeffo they asked me to write the solution in java.anyway thanks for the idea.
Suresh S
A: 

Untested, but illustrating my idea:

boolean IsNegative<T>(T v) {
  return (v & ((T)-1));
}
Will
@Will can you explain it?
Suresh S
Mitch Wheat
I don't know much Java in this respect; but to make something 'generic' you can use Java generics - the templated argument so it should work on a variety of number widths; then, you want to see if the high bit is set (don't know which bit in a double or float gives the sign, reliably, but it can be worked out - does java support generic specialisations?). So you take -1 as whatever the appropriate width is, and treat that as the high bit flag (there isn't a sizeof() in java iirc). On reflection, I think this code would have to be much uglier to work.
Will
Nice idea, but I think it will give you a compilation error. You cannot cast to a type parameter.
Stephen C
Yeah, won't work at all. Java generics don't work with primitive tpyes, and arithmetic and bitwise operators don't work on wrapper types, and autounboxing again doesn't work generically.
Michael Borgwardt
A: 

Sorry bitwise operators cannot be applied on double and float in traditional sense.

kuriouskat
@kuriouskat: Note that you shouldn't post comments as separate answers (though I assume you probably did this because you can't comment due to not yet having enough points?)
stakx
+18  A: 

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
    }
  }
}
ItzWarty
eeeek!..................
Mitch Wheat
That one made ma laugh. :D
Rekin
thanks, but it is like blowing a bomb and knowing the result.
Suresh S
What if number is `1.5` ,it won't result in 0 in any case directly, `0.5` and `-0.5` you should consider that also, otherwise nice idea:)
org.life.java
@Suresh S, did they say your code had to be "efficient"?; @org.life.java: grah, you got me :P
ItzWarty
@Suresh S @ItzWarty Check mine solution, no need to lighten up bomb :)
org.life.java
@ItzWarty nothing on efficiency of code, but should work for higher numbers(scientific numbers),that's what he said and went out after giving this question:|.
Suresh S
This solution won't work for `1.5` or for any such real number
org.life.java
It won't work for 0.0001, will it? Any number that is positive and non-integer that is...
Jason Goemaat
@Jason, no, it won't. I'm brainstorming still, hehe.
ItzWarty
+8  A: 

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

Nabb
@Nabb care to explain clearly!!
Suresh S
@nanda Casting a double which is too large to a long will result in the largest representable value of type long as per the Java language specification (negatives behave the same way). Anyway, if num fits within a long, we're pretty much multiplying it to infinity anyway (with the exception of zero).
Nabb
@Nabb Since You have answered quickly for subnormal numbers , consider i accepted your answer.
Suresh S
+2  A: 
// 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...

Steven Schlansker
@Steven no API's Double.doubleToLongBits, why u are AND ing with 0x8000000000000000L , any significance on this number.
Suresh S
@Suresh S: how about now? And that's the highest bit, which is the sign bit...
Steven Schlansker
@Steven thanks, i think this answer is close ,i am testing ur code with 1E08 number. will let u know.
Suresh S
@Steven you are returning something and having void in method definition.
Suresh S
@Suresh S: easy enough to fix. Was just a brain fart :-p
Steven Schlansker
+5  A: 

What about this?

return ((num + "").charAt(0) == '-');
Jess
Sorry, edited - better?
Jess
it won't still ...
org.life.java
@Jess syntax error in java
Suresh S
Drats. I don't have a java compiler handy, that's how you can do it in c#, thought maybe it would work here.
Jess
This would be a clever alternative to toString, and it follows the guidelines. I'm not sure that Java allows this syntax, though. C# and JavaScript will, though. I love this logic, though.
ItzWarty
Definitely clever, but won't work with Java unfortunately.
musicfreak
Fixed to match java syntax. Nice solution :)
Peter Štibraný
@Peter, is charAt considered part of the java API, though?
ItzWarty
@ItzWarty: it is part of java.lang.String API, so probably yes.
Peter Štibraný
Even `num + ""` translates to `sb = new StringBuilder(); sb.append(num); sb.append("")` ... is that java API usage or not? :)
Peter Štibraný
it is simple with indexOf anyways cannot be used (num+"").indexOf("-") > 1
Suresh S
`java built in functions (like substring,indexOf,charAt,startsWith)`
org.life.java
+15  A: 

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;
nanda
Pretty cool solution! For the 0/1 you could cast to an integer and if it's equal to 0 or 1 then return true (or something like that).
Jess
Isn't == a conditional operator?
billynomates
@billynomates: yes it is. However, looking at the answers, even the non valid answers, you practically don't have solution if you may not use it as well. It is after all not explicitly stated as part of the question
nanda
A: 

It seems arbitrary to me because I don't know how you would get the number as any type, but what about checking Abs(number) != number? Maybe && number != 0

Jason Goemaat
@Jason No API's Math.ABS()
Suresh S
+1  A: 

Integers are trivial; this you already know. The deep problem is how to deal with floating-point values. At that point, you've got to know a bit more about how floating point values actually work.

The key is Double.doubleToLongBits(), which lets you get at the IEEE representation of the number. (The method's really a direct cast under the hood, with a bit of magic for dealing with NaN values.) Once a double has been converted to a long, you can just use 0x8000000000000000L as a mask to select the sign bit; if zero, the value is positive, and if one, it's negative.

Donal Fellows
And if they consider that to be an API, it's time to get your ass out of there and find an employer who isn't utterly retarded.
Donal Fellows
@Donal he he "it's time to get your ass out of there" nice quote.he said dont use API's.
Suresh S
Well, you can't do bitmagic in Java on floats or doubles without going through that particular needle (or something equivalent and nastier).
Donal Fellows
In particular, Java's *specified* to use round-to-zero when going from floating point to integer, so values like `-1e-20` will be deeply problematic (i.e., they convert to a value of the wrong sign). Math.floor would help, but that's prohibited. Stupid problem. Stupider company for asking it.
Donal Fellows
A: 

Why not get the square root of the number? If its negative - java will throw an error and we will handle it.

         try {
            d = Math.sqrt(THE_NUMBER);
         }
         catch ( ArithmeticException e ) {
            console.putln("Number is negative.");
         }
DreamWave
no API! Math.sqrt() is API
nanda
+1  A: 

one more option I could think of

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;
}
Siri
Math.sqrt is Java API
nanda
however, (number*number)^0.5 is not!
Phoshi
@Phoshi: operator ^ is not recognized in Java
nanda
@nanda; Oh. That blows this one out, then.
Phoshi
+1  A: 

If it is a valid answer

boolean IsNegative(char[] v) throws NullPointerException, ArrayIndexOutOfBoundException
{ 
  return v[0]=='-'; 
} 
Dennis Cheung
How do you get the char array without using String's toCharArray() method?
Helper Method
@Helper method: in this case, that's not the method's problem ;)
RCIX
A: 

Get the binary representation of the number you want to check. Get its most significant bit. If its one, then its negative else its positive.

jase21
10000 <-- Negative number? -1
Billy ONeal
I think you meant the most significant bit.
I'm going to give him the benefit of the doubt, assuming that he's using "digit" as shorthand for binary digit, aka, bit. nevertheless, it need fleshing out for float, etc.
Don Branson
In binary not in decimals.
jase21
What's the most significant digit in a decimal number? In 10000 is it 1? That's supposed to be a binary number when we refer to most-significant bits etc. Anyway sorry for the ambiguity. I paid its price ;)
jase21
@jase21: Edit the answer to say what you meant?
Merlyn Morgan-Graham
@Merlyn Morgan-Graham duh! Edited :)
jase21
A: 
static boolean isNegative(double v) {
  return new Double(v).toString().startsWith("-");
}
Curd
@Curd startsWith is an API.
Suresh S
@Suresh: Okay, [0] == '-'; then.
Billy ONeal
example is wrong, .toString() is a built-in Java function.
rochal
@Suresh S and rochal: you are right. I misunderstood the rules. I thought only conditional operators are not allowed.
Curd
A: 

Well, taking advantage of casting (since we don't care what the actual value is) perhaps the following would work. Bear in mind that the actual implementations do not violate the API rules. I've edited this to make the method names a bit more obvious and in light of @chris' comment about the {-1,+1} problem domain. Essentially, this problem does not appear to solvable without recourse to API methods within Float or Double that reference the native bit structure of the float and double primitives.

As everybody else has said: Stupid interview question. Grr.

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

  }

}
Gary Rowe
What about the domain:x in (-1,1)
chris
Also, will your solution work for 64 bit machines? How is an `int` represented on 64 bit platform?
The Elite Gentleman
@The Elite Gentleman As I understand it, it's the JVM specification rather than the underlying hardware that defines the size of the various natives. But this may be different on 64-bit machines - I've not researched this. To be honest, the whole question is flawed since floating point cannot be covered.
Gary Rowe
@The Elite Gentleman You may want to review this SO question: http://stackoverflow.com/questions/400477/on-a-64-bit-machine-is-the-size-of-an-int-in-java-32-bits-or-64-bits
Gary Rowe
+29  A: 

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;
}
public static 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");
}
Strilanc
+1. made me laugh, but is really cool :D
back2dos
the double solution is very clever/slick
Ivan
Based on prior comments on other answers, We could say the Double.POSITIVE_INFINITY is part of the API. I do like it. Could be made complete generic via a (double) cast.
chris
I like the double solution too! However, the first two methods should return boolean to compile.
unhillbilly
@unhillbilly Whoops. I didn't run the int methods through an actual compiler. Fixed now.
Strilanc
@chris There's a note that the named double constants can be replaced with literal expressions. I'm not killing the clarity unless it's necessary.
Strilanc
A: 

I don't know how exactly Java coerces numeric values, but the answer is pretty simple, if put in pseudocode (I leave the details to you):

sign(x) := (x == 0) ? 0 : (x/x)
back2dos
The problem here is that -1/-1 = +1...
Manur
@Manur: doh, you're right. Well, I'll leave it as an inspiration :)
back2dos
A: 

If you are allowed to use "==" as seems to be the case, you can do something like that taking advantage of the fact that an exception will be raised if an array index is out of bounds. The code is for double, but you can cast any numeric type to a double (here the eventual loss of precision would not be important at all).

I have added comments to explain the process (bring the value in ]-2.0; -1.0] union [1.0; 2.0[) and a small test driver as well.

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

The output is:

-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
Samuel Tardieu
+1  A: 

This one is roughly based on ItzWarty's answer, but it runs in logn time! Caveat: Only works for integers.

Boolean isPositive(int a)
{
  if(a == -1) return false;
  if(a == 0) return false;
  if(a == 1) return true;
  return isPositive(a/2);
}
Clark Gaebel
Couldn't you use casting to make this work for floating-point values?
stakx
Why is zero return false? Isn't zero a positive value?
The Elite Gentleman
@stakx - I don't think so. Imagine if I passed in 0.5...@TEG - "Isn't zero a positive value?" Zero is not positive, it is non-negative.
Clark Gaebel
A: 

Not efficient, but I guess that's not important here: (I'm also a little rusty with Java, I hope this is more or less correct syntax.)

boolean isPositive = false;

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

This should work because x will be decremented at most x * x times (always a positive number) and if x is never equal to 0, then it must have been negative to begin with. If x, on the other hand, equals 0 at some point, it must have been postive.

Note that this would result in isPositive being false for 0.

P.S.: Admittedly, this won't work with very large numbers, since (int)(x * x) would overflow.

stakx
A: 

This solution uses no conditional operators, but relies on catching two excpetions.

A division error equates to the number originally being "negative". Alternatively, the number will eventually fall off the planet and throw a StackOverFlow exception if it is positive.

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


   }
l337x911
the while loop has a condition built in.
Merlyn Morgan-Graham
Thank you Merlyn for pointing that out. Even in my pseudo code I hate using recursive functions. Without the while loop, this would most likely have recursion depth issues.
l337x911
A: 

I think there is a very simple solution:

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

tell me if I'm wrong!

HowHigH
Will this work for -0.5
Suresh S
Won't work at all, I did this too fast! Sorry
HowHigH
No sorry necessary.:)
Suresh S
+1  A: 

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
Merlyn Morgan-Graham