|
> No.3985[元記事へ]
旧版 eratos.dllをOPEN MP(マルチスレッド化)にとりあえず成功しました。
#3986
VC++2015(x86)にて、ビルド(コンパイル)しています。
こちらの環境では、およそ1.4倍高速化しました。(8スレッドで実行)
但し、OPEN MP上の制約により、unsignedが使えず、2^63-1までになります。
実行にはOPEN MPランタイム(vcomp140.dll)が必要です。(basic.exeと同じフォルダに入れてください)
なお、vcomp140.dllはライセンス上再配布可能らしいので、ビルドしたdllファイルと同梱し
アップローダーにupしておきました。(eratos.zip) 下記 URLの有効期限は現時点より1ヶ月間となります。
ダウンロードパス:shibacchi
OPTION ARITHMETIC NATIVE
LET S=1E+13+1
LET E=S+1E+8
LET S$=STR$(S)
LET E$=STR$(E)
LET T=TIME
PRINT "シングルスレッド"
PRINT ERATOS(S$,E$);"個"
LET T1=TIME-T
PRINT T1;"秒"
LET T=TIME
PRINT "マルチスレッド"
PRINT ERATOS2(S$,E$,0);"個"
LET T2=TIME-T
PRINT T2;"秒"
PRINT T1/T2;"倍"
END
EXTERNAL FUNCTION ERATOS(S$,E$)
OPTION ARITHMETIC NATIVE
ASSIGN "eratos.dll","eratos",FPU
END FUNCTION
EXTERNAL FUNCTION ERATOS2(S$,E$,THREADS) !'THREADS=実行スレッド数(0の時 自動設定)
OPTION ARITHMETIC NATIVE
ASSIGN "eratos_parallel.dll","eratos",FPU
END FUNCTION
-------------------------------------------------------------------------------------------
eratos_parallel.cpp
#include <cstdlib>
#include <omp.h>
using namespace std;
long long isqrt(long long num)
{
long long n,n1;
if(num==0) return 0;
n=num/2+1;
n1=(n+(num/n))/2;
while (n1<n) {
n=n1;
n1=(n+(num/n))/2;
}
return n;
}
extern "C" __declspec(dllexport) double eratos(char *s,char *e,int threads)
{
long long n,nn,m,i,j,count=0;
bool *x;
n=atoll(s);
m=atoll(e);
if (n>=m || n<1) return -1.0;
if (n==1 || n==2) count++;
if (n==1) n+=2;
if (n % 2==0) n++;
x=new bool [m-n+2];
if (x==NULL) return -999.0;
if (threads>0) omp_set_num_threads(threads);
#pragma omp parallel for
for(i=0;i<=m-n+1;i++) x[i]=true;
#pragma omp parallel for private(j,i,nn) schedule(dynamic)
for(i=3;i<=isqrt(m);i+=2){
if (n % i==0) nn=n;
else
nn=((n/i)+1)*i;
if (n<=i && x[nn-n]==true) nn+=i;
for(j=nn;j<=m;j+=i) x[j-n]=false;
}
#pragma omp parallel for
for(j=n;j<=m;j+=2)
if (x[j-n]==true) {
#pragma omp atomic
count++;
}
delete [] x;
return (double)count;
}
|
|