我担心这是一个很长的代码。我正在使用英特尔TBB和C ++编写一个基于任务的并行,递归,基于任务的Euler分区公式版本,我不会认为这个程序的逻辑存在很多问题,但我有一种感觉变量被错误地访问,我可能已经在错误的地方或其他地方声明了它们。我这样说是因为输入数字n应该总是给出相同的结果,并且它在n = 11以下,但是在它之上它给出了不同的答案。更奇怪的是,添加输出行来尝试对程序进行故障排除会导致稍微更准确的答案(好像以某种方式填充计算的每个部分所花费的时间有助于它)。我不知道如何避免这个问题或者哪个变量确切地导致它,因为答案通常相当接近,它不仅仅是一个随机数。所以这有点棘手,我道歉,但如果有人能帮助我,我会非常感激,我已经花了好几个小时来解决这个问题。
这是并行任务:
class ParallelFormula : public task {
public:
int n;
int* pTot;
//Task constructor
ParallelFormula(int n_, int* pTot_) : n(n_), pTot(pTot_) {}
//Task definition
task* execute() {
//Iterating for formula to work
for (int k = 1; k > 0; k++) {
//Add fixed values to pTot for any case where 2 >= n >= 0
switch (n) {
case 0:
if (k % 2 != 0)
*pTot += 1;
else
*pTot -= 1;
return NULL;
case 1:
if (k % 2 != 0)
*pTot += 1;
else
*pTot -= 1;
return NULL;
case 2:
if (k % 2 != 0)
*pTot += 2;
else
*pTot -= 2;
return NULL;
}
//Calculate p numbers using section of Euler's formula (relies on iteration number)
p1 = (k*((3 * k) - 1)) / 2;
p2 = (k*((3 * k) + 1)) / 2;
if (n >= p2) {
//If n is more than p2, must call recursive tasks to break down problem to smaller n's, and adds result to total result pTot (i.e. p(n))
int x = 0;
int y = 0;
ParallelFormula& a = *new(allocate_child()) ParallelFormula(n - p1, &x);
ParallelFormula& b = *new(allocate_child()) ParallelFormula(n - p2, &y);
//Set ref_count to two children plus one for the wait
set_ref_count(3);
//Start b running
spawn(b);
//Start a running and wait for all children (a and b)
spawn_and_wait_for_all(a);
//Sum the total
if (k % 2 != 0)
*pTot += (x + y);
else
*pTot -= (x + y);
}
else if (n >= p1) {
//If n is more than p1, problem is small and therefore need not be parallelised, result added to pTot
if (k % 2 != 0)
*pTot += serialLoop(n - p1);
else
*pTot -= serialLoop(n - p1);
return NULL;
}
else
return NULL;
}
}
};
调用并行任务的方法:
int parallelLoop(int n) {
int pTot = 0;
ParallelFormula& a = *new(task::allocate_root()) ParallelFormula(n, &pTot);
task::spawn_root_and_wait(a);
return pTot;
}
如果您想查看所有上下文的完整代码:
// Assignment2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "iostream"
#include "tbb/task_scheduler_init.h"
#include "tbb/parallel_reduce.h"
#include "tbb/partitioner.h"
#include "tbb/blocked_range.h"
#include "tbb/tick_count.h"
#include "math.h"
using namespace tbb;
using namespace std;
int p, p1, p2;
int serialLoop(int n);
int n;
int m;
int serialFormula(int pTemp) {
switch (pTemp) {
case 0:
return 1;
case 1:
return 1;
case 2:
return 2;
}
//If p is any other value it is less than 0 and therefore has nothing to calculate - the current calculation is complete
return 0;
}
int serialLoop(int n) {
int pTot = 0;
for (int k = 1; k > 0; k++) {
//Checking whether k is even or odd to determine if adding or substracting value of p(x) to make p(n)
if (n == 0)
return pTot += 1;
else if (k % 2 != 0) {
//Calculate p number using section of Euler's formula
p = n - ((k*((3 * k) - 1)) / 2);
//If p is more than 2, must call recursive function to break down problem to smaller n's, and adds result to total result P (i.e. p(n))
if (p > 2) {
pTot += serialLoop(p);
}
else if (p >= 0) {
pTot += serialFormula(p);
}
else return pTot;
p = n - ((k*((3 * k) + 1)) / 2);
if (p > 2) {
pTot += serialLoop(p);
}
else if (p >= 0) {
pTot += serialFormula(p);
}
else return pTot;
}
else {
p = n - ((k*((3 * k) - 1)) / 2);
if (p > 2) {
pTot -= serialLoop(p);
}
else if (p >= 0) {
pTot -= serialFormula(p);
}
else return pTot;
p = n - ((k*((3 * k) + 1)) / 2);
if (p > 2) {
pTot -= serialLoop(p);
}
else if (p >= 0) {
pTot -= serialFormula(p);
}
else return pTot;
}
}
}
class ParallelFormula : public task {
public:
int n;
int* pTot;
//Task constructor
ParallelFormula(int n_, int* pTot_) : n(n_), pTot(pTot_) {}
//Task definition
task* execute() {
//Checking task is called
for (int k = 1; k > 0; k++) {
//Calculate p number using section of Euler's formula
switch (n) {
case 0:
if (k % 2 != 0)
*pTot += 1;
else
*pTot -= 1;
cout << "Case 0" << endl;
cout << *pTot << endl;
return NULL;
case 1:
if (k % 2 != 0)
*pTot += 1;
else
*pTot -= 1;
cout << "Case 1" << endl;
cout << *pTot << endl;
return NULL;
case 2:
if (k % 2 != 0)
*pTot += 2;
else
*pTot -= 2;
cout << "Case 2" << endl;
cout << *pTot << endl;
return NULL;
}
p1 = (k*((3 * k) - 1)) / 2;
p2 = (k*((3 * k) + 1)) / 2;
if (n >= p2) {
//If p is more than 2, must call recursive function to break down problem to smaller n's, and adds result to total result P (i.e. p(n))
int x = 0;
int y = 0;
ParallelFormula& a = *new(allocate_child()) ParallelFormula(n - p1, &x);
ParallelFormula& b = *new(allocate_child()) ParallelFormula(n - p2, &y);
//Set ref_count to two children plus one for the wait
set_ref_count(3);
//Start b running
spawn(b);
//Start a running and wait for all children (a and b)
spawn_and_wait_for_all(a);
//Sum the total
if (k % 2 != 0)
*pTot += (x + y);
else
*pTot -= (x + y);
cout << "Double p" << endl;
cout << *pTot << endl;
}
else if (n >= p1) {
if (k % 2 != 0)
*pTot += serialLoop(n - p1);
else
*pTot -= serialLoop(n - p1);
cout << "Single p" << endl;
cout << *pTot << endl;
return NULL;
}
else
return NULL;
}
}
};
int parallelLoop(int n) {
int pTot = 0;
ParallelFormula& a = *new(task::allocate_root()) ParallelFormula(n, &pTot);
task::spawn_root_and_wait(a);
return pTot;
}
int main()
{
//Take inputs n and m.
cout << "Enter partition number n:" << endl;
cin >> n;
cout << "Enter modulo m:" << endl;
cin >> m;
//Start timer for serial method
tick_count serial_start = tick_count::now();
//Serial method for computing partition function modulo m.
int sP = serialLoop(n);
int serialMod = sP % m;
//Finish timer for serial method
tick_count serial_end = tick_count::now();
//Output serial results
cout << "Serial result for p(n) is: " << sP << endl;
cout << "Serial result for p(n) mod m is: " << serialMod << endl;
cout << "Serial time (s): " << (serial_end - serial_start).seconds() << endl;
//Start timer for parallel method
tick_count parallel_start = tick_count::now();
//Parallel method for computing partition function
int pP = parallelLoop(n);
int parallelMod = pP % m;
//Finish timer for parallel method
tick_count parallel_end = tick_count::now();
//Output parallel results
cout << "Parallel result for p(n) is: " << pP << endl;
cout << "Parallel result for p(n) mod m is: " << parallelMod << endl;
cout << "Parallel time (s): " << (parallel_end - parallel_start).seconds() << endl;
//Acceleration achieved
cout << "Acceleration achieved was: " << (serial_end - serial_start).seconds() / (parallel_end - parallel_start).seconds() << endl;
return 0;
};
P.S。这部分是基于英特尔TBB文档中的Fibonacci序列示例,所以如果我通过遵循该示例做了一些非常愚蠢的事情,那么我也为此道歉。
答案 0 :(得分:1)
变量p1
和p2
是全局变量,但您同时在ParallelFormula::execute
中写入变量。尝试在ParallelFormula::execute
方法中声明它们,例如
int p1 = (k*((3 * k) - 1)) / 2;
int p2 = (k*((3 * k) + 1)) / 2;
同样不要忘记p
中的int serialLoop(int n)
变量,因为您从ParallelFormula::execute
调用此函数。