2012-01-05 15 views
3

:Math.random()がダブルス「よりも大きいか等しい戻りますので、要約すると奇妙な二重の丸めの問題

public static String findOutWhatLifeIsAllAbout() { 
    int meaning = 0; 
    for (int i = 0; i < 10; i++) { 
     for (int j = 0; j < 20; j++) { 
     for (int k = 0; k < 300; k++) { 
      for (int m = 0; m < 7000; m++) { 
      meaning += Math.random() + 1; 
      } 
     } 
     } 
    } 
    return String.valueOf(meaning).replaceAll("0*$", ""); 
} 

は、期待される結果は、文字列「42」であります0.0以上1.0未満」とする。実際には、Ubuntuの下でi5を実行すると、結果の文字列は "420000011"、 "420000008"に似ています! (意味時々Math.random()、何とかラウンド 1秒結果の結果がはMath.random()を引き起こすdouble値のどのような種類のグリップを取得するには

を切り上げなっています "私はいくつかの例を見て期待し、代わりにこの機能を試してみました。

public static String findOutWhatLifeIsAllAboutAltered() { 
    int meaning = 0; 
    for (int i = 0; i < 10; i++) { 
     for (int j = 0; j < 20; j++) { 
     for (int k = 0; k < 300; k++) { 
      for (int m = 0; m < 7000; m++) { 
      double randomResult = Math.random(); 
      int converted = randomResult; 

      if (converted > 0) { 
       System.out.println("Misbehaving double = " + randomResult); 
      } 

      meaning += converted + 1; 
      } 
     } 
     } 
    } 
    return String.valueOf(meaning).replaceAll("0*$", ""); 
} 

しかし、この製剤は常に「42」を返します!誰もが変更された機能で、なぜ行動の変化についての洞察を提供することはできますか?ありがとう。

さらに理由Javaは元のfunctioを許可しますか? nコンパイルは全くですか? +=コールで精度の損失が発生しないようにしてください。

編集あなたが見たいと思っていたコードを投稿しました。「元の」バージョンはキャストされていませんでした。

+2

これをコンパイルするJavaのバージョンは何ですか?私はこれをテストし、Java 1.6を使って正解を返します。 – Yuushi

+0

また、私のシステム(OS X上のJava 1.6)では、両方の関数が '' 42 "'を返します。 –

+0

"修正された"最初の例。 intにキャストされるはずがありませんでした。そのコードは、予期しない結果をコンパイルして示します。 –

答えて

2

meaning += Math.random() + 1; // link 

対、それは深刻なバグです。 0でマスト結果ことMath.random()の結果が明示的に、intにキャストされる。ここで

は、次いで、1は、次にmeaningに添加され、1で得られた、添加されます。 Math.random()の結果はに十分近い場合

連結後にコードが、しかし、今基本的に、meaningにその1に及び

meaning = (int)(Math.random() + (double)1 + (double)meaning); 

Math.random()の結果を追加した後intへの暗黙的なキャストを行います1.0では、doubleの結果が切り上げられ、最終結果がすぐに予想よりわずかに大きくなる場合があります。

1

+ =呼び出し時に精度の損失が発生しないようにしてください。最初のケースで

は、明示的intMath.random()から返された値をキャストしています。第2のケースでは、meaning,convertedおよび1はすべて整数です。


があり、しかし、損失の精度の可能なこの行で:全く、彼らは」ので、精度誤差の損失が存在することはありません

int converted = randomResult; 

http://ideone.com/1ZTDi

+0

Math.random()によって返されたdoubleからキャストされた(int)キャストが精度を失うことになります...すべての値が0. –

+0

明示的に 'double'から' int'へのキャストは、精度の低下の可能性から決してコンパイルされません。 –

1

この例ではすべてintです - 実際には倍精度を追加していません!

Math.random()の結果をintにキャストすることができる唯一の行です.2つのintを一緒に追加するだけです。 JLSは、事業者のこれらのタイプのための暗黙的なキャストを定義するため

しかし、あなたはintにダブルスを追加した場合でも、その後も残っていないでしょう。

フォームE1 OPの複合代入式= E2はE1 =(T)((E1)op(E2))と等価であり、ここでTはE1が1回だけ評価されることを除いてE1のタイプである。

出典:あなたは型変換をやっていると精度の http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.26.2

+0

私は彼がこの行で精度の喪失を意味すると信じています:意味+ =(int)Math.random()+ 1; –

+0

キャストはそこにあると考えて、それはまだ彼が一緒に追加している2 intsです! – berry120

+0

追加は精度の低下を引き起こさない(私は彼がそれを示唆しているとは思わない)。 –

0

損失はこれらのラインに来ることができました:

double randomResult = Math.random(); 
int converted = randomResult; 

としてMath.random()ダブルを返しは、,となり、.となり、var ible に変換され、に変換されるため、0が含まれます。ダブル> int型からキャストの詳細について

、ここを参照してください:私は、Mac OS X(ライオン)上で動作するJava 6のシステムであなたの元のプログラムを試してみたDifferent answer when converting a Double to an Int - Java vs .Net

、それが唯一の42を出力しますJRE/JDKを使用していますか?

meaning += (int)Math.random() + 1; // StackOverflow 

ここに掲載のコードが42以外のものをプリントアウトした場合、リンクのコードと、もともとここに掲載のコードの間に小さいが、重要な違いがあります