2012-12-21 13 views
22

Chciałbym uzyskać znak wartości float jako wartość int -1 lub 1.Najszybszy sposób na zalogowanie się w Javie?

Unikanie warunkowych jest zawsze dobry pomysł na zmniejszenie kosztów obliczeniowej. Na przykład, jeden sposób mogę myśleć byłoby użyć szybki bit-shift aby uzyskać znak:

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. 

lub więcej zwięźle:

int sign = (~(a >> 31) << 1) - 1; 
  1. Czy to wydawać się dobrym podejściem?
  2. Czy to działa na wszystkich platformach, ze względu na problemy z endianizmem (jak MSB trzyma znak)?

Odpowiedz

56

jakichkolwiek powodów, dlaczego nie wystarczy użyć:

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

Dodatkowo większość implementacji metody numeryczne mają signum biorąc prymitywne tego typu i powracający int, dzięki czemu można uniknąć rzucania dla dodatkowej wydajności .

Zwróci +1/0/-1 i został zoptymalizowany, aby zapewnić dobrą wydajność.

Dla odniesienia, możesz rzucić okiem na the implementation in openJDK. Odpowiednie bity są:

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

Nie wiedziałem o tym. Prawdopodobnie masz rację co do osiągów. –

+0

+1 It * has * został zoptymalizowany i może obsługiwać takie przypadki, jak NaN itp. – arshajii

+7

Co z Integer.signum(), Long.signum() itp.? Nie musisz wtedy rzutować na typ partnera. –

5

Należy starać tylko do korzystania trudne do odczytu/zrozumieć optymalizacje, jeśli jest to absolutnie neccessary.

Problem z

int sign = Math.signum(a); 

może być to, że zwraca 0 jeśli 0,0 ==

Ale trzeba polegać na istniejących funkcji bibliotecznych o ile to możliwe, aby utrzymać swój kod łatwy do odczytu/zrozumieć.

Jeśli chcesz 1 do 0,0 == a Co o tym:

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

Twoja formuła zwraca +1 dla 'Float.NaN'. To może być do zaakceptowania. – assylias

8

Jeśli chcesz po prostu IEEE 754 bit znaku od wartości typu float można użyć:

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

Jest bardzo szybki i ma tę zaletę, że nie ma oddziałów. Myślę, że jest to najszybszy z dostępnych na JVM.

Ale upewnij się, że tego właśnie chcesz! Zwróć szczególną uwagę na specjalne przypadki, np. NaN może technicznie mieć bit znaku 0 lub 1.

Powiązane problemy