37

我想将float值的符号作为int-1 或 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 持有符号),这是否适用于所有平台?
4

3 回答 3

83

您不简单使用的任何原因:

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

此外,大多数 Number 实现都有一个 signum 方法,该方法采用该类型的原语并返回一个 int,因此您可以避免强制转换以获得额外的性能。

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;
}
于 2012-12-21T10:56:41.917 回答
8

如果您只想要浮点值中的 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 符号位。

于 2012-12-21T12:04:51.897 回答
5

如果绝对必要,您应该只尝试使用难以阅读/理解的优化。

问题与

int sign = Math.signum(a);

可能是它返回 0 如果 0.0==a

但是您应该尽可能依赖现有的库函数,以使您的代码易于阅读/理解。

如果你想要 1 代表 0.0==a 这个怎么办:

int sign = (0>a)?-1:1;
于 2012-12-21T11:03:56.077 回答