[펌] 10000000까지의 소수 표와, 구하는 프로그램의 속도를 높여보자.

10000000까지의 소수는 직접 적어드릴수는 없습니다.

10000000까지의 소수의 개수는 정확하게  664579개입니다.

이 글에서는, 소수 구하는 프로그램 소스는 가르쳐 드리지 않습니다.

중간중간에 써드리는 소스 만으로도 충분히 짜맞추실수 있기 때문이죠.

소수 구하는 법을 아시는 분만 보시기 바랍니다.

C++ 배우시는 분들이라면 소수 구하기는 80% 이상 해보셨을 겁니다.

일반적으로, 100 정도밖에 안 구해 보셨을텐데요..

그렇기 때문에 속도 차가 별로 나지가 않죠.

하지만, 구하는 범위가 아주 넓어진다면 어떨까요??(이런.. 드라군 놀이가 생각나는걸..)

시간차가 많이 날겁니다.

죄송한 말씀이지만, C++를 처음 다루시는 분들이라면 정중히 뒤로 버튼을 누르라고 할께요.

소수 구하는 프로그램을 짤때의 실수 유형을 봅시다!

[1차원 배열을 사용해서 푸는 분들..]

배열을 사용하는 방법은 작은 수에서는 상관이 없지만,

10만이 넘어가는 경우에는 오류가 납니다.

배열을 쓰시면 안되고, Check라는 변수를 만드세요!

Check=0;

if(i%j==0) Check=1;

Check방을 0으로 초기화합니다. 그리고, i를 j로 나눕니다(꼭 i, j가 아니여도 됩니다.)

그리고, i를 j로 나눴을대 나머지가 0이라면 결국 나누어 떨어진다는 말이므로,

Check방을 1로 만듭니다. 그리고 그 아래부분에 이런 코드를 삽입해보죠.

if(Check==1) break;

한번이라도 나누어 떨어졌다면, 밖으로 튕겨 버리세요.

(계속 해봤자 소수가 아니기 때문에 시간 낭비입니다.)

그러면, 본격적으로 들어갑시다!

[나누는 수를 몇까지 해야 할까?]

일반적으로 소수는 에라토스테네스의 체 방법을 사용하죠.

하지만, 이 방법은 시간이 조금 오래 걸린다는 단점이 있습니다.

하지만, 가장 쉬운 방법이기도 하죠.

쉽고, 빠르게 하는 방법이 있을까요?

예! 있죠, 나누는 수의 범위를 바꿉시다.

다음 코드를 볼까요?

for(i=2;i<=10000000;i++){
check=0;
for(j=2;j<=i;j++){

check방은 아까 설명 드렸을 겁니다. 초기화 시키는 것이죠.

다중 for문을 사용했는데요, i 나누기 j 를 해서 값을 구할 것입니다.

초보자 분들이시라면 저렇게 짜셨을 겁니다.

그러면, for(j) 부분을 살펴 봅시다~!

그 부분이 나누는 수 부분이 되겠지요.

소수를 판별하려면 어디까지 다 나눠보아야 할까요?

5라는 수가 있습니다. 일반적으로, 이 수가 소수인지 아닌지 판별하려면

2부터 4까지 모두 나눠보게 되죠.

(자기 자신과 1은 나누어 떨어지기 때문에 생략해야 합니다.)

5÷2, 5÷3, 5÷4    <= 3번 계산을 하게 됩니다.

물론, 3번 정도야 0.01초도 안걸리지만, 숫자가 무지하게 커진다면 어떨까요?

저같은 경우는 1000만까지의 소수를 구해보려고 합니다.

1000만개를 모두 나눠 보아야 할텐데, 언제 다 하겠습니까..

그래서, 더 효과적인 방법을 찾아보자는 겁니다.

1. for(j=2;j<=i/2;j++)

이 방법은 아까 전보다는 시간을 2배 절약할 수 있습니다.

이 방법도 정답이 틀리지는 않죠.

왜냐하면, 어떤 수의 2분의 1보다  약수는 1개밖에(자기 자신) 없기 때문이죠.

어떤 수의 2분의 1보다 큰 약수가 2개라면

1개는 자기 자신이고, 나머지 1개는 어떤수의 2분의 1보다는 큰수.

0

정도로 식이 만들어지겠네요.

j 의 값들 중에서, 자연수는 존재하지가 않기 때문에, 이렇게 해도 된다는 것입니다.

하지만, 이것보다 효과적인 방법이 있을까요?

예! 있습니다!

바로, 그 수의 제곱근 까지만 구해보면 됩니다.

이것은 제가 직접 증명은 못해드리지만, 적당히 해보시면 답이 똑같다는 것을 알수 있습니다.

제곱근은  대략 √  요녀석을 말합니다.

제곱근 함수를 쓰시려면, #include 로 하나를 더 불러와야 하는데요,

math.h  를 불러와야 합니다.

#include[math.h] 처럼요.

[는 <로 바꿔주셔야 하는거 아시죠?

sqrt(a)

라고 쓰시면, a 의 제곱근이 구해집니다.

그러면, 이렇게 변신하겠죠.

for(j=2;j<=sqrt(i);j++){

그러면 얼마나 속도가 향상될까요?

제가 위의 세방법의 시간을 모두 재봤습니다.

1번째 방법 : 측정 불가 (1시간 이상)

2번째 방법 : 27분

3번째 방법 : 1분 24초 -_-;;

엄청난 차이가 있습니다.

프로그래밍을 잘하려면 수학적 능력도 필요하다는 것을 절실히 느끼게 해주는 문제이네요.

엉터리 단어 스크립트

; ————————————————————–
; | Coded by PSG-01 (Perl)                                                       |
; | Converted by Xeriars (MSL)                                                  |
; | (변경해서 쓰는건 니맘대로지만 이 부분은 지우지 말아주세요.)     |
; ————————————————————–

on *:text:*:#: {
if ($1 == @엉터리단어) {
if (!$2) { msg $chan Usage : @엉터리단어 단어명(영어만) | halt }
unset %jscript.*
set %jscript.chan $chan
set %jscript.word $2
set %jscript.error1 Your acronym must be composed only of letters. Call it a Y2K bug.
set %jscript.error2 Your acronym must have between 2 and 6 letters. Sorry about that, but TANSTAAFL.
sockclose junkword
sockopen junkword brunching.com 80
}
}
on *:sockopen:junkword*: {
sockwrite -nt $sockname GET /cgi/toy-acronymer.cgi?acronym= $+ %jscript.word HTTP/1.1
sockwrite -nt $sockname User-Agent: Kagebot Web Client
sockwrite -nt $sockname Host: brunching.com
sockwrite -nt $sockname Connection: Close
sockwrite -nt $sockname $crlf
}
on *:sockread:junkword: {
sockread %tmp
if (%jscript.temp == 1) {
set %jscript.result %tmp
unset %jscript.temp
if (%jscript.error1 == %jscript.result) { msg %jscript.chan Y2K 버그를 일으키고 싶지 않거든, 영어로만 입력하세요. | halt }
if (%jscript.error2 == %jscript.result) { msg %jscript.chan 단어는 2~6글자만 가능합니다. 다시 시도해주세요. | halt }
msg %jscript.chan $head %jscript.word : $+ %jscript.result
halt
}
if (<P><BIG><B> isin %tmp) {
set %jscript.temp 1
}
}

사용 예제 및 결과
[13:37:56] <@[Kage]> @엉터리단어 Kage
[13:37:57] <@[Kagebot^MKII]> KageBot – Kage : Kilo-Asymmetric Gateway Equipment

사실 예전에 만든건데.. 요즘 블로그가 썰렁해서.
한달전쯤인가 참진에 올렸던걸 고대로 올려주는 센스..;

원래 코딩은 푸성귀님이 펄로 하셨고. 그걸 다시 MSL로 컨버팅한것.

심심해서 만든 바람의나라 종합계산기 – 개발중지



바람의나라를 접게되어 개발 중지 되었습니다.

뭐 심심해서 만들어본 바람의나라 종합계산기다.
공식은 인터넷에 있길래 요즘 학교에서 c도 배우고 있겠다 싶어서 만들어보았다.

흠흠.. 약간 어설픈감이 있긴하다만 그냥저냥 괜찮게 쓸수 있을듯.

소스파일은 다음과 같다. (혹시 읽기 불편하신분은 첨부파일 참고)

#include <stdio.h>
#include <math.h>

int def,cont,select,mleft,vtype;
float dcalc,fst_flr,snd_flr,thd_flr,health,mana,clr_flr,calcsum,exresult,excalc,extime,tdiv;
long damre,dam = 1000000;

int main () {
system(“cls”);
printf(“tt바람의나라 종합 계산기 by 혈폭사신(Xeriars) – Ver 0.1bnnnn”);
mainm:
printf(“[1] 방어력 계산기n”);
printf(“[2] 천명 경험치 계산기n”);
printf(“[3] 공성 경험치 계산기n”);
printf(“[4] 비율 계산기n”);
printf(“[0] 종료nn”);
printf(“사용하시려는 계산기 번호를 입력하세요. : “);
scanf(“%d”, &select);
selectob:
// 방어력 계산기
if (select == 1) {
system(“cls”);
printf(“[1] 방어력 계산기nn”);
input:
printf(“현재방어력을 입력하여 주십시요. : “);
scanf(“%d”, &def);
if (def > 200 || def < -200) {
printf(“입력범위를 초과하셨습니다. 범위는 -200 ~ +200까지 입니다.n”);
goto input;
}

dcalc = 100 – pow((double)(def + 200) / 20,2);
damre = dam – (dam * (dcalc / 100));

printf(“방어력이 %d일때는 %f%의 감소율이 생기며n”, def, dcalc);
printf(“데미지 %ld을 받았을때 %ld만큼의 데미지만 받습니다.n”, dam, damre);
goto checkcon;
}
if (select == 2)
{
system(“cls”);
printf(“[2] 천명 경험치 계산기nn”);
recalc:
printf(“현재 체력을 입력하여 주십시요. : “);
scanf(“%f”, &health);
printf(“현재 마력을 입력하여 주십시요. : “);
scanf(“%f”, &mana);
if ((health + mana*2) > 6150000 || (health + mana*2) < 0 )
{
printf(“계산할수 있는 입력범위를 초과하셨습니다. 다시 입력하여 주십시오.n”);
goto recalc;
}
printf(“체력 : %ld 마력 : %ldn”, (long)health, (long)mana);
fst_flr = (health * 2 + mana * 3.4) * 4 * 16;
snd_flr = (health * 2 + mana * 3.4) * 8 * 16;
thd_flr = (health * 2 + mana * 3.4) * 12 * 16;
clr_flr = (health * 2 + mana * 3.4) * 250;
calcsum = (fst_flr + snd_flr + thd_flr + clr_flr) / 100000000;
printf(“첫번째 스테이지 클리어시 %ld의 경험치를 받고n”, (long)fst_flr);
printf(“두번째 스테이지 클리어시 %ld의 경험치를 받고n”, (long)snd_flr);
printf(“세번째 스테이지 클리어시 %ld의 경험치를 받고n”, (long)thd_flr);
printf(“천명 퀘스트 클리어시 %.0lf의 추가경험치를 받아n”, (double)clr_flr);
printf(“총 %f억의 경험치를 얻습니다.n”, calcsum);
goto checkcon;
}
if (select == 3)
{
system(“cls”);
printf(“[3] 공성 경험치 계산기nn”);
recal:
printf(“현재 체력을 입력하여 주십시요. : “);
scanf(“%f”, &health);
printf(“현재 마력을 입력하여 주십시요. : “);
scanf(“%f”, &mana);
if ((health + mana*2) > 6150000 || (health + mana*2) < 0 )
{
printf(“계산할수 있는 입력범위를 초과하셨습니다. 다시 입력하여 주십시오.n”);
goto recal;
}
rein:
printf(“탁조,연노차,발석차인경우 1, 충차인경우 2를 입력하여 주십시오. : “);
scanf(“%d”, &vtype);
if (vtype != 1 && vtype != 2)
{
printf(“입력이 올바르지 않습니다.n”);
}
printf(“몇분동안 공성경험치를 얻을것인지 입력하여 주십시오. : “);
scanf(“%d”, &mleft);
printf(“몇초당 한발을 쏘실것인지 입력하여 주십시오. (소수입력가능) : “);
scanf(“%f”, &tdiv);
printf(“체력 : %ld 마력 : %ldn”, (long)health, (long)mana);
extime = mleft * 60;
if (vtype == 1) {
excalc = (health * 2 + mana * 3.4);
exresult = (excalc * (extime / tdiv)) / 100000000;
printf(“탁조,연노차,발석차인경우 한발당 %.0f의 경험치를 얻으며n”, excalc);
printf(“%d분동안 돌릴시 총 경험치는 %.0f억의 경험치를 얻습니다. n”, mleft, exresult);
goto checkcon;
}
if (vtype == 2) {
excalc = (health * 2 + mana * 3.4) * 2;
exresult = (excalc * (extime / tdiv)) / 100000000 ;
printf(“충차인경우 한발당 %.0f의 경험치를 얻으며n”, excalc);
printf(“%d분동안 돌릴시 총 경험치는 %.0f억의 경험치를 얻습니다. n”, mleft, exresult);
goto checkcon;
}
}
if (select == 4)
{
int contype,cratio,cash;
float cratio2,cashre;
printf(“[4] 비율 계산기nn”);
retype:
printf(“바돈 → 캐시 환산은 1번, 캐시 → 바돈 환산은 2번을 입력하여 주십시오 : “);
scanf(“%d”, &contype);
if (contype != 1 && contype != 2)
{
printf(“입력이 올바르지 않습니다.n”);
goto retype;
}
if (contype == 1)
{
printf(“캐시로 환산할 바돈금액을 입력하여 주십시오. : “);
scanf(“%d”, &cash);
printf(“바돈비율1을 입력하여 주십시오. (300:1.1이면 300입력) : “);
scanf(“%d”, &cratio);
printf(“바돈비율2을 입력하여 주십시오. (300:1.1이면 1.1입력, 소수입력가능) : “);
scanf(“%f”, &cratio2);
cashre = (cash * cratio2) / cratio;
printf(“바돈가격이 %d원이고 비율이%d:%.2f 일때n” ,cash,cratio,cratio2);
printf(“캐시로 환산하면 %.0f전 입니다.n” ,cashre);
goto checkcon;
}
if (contype == 2)
{
printf(“바돈으로 환산할 캐시금액을 입력하여 주십시오. : “);
scanf(“%d”, &cash);
printf(“캐시비율1을 입력하여 주십시오. (300:1.1이면 300입력) : “);
scanf(“%d”, &cratio);
printf(“캐시비율2을 입력하여 주십시오. (300:1.1이면 1.1입력) : “);
scanf(“%f”, &cratio2);
cashre = cash * cratio / cratio2;
printf(“캐시가격이 %d원이고 비율이%d:%.02f 일때n” ,cash,cratio,cratio2);
printf(“바돈으로 환산하면 %.0f전 입니다.n” ,cashre);
goto checkcon;
}
}
if (select == 0)
{
goto eof;
}
else { printf(“입력하신 번호가 올바르지 않습니다.n”);
goto mainm;
}
checkcon:
printf(“계속 계산 하시려면 1, 메인메뉴는 9, 종료는 0번을 입력하세요. : “);
scanf(“%d”, &cont);
if (cont == 1) { goto selectob; }
if (cont == 9) { goto mainm; }
if (cont == 0) { goto eof; }
if (cont != 1 && cont != 9 && cont != 0) {
printf(“입력하신 번호가 올바르지 않습니다.n”);
goto checkcon;
}
eof:
printf(“nn** 이용하여 주셔서 감사합니다! ** n”);
return 0;
}

진수변환 스크립트

“디지털 공학” 이란 과목을 듣는중
교수가 진수변환을 해오라는 무지막지한 숙제를 내준 관계로 (다합치면 백문제넘으려나)
귀찮아서 만들어버린 스크립트

; ————————————————————
; | Made by Xeriars                                                               |
; | (변경해서 쓰는건 니맘대로지만 이 부분은 지우지 말아주세요.)  |
; ————————————————————

alias dec2bqox {
if ($exists(div_tmp.txt)) { remove div_tmp.txt }
if (!$1) {
return 변환할숫자와 진법을 입력하여 주십시요. (ex : $chr(36) $+ dec2bqo(100,bin))
halt
}
if ($1 !isnum) {
return $1 $+ 은(는) 올바른 숫자가 아닙니다. 다시 확인하여 주십시요.
halt
}
if (!$2) {
return 몇진법으로 환산하실것인지 입력하여 주십시요.
halt
}
if ($1 > 100000000000000000000) {
return 숫자가 너무 큽니다. 다시 입력하여 주십시요.
halt
}
if ($2 == bin) { goto narycalc } | if ($2 == qua) { goto narycalc } | if ($2 == oct) { goto narycalc } | if ($2 == hex) { goto narycalc }
else {
return $2 $+ 은(는) 변환할수 없는 진법입니다.
return bin : 2진수, qua : 4진수, oct : 8진수, hex : 16진수 (ex : $chr(36) $+ dec2bqo(100,bin))
halt
}
:narycalc
var %i 0
var %divider $1
var %nary = $replace($2,bin,2,qua,4,oct,8,hex,16)
:div
write div_tmp.txt $calc(%divider % %nary)
if (%divider > 1) {
var %divider = $int($calc(%divider / %nary))
inc %i
goto div
}
var %q 0
while (%q < $lines(div_tmp.txt)) {
if (%nary == 16) {
var %div_result = %div_result $+ $replace($read(div_tmp.txt,%q),10,A,11,B,12,C,13,D,14,E,15,F)
}
if (%nary != 16) {
var %div_result = %div_result $+ $read(div_tmp.txt,%q)
}
inc %q
}
remove div_tmp.txt
return $reverse(%div_result,%div_result)
}
alias 숙제 {
var %i 00
var %amount 150
var %num $rand(1000,9999)
while (%i < %amount) {
inc %i
write con_result.txt %i $+ $chr(46) %num
write con_result.txt 2진수 : $dec2bqox(%num,bin)
write con_result.txt 4진수 : $dec2bqox(%num,qua)
write con_result.txt 8진수 : $dec2bqox(%num,oct)
write con_result.txt 16진수 : $dec2bqox(%num,hex)
write con_result.txt $crlf
var %num $rand(1000,9999)
}
}

결과는 다음과 같이 con_result.txt로 저장.

1. 4492
2진수 : 1000110001100
4진수 : 1012030
8진수 : 10614
16진수 : 118C

2. 4954
2진수 : 1001101011010
4진수 : 1031122
8진수 : 11532
16진수 : 135A

3. 2697
2진수 : 101010001001
4진수 : 0222021
8진수 : 05211
16진수 : 0A89

냠냠.. 귀찮~
위 함수로 살짝 건드려서 만든.. @진수변환 스크립트

; ————————————————————
; | Made by Xeriars                                                               |
; | (변경해서 쓰는건 니맘대로지만 이 부분은 지우지 말아주세요.)  |
; ————————————————————

on *:text:*:#: {
if ($1 == @진수변환) {
if (!$2) { msg $chan Usage : @진수변환 변환할진수. (10진수만 가능) | halt }
if ($2 !isnum) { msg $chan 올바른 숫자가 아닙니다. 숫자로만 입력하십시오. | halt }
msg $chan 2진수 : $dec2bqox($2,bin)
msg $chan 4진수 : $dec2bqox($2,qua)
msg $chan 8진수 : $dec2bqox($2,oct)
msg $chan 16진수 : $dec2bqox($2,hex)
halt
}
}

골라줘 스크립트

이것저것 할일이 많아져서 뭘할까 고민중에 결국 스크립트를 만들어서 골라보기로 했다.
뭐 예전에 IRC상에서 한번 본 스크립트인 choice랑 똑같은 기능인가..;; ————————————————————
; | Made by Xeriars                                                               |
; | (변경해서 쓰는건 니맘대로지만 이 부분은 지우지 말아주세요.)  |
; ————————————————————

on *:text:*:#: {
if ($1 == @골라줘) {
if (!$2) { msg $chan “@골라줘 항목1 항목2 … 항목n”와 같은 형식으로 입력하셔야 합니다. (최대 10개) | halt }
if ($0 > 11) { msg $chan 고를수있는 최대치를 넘어섰습니다. (최대 10개) | halt }
var %result $rand(2,$0)
var %randchoice $replacecs(%result,2,$2,3,$3,4,$4,5,$5,6,$6,7,$7,8,$8,9,$9,10,$10,11,$11)
msg $chan %randchoice $+ 을(를) 골랐습니다.
halt
}
}

결과
[10:21:04] <@[Kage]> @골라줘 갈비 양념통닭 회 피자 프라이드치킨
[10:21:05] <@[Kagebot^MKII]> * KageBot – ㄴ(º皿 ºㆀ)ㄱ 피자을(를) 골랐습니다.

p.s 지나치게 봇에 의존하는것은 건강에 해롭습니다.

감기…

on *:abnormal_my_condition:#: {

if ($asctime(mm) > 11) {

set %season winter

}

if (%season == winter) {

while (%influenza == cured) {

set %influenza activation

if (%influenza isin $mybody) {

if (%influenza == activation) {

if (%syndrome == $throat) {

msg $mouth 콜록콜록..

}

if (%syndrome == $nose) {

msg $nose 훌쩍훌쩍..

}

}

}

}

}

halt

}

alias for_a_cold_in_the_head {

set %influenza cured

return %influenza

}

//echo -a %syndrome

result : (in my $nose) 훌쩍훌쩍..

……i need a alias vaccine { for_a_cold_in_the_head | halt }

얼마전에 핸드폰을 바꿨다.


모델명은 EV-K150

수원역 지하상가에서 돌아다니다가 10만원에 구입했다.

수원역 지하상가라도 대리점이 워낙 많아서 저 기종이 최고 25만원까지 부르기도 하고 보통은 18만원정도 불렀는데 마지막으로 갔던데에서 10만원에 팔던걸 얼른 샀다.

내부 메모리가 좀 작아서 (50메가, 추가 확장 불가.. -_-;;;) 불편한 감이 없지 않아 있지만

뭐 엠피삼을 들을때는 음질을 좀 떨궈서 인코딩하면 25곡정도 들어가지만 k3g로 영화보기엔 좀 무리인듯 보인다..;

슬림형이라 그런지 상당히 얇은게 장점이다.

최대 장점은 QPST로 자유로이 수정이 가능하다는점?

QPST로 접속해서 내부 파일을 울트라 에디터로 살짝 건드려줬더니 카메라 촬영음이 나질 않는다. (흐흐흐흐…)

벨소리 역시 상당히 커서 맘에 든다.

아무튼 이번 핸드폰은 기존에 썼던것보다 압도적으로 맘에 든다는..

블로그 이전!!

전에쓰던 http://blog.my.lv/xeriars 가 해외에서는 접속이 안된다는 사실을 알고

블로그 서비스를 찾던 중 IRC #tokigun 채널에 계시는 분들의 추천과

아침놀님의 초청으로 티스토리에 이사오게 되었다.

흠.. 이번에는 안옮기고 오래 쓸수 있겠지?

안옮기기는… 결국 17년이 지난 2023년 11월에 옮겼다.

자동반응 검색 (자반검색) 스크립트

; ————————————————————

; | Made by Xeriars                                                               |

; | (변경해서 쓰는건 니맘대로지만 이 부분은 지우지 말아주세요.)  |

; ————————————————————

on *:text:*:#: {

if ($1 == @자반검색) {

if (!$2) { msg $chan “@자반검색 이름”과 같은 형식으로 입력하셔야 합니다. 리스트를 검색시에는 “@자반검색 리스트”로 검색해주시기 바랍니다. | halt }

else {

if ($2 == 리스트) {

var %i 1

while (%i <= $ini(automsg.ini,0)) {

var %amsglist %amsglist $+ $ini(automsg.ini, $+ %i $+ ) $+ $chr(44)

inc %i

}

msg $chan 현재 검색가능한 자동반응은 %amsglist 입니다.

halt

}

if (!$readini(automsg.ini,$2,1)) { msg $chan $2 $+ (은)는 아직 추가된 자동반응이 아닙니다. | halt }

var %i 1

while (%i <= $ini(automsg.ini,$2,0)) {

msg $chan $readini(automsg.ini,$2,%i)

inc %i

}

halt

}

}

}

; automsg.ini의 내용

; [블로그]

; 1=카게의 블로그입니다. 가끔 놀러오세요. http://xeriars.tistory.com