Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to get sign in Java?

I'd like to get the sign of a float value as an int value of -1 or 1.

Avoiding conditionals is always a good idea in reducing computational cost. For instance, one way I can think of would be to use a fast bit-shift to get the sign:

float a = ...;
int sign = a >> 31; //0 for pos, 1 for neg
sign = ~sign; //1 for pos, 0 for neg
sign = sign << 1; //2 for pos, 0 for neg
sign -= 1; //-1 for pos, 1 for neg -- perfect.

Or more concisely:

int sign = (~(a >> 31) << 1) - 1;
  1. Does this seem like a good approach?
  2. Will this work for all platforms, given endianness concerns (as MSB holds sign)?
like image 854
Engineer Avatar asked Dec 21 '12 10:12

Engineer


People also ask

How to get the sign of a number in Java?

Integer signum() Method in Java signum() method of java. lang returns the signum function of the specified integer value. For a positive value, a negative value and zero the method returns 1, -1 and 0 respectively.

How to use sign function in Java?

Java signum() method with ExamplesMath. signum() returns the Sign function of a value passed to it as argument. The signum() function returns the following values depending on the argument passed to it: If the argument passed is greater than zero, then the signum() function will return 1.0.


3 Answers

Any reasons why you don't simply use:

int sign = (int) Math.signum(a); //1 cast for floating-points, 2 for Integer types 

Additionally most Number implementations have a signum method taking a primitive of that type and returning an int, so you can avoid casting for extra performance.

int sign1 = Integer.signum(12); //no casting int sign2 = Long.signum(-24l); //no casting 

It will return +1 / 0 / -1 and it has been optimized to deliver a good performance.

For reference, you can have a look at the implementation in openJDK. The relevant bits are:

public static float signum(float f) {     return (f == 0.0f || isNaN(f)) ? f : copySign(1.0f, f); }  public static boolean isNaN(float f) {     return (f != f); }  public static float copySign(float magnitude, float sign) {     return rawCopySign(magnitude, (isNaN(sign) ? 1.0f : sign)); }  public static float rawCopySign(float magnitude, float sign) {     return Float.intBitsToFloat((Float.floatToRawIntBits(sign)             & (FloatConsts.SIGN_BIT_MASK))             | (Float.floatToRawIntBits(magnitude)             & (FloatConsts.EXP_BIT_MASK             | FloatConsts.SIGNIF_BIT_MASK))); }  static class FloatConsts {     public static final int SIGN_BIT_MASK = -2147483648;     public static final int EXP_BIT_MASK = 2139095040;     public static final int SIGNIF_BIT_MASK = 8388607; } 
like image 69
assylias Avatar answered Sep 18 '22 16:09

assylias


If you just want the IEEE 754 sign bit from the float value you can use:

/**  * Gets the sign bit of a floating point value  */ public static int signBit(float f) {     return (Float.floatToIntBits(f)>>>31); } 

This is very fast and has the advantage of no branches. I think it is the fastest you can get on the JVM.

But make sure it is what you want! Especially watch out for the special cases, e.g. NaN can technically have either a 0 or 1 sign bit.

like image 20
mikera Avatar answered Sep 21 '22 16:09

mikera


You should only try to use hard to read/understand optimizations, if it is absolutely neccessary.

The issue with

int sign = Math.signum(a);

may be that it returns 0 if 0.0==a

But you should rely on existing library functions whenever possible to keep your code easy to read/understand.

If you want 1 for 0.0==a what about this:

int sign = (0>a)?-1:1;
like image 31
MrSmith42 Avatar answered Sep 18 '22 16:09

MrSmith42