所以我尝试解决以下任务:
开发一个CREW PRAM算法,用于计算整数序列x_1,x_2,... x_n的奇数。
n是处理器的数量 - 复杂度应为O(log n),log_2 n为自然数
到目前为止我的解决方案:
Input: A:={x_1,x_2,...,x_n} Output:=oddCount
begin
1. global_read(A(n),a)
2. if(a mod 2 != 0) then
oddCount += 1
问题是,由于CREW,我不允许同时使用多个写入指令oddCount += 1
正在读取oddCount然后写入oddCount + 1
,因此会有多次写入。
我必须做这样的事吗
Input: A:={x_1,x_2,...,x_n} Output:=oddCount
begin
1. global_read(A(n),a)
2. if(a mod 2 != 0) then
global_write(1, B(n))
3. if(n = A.length - 1) then
for i = 0 to B.length do
oddCount += B(i)
首先,每个过程确定它是奇数还是偶数,最后一个过程计算总和?但是这会如何影响复杂性并且有更好的解决方案吗?
感谢libik,我来到了这个解决方案:(n从0开始)
Input: A:={x_1,x_2,...,x_n} Output:=A(0):=number off odd numbers
begin
1. if(A(n) mod 2 != 0) then
A(n) = 1
else
A(n) = 0
2. for i = 1 to log_2(n) do
if (n*(2^i)+2^(i-1) < A.length)
A(n*(2^i)) += A(n*(2^i) + (2^(i-1)))
end
i = 1 - &gt; A(n * 2):0 2 4 6 8 10 ... A(n * 2 + 2 ^ 0):1 3 5 7 ...
i = 2 - &gt; A(n * 4):0 4 8 12 16 ... A(n * 4 + 2 ^ 1):2 6 10 14 18 ...
i = 3 - &gt; A(n * 8):0 8 16 24 32 ... A(n * 8 + 2 ^ 2):4 12 20 28 36 ......
所以第一个if是第1步,而for表示log_2(n)-1步,所以总共有log_2(n)步。解决方案应该在A(0)。
答案 0 :(得分:1)
你的解决方案是O(n)因为循环必须经过所有数字(这意味着你根本不使用多个处理器)
CREW意味着您无法写入同一个单元格(在您的示例单元格=处理器内存中),但您可以一次写入多个单元格。
那么如何尽可能快地完成?
在初始化时,所有处理器都以1或0(具有奇数或非奇数)开始
在第一轮中,将邻居x_2与x_1相加,然后将x_4与x_3等相加。 它将在O(1)中作为每个第二个处理器&#34; p_x&#34;期待&#34; p_x + 1&#34;处理器并行并添加0或1(是否有奇数)
然后在处理器p1,p3,p5,p7 ....你有一部分解决方案。让我们再次这样做,但现在p1看起来是p3,p5看起来是p7而p_x看起来是o_x + 2
然后,您只能在处理器p1,p5,p9等中获得部分解决方案。
重复此过程。每一步处理器的数量减半,因此需要log_2(n)步。
如果这是现实生活中的例子,通常会计算同步成本。基本上在每一步之后,所有处理器都必须自己同步,所以现在,他们可以做第二步(当你在每个处理器中运行所描述的代码时,但是你怎么知道你是否已经可以从处理器p_x中添加数字,因为你可以在p_x完成工作后执行此操作)。
你需要某种&#34;时钟&#34;或同步。
在此示例中,最终的复杂性为log(n)*k
,其中k
是同步的复杂性。
费用取决于机器或定义。通知处理器已完成的一种方法基本上与此处描述的用于计算奇数的方法相同。然后它也会花费k=log(n)
,这将导致log^2(n)