2012-12-21 30 views
22

Ben -1 veya 1.Java'da oturum açmanın en hızlı yolu?

kaçınmak Koşullamalar bir int değeri olarak bir float değerinin işaretini almak istiyorum her zaman hesap maliyeti azaltmada iyi bir fikirdir. daha kısaca

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. 

Veya:

int sign = (~(a >> 31) << 1) - 1; 
  1. bu iyi bir yaklaşım gibi görünüyor mu Mesela Aklıma tek yön işareti almak için hızlı bit-shift kullanmak olacaktır?
  2. Bu, tüm platformlar için, enderlik endişeleri (MSB'nin işareti olduğu gibi) göz önünde bulundurulacak mı?

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

    Ayrıca çoğu Numara uygulamaları bir sinyalnum yöntemi bu tür ilkel alıp bir int dönen var, yani ekstra performans için döküm önleyebilirsiniz: basitçe yok neden

cevap

56

Herhangi nedenleri kullanmak .

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

+1/0/-1 döndürecek ve iyi bir performans sunmak için optimize edilmiştir.

Referans için, the implementation in openJDK'a bakabilirsiniz. İlgili bit şunlardır: absolutly gerekli ise

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

Bunu bilmiyordum. Muhtemelen performans konusunda da haklısın. –

+0

+1 * * optimize edilmiş ve NaN vb. Gibi durumları ele alabilir. – arshajii

+7

Integer.signum(), Long.signum(), vb. Öyleyse, ilişkilendirilecek kişi türüne yayınlamak zorunda değilsiniz. –

5

Yalnızca/okumak zor kullanmaya çalışmalısınız, optimizasyonlar anlıyoruz.

int sign = Math.signum(a); 

ile

sorunu, 0

== 0.0 eğer döner Ama mümkünse anlama/okunması kolay kodunuzu tutmak için varolan kitaplık bağlı durumdadır gerektiğini olabilir. Sadece şamandıra değerinden IEEE 754 işareti istemek biraz

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

Formülünüz, Float.NaN için +1 değerini döndürür. Kabul edilebilir. – assylias

8

kullanabilirsiniz:

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

Bu bir ya bu 1 0.0 için == istiyorsanız

çok hızlı ve hiçbir şube avantajı vardır. Bence JVM'de alabileceğin en hızlısı.

Ama istediğin şeyin olduğundan emin ol! Özellikle özel durumlara dikkat edin, örn. NaN teknik olarak ya 0 ya da 1 işaret biti alabilir.

İlgili konular