[問題] 大整數乘法改寫(C++ to CUDA C)

看板C_and_CPP作者 (雨神妹妹的男朋友)時間7年前 (2017/01/03 17:17), 7年前編輯推噓5(5021)
留言26則, 7人參與, 最新討論串1/1
開發平台(Platform): (Ex: Win10, Linux, ...) Linux上安裝CUDA環境 (CUDA版本為8.0 運算能力為3.7)(Tesla K80) 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出) NVCC 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...) 問題(Question): 研究上要作大整數乘法,我找到一個可以成功執行的程式,只不過這個程式是用C++寫的 ,並且其中的fft是使用複數的方式來做計算。我想把它改成CUDA C版本,並且其中的fft 是用整數來做運算,請問這樣是可行的嗎?程式我自己有先看過了,大概了解每一個func tion的動作,但是其中還有一些小細節看不太懂(不懂的地方我有註解),請各位大大幫 我看看,謝謝。 餵入的資料(Input): 預期的正確結果(Expected Output): 錯誤結果(Wrong Output): 程式碼(Code):(請善用置底文網頁, 記得排版) #include <iostream> #include <cmath> #include <complex> #include <cstring> using namespace std; const double PI = acos(-1.0); typedef complex<double> cp; typedef long long int64; const int N = 1 << 16; int64 a[N], b[N], c[N << 1]; void bit_reverse_copy(cp a[], int n, cp b[]) { int i, j, k, u, m; for (u = 1, m = 0; u < n; u <<= 1, ++m); for (i = 0; i < n; ++i) { j = i; k = 0; for (u = 0; u < m; ++u, j >>= 1) k = (k << 1) | (j & 1); b[k] = a[i]; } } void FFT(cp _x[], int n, bool flag) // bool flag怎麼改成c版本參數? { static cp x[N << 1]; bit_reverse_copy(_x, n, x); int i, j, k, kk, p, m; for (i = 1, m = 0; i < n; i <<= 1, ++m); double alpha = 2 * PI; if (flag) alpha = -alpha; //這行是什麼意思? for (i = 0, k = 2; i < m; ++i, k <<= 1) { cp wn = cp(cos(alpha / k), sin(alpha / k)); for (j = 0; j < n; j += k) { cp w = 1, u, t; kk = k >> 1; for (p = 0; p < kk; ++p) { t = w * x[j + p + kk]; u = x[j + p]; x[j + p] = u + t; x[j + p + kk] = u - t; w *= wn; } } } memcpy(_x, x, sizeof(cp) * n); } void polynomial_multiply(int64 a[], int na, int64 b[], int nb, int64 c[], int &nc) { int i, n; i = max(na, nb) << 1; for (n = 1; n < i; n <<= 1); static cp x[N << 1], y[N << 1]; for (i = 0; i < na; ++i) x[i] = a[i]; for (; i < n; ++i) x[i] = 0; FFT(x, n, 0); for (i = 0; i < nb; ++i) y[i] = b[i]; for (; i < n; ++i) y[i] = 0; FFT(y, n, 0); for (i = 0; i < n; ++i) x[i] *= y[i]; FFT(x, n, 1); for (i = 0; i < n; ++i) { c[i] = (int64)(x[i].real() / n + 0.5); } for (nc = na + nb - 1; nc > 1 && !c[nc - 1]; --nc); } const int LEN = 5, MOD = 100000; void convert(char *s, int64 a[], int &n) { int len = strlen(s), i, j, k; for (n = 0, i = len - LEN; i >= 0; i -= LEN) { for (j = k = 0; j < LEN; ++j) k = k * 10 + (s[i + j] - '0'); a[n++] = k; } i += LEN; if (i) { for (j = k = 0; j < i; ++j) k = k * 10 + (s[j] - '0'); a[n++] = k; } } void print(int64 a[], int n) { printf("%I64d", a[--n]); while (n) printf("%05I64d", a[--n]); puts(""); } char buf[N + 10]; int main() { int na, nb, nc; while (scanf("%s", buf) != EOF) { bool sign = false; //這行是什麼意思? if (buf[0] == '-') { sign = !sign; // 這行是什麼意思? convert(buf + 1, a, na); } else convert(buf, a, na); scanf("%s", buf); if (buf[0] == '-') { sign = !sign; convert(buf + 1, b, nb); } else convert(buf, b, nb); polynomial_multiply(a, na, b, nb, c, nc); int64 t1, t2; t1 = 0; for (int i = 0; i < nc; ++i) { t2 = t1 + c[i]; c[i] = t2 % MOD; t1 = t2 / MOD; } for (; t1; t1 /= MOD) c[nc++] = t1 % MOD; if (sign) putchar('-'); print(c, nc); } return 0; } 補充說明(Supplement): 大整數乘法中有一個mod p(質數)的運算,論文上選擇的p=0xFFFFFFFF00000001,我該 怎麼在程式中定義一個這麼大的變數呢?如果我只要讓GPU作fft運算,是否只要將fft那 個function改寫成cuda函式就可以了呢? -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.136.45.205 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1483435022.A.D71.html

01/03 18:3, , 1F
sign是為了處理負數
01/03 18:3, 1F

01/03 18:45, , 2F
flag也是為了處理負數
01/03 18:45, 2F

01/03 18:45, , 3F
c沒有bool你用int 0跟1就可以處理了
01/03 18:45, 3F

01/03 18:46, , 4F
然後我不懂你是為了什麼要用CUDA
01/03 18:46, 4F

01/03 18:47, , 5F
如果你是為了加速運算,這種程度的運算改成CUDA只會變慢
01/03 18:47, 5F

01/03 18:47, , 6F
如果你是為了交差就當我沒說就好
01/03 18:47, 6F
謝謝nick大,會使用CUDA是為了實現論文上的大整數數乘法(65536點的FFT,大整數可達2 的786432次方),是為了加速運算沒錯。想用這個程式去改的原因是,作者有註明可以支 援到30萬位元整數乘法,這個運算量對GPU來說,應該也不算小才是阿,為什麼會變慢呢 ?
謝謝p大,不過這個fft程式似乎也是使用複數的方式做運算,不是用整數的方式。

01/03 19:51, , 8F
不想小數運算可以用數論變換ntt來做,可是大量的取模以
01/03 19:51, 8F

01/03 19:51, , 9F
防及溢位的細結放一起後,實測上沒fft快
01/03 19:51, 9F

01/04 11:38, , 10F
我記得沒錯的話fft 要到1000 bit 以上才有競爭力
01/04 11:38, 10F
※ 編輯: tmbyksdG (59.115.156.82), 01/05/2017 00:55:46 ※ 編輯: tmbyksdG (59.115.156.82), 01/05/2017 01:01:23

01/05 09:21, , 11F
CUDA可能比較慢的原因是在PCIE的頻寬
01/05 09:21, 11F

01/05 09:23, , 12F
加上個人認為你對C不太熟
01/05 09:23, 12F

01/05 09:23, , 13F
如果這只是你其中一部分研究 可以考慮改multi thread就
01/05 09:23, 13F

01/05 09:23, , 14F
01/05 09:23, 14F

01/05 09:24, , 15F
如果真的還是覺得慢再評估要不要改成CUDA
01/05 09:24, 15F

01/05 09:25, , 16F
一樣project改成multi thread跟cuda所需時間絕對不同
01/05 09:25, 16F

01/05 09:25, , 17F
也不是說改成CUDA就一定會比multi thread快的
01/05 09:25, 17F

01/05 09:31, , 18F
其他比較慢的原因就是演算法的問題了 這邊你可以翻看看
01/05 09:31, 18F

01/05 09:31, , 19F
一般cuda的tutorial看看再和你這個比比看
01/05 09:31, 19F

01/05 09:32, , 20F
簡單說就是平行化的問題 大概就這樣
01/05 09:32, 20F
之前學完C之後,的確有一段時間沒有繼續碰它,這學期修資料結構,才又開始惡補這樣 。我想請教nick大,如何在具有C的基本知識條件下,進一步去加強寫C的能力。平行化相 關的知識有沒有推薦的書籍?我的研究必須用CUDA來實現來實現,利用其他途徑目前是不 考慮的。

01/05 10:50, , 21F
實數、虛數計算和整數定義不一樣,感覺難以達成。
01/05 10:50, 21F

01/05 12:37, , 22F
樓主好像對C/CPP也不熟,對平行化也不熟
01/05 12:37, 22F
是的,我的確沒學過CPP。我想請教a大,如何在具有C的基本知識條件下,進一步去加強 寫C的能力。平行化相關的知識有沒有推薦的書籍?

01/05 12:38, , 23F
先用openmp加速,熟悉這個程式,想好相依性和可平行化
01/05 12:38, 23F

01/05 12:38, , 24F
的部分,再改cuda吧。
01/05 12:38, 24F

01/06 20:57, , 25F
是可以用cuda啦 只是你的寫法不好的話 效率不會比較好
01/06 20:57, 25F
※ 編輯: tmbyksdG (114.136.66.135), 01/09/2017 12:55:00

02/02 21:30, , 26F
你乾脆用cufft ...
02/02 21:30, 26F
文章代碼(AID): #1OQsmErn (C_and_CPP)