精度の喪失の可能性のための変化する動作
-
01-10-2019 - |
質問
Javaで、あなたがそうするとき
int b = 0;
b = b + 1.0;
精密エラーの損失の可能性があります。しかし、なぜそうするなら
int b = 0;
b += 1.0;
エラーはありませんか?
解決
それはだからです b += 1.0;
に相当します b = (int) ((b) + (1.0));
. 。 原始変換の狭窄(JLS 5.1.3) 複合割り当て操作に隠されています。
JLS 15.26.2化合物割り当て演算子 (JLS第3版):
フォームの複合割り当て式 E1 op = e2 に相当します e1 =(t)((e1)op(e2)), 、 どこ t のタイプです E1, 、 それ以外で E1 一度だけ評価されます。
たとえば、次のコードは正しいです。
short x = 3; x += 4.6;
との結果
x
価値を持っています7
それは次のようなものだからです:short x = 3; x = (short)(x + 4.6);
これは、次のコードがコンパイルされる理由も説明しています。
byte b = 1;
int x = 5;
b += x; // compiles fine!
しかし、これはそうではありません:
byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!
この場合、明示的にキャストする必要があります。
byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!
複合割り当ての暗黙のキャストがの主題であることは注目に値します パズル9:Tweedledum 素晴らしい本から Java Puzzlers. 。本からの抜粋を次に示します(Brevityのためにわずかに編集):
多くのプログラマーはそれを考えています
x += i;
単に速記ですx = x + i;
. 。これはまったく真実ではありません。結果のタイプが変数のタイプよりも広い場合、複合割り当て演算子はサイレント狭窄の原始変換を実行します。不快な驚きを避けるために、 タイプの変数に複合割り当て演算子を使用しないでください
byte
,short
, 、 またchar
. 。タイプの変数で複合割り当て演算子を使用する場合int
, 、右側の式がタイプでないことを確認してくださいlong
,float
, 、 またdouble
. 。タイプの変数で複合割り当て演算子を使用する場合float
, 、右側の式がタイプでないことを確認してくださいdouble
. 。これらのルールは、コンパイラが危険な狭窄キャストを生成するのを防ぐのに十分です。言語デザイナーにとって、おそらく複合割り当てオペレーターが目に見えないキャストを生成することは間違いです。変数が計算の結果よりも狭いタイプを持っている複合割り当ては、おそらく違法である必要があります。
最後の段落は注目に値します。C#はこの点ではるかに厳格です(参照 C#言語仕様7.13.2化合物の割り当て).