【问题标题】:Efficient way of counting specific occurrences during a for loop在 for 循环期间计算特定事件的有效方法
【发布时间】:2016-11-09 00:10:24
【问题描述】:

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

目前我正在这样做:

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]++;
}

有没有更高效、更优雅的方式来做到这一点?
也许不使用数组?

【问题讨论】:

    标签: c# loops optimization histogram data-visualization


    【解决方案1】:

    有没有更高效和优雅的方式来做到这一点?

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

    也许不使用数组?

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

    【讨论】:

      【解决方案2】:

      假设 getExponentgetValue 已优化,那么优化它的唯一方法是使用 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);
      

      【讨论】:

      • 哇等等,这个增量不是线程安全的! E:如果是的话,那么超高的共享不会比单线程快多少。使用单独的数组并在解决两者后求和,但写起来不太好。
      • 只有当计算本身足够慢以补偿并行开销时,这才是一个改进。使用分析器,看看它是否对您有所帮助。
      【解决方案3】:

      条件和数组访问没有太多需要优化的地方。但是,如果 getExponent 函数是一个耗时的操作,您可以缓存结果。很多东西真的取决于典型数据的样子。配置文件,看看它是否有帮助。此外,其他人提到使用 Parallel。这也值得分析,因为如果 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]++;
      }
      

      【讨论】:

      • Enumerable.Repeat(0, 51).ToArray() - 为什么有人会写这个?
      • @harold 哈!这是我尝试优化的一些实验的产物(它并不总是零)。
      • 公平合理的借口:)
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2012-12-09
        • 1970-01-01
        • 2011-06-27
        • 2022-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-21
        • 2021-04-05
        相关资源
        最近更新 更多