2

次のコードがstartTimeに間違った値を出力するのは驚くべきことですか?

public class Temp {
    public static void main(String args[]){
       float duration = (float) 2.0;
       long endTime = 1353728995;
       long startTime = 0;
       startTime = (long) (endTime - duration);
       System.out.println(startTime);
}
}
4

4 に答える 4

4

間違った値を出力しません。予期しない値を出力するだけです。

重要な点は、ここで何が起こるかです。

endTime - duration

これは実際には次のように評価されます。

(float) endTime - duration;

ここでデータが失われます。1353728995に最も近いfloat値は1353729024であり、float2を引いた結果に最も近い値は1353729024のままです。

これはすべて言語仕様に従います。JLSセクション15.8.2(加算演算子)は、2進数値昇格がオペランドに適用されると述べています。

セクション5.6.2(2進数の昇格)は次のように始まります。

演算子が2進数の昇格をオペランドのペアに適用する場合、各オペランドは数値タイプに変換可能な値を示す必要があり、次の規則が順番に適用されます。

  • いずれかのオペランドが参照型である場合、そのオペランドはボックス化解除変換の対象になります(§5.1.8)。

  • 拡大プリミティブ変換(§5.1.2)は、次の規則で指定されているように、一方または両方のオペランドを変換するために適用されます。

    • いずれかのオペランドがdouble型の場合、もう一方はdoubleに変換されます。

    • それ以外の場合、いずれかのオペランドがタイプのfloat場合、もう一方はに変換されfloatます。

    • ..。

したがって、これらの規則に従って、のlongendTimeはに変換されfloat、減算はfloat算術で実行されます。

floatのみが有効数字7桁を提供し、残りはかなり明白であることを忘れないでください。

結果をにキャストしないとlong、コンパイラーは何が起こっているのかをより明確にすることに注意してください。

Test.java:8: error: possible loss of precision
    long startTime = endTime - duration;
                             ^
  required: long
  found:    float
1 error

floatこれにより、結果がになり、操作がどのように実行されるか、およびどのような精度が期待されるかについて警告ベルが鳴るはずであることがかなり明確になります。

于 2012-11-28T19:24:37.377 に答える
0

結果を長くしたい場合は、浮動小数点をlongにキャストします。

 float duration = (float) 2.0;
    long endTime = 1353728995;
    long startTime = 0;
    startTime = endTime - (long)duration;
    System.out.println(startTime);

出力:

1353728993

キャストしないと、float値として扱われ、予期しない結果になります。

于 2012-11-28T19:22:02.040 に答える
0

これはすべて浮動小数点表記によるものです。

float引数の少なくとも1つを使用して操作を実行すると、参加しているすべての番号がに昇格しfloatます。ここでは、指数表現を使用しているため、減算の前にfloatとしてendTime変換されます。この表現はあまり正確ではないため、異なる結果が表示されます。1.35372902E9IEEE 754 notation

あなたがするかのように

    startTime =  (endTime - (long)duration);

次に、longを使用してその操作を行うと、期待どおりの結果が得られるはずです。

于 2012-11-28T19:26:04.057 に答える
0

doublefloat精度が低下することがよくあります。これはおそらくあなたがここで見ているものです。

実際には、次のことを計算していることに注意してください。

startTime = (long) ((float)endTime - duration);

コンパイラは、減算のためにlongをfloatに自動的に変換するためです。これは十分に文書化されており、いくつかの優れたコードチェッカーは実際にこれを警告します。

あなたがおそらく望んでいたのはこれです:

startTime = endTime - (long)duration;

しかし、あなたはそう言うべきです。

おそらく、を使用して正しいものを取得することもできます

startTime = (long) (endTime - (double)duration);

しかし、これも安全ではありません。

于 2012-11-28T19:26:48.610 に答える