Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent function for Math.signum(double) for int or long in Java

Is there an equivalent function for Math.signum(double) or Math.signum(float) in Java for other primitive numbers like int or long. I don't want to write code like

  int sign = (int) Math.signum((double) intValue);

when there is a better alternative.

like image 949
Maarten Avatar asked Jan 18 '17 10:01

Maarten


2 Answers

You can use it this way:

Integer.signum(int i) and Long.signum(long l)

Link to javadoc: https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#signum-int-

like image 151
AMB Avatar answered Sep 28 '22 16:09

AMB


Just an addendum of some implementation details of that :

public static int signum(int i) {
    // HD, Section 2-7
    return (i >> 31) | (-i >>> 31);
}

Integer::signum says : I'll give you -1 if the number is negative, 0 if number is zero and 1 if number is positive. This is fairly trivial via some nested if/else for example.

Instead JDK uses a solution that is a bit more fancy. (x >> 31) | (-x >>> 31). Looks easy right? the first part : x >> 31 is signed shift to the right; it's called signed because it keeps the sign after the shift.

Suppose we live in a world where 4 bits numbers exist only (for simplicity).

We have 0100 (+4), a single shift 0100 >> 1 will make it 0010 (+2). Now, if our number is 1100 (-4; the first bit is the sign), a shift signed to the right : 1100 >> 1 is 1110 (-2). Do a division, but keep the sign.

Thus if we shift 31 times, we throw away the last 31 bits of the number, move the bit for the sign in the least significant position and keep the original sign. Or in simple words take the 31 bit, put it into 0 position and throw away everything else.

 0 00000 ..... 11111
 x --------------->0 // x is kept
        ignore

The second part -x >>> 31 is a unsigned shift, meaning the sign is not kept when we shift.

For example 0100 >>> 1 (+4) will give you 0010 (+2). Nothing is really different so far from the signed shift and the example above. The interesting part comes when numbers are negative:

1100 (-4) and we try to shift it once : 1100 >>> 1, because the sign is not kept, we put zero in the most significant bit and move to the right, thus we get : 0110 (+6!).

In reality, taking 32 bits into the picture. -4 == 1111...111100 and we shift it to the right: sign is zero, everything else is moved to the right, thus: 0111...11110 or Integer.MAX_VALUE - 1.

System.out.println(-4 >>> 1);
System.out.println(Integer.MAX_VALUE - 1);

Thus the part x >>> 31 will move the sign bit into the least significant position, zeroing everything else. No matter the number you give it, you will always get 1 or 0.

1 00000 ..... 11111
x --------------->1 // x is "zeroed also"
       ignore

And the addition of -x to that x >>> 31 is simply done so that | would work correctly satisfy our needed result.

like image 45
Eugene Avatar answered Sep 28 '22 16:09

Eugene