κ²°μ μ (deterministic) λ°λ¬λΌλΉ(Miller-Rabin) μκ³ λ¦¬μ¦μ μ¬μ©νμ¬ κΈΈμ΄κ° μ΅λ 64 λΉνΈμΈ μμλ₯Ό μ°Ύλ
νλ‘κ·Έλ¨μ ꡬννλ€. λ² μ΄μ€(base) κ° πλ₯Ό 무μμλ‘ μ ννλ νλ₯ μ λ°λ¬λΌλΉ μκ³ λ¦¬μ¦κ³Όλ λ¬λ¦¬ κ²°μ
μ λ°λ¬λΌλΉ μκ³ λ¦¬μ¦μ λ§€μ° μμ μ§ν©μ μ ν΄μ§ λ² μ΄μ€ κ°λ§ κ²μ¦νλ€. κ·Έ μ΄μ λ π < 2^64μ΄λ©΄ λ² μ΄μ€
κ° πλ₯Ό μ§ν© {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}μμλ§ κ²μ¦νλ©΄ μΆ©λΆνλ€λ κ²μ΄ λ°νμ‘κΈ° λλ¬Έμ΄λ€.
νμλ€μ΄ ꡬνν ν¨μμ νλ‘ν νμ μ μλμ μ΄κ±°λμ΄ μλ€. κ° ν¨μμ λν μꡬμ¬νμ λ€μκ³Ό κ°λ€.
β’ int miller_rabin(uint64_t n) β 64λΉνΈ μμ΄ μλ μ μ nμ΄ μμμ΄λ©΄ PRIMEμ, κ·Έλ μ§ μμΌ
λ©΄ COMPOSITEμ λ겨μ€λ€. nμ΄ 2^64 λ³΄λ€ μμΌλ―λ‘ κ²°μ μ λ°λ¬λΌλΉ μκ³ λ¦¬μ¦μ μ¬μ©νλ€.
β’ uint64_t mod_add(uint64_t a, uint64_t b, uint64_t m) β π + π mod πμ κ³μ°νμ¬ λ
겨μ€λ€. πμ πκ° κ°κ° πλ³΄λ€ μλ€λ κ°μ νμμ πμ πμ ν©μ΄ πλ³΄λ€ ν¬κ±°λ κ°μΌλ©΄ κ²°κ³Όμμ
πμ λΉΌμ€μΌ νλ€. μ΄ κ²½μ° μ€μ κ³μ°μ π β (π β π)λ‘ νλ κ²μ΄ μ€λ²νλ‘λ₯Ό νΌν μ μλ μ’μ
λ°©λ²μ΄λ€. λν π + π >= πμ κ²μ¬νλ κ³Όμ μμ μ€λ²νλ‘κ° λ°μν μ μμΌλ―λ‘ πλ₯Ό μ€λ₯Έμͺ½μΌλ‘
λ겨 π >= π β πλ₯Ό κ²μ¬νλ κ²μ΄ μ€λ²νλ‘λ₯Ό νΌν μ μλ νλͺ
ν λ°©λ²μ΄λ€.
β’ uint64_t mod_sub(uint64_t a, uint64_t b, uint64_t m) β πβπ mod πμ κ³μ°νμ¬ λ겨
μ€λ€. πμ πκ° κ°κ° πλ³΄λ€ μλ€λ κ°μ νμμ πκ° πλ³΄λ€ μμΌλ©΄ κ²°κ³Όκ° μμ΄ λλ―λ‘ πμ λν΄μ€λ€.
μ¦, π + (π β π)μΌλ‘ κ³μ°νλ€. κ·Έλ μ§ μμΌλ©΄ μλλλ‘ π β πλ‘ κ³μ°νλ€.
β’ uint64_t mod_mul(uint64_t a, uint64_t b, uint64_t m) β ππ mod πμ κ³μ°νμ¬ λ겨
μ€λ€. μ€λ²νλ‘κ° λ°μν μ μκΈ° λλ¬Έμ νλ‘κ·Έλλ° μΈμ΄κ° μ 곡νλ κ³±μ
μΌλ‘λ κ³μ°μ΄ μ¬λ°λ₯΄μ§
μμ μ μλ€. μμμ μ μν mod_add()κ° μ€λ²νλ‘λ₯Ό κ³ λ €νλ€λ μ κ³Ό κ³±μ
μ λ§μ
μ μ¬μ©νμ¬
λΉ λ₯΄κ² κ³μ°ν μ μλ βdouble additionβ μκ³ λ¦¬μ¦μ μ¬μ©νλ©΄ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€. κ·Έ μκ³ λ¦¬
μ¦μ λ€μκ³Ό κ°λ€.
r = 0;
while (b > 0) {
ββif (b & 1)
ββββr = mod_add(r, a, m);
ββb = b >> 1;
ββa = mod_add(a, a, m);
}
return r;
β’ uint64_t mod_pow(uint64_t a, uint64_t b, uint64_t m) β π^π mod πμκ³μ°νμ¬λ겨μ€
λ€. μ€λ²νλ‘κ° λ°μν μ μκΈ° λλ¬Έμ μ΄ μμ νλ‘κ·Έλλ° μΈμ΄κ° μ 곡νλ μ§μν¨μλ‘λ κ³μ°μ΄
μ¬λ°λ₯΄μ§ μμ μ μλ€. μμμ μ μν mod_mul()μ΄ μ€λ²νλ‘λ₯Ό κ³ λ €νλ€λ μ κ³Ό μ§μμ°μ°μ κ³±
μ
μ μ¬μ©νμ¬ λΉ λ₯΄κ² κ³μ°ν μ μλ βsquare multiplicationβ μκ³ λ¦¬μ¦μ μ¬μ©νλ©΄ λ¬Έμ λ₯Ό ν΄κ²°ν
μ μλ€. κ·Έ μκ³ λ¦¬μ¦μ λ€μκ³Ό κ°λ€.
r = 1;
while (b > 0) {
ββif (b & 1)
ββββr = mod_mul(r, a, m);
ββb = b >> 1;
ββa = mod_mul(a, a, m);
}
return r;
OpenMP (Open Multi-Processing)λ λ€μ€μ½μ΄ νκ²½μμ λ³λ ¬νλ‘κ·Έλλ°μ μ§μνλ APIμ΄λ€. μ΄ κ³Όμ
μμλ μμλ₯Ό 빨리 μ°ΎκΈ° μν΄ OpenMP λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ€. νμλ€μ΄ κ³Όμ λ₯Ό μννλλ° OpenMP
μ λν μ§μμ΄ κΌ νμν κ²μ μλμ§λ§ κ²μ¦ νλ‘κ·Έλ¨μ λ리기 μν΄μλ OpenMPλ₯Ό μ€μΉν΄μΌ νλ€.
β’ Linux νκ²½μμλ μ€μΉνμ§ μλλ€. μ»΄νμΌλ¬μ λ΄μ₯λμ΄ μλ€.
β’ macOS νκ²½μμλ λ¨Όμ Homebrewλ₯Ό μ€μΉν΄μΌ νλ€. μ΄λ―Έ Homebrewκ° μ€μΉλμ΄ μλ€λ©΄ μ΄
λΆλΆμ 건λλ΄λ€. Homebrewλ₯Ό μ€μΉνλ €λ©΄ ν°λ―Έλμ μ΄κ³ λ€μ λͺ
λ Ήμ΄λ₯Ό μ€ννλ€.
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
Homebrew μ€μΉκ° μλ£λλ©΄ λ€μ λͺ λ Ήμ΄λ₯Ό μ€ννμ¬ OpenMP λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μΉνλ€.
% brew install libomp
μ ν μ€λ¦¬μ½μ΄ νμ¬λ λ§₯μμλ brew λͺ
λ Ήμ΄λ₯Ό μ°Ύμ§ λͺ»νλ μ€λ₯κ° λ°μν μ μλ€. brew λͺ
λ Ήμ΄κ°
/usr/local/bin λ°μ μμ§ μκ³ /opt/homebrew/bin λ°μ μκΈ° λλ¬Έμ΄λ€. /opt/homebrew/bin
μ μμ€ν
κΈ°λ³Έ μ€ν κ²½λ‘μ ν¬ν¨μμΌμΌ νλ€. ν€λ νμΌκ³Ό λΌμ΄λΈλ¬λ¦¬ νμΌ κ²½λ‘λ gcc μ»΄νμΌλ¬
νκ²½λ³μμ μΆκ°ν΄μΌ νλ€. μ¬μ©μ νλλ ν λ¦¬λ‘ μ΄λνμ¬ λ¬ΈμνΈμ§κΈ°λ‘ .zshrc νμΌμ μ΄κ±°λ
μλ‘ μμ±νλ€. μλ μΈ μ€μ μΆκ°νκ³ μ μ₯ν ν ν°λ―Έλμ λ€μ μμνλ€.
export PATH=/opt/homebrew/bin:/opt/homebrew/sbin:$PATH
export LIBRARY_PATH=/opt/homebrew/lib:$LIBRARY_PATH
export C_INCLUDE_PATH=/opt/homebrew/include:$C_INCLUDE_PATH
ꡬνμ΄ νμν 골격νμΌ miller_rabin.skeleton.cμ ν¨κ» νλ‘κ·Έλ¨μ κ²μ¦ν μ μλ test.c, ν€
λνμΌ miller_rabin.h, κ·Έλ¦¬κ³ Makefileμ μ 곡νλ€. μ΄ κ°μ΄λ° test.cλ₯Ό μ μΈν λλ¨Έμ§ νμΌμ
μ©λμ λ§κ² μμ λ‘κ² μμ ν μ μλ€.