web-dev-qa-db-fra.com

Déclaration d'un entier non signé dans Java

Existe-t-il un moyen de déclarer un entier non signé en Java?

La question peut également être formulée ainsi: Quel est l’équivalent Java de unsigned?

Juste pour vous dire le contexte, je regardais l'implémentation de String.hashcode() par Java. Je voulais tester la possibilité de collision si l'entier était de 32 unsigned int.

279
Harshdeep

Java n'a pas de type de données pour les entiers non signés .

Vous pouvez définir un long au lieu d'un int si vous devez stocker de grandes valeurs.

Vous pouvez également utiliser un entier signé comme s'il n'était pas signé. L’avantage de la représentation du complément à deux est que la plupart des opérations (telles que l’addition, la soustraction, la multiplication et le décalage à gauche) sont identiques sur un niveau binaire pour les signataires et les signataires. entiers non signés. Quelques opérations (division, décalage à droite, comparaison et casting) sont toutefois différentes. À partir de Java SE 8, les nouvelles méthodes de la classe Integer vous permettent d’utiliser pleinement le type de données intpour effectuer une arithmétique non signée :

Dans Java SE 8 et versions ultérieures, vous pouvez utiliser le type de données int pour représenter un entier non signé de 32 bits, qui a une valeur minimale de 0 et une valeur maximale de 2 ^ 32-1. Utilisez la classe Integer pour utiliser le type de données int en tant qu'entier non signé. Des méthodes statiques telles que compareUnsigned , divideUnsigned etc. ont été ajoutées à la classe Integer. pour supporter les opérations arithmétiques des entiers non signés.

Notez que les variables int sont toujours signées lorsqu'elles sont déclarées, mais que l'arithmétique non signée est désormais possible en utilisant ces méthodes dans la classe Integer.

276
Simeon Visser
67
baraber

Le fait qu'une valeur dans un entier soit signée ou non signée dépend de la façon dont les bits sont interprétés - Java interprète les bits comme une valeur signée (il n'y a pas de primitives non signées).

Si vous avez un int que vous voulez interpréter comme une valeur non signée (par exemple, vous lisez un int d'un DataInputStream dont vous savez qu'il contient une valeur non signée), vous pouvez faire le tour suivant.

int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffl;

Notez qu'il est important que le littéral hexadécimal soit un littéral long et non un littéral int - d'où le 'l' à la fin.

60
Zsolt Safrany

Nous avions besoin de nombres non signés pour modéliser le TINYINT, SMALLINT, INT, BIGINT non _ signé de MySQL jOOQ , c’est pourquoi nous avons créé jOUM , une bibliothèque minimaliste proposant des types de wrapper pour les nombres entiers non signés en Java. Exemple:

import static org.joou.Unsigned.*;

// and then...
UByte    b = ubyte(1);
UShort   s = ushort(1);
UInteger i = uint(1);
ULong    l = ulong(1);

Tous ces types étendent Java.lang.Number et peuvent être convertis en types primitifs d'ordre supérieur et BigInteger. J'espère que cela t'aides.

(Avertissement: je travaille pour l'entreprise derrière ces bibliothèques)

18
Lukas Eder

Pour les nombres non signés, vous pouvez utiliser ces classes à partir de bibliothèque Guava:

Ils supportent diverses opérations:

  • plus
  • moins
  • fois
  • mod
  • divisé par

Ce qui semble manquer pour le moment, ce sont les opérateurs de décalage d'octet. Si vous en avez besoin, vous pouvez utiliser BigInteger à partir de Java.

7
Andrejs

Utilisez char pour les entiers non signés 16 bits.

4

Il semble que vous puissiez gérer le problème de signature en effectuant un "ET logique" sur les valeurs avant de les utiliser:

Exemple (valeur de byte[]header[0] est 0x86):

System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));

Résultat:

Integer -122 = 134
2
Carsten Semark

C'est peut-être ce que tu voulais dire?

long getUnsigned(int signed) {
    return signed >= 0 ? signed : 2 * (long) Integer.MAX_VALUE + 2 + signed;
}
  • getUnsigned(0) → 0
  • getUnsigned(1) → 1
  • getUnsigned(Integer.MAX_VALUE) → 2147483647
  • getUnsigned(Integer.MIN_VALUE) → 2147483648
  • getUnsigned(Integer.MIN_VALUE + 1) → 2147483649
1
Matthias Ronge

Il ya de bonnes réponses ici, mais je ne vois aucune démonstration d’opérations au niveau des bits. Comme Visser (la réponse actuellement acceptée) dit: Java signe les entiers par défaut (Java 8 a des entiers non signés, mais je ne les ai jamais utilisés). Sans plus tarder, faisons-le ...

RFC 868 Exemple

Que se passe-t-il si vous devez écrire un entier non signé sur IO? Exemple pratique, lorsque vous souhaitez sortir l'heure selon RFC 868 . Cela nécessite un entier non signé 32 bits, big-endian, qui code le nombre de secondes depuis 12:00 AM. 1er janvier 1900. Comment encoderiez-vous cela?

Créez votre propre entier 32 bits non signé comme ceci:

Déclarer un tableau d'octets de 4 octets (2 ^ 31 bits)

Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)

Maintenant, vous devez remplir chaque octet du tableau avec des informations dans l'ordre big-endian (ou little-endian si vous voulez faire des ravages). En supposant que vous ayez une longue durée contenant le temps (les entiers longs ont une longueur de 64 bits en Java) appelée secondsSince1900 (qui utilise uniquement les 32 premiers bits, et que vous avez géré le fait que les références de date sont datées, le 1er janvier , 1970), vous pouvez alors utiliser le ET logique pour en extraire des bits et décaler ces bits dans des positions (chiffres) qui ne seront pas ignorées lorsqu’elles sont regroupées dans un octet et dans l’ordre big-endian.

my32BitUnsignedInteger[0] = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24); // first byte of array contains highest significant bits, then shift these extracted FF bits to first two positions in preparation for coersion to Byte (which only adopts the first 8 bits)
my32BitUnsignedInteger[1] = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
my32BitUnsignedInteger[2] = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
my32BitUnsignedInteger[3] = (byte) ((secondsSince1900 & 0x00000000000000FFL); // no shift needed

Notre my32BitUnsignedInteger est maintenant équivalent à un entier big-endian 32 bits non signé qui respecte la norme RCF 868. Oui, le type de données long est signé, mais nous l’avons ignoré, car nous avons supposé que secondesSince1900 utilisait uniquement les 32 bits inférieurs. En raison de la fusion du long dans un octet, tous les bits supérieurs à 2 ^ 7 (les deux premiers chiffres au format hexadécimal) seront ignorés.

Référence à la source: Java Programmation réseau, 4e édition.

1
Jonathan Komar

Je viens de créer ce morceau de code qui convertit "this.altura" d'un nombre négatif à un nombre positif. J'espère que cela aide quelqu'un dans le besoin

       if(this.altura < 0){    

                        String aux = Integer.toString(this.altura);
                        char aux2[] = aux.toCharArray();
                        aux = "";
                        for(int con = 1; con < aux2.length; con++){
                            aux += aux2[con];
                        }
                        this.altura = Integer.parseInt(aux);
                        System.out.println("New Value: " + this.altura);
                    }
1
Romulo