假設我有等間距雙打(64位浮點數)x0,x1,...,xn
。等間隔意味着對於所有i
,x(i+1) - xi
是恆定的;寬度爲w
。快速查找遭遇浮點不準確
給定y
的範圍[x0,xn]
我想找到最大的i
這樣的xi <= y
。
一個幼稚的方法將依次訪問每個i
(O(n)
)。更好的方法是使用二分查找(O(log n)
)。
恆定時間查找將計算(y-x0)/w
並將其轉換爲整數。但是,由於浮點不準確,這偶爾會給出錯誤的結果。例如。假設有寬0.01 100個間隔從0開始。
(int)(0.29/0.01) = 28 //want 29 here
我能保持恆定的時間查找,但確保結果總是相同的二進制搜索?使用小數進行計算而不是雙倍計算'w'和'x0'似乎可以在這裏工作,但它會一直工作嗎?我總是可以跟隨直接查找並與x
進行比較,但這看起來很醜並且效率低下。
澄清 - 我得到xi
和價值y
作爲雙打 - 我不能改變這一點。但是在返回整數索引之前執行的任何中間計算都可以使用我喜歡的任何數據類型。此外,我可以執行一次性「準備」工作,以便更快地運行計算。
編輯:道歉 - 事實證明,我沒有正確檢查「等間隔」 - 當它們的差異是使用浮點算法計算時,這些數字通常不是「等距」。
'(int)(0.29/0.01 + 0.5)= 28'如果你想四捨五入,而不是截斷。 (0.289999/0.01 = 28.999999,在截斷時給出28) – kiwixz 2015-02-11 12:11:19
1)舍入而不是截斷將減少需要調整的可能性。 '(int)Math.Round(0.29/0.01)'2)我會使用索引計算,然後是一個循環,通過向上/向下進行調整,直到您處於正確的位置。對於充分的病理情況,通過一步調整可能是不夠的。 3)C#的浮點規範非常邪惡,除非你在正確的位置將double放置到double(強制精度降低爲double),否則上述算法可能不會總是工作。 – CodesInChaos 2015-02-11 12:11:24
@iKiWiXz更好的是明確和使用Math.Round,Math.Floor,Math.Ceiling比試圖強制演員做到這一點 – 2015-02-11 12:12:31