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;
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;
}
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.
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;