C# 计算for循环期间特定事件的有效方法

C# 计算for循环期间特定事件的有效方法,c#,loops,optimization,histogram,data-visualization,C#,Loops,Optimization,Histogram,Data Visualization,我有一个大约一百万个值的循环。我只想存储每个值的指数以显示它们,例如在直方图中 目前我正在这样做: int histogram[51]; //init all with 0 for(int i = 0; i < 1000000; i++) { int exponent = getExponent(getValue(i)); //getExponent(double value) gives the exponent(base 10) //getValue(int

我有一个大约一百万个值的循环。我只想存储每个值的指数以显示它们,例如在直方图中

目前我正在这样做:

int histogram[51]; //init all with 0
for(int i = 0; i < 1000000; i++)
{
    int exponent = getExponent(getValue(i)); 
    //getExponent(double value) gives the exponent(base 10)
    //getValue(int i) gives the value for loop i
    if(exponent > 25)
        exponent = 25;
    if(exponent < -25)
        exponent = -25;
    histogramm[exponent+25]++;
}
int直方图[51]//使用0初始化所有
对于(int i=0;i<1000000;i++)
{
int-exponent=getExponent(getValue(i));
//getExponent(双倍值)给出指数(以10为基数)
//getValue(inti)给出循环i的值
如果(指数>25)
指数=25;
如果(指数<-25)
指数=-25;
组织程序[指数+25]++;
}
有没有更高效、更优雅的方法
也许不使用数组?

尝试使用公共属性为您存储值,以便测试和检查结果

至于优雅,我将使用实际函数或子例程简化
if
条件,并使用清晰简洁的命名创建额外的抽象

有没有更有效、更优雅的方法

唯一更优雅的方法是使用
Math.Min
Math.Max
,但效率不会更高
historogram[Math.Max(0,Math.Min(50,指数+25))]++
在我看来是更少的字符,但没有更多的性能或优雅

也许不使用数组


数组是一组原始值,因此是存储它们的最直接的方法。

假设
getExponent
getValue
都经过优化,唯一的优化方法是使用
parralel.For
。我不认为差别会很大,但我认为这是唯一的办法

至于数组,它是可用于存储数据的最佳索引低级数据结构

使用并行库[
使用System.Threading.Tasks;
]:

int[] histogram = new int[51]; //init all with 0

Action<int> work = (i) =>
{
    int exponent = getExponent(getValue(i));
    //getExponent(double value) gives the exponent(base 10)
    //getValue(int i) gives the value for loop i
    if (exponent > 25)
        exponent = 25;
    if (exponent < -25)
        exponent = -25;
    histogram[exponent + 25]++;
};

Parallel.For(0, 1000000, work);
int[]直方图=新的int[51]//使用0初始化所有
行动工作=(i)=>
{
int-exponent=getExponent(getValue(i));
//getExponent(双倍值)给出指数(以10为基数)
//getValue(inti)给出循环i的值
如果(指数>25)
指数=25;
如果(指数<-25)
指数=-25;
直方图[指数+25]+;
};
平行。对于(1000000,工作);

条件访问和数组访问并没有太多需要优化的地方。但是,如果getExponent函数是一个耗时的操作,则可以缓存结果。很多都取决于典型数据的外观。配置文件以查看是否有帮助。另外,还有人提到使用并行。这也值得分析,因为如果getValue或getExponent足够慢,足以克服并行和锁定开销,那么它可能会产生不同

重要提示:对于字典来说,使用double可能是个坏主意。但是我被正在进行的数学运算和从double到int的转换弄糊涂了

无论如何,这里的想法是缓存一个计算。因此,如果这个测试被证明是有用的,也许你可以找到一个更好的方法

int[] histogram = Enumerable.Repeat(0, 51).ToArray();
...
Dictionary<double, int> cache = new Dictionary<double, int>(histogram.Length);
...

for (int i = 0; i < 1000000; i++)
{
    double value = getValue(i);
    int exponent;
    if(!cache.TryGetValue(value, out exponent))
    {
        exponent = getExponent(value);
        cache[value] = exponent;
    }

    if (exponent > 25)
        exponent = 25;
    else if (exponent < -25)
        exponent = -25;

    histogram[exponent + 25]++;
}
int[]直方图=可枚举。重复(0,51).ToArray();
...
字典缓存=新字典(直方图长度);
...
对于(int i=0;i<1000000;i++)
{
双值=getValue(i);
整数指数;
如果(!cache.TryGetValue(值,输出指数))
{
指数=getExponent(值);
缓存[值]=指数;
}
如果(指数>25)
指数=25;
否则如果(指数<-25)
指数=-25;
直方图[指数+25]+;
}

等等,这个增量不是线程安全的!E:如果是的话,那么超高共享将不会比单线程快多少。使用单独的数组和事后求和可以同时解决这两个问题,但写起来并不那么好。只有当计算本身足够慢,足以补偿并行开销时,这才是一种改进。拿出一个分析器,看看它是否对你有影响。
可枚举。重复(0,51)。ToArray()
-为什么会有人写这个?@harold Hah!这是我试图优化的一些实验的产物(它并不总是零)