2008-12-04 66 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,但这意味着编写可能会破坏您的需求的本机汇编代码。