Question

Je stocke des modèles de bits de nombres 64 bits non signés dans une variable long et je souhaite calculer la distance entre deux d'entre eux sur la plage non signée. Parce que Java interprète long comme un entier signé à complément à deux, je ne peux pas simplement faire a - b , comme le montre l'exemple suivant:

// on the unsigned range, these numbers would be adjacent
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;

// but as two's complement (or any representation that 
// stores the sign in the first bit), they aren't
assert b - a == 1;

Quelle est la bonne façon de faire cela?

Était-ce utile?

La solution

Si vous utilisez des additions et des soustractions, peu importe que vous utilisiez des types signés ou non signés, tant que les arguments sont signés ou non signés. Si vous avez besoin de comparer a et b, comparez a-b à 0.

Autres conseils

Au fur et à mesure que l'arithmétique se termine, cela fonctionne de la même manière pour le cas que vous donnez. Si vous interprétez le résultat comme une valeur non signée, ce sera vrai dans tous les cas - vous ne modifiez que l'interprétation du motif binaire, il reste un ensemble homomorphe à & # 918; 2 64 .

Fonctionne pour moi:

long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1

J'ai utilisé cette solution:

if (longA == longB) return 0;
return (longA < longB) ^ (longA < 0) ^ (longB< 0) ? 1 : -1;

Tous les crédits vont à ce site

À partir de Java 8 , vous pouvez comparer long en tant qu'entiers non signés via Long.compareUnsigned (x, y) .

Voici un backport simple pour Java 7 et les versions antérieures:

public static int compareUnsigned(long x, long y) {
   return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
}

Comme mentionné précédemment, vous n'aurez pas de problème de soustraction, donc si c'est tout ce que vous essayez de faire, ne vous inquiétez pas.

Mais, selon votre exemple, l'addition débordera et aucun des opérateurs relationnels ne fonctionnera correctement. Si cela vous pose problème, vous pouvez écrire vos propres opérations relationnelles ou utiliser un type de boîte supérieur à Long.

Solutions: 1. Utilisez BigInteger au lieu de Long. BigInteger a été créé pour effectuer des calculs avec de grandes chiffres et peut facilement prendre en charge les calculs 128 bits.

  1. Ecrivez vos propres opérations relationnelles et excluez l’utilisation de l’addition ou de la multiplication comme possibilité. Écrire votre propre opérateur relationnel n’est vraiment pas si difficile. Vous comparez d’abord le bit le plus significatif. Si le bit le plus significatif est identique pour les deux nombres, vous pouvez le masquer en effectuant un bit à l'aide de (& amp;) avec 0X7FFFFFFFFFFFFFFF, puis de comparer les valeurs masquées.

J'utilise le code suivant:

static boolean unsignedLessThan(long left, long right) { 
    return (left < right) ^ (left < 0) ^ (right < 0);
}

(d'après l'exemple de Tamutnefret)

Évidemment, vous avez besoin de traiter les bits.

static boolean compare(long a, long b)
{
    if(( a &  (Long.MAX_VALUE + 1)) != 0)
        return ( b & (Long.MAX_VALUE + 1) )  != 0
            ? (a < b) //same sign 
            : true; //a is greater b
    else 
        return ( b & (Long.MAX_VALUE + 1) )  != 0
            ? false //b is greater a
            : a < b; //same sign
}

Ou vous pouvez faire la moitié et la moitié comme ça,

public static long unsignedDiff(long a, long b) {
    long mask = 0xFFFFFFFFL;
    return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
       + ((a & mask) - (b & mask));
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top