web-dev-qa-db-fra.com

Le moyen le plus rapide de se connecter en Java?

Je voudrais obtenir le signe d'une valeur float en tant que valeur int de -1 ou 1.

Éviter les conditions est toujours une bonne idée pour réduire les coûts de calcul. Par exemple, une façon de penser serait d'utiliser un bit-shift Rapide pour obtenir le signe:

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.

Ou plus précisément:

int sign = (~(a >> 31) << 1) - 1;
  1. Cela vous semble-t-il une bonne approche?
  2. Cela fonctionnera-t-il pour toutes les plates-formes, compte tenu des problèmes d'endianité (comme le signale MSB)?
27
Engineer

Toutes les raisons pour lesquelles vous n'utilisez pas simplement:

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

De plus, la plupart des implémentations de Number ont une méthode de signalisation prenant une primitive de ce type et retournant un entier, vous pouvez donc éviter de transtyper pour des performances supplémentaires.

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

Il renverra +1/0/-1 et il a été optimisé pour offrir de bonnes performances.

Pour référence, vous pouvez jeter un œil à l'implémentation dans openJDK . Les bits pertinents sont:

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

Si vous voulez juste le bit de signe IEEE 754 à partir de la valeur flottante, vous pouvez utiliser:

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

C'est très rapide et a l'avantage de ne pas avoir de succursales. Je pense que c'est le plus rapide que vous pouvez obtenir sur la JVM.

Mais assurez-vous que c'est ce que vous voulez! Faites particulièrement attention aux cas particuliers, par ex. NaN peut techniquement avoir un bit de signe 0 ou 1.

9
mikera

Vous ne devriez essayer d'utiliser des optimisations difficiles à lire/à comprendre que si elles sont absolument nécessaires.

Le problème avec

int sign = Math.signum(a);

peut être qu'il retourne 0 si 0,0 == a

Mais vous devez vous fier autant que possible aux fonctions de bibliothèque existantes pour garder votre code facile à lire/à comprendre.

Si vous voulez 1 pour 0.0 == a, pourquoi?

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