Javaでのunsigned intの宣言


316

Javaでunsigned intを宣言する方法はありますか?

または、質問も次のように構成されます。Javaのunsignedに相当するものは何ですか?

ちょうど私がJavaの実装を見ていたコンテキストをあなたに伝えるためにString.hashcode()。整数が32の符号なし整数の場合、衝突の可能性をテストしたかったのです。


7
Javaには符号なしの型はありません。
Andrew Logvinov

1
この投稿は、stackoverflow.com
a / 4449161/778687

2
AFAICTの方法ではないようです。関連:stackoverflow.com/questions/430346/…–
James Manning

11
それはあなたが達成しようとしている目的に依存します。ほとんどの場合、Javaのすべての整数は署名されています。ただし、特定のケースでは、符号付き整数を符号なしとして扱うことができます。の>>>代わりに演算子を使用することにより、符号拡張なしで右シフトできます>>
dasblinkenlight 2012年

回答:


310

Javaには、符号なし整数のデータ型はありません。

大きな値を格納する必要longがあるint場合は、の代わりにを定義できます。

符号なし整数のように、符号付き整数を使用することもできます。2の補数表現の利点は、ほとんどの演算(加算、減算、乗算、左シフトなど)が、符号付き整数と符号なし整数のバイナリレベルで同一であることです。ただし、いくつかの操作(除算、右シフト、比較、およびキャスト)は異なります。Java SE 8以降、Integerクラスの新しいメソッドを使用すると、intデータ型完全に使用して符号なし演算を実行できます。

Java SE 8以降では、intデータ型を使用して、最小値が0、最大値が2 ^ 32-1の符号なし32ビット整数を表すことができます。Integerクラスを使用して、intデータ型を符号なし整数として使用します。符号なし整数の算術演算をサポートするためにcompareUnsigneddivideUnsignedなどの静的メソッドがIntegerクラスに追加されました。

注ことをint宣言したが、符号なしの算術でこれらのメソッドを使用することによって可能になりました時に、変数がまだ署名されIntegerたクラス。


11
公平を期すために、多くのプロジェクトの技術要件はそれほど厳しくなく、実際にそのようなメモリを「浪費」する余裕があります。
Simeon Visser 2013年

6
Javaの本来の目的も理解しています。しかし、例えばスマートフォンは余分なメモリを必要としません。そして、私が知る限り、彼らは通常Javaを使用しています。しかし、まあ、私はJavaプログラマーと他のプログラマーとの間で戦争を始めたくありません。
トマーシュZato -復活モニカ

122
私にとってこれはお金を浪費するだけのケースではありません。ビットレベルで作業する場合、署名なしの方が扱いが簡単です
Cruncher

24
Java 8以降、これは当てはまりません。Java SE 8以降では、intデータ型を使用して、の最小値0と最大値を持つ符号なし32ビット整数を表すことができます2^32-1。-参照docs.oracle.com/javase/tutorial/java/nutsandbolts/...docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie

2
@ 7SpecialGems:その情報を含めるように回答を更新しました。とはいえ、符号なし整数を宣言したり、負の値を除外したりすることはできませんint。さまざまな方法を使用して、unsignedであるかのようにのみ使用できます。
Simeon Visser、2015年

70

1
@stas署名のないデータ型を使用する機能を使用することについて、理解と理解が困難です。私がオンラインで読んださまざまな情報源から、それは単に最大値を広げることを中心に展開しているようであり、暗黙の性質により、それが正の数であることを保証します。私の理解は正しいですか、それとも他の主な理由がありますか?また、IntegerJava 8 のクラスでunsigned intを使用できるようになったのは、空間内と速度の違いです(C / C ++ではプリミティブですが、Javaではオブジェクトラッパー全体です)
Abdul

2
@Abdul-ビットレベルで作業する場合(通常、ハードウェアとのインターフェースのため)、特定の方法で動作するように値を指定する必要があります。つまり、11111111の後に00000000などにロールオーバーします。unsignedの代わりにsignedを使用すると、CRC計算などが失敗する可能性があります。これは、表示のストッパーではなく、時間を浪費するだけです。
Lorne K

3
@Lorne K:Javaでは、int署名されていてもロールオーバーします。符号なしのロールオーバーはC / C ++ですが、符号付きの場合、オーバーフロー時に「未定義の動作」が発生します。「ロールオーバー」が唯一の懸念事項である場合は、無署名である必要はありません。それがCRCルーチンなどが余計な手間をかけずにJavaで機能する理由だと思います。そしてそれが、新しいAPIが解析、フォーマット、比較、除算、および剰余のみを追加する理由です。他のすべての演算、つまりすべてのビット操作だけでなく、加算、減算、乗算なども、とにかく正しいことをしています。
Holger

4
@Ciprian Tomoiaga:ロールオーバーで追加する場合、入力のビットパターンと結果は、それを符号付き数として解釈するか、符号なし数として解釈するかによって異なります。あなたが忍耐を持っている場合は、すべての2⁶⁵組み合わせ...でそれを試すこと
ホルガー

3
@ホルガー、説明ありがとうございます!実際、2の補数を実際に使用するのはそのためです。私はそれを試したいくつか 2 ^ 8の組み合わせ^^
シプリアンTomoiagă

66

intの値が符号付きか符号なしかは、ビットの解釈方法によって異なります。Javaはビットを符号付き値として解釈します(符号なしプリミティブはありません)。

符号なしの値として解釈するintがある場合(たとえば、符号なしの値が含まれていることがわかっているDataInputStreamからintを読み取る場合)、次のトリックを実行できます。

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

16進リテラルがintリテラルではなく長いリテラルであることが重要であることに注意してください。したがって、最後に「l」が付きます。


3
私にとってはこれが最良の答えです...私のデータは4または8バイトのNFCカードUIDから来ています... 4バイトの場合、それをunsigned intにキャストする必要があり、できませんでしたByteBuffer.getLongを使用してください。64ビットデータではなかったためです。ありがとう。
Loudenvier 2014年

なぜ長くする必要があるのですか?0xFFFFFFintを保持することはできませんか?
Displee

19

私たちは、MySQLの符号なしをモデル化する符号なしの数値を必要に応じTINYINTSMALLINTINTBIGINTjOOQ我々が作成した理由である、女王、Javaで符号なし整数の型のラッパー最小限のライブラリーの提供を。例:

import static org.joou.Unsigned.*;

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

これらのタイプはすべて拡張java.lang.Numberされ、より高次のプリミティブタイプおよびに変換できますBigInteger。お役に立てれば。

(免責事項:私はこれらのライブラリの背後にある会社で働いています)


これはとても便利に聞こえます!言及いただきありがとうございます。:)
Lucas Sousa

7

符号なしの数値については、Guavaライブラリの次のクラスを使用できます。

これらはさまざまな操作をサポートします。

  • プラス
  • マイナス
  • モッド
  • で割った

現在欠けているように見えるのはバイトシフト演算子です。それらが必要な場合は、JavaからBigIntegerを使用できます。



2

おそらくこれがあなたの意図したことでしょうか?

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

ifステートメントの代わりに三項演算子を使用した遅延型指定では、何十億分の1秒のパフォーマンス時間が犠牲になります。良くない。(冗談)
ytpillai

5
本当に2 * (long) Integer.MAX_VALUE + 2理解しやすい0x1_0000_0000Lですか?その点で、なぜ単純ではないのですreturn signed & 0xFFFF_FFFFL;か?
Holger

2

値を使用する前に値に対して「論理AND」を実行することで、署名の問題を処理できるようです。

例(の値 byte[] header[0]0x86):

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

結果:

Integer -122 = 134

2

ここには良い答えがありますが、ビット単位の操作のデモはありません。Visser(現在受け入れられている回答)が言うように、Javaはデフォルトで整数に署名します(Java 8には符号なし整数がありますが、私はそれらを使用したことがありません)。さらに騒ぎなくして、それをやってみましょう...

RFC 868の例

符号なし整数をIOに書き込む必要がある場合はどうなりますか?実際の例は、時間を出力したい場合です RFC 868。これには、1900年1月1日の午前12時からの秒数をエンコードする32ビットのビッグエンディアンの符号なし整数が必要です。これをどのようにエンコードしますか?

次のように独自の符号なし32ビット整数を作成します。

4バイト(32ビット)のバイト配列を宣言する

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

これは配列を初期化します。バイト配列はJavaでゼロに初期化されますか?を参照してください。次に、配列の各バイトをビッグエンディアン順(または、大混乱を壊したい場合はリトルエンディアン)の情報で埋める必要があります。(long整数はJavaでは64ビット長である)を含むlongが呼び出されていると仮定しますsecondsSince1900(これは最初の32ビットの価値のみを利用し、Dateが1970年1月1日午前12:00を参照するという事実を処理した)。論理ANDを使用してビットを抽出し、それらのビットをバイトに強制変換されてもビッグエンディアン順で無視されない位置(数字)にシフトできます。

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

これでmy32BitUnsignedInteger、RCF 868標準に準拠する32ビットの符号なしビッグエンディアン整数に相当するようになりました。はい、長いデータ型は署名されていますが、secondsSince1900は下位32ビットのみを使用すると想定したため、この事実は無視しました。longを1バイトに強制変換するため、2 ^ 7(16進数の最初の2桁)より大きいすべてのビットは無視されます。

参照元:Javaネットワークプログラミング、第4版。


1

このコードを作成すると、「this.altura」が負の数から正の数に変換されます。これが困っている人を助けることを願っています

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

-19

Math.abs(number)関数を使用できます。正の数を返します。


12
nitpick:合格しない場合MIN_VALUE
Dennis Meng

2
@ kyo722これが符号なしプリミティブの範囲で正の値を返すとは思えません。
Florian R. Klein

1
nitpick#2:合格した場合は0
不可
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.