2008-12-04 69 views
2

我有一個C#方法,它將一個數字的值從一個區間投影到一個目標區間。
例如:我們有一個-1000和9000的區間和5000的值;如果我們想突出這個值的0..100的間隔,我們得到60使C#算法更有效

這裏是方法:

/// <summary> 
/// Projects a value to an interval 
/// </summary> 
/// <param name="val">The value that needs to be projected</param> 
/// <param name="min">The minimum of the interval the value comes from</param> 
/// <param name="max">The maximum of the interval the value comes from</param> 
/// <param name="intervalTop">The minimum of the interval the value will 
/// be projected to</param> 
/// <param name="intervalBottom">The maximum of the interval the value will 
/// be projected to</param> 
/// <returns>Projected value</returns> 
public decimal ProjectValueToInterval(decimal val, 
             decimal min, 
             decimal max, 
             decimal intervalBottom, 
             decimal intervalTop) 
{ 
    decimal newMin = Math.Min(0, min); 
    decimal valueIntervalSize = Math.Abs(max - newMin); 
    decimal targetIntervalSize = Math.Abs(intervalTop - intervalBottom); 

    decimal projectionUnit = targetIntervalSize/valueIntervalSize; 

    return (val * projectionUnit) + Math.Abs((newMin * projectionUnit)); 
} 

這種方法需要被稱爲千值。
我想知道是否有更有效的方式在C#中做到這一點?如果是的話,你有什麼改變建議?

+0

爲什麼「decimal newMin = Math.Min(0,min);」?對於任何積極的最低要求,這不會給你錯誤的答案嗎? – VVS 2008-12-04 10:16:28

+0

你是對的,Math.Min(0,min)使得數值範圍從0;我忘了拿出這個,但它不影響這個問題... – Germstorm 2008-12-04 13:27:56

回答

4

只是數學。你所「預測」的是範圍AB和A'-B'的歸一化,以便:

比率r =(xA)/(BA)=(yA')/(B'-A' )

其中使用的術語是:

(VAL-分鐘)/(最大值 - 最小值)=(的returnValue-intervalBottom)/(intervalTop-intervalBottom)

這解決了的returnValue爲:

returnValue = ((intervalTop-intervalBottom) * (val-min)/(max-min)) + intervalBottom 
4

答案是:不要在快速操作中使用小數。

是否有任何理由浮動或雙重不適合你?

2

除了沒有像已經提出的那樣使用Decimal,您可以在其他地方將最大/最小值展示出來,這樣您就不需要遍佈整個地方的所有Abs調用。

我懷疑只有這個部分需要重複執行是一個浮點乘法,後面跟着(或繼續)一個浮點數。其他一切可以預先檢查&預先計算。

+0

你是那麼對! – Germstorm 2008-12-04 10:14:06

7

只有數千個值?你真的需要進一步優化嗎?我無法想象它現在實際上是一個瓶頸。你有沒有分析應用程序來檢查這是一個真正的問題?

鑑於方法是O(1),您不會進行通常針對的最激烈的優化 - 提高複雜性。

話雖如此 - 當你撥打這個數千次的時候,任何值都保持不變嗎?例如,你是否反覆使用相同的最小值和最大值?如果是這樣,你可以創建一個類,它在構造函數中使用這些值並預先計算出它的值,然後有一個方法取得其餘的參數。這會稍微改善一些事情,但我會回到我原來的觀點 - 只是擔心這會導致問題。

1

您的代碼看起來比實際需要的要複雜得多。公式是:

intervalTop + (intervalBottom - intervalTop) * (val - min)/(max - min); 

它比你的版本更簡單(並且適用於整型)。在那裏沒有條件分支(Math.Min調用)或方法調用。好的,它假定intervalTop < intervalBottom和最小值<。如果intervalTop,intervalBottom,min和max對於一組值是常量,那麼可以預先計算(intervalBottom - intervalTop)和(max - min),並將這些結果用於對函數的所有調用。您可以消除的另一個開銷是將函數內聯到調用循環中。我不知道C#(或者JIT編譯器)對內聯方法做了什麼,所以這可能已經在引擎蓋下發生了。

如果您可以使用整數或浮點數據類型,一種可能的解決方案是使用SIMD,但這意味着編寫可能會破壞您的需求的本機彙編代碼。