You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenMP并行实现埃拉托斯特尼筛法出现invalid controlling predicate错误

错误成因
  1. 编译错误直接原因:OpenMP 规范要求 #pragma omp for 修饰的 for 循环,终止判断必须是循环变量与循环外不变量直接进行大小比较,不支持循环变量参与运算的表达式作为判断主体。你的代码中外层循环终止条件为 p * p <= n,判断主体是 p*p 而非循环变量 p 本身,编译器无法识别为合法的并行循环,因此抛出 invalid controlling predicate 错误。
  2. 额外逻辑错误:即使解决编译问题,代码也无法得到正确结果:
    • prime 数组定义在并行块内部,属于线程私有变量,每个线程持有独立副本,不同线程的修改无法同步,结果会完全混乱。
    • 埃氏筛外层循环天然存在数据依赖:小素数的标记操作必须先完成,更大的 p 才能正确判断 prime[p] 是否为真素数,直接并行外层循环会出现读取 prime[p] 时前置标记未完成的问题,导致判断错误。
修复方案

按如下步骤修改即可正常运行:

  • 提前计算外层循环上限 int sqrt_n = sqrt(n);,将循环条件改为 p <= sqrt_n,满足 OpenMP 并行循环的格式要求,解决编译报错。
  • 将 prime 数组移到并行块外部,声明为共享变量,初始化操作放在并行块前执行,避免多线程私有副本问题。
  • 调整并行策略,选择并行内层无数据依赖的标记循环(不同位置的写入操作互不干扰),避免外层循环的依赖问题。
  • 修复 main 函数中的参数类型错误、笔误。

修复后完整代码

#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
using namespace std;
 
void SieveOfEratosthenes(int n)
{
    bool *prime = new bool[n + 1];
    memset(prime, true, sizeof(bool) * (n + 1));
    int sqrt_n = sqrt(n);

    #pragma omp parallel for schedule(dynamic)
    for (int p = 2; p <= sqrt_n; p++)
    {
        if (prime[p] == true)
        {
            #pragma omp simd
            for (int i = p * p; i <= n; i += p)
                prime[i] = false;
        }
    }
    
    for (int p = 2; p <= n; p++)
        if (prime[p])
            printf("%d  ", p);
    delete[] prime;
}
 
int main()
{
    printf("Enter the size: ");
    int n ;
    scanf("%d", &n);
    int limit = sqrt(n);
    printf("Following are the prime numbers from 2 to %d \n", limit);
    SieveOfEratosthenes(limit);
    printf("\n");
    return 0;
}

内容的提问来源于stack exchange,提问作者user17079709

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 03:57:02