web-dev-qa-db-ja.com

Javaでサインを取得する最速の方法は?

float値の符号を-1または1のint値として取得したいです。

条件を回避することは、計算コストを削減する上で常に良い考えです。たとえば、考えられる1つの方法は、高速のbit-shiftサインを取得するには:

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.

またはより簡潔に:

int sign = (~(a >> 31) << 1) - 1;
  1. これは良いアプローチのように思えますか?
  2. エンディアンネスの懸念を考慮して、これはすべてのプラットフォームで機能しますか(MSBがサインを保持しているため)。
27
Engineer

単に使用しない理由:

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

さらに、ほとんどのNumber実装には、その型のプリミティブを取得してintを返すsignumメソッドがあるため、パフォーマンスを向上させるためにキャストを避けることができます。

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

+1/0/-1を返し、良好なパフォーマンスを提供するように最適化されています。

参考として、 openJDKの実装 をご覧ください。関連するビットは次のとおりです。

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;
}
70
assylias

フロート値からIEEE 754符号ビットが必要な場合は、次を使用できます。

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

これは非常に高速で、分岐がないという利点があります。 JVMで取得できる最速だと思います。

しかし、それがあなたが望むものであることを確認してください!特に、特別な場合には注意してください。 NaNは技術的に0または1の符号ビットを持つことができます。

9
mikera

絶対に必要な場合にのみ、最適化の読み取り/理解に苦労してください。

の問題

int sign = Math.signum(a);

0.0 == aの場合、0を返す可能性があります

ただし、コードを読みやすく/理解しやすくするために、既存のライブラリ関数に可能な限り依存する必要があります。

0.0 == aで1が必要な場合はどうでしょうか:

int sign = (0>a)?-1:1;
5
MrSmith42