多线程程序,用于计算素数的频率,从而得出不准确的结果。

时间:2016-02-15 23:09:08

标签: c++ multithreading

我正在进行一项任务,我需要计算1到1千万的素数频率。我们要通过获取变量U(1000万)并将其划分为N个部分并使多个线程计算素数的频率来实现这一点,我们必须尝试使用​​不同的N值并观察我们的处理器滴答和时间。计算。程序的工作方式是1000万分为N个部分,上下界被放入一个线程向量中,每个线程调用一个计算素数的函数。 现在,来自100万的素数的频率应该是664579.当进行多线程时,我的结果会略微不准确。例如,如果我运行N = 1的程序,意味着只有一个线程将解决我获得6645780的频率,其关闭1. N = 2我得到664579的正确结果,N = 3 freq = 664578,并且等等。以下是代码,非常感谢任何帮助。

#include <iostream>
#include <thread>
#include <vector>
#include<algorithm>
#define MILLION 1000000
using namespace std;
using std::for_each;
void frequencyOfPrimes(long long upper, long long lower, long long* freq)
{
    long long i, j;
    if (lower == 2) { *freq = upper; }
    else { *freq = upper - lower; }
    for (i = lower; i <= upper; ++i)
        for (j = (long long)sqrt(i); j>1; --j)
            if (i%j == 0) { --(*freq); break; }
    return;
}

int main(int argc, char* argv[])
{

    clock_t ticks = clock();
    long long N = 10; //declare and initialize number of threads to calculate primes
    long long U = 10*MILLION;
    long long F=0; //total frequency
    long long d = U / N; // the quotient of 10mil/number of threads
    vector<thread> tV; //declare thread vector
    vector<long long> f, u, l; //vector for freq, upper and lower bounds
    f.resize(N);//initialize f
    for (long long i = 0; i<N; i++) { //initialize and populate vectors for upper and lower bounds
        if (i == 0) {
            l.push_back(2);
            u.push_back(d);
        }
        else {
            l.push_back(u.at(i-1)+ 1);
            u.push_back(u.at(i-1) + d);
        }
    }
    u.at(N-1) = U;  //make sure last thread has value of U for upper bound
    for (long long i = 0; i < N; i++) { //initialize thread vectors
        tV.push_back(thread(frequencyOfPrimes, u.at(i), l.at(i), &f.at(i)));
    }

    for_each(tV.begin(), tV.end(), mem_fn(&thread::join));

    ticks = clock() - ticks;

    for (long long i = 0; i < N; i++)
        F = f.at(i) + F;
    cout << "Frequency is " << F << endl;
    cout << "It took " << ticks << " ticks (";
    cout << ((float)ticks) / CLOCKS_PER_SEC << " seconds)" << endl;
    this_thread::sleep_for(chrono::seconds(5));
    return 0;
}

1 个答案:

答案 0 :(得分:2)

这与多线程无关。 始终测试您的功能:

#include <iostream>
#include <cmath>
using namespace std;

// this is your function with a shorter name
void fop_strange(long long upper, long long lower, long long* freq)
{
    long long i, j;
    if (lower == 2) { *freq = upper; }
    else { *freq = upper - lower; }
    for (i = lower; i <= upper; ++i)
        for (j = (long long)sqrt(i); j>1; --j)
            if (i%j == 0) { --(*freq); break; }
    return;
}

// attention, I switched order of upper and lower
long long fop(long long a, long long b) {
  long long f = 0;
  fop_strange (b, a, &f);
  return f;
}

int main() {
  cout << fop(2, 4) << endl;
  cout << fop(10, 14) << endl;
  return 0;
}

让我们先手动计算素数:

2 to 4 (inclusive) => 2 (2, 3)
10 to 14 (inclusive) => 2 (11, 13)

现在你的功能(live on ideone)

3
1

为什么呢?好吧,当你遇到非素数时,你正确地减少了计数,但你没有正确地初始化它。 2到4的范围包含3个数字,而不是4个.2到100万的范围有1 million - 2 + 1,而不是100万个数字。 10到14的范围包括5个数字,而不仅仅是4.等等。

这解释了您获得的结果:对于从2开始的范围,您的函数返回1个数字,每隔一个范围适合1个数字。因此,当仅使用一个线程并且因此只有一个以2开头的范围时,您的结果就是一个,并且您添加的每个线程都会添加一个减少一个的范围,从而将整体结果减少一个。