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!这是我试图优化的一些实验的产物(它并不总是零)