2015-11-21 105 views
-2

這裏是我的代碼看起來像剝了下來,儘可能:的Java奇怪的浮動行爲

float delay = (float)5000; 
     long startTime = System.nanoTime(); 
     int elapsed = 0; 
     for (int i = 0; i < 20; i++) { 
      elapsed = (int) ((System.nanoTime() - startTime)/1000000); 
//   System.out.println("Elapsed: " + elapsed); 
      float range = delay * 0.4f; 
      float randomNum = (float)(Math.random() * range - (delay * 0.2f)); 
      if (elapsed > (delay + randomNum)) { 
       System.out.println("Random Num: " + randomNum); 
       startTime = System.nanoTime(); 
      } else { 
       i--; 
       continue; 
      } 
     } 

正如你可以看到我的循環20次,5秒鐘後打印出一個隨機數(5000毫秒)。這是輸出的樣子:

enter image description here

正如你可以看到,所有的輸出都非常接近-1000。我試圖產生一個從-1000到1000的隨機浮動,但他們似乎都在-1000左右。所以,我檢查,以確保實際的隨機數發生器工作時,使用此代碼:

float delay = (float)5000; 
     long startTime = System.nanoTime(); 
     int elapsed = 0; 
     for (int i = 0; i < 20; i++) { 
      elapsed = (int) ((System.nanoTime() - startTime)/1000000); 
//   System.out.println("Elapsed: " + elapsed); 
      float range = delay * 0.4f; 
      float randomNum = (float)(Math.random() * range - (delay * 0.2f));     
      System.out.println("Random Num: " + randomNum); 
      startTime = System.nanoTime(); 
     } 

基本上我拿了過去的方程和剛剛打印的隨機數,而不if語句。這是我得到的輸出:

enter image description here

在這個例子中,我很隨意輸出,完全像你期望的那樣。但是,如果像第一組代碼中一樣添加過去後,輸出將回到-999,並帶有一些隨機小數位。

更有意思的是,如果你把打印語句正上方,如果randomNum後聲明和權限被分配一個值,你會得到這些輸出:再次

enter image description here

,數字是隨機的。由於某些原因,第一個示例代碼中放入了部分代碼,randomNum變量在調用if語句之後立即發生變化。爲什麼會發生?

+0

'range'的類型是什麼?你可以把它歸結爲一個獨立的例子嗎?您已經忽略了足夠的重要信息,任何人都很難提供幫助,問題可能會被解決。 –

+0

對不起,我只是儘可能地編輯它。你在這個問題中看到的所有代碼都在沒有任何其他外部代碼的主方法內部運行。 –

回答

1

問題是,雖然您在所需的範圍內生成隨機數,但您系統地丟棄了所有-999以上的數。

考慮這樣的代碼:

while (true) { 
    // generate a random number in the range [-1000, 1000): 
    final double randomNum = 2000 * Math.random() - 1000; 

    // print it if it's in the range [-1000, -999): 
    if (randomNum < -999) { 
     System.out.println("Random Num: " + randomNum); 
    } 
} 

上面的代碼將打印出一串隨機數的範圍在[− 1000,  − 999);你明白爲什麼?

你的代碼當然更復雜,但它實際上是在做同樣的事情。

要了解原因,讓我們看看你的代碼:

float delay = (float)5000; 
     long startTime = System.nanoTime(); 
     int elapsed = 0; 
     for (int i = 0; i < 20; i++) { 
      elapsed = (int) ((System.nanoTime() - startTime)/1000000); 
//   System.out.println("Elapsed: " + elapsed); 
      float range = delay * 0.4f; 
      float randomNum = (float)(Math.random() * range - (delay * 0.2f)); 
      if (elapsed > (delay + randomNum)) { 
       System.out.println("Random Num: " + randomNum); 
       startTime = System.nanoTime(); 
      } else { 
       i--; 
       continue; 
      } 
     } 

讓我們簡化/修剪了一點,所以它更容易閱讀—刪除註釋掉線,清理空格,刪除強制轉換爲intfloat(這是確定使用longdouble),內聯的各種值,改變for -loop - 即,包含代碼,也就是說,發生變異,其指數變量轉化爲更多的明確while -loop,將System.nanoTime()更改爲,但將百萬分結果更改爲System.currentTimeMillis(),將某些變量重命名萊爲清楚起見,等:

long prevTimeMillis = System.currentTimeMillis(); 
int i = 0; 
while (i < 20) { 
    final long elapsedMillis = System.currentTimeMillis() - prevTimeMillis; 
    final double randomNum = 2000 * Math.random() - 1000; 
    if (elapsedMillis > 5000 + randomNum) { 
     System.out.println("Random Num: " + randomNum); 
     prevTimeMillis = System.currentTimeMillis(); 
     i++; 
    } 
} 

即使在手是簡單的代碼,我們還需要兩個關鍵的見解:

  • elapsedMillis > 5000 + randomNum是寫randomNum < elapsedMillis - 5000的另一種方式。
  • 最初,elapsedMillis == 0;每次我們成功打印出一個數字後,再次輸入elapsedMillis == 0。在這之間,有一些循環迭代,其中elapsedMillis增加了1,但是在大多數循環迭代中它根本不會改變。
    • 這是因爲這個循環非常快,每毫秒有很大數量的迭代。 (這不是從第一原理一定是顯而易見的,但它的解釋你得到的輸出的唯一方式。)

所以這個代碼將循環快,產生一個又一個隨機數並放棄每一個一直到elapsedMillis == 4001,此時每個隨機數將被丟棄,除以外的隨機數小於-999。由於您每毫秒執行大量的循環迭代,並且每毫秒生成大量的隨機數,因此極有可能設法生成一個小於-999的隨機數,而elapsedMillis == 4001。然後elapsedMillis重置爲零。所以大於-999的隨機數從來沒有機會參與競爭:elapsedMillis從不大於4001,所以這樣的數字總是被丟棄。

要解決此問題,您需要預先選擇一個隨機數「我應該延遲多久?」 之前你開始循環,然後循環,直到你的elapsedMillis超過一個預選的隨機數。另外,假設你真正的目標是在[4秒,6秒]的範圍內延遲一段時間,你應該使用Thread.sleep()而不是這個輪詢/忙等待機制。這樣,您可以優雅地放棄此處理器,以供其他線程和進程使用,而不是僅僅刻錄CPU,直到您準備好繼續。要做到這一點,你可以寫:

for (int i = 0; i < 20; i++) { 
    final long millisToDelay = (long) (2000 * Math.random() - 1000); 
    System.out.println("Millis To Delay: " + millisToDelay); 
    Thread.sleep(millisToDelay); 
} 
+0

非常聰明!抓住這個好工作,並且非常感謝。 –

+0

@ScottyPippen:不客氣! – ruakh

0

我相信你確實有問題的答案位於你提供給我們的第二行代碼中。注意你如何轉換爲浮點數:(float)?

請在包含行同樣的事情:

浮點數=延遲+ randomNum;

,使得其看起來像:

浮點數=(浮點)延遲+ randomNum;

延遲不是浮點數據類型。我認爲應該這樣做。

+0

延遲是一種浮點型。我有這樣的代碼「float delay =(float)delayMS;」而delayMS是一個int。 –