(My)SQLのようにJavaで符号なしの数値を使用する方法はありますか?
byte
例:次のような範囲の8ビット変数()を使用したい: 0
... 256
; -128
...の代わりに127
。
(My)SQLのようにJavaで符号なしの数値を使用する方法はありますか?
byte
例:次のような範囲の8ビット変数()を使用したい: 0
... 256
; -128
...の代わりに127
。
char
いいえ、Javaには(事実上0〜65535の値を持つ)以外の符号なしプリミティブ型はありません。それは(特に)苦痛ですbyte
が、それはそうです。
通常、同じサイズを使用して「高い」数値の負の値にオーバーフローするか、より広いタイプ(たとえば)を使用short
しbyte
て余分なメモリ要件に対処します。
クラスを使用して、符号なしの数値をシミュレートできます。例えば
public class UInt8 implements Comparable<UInt8>,Serializable
{
public static final short MAX_VALUE=255;
public static final short MIN_VALUE=0;
private short storage;//internal storage in a int 16
public UInt8(short value)
{
if(value<MIN_VALUE || value>MAX_VALUE) throw new IllegalArgumentException();
this.storage=value;
}
public byte toByte()
{
//play with the shift operator ! <<
}
//etc...
}
ほとんどの場合、符号付きの数値は符号なしのように使用できます。ほとんどの操作は同じままで、一部は変更する必要があります。この投稿を参照してください。
内部的には、小さい値を使用するのではなく、intを使用するだけです。私が理解しているように、小さなユニットを使用すると、速度が低下するだけです。内部的にはJavaがすべてのストレージにシステムのワードサイズを使用するため、メモリを節約しません(ワードをパックしません)。
ただし、小さいサイズのストレージユニットを使用する場合は、操作ごとにそれらをマスクするか、範囲チェックなどを行う必要があります。
char(任意の演算)charがintを生成することに気づいたことがありますか?彼らは本当にあなたがこれらの他のタイプを使うことを期待していません。
例外は、配列(パックされると思います)と、小さいタイプを使用すると便利なI / Oですが、マスキングも機能します。
いいえ、変更することはできません。127より大きいものが必要な場合は、1バイトより大きいものを選択してください。
ストレージを最適化する必要がある場合(たとえば、大きな行列)、スペースを節約するために、負の数でより大きな正の数をコーディングできます。次に、必要に応じて数値をシフトして実際の値を取得する必要があります。たとえば、短い正の数だけを操作したいと思います。これがJavaでどのように可能であるかを次に示します。
short n = 32767;
n = (short) (n + 10);
System.out.println(n);
int m = (int) (n>=0?n:n+65536);
System.out.println(m);
したがって、短整数が範囲を超えると、負になります。ただし、少なくともこの数値を16ビットで格納し、シフト値(コード化できるさまざまな値の数)を追加することで正しい値を復元できます。値は、より大きな型(この場合はint)で復元する必要があります。これはあまり便利ではないかもしれませんが、私の場合はそうだと思います。
私はJavaとプログラミングにまったく慣れていません。それでも、最近、符号なしの値が必要になるという同じ状況に遭遇しました。
私が考えていたすべてをコーディングするのに約2週間かかりましたが、私はまったくの初心者なので、はるかに少ない費用で済みます。
一般的な考え方は、インターフェイスを作成することです。これに名前を付けました。UnsignedNumber<Base, Shifted>
抽象AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>>
クラスを実装しながらNumber.classを拡張します。
したがって、Baseパラメーター化タイプは基本タイプを表し、Shiftedは実際のJavaタイプを表します。Implは、この抽象クラスを実装するためのショートカットです。
ほとんどの時間は、Java8Lambdasの定型文と内部のプライベートクラスおよび安全手順を消費しました。重要なことは、減算や負の加算などの数学演算がゼロ制限を生成するときに符号なしの動作を実現することでした。つまり、符号付きの上限を逆方向にオーバーフローさせることです。
最後に、ファクトリと実装サブクラスをコーディングするのにさらに数日かかりました。
これまでのところ、私は知っています:UByteとMUByteUShortとMUShortUIntとMUInt...など。
それらはAbstractUnsignedの子孫です:UByteまたはMUByteextendAbstractUnsigned<Byte, Short, UByte>
またはAbstractUnsigned<Byte, Short, MUByte>
UShortまたはMUShortensendAbstractUnsigned<Short, Integer, UShort>
またはAbstractUnsigned<Short, Integer, MUShort>
...など。
一般的な考え方は、符号なしの上限をシフトされた(キャストされた)タイプとして取り、負の値がゼロからではなく符号なしの上限から来るようにコードを転置することです。
更新:( Ajeansの親切で丁寧な指示に感謝します)
/**
* Adds value to the current number and returns either
* new or this {@linkplain UnsignedNumber} instance based on
* {@linkplain #isImmutable()}
*
* @param value value to add to the current value
* @return new or same instance
* @see #isImmutable()
*/
public Impl plus(N value) {
return updater(number.plus(convert(value)));
}
これは、外部からアクセス可能な方法ですAbstractUnsigned<N, Shifted, Impl>
(または以前に言われたようにAbstractUnsigned<Base, Shifted, Impl>
)。さて、内部の仕事に:
private Impl updater(Shifted invalidated){
if(mutable){
number.setShifted(invalidated);
return caster.apply(this);
} else {
return shiftedConstructor.apply(invalidated);
}
}
上記のプライベートメソッドmutable
では、private final boolean
のAbstractUnsigned
です。は、への変換とその逆の変換をnumber
処理する内部プライベートクラスの1つです。前の「去年の夏のパートでやったこと」に対応して重要なのは、2つの内部オブジェクトです。Base
Shifted
caster
shiftedConstructor
final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;
これらは、の現在の実装インスタンスが不変である場合に、キャストN
(またはBase
)Shifted
または新しいインスタンスを作成するためのパラメーター化された関数です。Impl
AbstractUnsigned<>
Shifted plus(Shifted value){
return spawnBelowZero.apply(summing.apply(shifted, value));
}
このフラグメントには、number
オブジェクトのaddingメソッドが示されています。Shifted
'original'タイプの正の制限がいつ生成されるかは不明であるため、常に内部で使用するという考え方でした。shifted
全体の値を持つ内部パラメータ化フィールドAbstractUnsigned<>
です。他の2つのFunction<>
派生オブジェクトを以下に示します。
final private BinaryOperator<Shifted> summing;
final private UnaryOperator<Shifted> spawnBelowZero;
前者は2つのShifted
値の加算を実行します。そして後者はゼロ転位以下でスポーンを実行します。
AbstractUnsigned<Byte, Short>
そして今、特に前述の工場のボイラープレート「地獄」の1つからの例spawnBelowZero
UnaryOperator<Shifted>
:
...,
v-> v >= 0
? v
: (short) (Math.abs(Byte.MIN_VALUE) + Byte.MAX_VALUE + 2 + v),
...
が正の場合Shifted v
、実際には何も起こらず、元の値が返されます。Base
それ以外の場合:タイプの上限を計算し、Byte
その値を負に加算する必要がありますv
。たとえば、私が得たように、符号ビットによって切り取られた元の上限を取得するために+ 1を与えるを生成し、生成する場合、その場所に非常にv == -8
望ましいものがMath.abs(Byte.MIN_VALUE)
あり128
ます。しかし、最初の負の値は、実際にはそれが理由です。最後に、それは与えてByte.MAX_VALUE
127
255
256
256
+1
+2
255 + 2 + v
-8
255 + 2 + (-8)
249
または、より視覚的な方法で:
0 1 2 3 ... 245 246 247 248 249 250 251 252 253 254 255 256
-8 -7 -6 -5 -4 -3 -2 -1
そして、すべてを完成させるために、これは間違いなく作業を容易にしたり、メモリバイトを節約したりすることはありませんが、必要なときにかなり望ましい動作をします。Number.class
そして、その動作は他のサブクラスでもほとんど使用できます。AbstractUnsigned
それ自体のサブクラスであることは、他の「ネイティブ」サブクラスとNumber.class
同様のすべての便利なメソッドと定数を提供します。たとえば、の最も単純な操作を実行する、と呼ばれる可変サブクラスの便利なメソッドをコーディングしました。Number.class
MIN_VALUE
MAX_VALUE
makeDivisibileBy(Number n)
value - (value % n)
ここでの私の最初の努力は、私のような初心者でもそれをコーディングできることを示すことでした。そのクラスをコーディングしていたときの私の最初の努力は、常に使用するための便利で用途の広いツールを入手することでした。