代码之家  ›  专栏  ›  技术社区  ›  Totonga

最小、最大、中位数、平均值的OpenMP C++算法〔闭锁〕

  •  26
  • Totonga  · 技术社区  · 15 年前

    我在谷歌搜索提供一些简单OpenMP算法的页面。 可能有一个例子可以从一个巨大的数据数组中计算最小值、最大值、中间值和平均值,但我找不到它。

    至少我通常会尝试将数组分成每个核心的一个块,然后进行一些边界计算,以得到完整数组的结果。

    我只是不想重新发明轮子。


    附加说明: 我知道有成千上万的例子可以简单地简化。 例如,计算pi。

    const int num_steps = 100000; 
    double x, sum = 0.0; 
    const double step = 1.0/double(num_steps); 
    #pragma omp parallel for reduction(+:sum) private(x) 
    for (int i=1;i<= num_steps; i++){ 
      x = double(i-0.5)*step; 
      sum += 4.0/(1.0+x*x); 
    } 
    const double pi = step * sum;
    

    但是,当这些算法不可用时,几乎没有减少算法的例子了。

    4 回复  |  直到 9 年前
        1
  •  23
  •   baol    9 年前

    OpenMP(至少2.0)支持一些简单操作的缩减,但不支持max和min。

    在下面的示例中, reduction 子句用于生成和 critical 节用于使用线程本地变量更新共享变量,而不发生冲突。

    #include <iostream>
    #include <cmath>
    
    int main()
    {
      double sum = 0;
      uint64_t ii;
      uint64_t maxii = 0;
      uint64_t maxii_shared = 0;
    #pragma omp parallel shared(maxii_shared) private(ii) firstprivate(maxii)
      {
    #pragma omp for reduction(+:sum) nowait
        for(ii=0; ii<10000000000; ++ii)
          {
            sum += std::pow((double)ii, 2.0);
            if(ii > maxii) maxii = ii;
          }
    #pragma omp critical 
        {
          if(maxii > maxii_shared) maxii_shared = maxii;
        }
      }
      std::cerr << "Sum: " << sum << " (" << maxii_shared << ")" << std::endl;
    }
    

    编辑:更清晰的实现:

    #include <cmath>
    #include <limits>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <tr1/random>
    
    // sum the elements of v
    double sum(const std::vector<double>& v)
    {
      double sum = 0.0;
    #pragma omp parallel for reduction(+:sum)
      for(size_t ii=0; ii< v.size(); ++ii)
        {
          sum += v[ii];
        }
      return sum;
    }
    
    // extract the minimum of v
    double min(const std::vector<double>& v)
    {
      double shared_min;
    #pragma omp parallel 
      {
        double min = std::numeric_limits<double>::max();
    #pragma omp for nowait
        for(size_t ii=0; ii<v.size(); ++ii)
          {
            min = std::min(v[ii], min);
          }
    #pragma omp critical 
        {
          shared_min = std::min(shared_min, min);
        }
      }
      return shared_min;
    }
    
    // generate a random vector and use sum and min functions.
    int main()
    {
      using namespace std;
      using namespace std::tr1;
    
      std::tr1::mt19937 engine(time(0));
      std::tr1::uniform_real<> unigen(-1000.0,1000.0);
      std::tr1::variate_generator<std::tr1::mt19937, 
        std::tr1::uniform_real<> >gen(engine, unigen);
    
      std::vector<double> random(1000000);
      std::generate(random.begin(), random.end(), gen);
    
      cout << "Sum: " << sum(random) << " Mean:" << sum(random)/random.size()
           << " Min:" << min(random) << endl;
    }
    
        2
  •  10
  •   Mahesh    11 年前

    在OpenMP3.1以后的版本中,可以实现min max-through-reducation子句,您可以在 this link .

        3
  •  5
  •   Vladimir Obrizan    15 年前

    OpenMP不支持这些缩减操作。考虑英特尔线程构建块的并行减少算法,您可以在其中实现任意算法。

    这里举个例子。它使用部分结果的总和。你可以实现你想要的任何功能。

    #include <stdio.h>
    #include <tbb/blocked_range.h>
    #include <tbb/parallel_reduce.h>
    #include <tbb/task_scheduler_init.h>
    
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
    class PiCalculation
    {
    private:
        long num_steps;
        double step;
    
    public:
    
        // Pi partial value
        double pi;
    
        // Calculate partial value
        void operator () (const tbb::blocked_range<long> &r) 
        {
            double sum = 0.0;
    
            long end = r.end();
    
            for (int i = r.begin(); i != end; i++)
            {
                double x = (i + 0.5) * step;
                sum += 4.0/(1.0 + x * x);
            }
    
            pi += sum * step;
        }
    
        // Combine results. Here you can implement any functions
        void join(PiCalculation &p)
        {
            pi += p.pi;
        }
    
        PiCalculation(PiCalculation &p, tbb::split)
        {
            pi = 0.0;
            num_steps = p.num_steps;
            step = p.step;
        }
    
        PiCalculation(long steps)
        {
            pi = 0.0;
            num_steps = steps;
            step = 1./(double)num_steps;
        }
    };
    
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
    int main()
    {
        tbb::task_scheduler_init init;
    
        const long steps = 100000000;
    
        PiCalculation pi(steps);
    
        tbb::parallel_reduce(tbb::blocked_range<long>(0, steps, 1000000), pi);
    
        printf ("Pi is %3.20f\n", pi.pi);
    }
    

    请检查此链接以了解其他缩减算法。 http://cache-www.intel.com/cd/00/00/30/11/301132_301132.pdf#page=19 请看第3.3.1段。有一个在数组中查找最小值的例子。

        4
  •  3
  •   Stéphane Bonniez    15 年前

    这是典型的还原问题。

    此外 the page pointed by Suvesh ,您可以查看 reduction clause .