Javaでは、変数もfloatである場合、変数を否定することと、変数にfloatから1を引いた値を掛けることの間に違いはありますか?
4 に答える
Java は IEEE の 2 進浮動小数点表現を使用し、符号は別のビットで表されます。の乗算-1
と符号の反転は、-x
この符号ビットを反転することによって行われますが、残りの表現は変更されません。-1.0f
正確な表現があり、 の表現の精度を変更する可能性がないため、結果に違いがないのはそのためですx
。
JLS §15.15.4「単項マイナス演算子 -」では、
浮動小数点値の場合、x が +0.0 の場合、0.0-x は +0.0 ですが、-x は -0.0 であるため、否定はゼロからの減算と同じではありません。単項マイナスは、浮動小数点数の符号を反転するだけです。関心のある特別なケース:
オペランドが NaN の場合、結果は NaN になります。(NaN には符号がないことを思い出してください (§4.2.3)。)
オペランドが無限大の場合、結果は反対符号の無限大になります。
オペランドがゼロの場合、結果は反対符号のゼロになります。
(鉱山をハイライト)
違いは、発行されたバイトコードで確認できます。単項マイナスは単純なfneg
, while(-1f * x)
結果はfload
andfmul
になり、少し遅くなる可能性があります。
JIT コンパイラーが最適化するかどうかはわかりません。
読みやすくするために、-x
通常は を使用する方が優れています。
生成されるバイトコードにはわずかな違いがあります。
float one(float x) {
return -x;
}
float two(float x) {
return x * -1.f;
}
float three(float x) {
return -1.f * x;
}
次のように逆コンパイルします。
float one(float);
Code:
0: fload_1
1: fneg
2: freturn
float two(float);
Code:
0: fload_1
1: ldc #2 // float -1.0f
3: fmul
4: freturn
float three(float);
Code:
0: ldc #2 // float -1.0f
2: fload_1
3: fmul
4: freturn
fneg
命令はfload_1/fmul
;よりもわずかに速いと思います。しかし、違いは無視できる可能性があります (そして、JIT によって最適化される可能性が非常に高いです)。
x
すでに だった場合float
、違いはありません。ただし、の-x
方が読みやすいです。