2012-12-21 23 views
22

Ich mag würde das Zeichen eines float Wert als int Wert von -1 oder 1.Schnellste Möglichkeit, Java zu erhalten?

Vermeiden conditionals zu bekommen, ist immer eine gute Idee Rechenaufwand zu reduzieren. Zum Beispiel von einer Art, wie ich denken kann, wäre ein schnelles bit-shift zu verwenden, um das Zeichen zu erhalten:

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. 

Oder prägnanten:

int sign = (~(a >> 31) << 1) - 1; 
  1. dies wie ein guter Ansatz scheint?
  2. Wird dies für alle Plattformen funktionieren, wenn man bedenkt, dass Endianess Bedenken bestehen (wie MSB Zeichen hält)?

Antwort

56

Irgendwelche Gründe, warum Sie nicht einfach tun verwenden:

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

Zusätzlich meisten Anzahl Implementierungen ein signum Verfahren haben eine primitive dieser Art nehmen und einen int zurückkehrt, so können Sie vermeiden, für zusätzliche Leistung durch Gießen .

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

Es gibt +1/0/-1 und es wurde optimiert, um eine gute Leistung zu liefern.

Als Referenz können Sie sich the implementation in openJDK ansehen. Die entsprechenden Bits sind:

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

Ich wusste nicht darüber. Sie haben wahrscheinlich auch Recht bezüglich der Leistung. –

+0

+1 Es * wurde * optimiert und kann Fälle wie NaN usw. behandeln – arshajii

+7

Was ist mit Integer.signum(), Long.signum(), etc? Sie müssen dann nicht zum Associate-Typ wechseln. –

5

Sie sollten nur versuchen, schwer zu bedienen Optimierungen zu lesen/verstehen, wenn es absolut notwendig ist.

Das Problem mit

int sign = Math.signum(a); 

kann sein, dass es 0 ist, wenn 0,0 == ein leicht zu lesen/verstehen

Aber Sie sollten auf bestehenden Bibliotheksfunktionen verlassen, wann immer möglich zu halten Ihren Code zurückgibt.

Wenn Sie 1 für 0.0 == wollen ein, was dazu:

int sign = (0>a)?-1:1; 
+2

Ihre Formel gibt +1 für 'Float.NaN' zurück. Es könnte akzeptabel sein. – assylias

8

Wenn Sie nur den IEEE 754 Vorzeichenbits aus dem Float-Wert möchten, können Sie verwenden:

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

Dies ist sehr schnell und hat den Vorteil, keine Verzweigungen. Ich denke, es ist der schnellste Weg, den man auf der JVM finden kann.

Aber stellen Sie sicher, dass es das ist, was Sie wollen! Achten Sie besonders auf die speziellen Fälle, z.B. NaN kann technisch entweder ein 0 oder 1 Vorzeichenbit haben.

Verwandte Themen