用IEEE-754浮點數去表示遊戲運行了多少秒,要多久才會導致加上1/30秒後,遊戲時間卻維持不變?

《遊戲引擎架構》中第 94 頁上寫道「假設我們用浮點數去表示遊戲從開始至今過了多少秒,並稱之為遊戲絕對時間,那麼,遊戲要運行多久,才會導致加上1/30秒後,遊戲絕對時間卻維持不變?答案是大約12.9日。」

但是我怎麼想也計算不出這個答案。

以下是我的計算方法,希望能指出其中的錯誤,謝謝!

設當前運行時間為t,且t = 2^E 	imes (1+m).

IEEE-754中尾數有23位,則加上2^{-24}相當於沒加.

(1+m+2^{-24}) 	imes 2^E = t + frac{1}{30}

t + 2^E 	imes 2^{-24} = t + frac{1}{30}

2^E = frac{2^{24}}{30}

t = 2^E 	imes (1+m) approx 6.47 days (m = 0)


樓主的計算方法是按加上2^{-24}後,時間變數不改變。但如標題所指,應該是加上1/30秒之後,時間變數維持不變。

要理論上計算出這個數值,可能並不容易。本人翻譯此書時,也沒有驗證。剛寫了個簡單程序去驗證結果:

#include &
#include &

using namespace std;

void main() {
float t = 0.0f;
const float dt = 1.0f / 30.0f;
for (unsigned i = 0;; i++) {
float t2 = t + dt;
if (t == t2) {
cout &<&< "t = " &<&< fixed &<&< t &<&< " seconds" &<&< " = " &<&< t / 86400.0f &<&< " days" &<&< endl; cout &<&< "i = " &<&< i &<&< " iterations" &<&< " = " &<&< (float)i / (86400.0f / dt) &<&< " days" &<&< endl; break; } t = t2; } }

我分開顯示t和i這兩個變數所表示的時間,i是實際累加dt的迭代次數,而t是累加後的結果。

在VC2010、x86下的輸出為:

t = 1048576.000000 seconds = 12.136296 days
i = 24986955 iterations = 9.640030 days

此結果與原文有一點差距,可能與具體機器的浮點運算實現及編譯器所造成的差異。

但無論如何,單精度浮點數不太適合存儲遊戲經過的絕對時間。除了經過實際時間約9天後其數值不能增加,還會累積誤差而偏離實際時間。


IEEE浮點數的間隔是不均勻的,距 『0』 越遠間隔越大,當其間隔大於遞增值的兩倍時,遞增部分不改變其表示,故而數值維持不變。

即當 2^E	imes2^{-23}  >  frac{1}{30} 	imes 2 時,遊戲絕對時間會維持不變。

以上可求得 E &> 19 ,設 E = 20,可求得當下時間值至少為 2^{20} = 1048576 秒 = 12.136 天 。


推薦閱讀:

當你玩了守望先鋒或者CF再玩 CS:GO 是什麼感覺?
星際2中如果一個種族可以完全控制另一個種族的兵(像星際1中的神族一樣),會出現什麼奇葩的戰術?
Windows 上的空當接龍第 11982 關到底能不能通過?
去現場參加暴雪嘉年華(Blizzcon)是怎樣的體驗?
如何評價WiiU遊戲《異度之刃X》 ?

TAG:遊戲 | 浮點數 | IEEE754 |