简体   繁体   English

使C#算法更有效

[英]Make C# algorithm more efficient

I have a C# method that projects the value of a number from an interval to a target interval. 我有一个C#方法,它将一个数字的值从一个区间投射到一个目标区间。
For example: we have an interval of -1000 and 9000 and a value of 5000; 例如:我们的间隔为-1000和9000,值为5000; if we want to project this value to an interval of 0..100 we get 60. 如果我们想将此值投影到0..100的间隔,我们得到60。

Here is the method: 这是方法:

/// <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));
}

This method needs to be called for thousands of values. 需要为数千个值调用此方法。
I was wondering if there is a more efficient way to do this in C#? 我想知道在C#中是否有更有效的方法来做到这一点? If yes, what changes do you suggest? 如果是,您建议做出哪些改变?

Only thousands of values? 只有数千个价值观? Do you really need to optimise this further? 你真的需要进一步优化吗? I can't imagine it's actually a bottleneck at the moment. 我无法想象它现在实际上是一个瓶颈。 Have you profiled the app to check that this is really an issue? 您是否已对该应用进行了分析,以确定这确实是一个问题?

Given that the method is O(1), you're not going to make the most drastic kind of optimisation you normally aim at - improving the complexity. 鉴于该方法是O(1),您不会进行通常目标最激烈的优化 - 提高复杂性。

Having said that - when you call this thousands of times, do any of the values stay constant? 话虽如此 - 当你召唤这几千次时,任何一个值是否保持不变? For example, are you using the same min and max repeatedly? 例如,您是否重复使用相同的最小值和最大值? If so, you could create a class which takes those values in the constructors and precomputes what it can, then has a method taking the rest of the parameters. 如果是这样,您可以创建一个类,它在构造函数中获取这些值并预先计算它可以执行的操作,然后使用一个方法获取其余参数。 This will improve things slightly, but I go back to my original point - only worry about this if it's actually causing problems. 这会略微改善一些事情,但我回到原来的观点 - 只有在实际导致问题时才会担心这一点。

The answers is: Do NOT use decimal for fast operations. 答案是:不要使用小数进行快速操作。

Is there any reason why float or double does not work for you? 有浮动或双重不适合你的原因吗?

Just maths. 只是数学。 What you're "projecting" is a normalisation of ranges AB and A'-B' such that: 你所谓的“投射”是范围AB和A'-B'的标准化,这样:

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

which using your terms is: 使用您的条款是:

(val-min) / (max-min) = (returnValue-intervalBottom) / (intervalTop-intervalBottom) (val-min)/(max-min)=(returnValue-intervalBottom)/(intervalTop-intervalBottom)

which solves for returnValue as: 它解决了returnValue:

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

In addition to not using Decimal as has already been suggested, you could santise your max/min values somewhere else, so that you didn't need all those Abs calls all over the place. 除了已经建议的不使用Decimal之外,你可以在其他地方放弃你的最大/最小值,这样你就不需要在所有地方进行所有那些Abs调用。

I suspect that only part of this you need to do repeatedly is a floating point multiply followed (or proceeded) by a floating point add. 我怀疑你需要重复做的部分只是一个浮点乘以浮点加法后跟(或继续)。 Everything else can be pre-checked & pre-calculated. 其他所有内容都可以预先检查和预先计算。

You code appears more complex than it really needs to be. 您的代码看起来比实际需要的更复杂。 The formula is: 公式是:

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

which is much simpler than your version (and works for integral types). 这比你的版本简单得多(适用于整数类型)。 There's no conditional branches in there (the Math.Min call) or method calls. 那里没有条件分支(Math.Min调用)或方法调用。 OK, it assumes that intervalTop < intervalBottom and min < max. 好的,它假设intervalTop <intervalBottom和min <max。 If intervalTop, intervalBottom, min and max are constant for a set of values then you can precompute (intervalBottom - intervalTop) and (max - min) and use those results for all calls to the function. 如果intervalTop,intervalBottom,min和max对于一组值是常量,那么您可以预先计算(intervalBottom - intervalTop)和(max - min)并将这些结果用于对函数的所有调用。 Another overhead you can eliminate is to inline the function into the calling loop. 您可以消除的另一个开销是将函数内联到调用循环中。 I don't know what C# (or rather the JIT compiler) does about inlining methods so this might already be happening under the hood. 我不知道C#(或者说JIT编译器)对内联方法做了什么,所以这可能已经在幕后发生了。

If you can live with ints or float data types, one possible solution is to use SIMD but this would mean writing native assembler code which might break your requirements. 如果您可以使用整数或浮点数据类型,一种可能的解决方案是使用SIMD,但这意味着编写可能会破坏您的要求的本机汇编程序代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM