¿La forma más rápida de iniciar sesión en Java?


Me gustaría obtener el signo de un valor float como un valor int de -1 o 1.

Evitar condicionales es siempre una buena idea para reducir el costo computacional. Por ejemplo, una forma que se me ocurre sería usar un rápido bit-shift para obtener el signo:

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.

O más concisamente:

int sign = (~(a >> 31) << 1) - 1;
  1. ¿Esto parece un buen enfoque?
  2. ¿Funcionará esto para todas las plataformas, dadas las preocupaciones de endianness (como MSB sostiene el signo)?
Author: Subhrajyoti Majumder, 2012-12-21

3 answers

Cualquier razón por la que no se utiliza simplemente:

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

Además, la mayoría de las implementaciones de números tienen un método signum que toma una primitiva de ese tipo y devuelve un int, por lo que puede evitar el casting para un rendimiento adicional.

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

Volverá +1 / 0 / -1 y se ha optimizado para ofrecer un buen rendimiento.

Como referencia, puede echar un vistazo a la implementación en OpenJDK. Los bits relevantes son:

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;
}
 61
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-11 20:31:41

Si solo desea el bit de signo IEEE 754 del valor flotante, puede usar:

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

Esto es muy rápido y tiene la ventaja de no tener ramas. Creo que es lo más rápido que puedes conseguir en la JVM.

¡Pero asegúrate de que es lo que quieres! Especialmente tenga cuidado con los casos especiales, por ejemplo, NAN técnicamente puede tener un bit de signo 0 o 1.

 8
Author: mikera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-21 12:12:57

Solo debe intentar usar optimizaciones difíciles de leer/comprender, si es absolutamente necesario.

El problema con

int sign = Math.signum(a);

Puede ser que devuelve 0 si 0.0 = = a

Pero debe confiar en las funciones de biblioteca existentes siempre que sea posible para mantener su código fácil de leer/entender.

Si quieres 1 para 0.0 = = a qué pasa con esto:

int sign = (0>a)?-1:1;
 5
Author: MrSmith42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-21 11:03:56