在 for 循环期间计算特定事件的有效方法
本文关键字:事件 有效 方法 计算 for 循环 | 更新日期: 2023-09-27 17:55:19
我有一个大约一百万个值的循环。我只想存储每个值的指数以显示它们,例如在直方图中。
目前我这样做:
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]++;
}
有没有更有效、更优雅的方法?
也许不使用数组?
有没有更有效、更优雅的方法?
唯一更优雅的方法是使用Math.Min
和Math.Max
但它不会更有效率。 在我看来,histogramm[Math.Max(0,Math.Min(50,exponent+25))]++
角色更少,但没有更表演或优雅。
也许不使用数组?
数组是一组原始值,因此是存储它们的最直接方法。
假设优化了getExponent
和getValue
,优化的唯一方法是使用 Parrallel.For
。我不认为差异会很大,但我认为这是唯一的方法。
至于数组,它是可用于存储数据的最佳索引低级数据结构。
使用并行库 [ using 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);
条件和数组访问没有太多需要优化的地方。但是,如果 getExponent 函数是一项耗时的操作,则可以缓存结果。很大程度上取决于典型数据的样子。配置文件以查看是否有帮助。另外,其他人提到了使用并行。这也值得分析,因为如果getValue或getExponent足够慢以克服并行和锁定开销,则可能会有所不同。
重要提示:对于字典来说,使用double可能是一个坏主意。但是我对正在进行的数学以及从双精度到整数的转换感到困惑。
无论哪种方式,这里的想法都是缓存计算。因此,如果此测试证明有用,也许您可以找到更好的方法。
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]++;
}
尝试使用公共属性来存储指数的值,以便可以测试和检查结果。
至于优雅,我会用实际的函数或子例程简化if
条件,并通过清晰简洁的命名创建额外的抽象。