【sosuusoinsuu.cのソースコード】
/*
* ある範囲の自然数が素数かどうかを判定し、素数の一覧を表示し、
* 素数でない数は素因数分解してその結果を表示するプログラム
* sosuusoinsuu.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h> /* strlen(), strcmp(), strcpy(), strcat() */
#include <ctype.h> /* isdigit() */
#define BUF_SIZE 256
/*
* 自作のbool型の定義
*/
typedef enum {
false, /* 0 */
true /* 1 */
} bool;
/*
* ユーザー定義関数のプロトタイプ宣言
*/
void print_title(void);
void input_lu(void);
bool is_valid_number(char buf[]);
void sel_outputto(void);
void output(void);
void output_result(void);
void foutput_result(char filename[], char oldfilename[]);
bool is_prime_number(int n);
void prime_fact(int n);
void fprime_fact(int n);
int get_dec_digit(int n);
void gen_filename(char filename[]);
bool retry(void);
/*
* グローバル変数
*/
int lower, upper;
char outputto,
filename[BUF_SIZE] = {1}, /* filenameとoldfilenameの初期値を */
oldfilename[BUF_SIZE] = {0}; /* 異なるものに設定 */
/* (ファイルへの追記の判断に使用) */
FILE *fp;
/*
* メイン関数
*/
int main(void)
{
while (1) {
/* 表題の表示 */
print_title();
/* 下限値と上限値の入力 */
input_lu();
/* 出力先の選択 */
sel_outputto();
/* 出力 */
output();
/* 操作を続けるかどうかの選択 */
if (!retry())
break;
}
return EXIT_SUCCESS;
}
/*
* 表題を表示する関数
*/
void print_title(void)
{
printf("【「下限値」以上「上限値」以下の素数を表示します】\n");
}
/*
* 下限値と上限値を入力する関数
* is_valid_number()関数を使用する
*/
void input_lu(void)
{
char buf[BUF_SIZE], zz;
while (1) {
printf("下限値 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &lower, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("半角整数値を入力してください。\n\n");
continue;
} else if (lower < 2) {
printf("2以上の整数を入力してください。\n\n");
continue;
} else
break;
}
while (1) {
printf("上限値 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &upper, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("半角数字を入力してください。\n\n");
continue;
} else if (lower > upper) {
printf("下限値以上の整数を入力してください。\n\n");
continue;
} else
break;
}
}
/*
* 文字列が正しい形式の数値かどうかを判定する関数
* true: 正しい形式である、false: 無効な形式である
*/
bool is_valid_number(char buf[])
{
int i = 0;
/* 最初は符号(省略可) */
if (buf[i] == '+' || buf[i] == '-')
i++;
/* 次に数字(省略不可) */
if (!isdigit(buf[i]))
return false;
i++;
/* 次に数字列(省略可) */
while (isdigit(buf[i]))
i++;
return buf[i] == '\0';
}
/*
* 出力先(outputto)を選択する関数
*/
void sel_outputto(void)
{
char buf[BUF_SIZE], zz;
while (1) {
printf("結果の出力先を1、2、3から選んでください。\n");
printf("1. 画面だけに出力する。\n");
printf("2. ファイルだけに出力する。\n");
printf("3. 画面とファイルの両方に出力する。\n");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &outputto, &zz);
if (outputto != '1' && outputto != '2' && outputto != '3' || zz != '\n') {
printf("無効な入力です。\n");
printf("1、2、3のいずれかを入力してください。\n\n");
continue;
} else
break;
}
}
/*
* 出力する関数
* output_result()関数とfoutput_result()関数を使用する
*/
void output(void)
{
switch (outputto) {
case '1':
output_result();
break;
case '2':
foutput_result(filename, oldfilename);
break;
case '3':
output_result();
foutput_result(filename, oldfilename);
break;
default:
break;
}
}
/*
* 結果を画面へ出力する関数
* is_prime_number()関数、get_dec_digit()関数と
* prime_fact()関数を使用する
*/
void output_result(void)
{
int i, j, k, max_prime_number, max_nprime_number;
printf("■%d~%dについて調べる■\n", lower, upper);
printf("【素数の一覧】\n");
/* 素数の最大値を求める(出力の体裁調整のため) */
for (i = lower; i <= upper; i++)
if (is_prime_number(i))
max_prime_number = i;
/* 素数を画面出力する */
for (i = lower, j = 0; i <= upper; i++) {
if (is_prime_number(i)) {
if (j % 10 != 0)
printf(" ");
/* 出力の体裁調整 */
for (k = 0; k < get_dec_digit(max_prime_number)-get_dec_digit(i); k++)
printf(" ");
printf("%d", i);
j++;
}
/* 「iが素数、かつ、10個表示したとき」 */
if (is_prime_number(i) && (j % 10 == 0))
printf("\n");
}
/* 素数でない数の最大値を求める(出力の体裁調整のため) */
for (i = lower; i <= upper; i++)
if (!is_prime_number(i))
max_nprime_number = i;
/* 素数でない数を素因数分解して結果を画面出力する */
printf("\n【素数でない数の素因数分解の結果】\n");
for (i = lower; i <= upper; i++) {
if (!is_prime_number(i)) {
/* 出力の体裁調整 */
for (k = 0; k < get_dec_digit(max_nprime_number)-get_dec_digit(i); k++)
printf(" ");
printf("%d =", i);
prime_fact(i);
}
}
}
/*
* 結果をファイルへ出力する関数
* gen_filename()関数、is_prime_number()関数、get_dec_digit()関数と
* fprime_fact()関数を使用する
*/
void foutput_result(char filename[], char oldfilename[])
{
int i, j, k, max_prime_number, max_nprime_number;
/* ifによる分岐は、2行目以降を同一ファイルに追記出力させるため */
if (strcmp(filename, oldfilename) == 0) { /* ファイル名が同じなら(2行目以降なら) */
fp = fopen(oldfilename, "a"); /* oldfilenameを開く */
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
} else { /* ファイル名が違うなら(初めての出力なら) */
gen_filename(filename); /* 新規にファイル名を生成して */
fp = fopen(filename, "a"); /* そのファイル(filename)を開いて */
strcpy(oldfilename, filename); /* oldfilenameを更新する */
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
}
fprintf(fp, "■%d~%dについて調べる■\n", lower, upper);
fprintf(fp, "【素数の一覧】\n");
/* 素数の最大値を求める(出力の体裁調整のため) */
for (i = lower; i <= upper; i++)
if (is_prime_number(i))
max_prime_number = i;
/* 素数をファイル出力する */
for (i = lower, j = 0; i <= upper; i++) {
if (is_prime_number(i)) {
if (j % 10 != 0)
fprintf(fp, " ");
/* 出力の体裁調整 */
for (k = 0; k < get_dec_digit(max_prime_number)-get_dec_digit(i); k++)
fprintf(fp, " ");
fprintf(fp, "%d", i);
j++;
}
/* 「iが素数、かつ、10個表示したとき」 */
if (is_prime_number(i) && (j % 10 == 0))
fprintf(fp, "\n");
}
/* 素数でない数の最大値を求める(出力の体裁調整のため) */
for (i = lower; i <= upper; i++)
if (!is_prime_number(i))
max_nprime_number = i;
/* 素数でない数を素因数分解して結果をファイル出力する */
fprintf(fp, "\n【素数でない数の素因数分解の結果】\n");
for (i = lower; i <= upper; i++) {
if (!is_prime_number(i)) {
/* 出力の体裁調整 */
for (k = 0; k < get_dec_digit(max_nprime_number)-get_dec_digit(i); k++)
fprintf(fp, " ");
fprintf(fp, "%d =", i);
fprime_fact(i);
}
}
fclose(fp);
}
/*
* 素数かどうかを判定する関数
* true: 素数である、false: 素数でない
*/
bool is_prime_number(int n)
{
int i;
bool flag = true;
if(n < 4)
return flag;
for(i = 2; i * i <= n; i++)
if((n % i) == 0)
flag = false;
return flag;
}
/*
* 素因数分解をして結果を画面に出力する関数
*/
void prime_fact(int n)
{
int i, j = 0, cnt = 0;
while (n % 2 == 0) { /* 偶数の素数は2のみ */
n /= 2;
cnt++;
}
if (cnt > 1) {
if (j != 0)
printf(" *");
printf(" 2^%d", cnt);
j++;
} else if (cnt == 1) {
if (j != 0)
printf(" *");
printf(" 2");
j++;
}
for (i = 3; i * i <= n; i += 2) { /* 他の奇数で割っていく */
cnt = 0;
while (n % i == 0) {
n /= i;
cnt++;
}
if (cnt > 1) {
if (j != 0)
printf(" *");
printf(" %d^%d", i, cnt);
j++;
} else if (cnt == 1) {
if (j != 0)
printf(" *");
printf(" %d", i);
j++;
}
}
/* ここまででnは1またはnの平方根以下で最大の素数 */
if (n != 1) {
if (j != 0)
printf(" *");
printf(" %d", n); /* 後者なら追記 */
}
printf("\n");
}
/*
* 素因数分解をして結果をファイルに出力する関数
*/
void fprime_fact(int n)
{
int i, j = 0, cnt = 0;
while (n % 2 == 0) { /* 偶数の素数は2のみ */
n /= 2;
cnt++;
}
if (cnt > 1) {
if (j != 0)
fprintf(fp, " *");
fprintf(fp, " 2^%d", cnt);
j++;
} else if (cnt == 1) {
if (j != 0)
fprintf(fp, " *");
fprintf(fp, " 2");
j++;
}
for (i = 3; i * i <= n; i += 2) { /* 他の奇数で割っていく */
cnt = 0;
while (n % i == 0) {
n /= i;
cnt++;
}
if (cnt > 1) {
if (j != 0)
fprintf(fp, " *");
fprintf(fp, " %d^%d", i, cnt);
j++;
} else if (cnt == 1) {
if (j != 0)
fprintf(fp, " *");
fprintf(fp, " %d", i);
j++;
}
}
/* ここまででnは1またはnの平方根以下で最大の素数 */
if (n != 1) {
if (j != 0)
fprintf(fp, " *");
fprintf(fp, " %d", n); /* 後者なら追記 */
}
fprintf(fp, "\n");
}
/*
* 10進整数の桁数を返す関数
*/
int get_dec_digit(int n)
{
int digit = 0;
while(n){
n /= 10;
digit++;
}
return digit;
}
/*
* 現在日付時刻からファイル名を生成する関数
*/
void gen_filename(char filename[])
{
struct tm *t;
time_t tt;
char snumrand[10];
time(&tt);
t = localtime(&tt);
srand((unsigned int)time(NULL));
sprintf(filename, "sosuusoinsuu%04d%02d%02d_%02d%02d%02d_",
1900+(t->tm_year), 1+(t->tm_mon), t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
sprintf(snumrand, "%04d", rand() % 10000);
filename = strcat(filename, snumrand);
filename = strcat(filename, ".txt");
}
/*
* 操作を続けるかどうかを選択する関数
* true: 繰り返す、false: 終了する
*/
bool retry(void)
{
bool ret;
char buf[BUF_SIZE], ch, zz;
while (1) {
printf("続けますか?(y/n) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &ch, &zz);
if ((ch == 'y' || ch == 'Y') && zz == '\n') {
printf("\n+++++\n\n");
ret = true;
break;
} else if ((ch == 'n' || ch == 'N') && zz == '\n') {
ret = false;
break;
}
printf("無効な入力です。\n");
printf("yまたはnを入力してください。\n\n");
}
return ret;
}
C:\Users\skonishi\Documents>sosuusoinsuu
【「下限値」以上「上限値」以下の素数を表示します】
下限値 = ? 2
上限値 = ? 10
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【「下限値」以上「上限値」以下の素数を表示します】
下限値 = ? 100
上限値 = ? 110
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【「下限値」以上「上限値」以下の素数を表示します】
下限値 = ? 1000
上限値 = ? 1010
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【「下限値」以上「上限値」以下の素数を表示します】
下限値 = ? 10000
上限値 = ? 10010
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【「下限値」以上「上限値」以下の素数を表示します】
下限値 = ? 2
上限値 = ? 1100
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) n
■2~10について調べる■
【素数の一覧】
2 3 5 7
【素数でない数の素因数分解の結果】
4 = 2^2
6 = 2 * 3
8 = 2^3
9 = 3^2
10 = 2 * 5
■100~110について調べる■
【素数の一覧】
101 103 107 109
【素数でない数の素因数分解の結果】
100 = 2^2 * 5^2
102 = 2 * 3 * 17
104 = 2^3 * 13
105 = 3 * 5 * 7
106 = 2 * 53
108 = 2^2 * 3^3
110 = 2 * 5 * 11
■1000~1010について調べる■
【素数の一覧】
1009
【素数でない数の素因数分解の結果】
1000 = 2^3 * 5^3
1001 = 7 * 11 * 13
1002 = 2 * 3 * 167
1003 = 17 * 59
1004 = 2^2 * 251
1005 = 3 * 5 * 67
1006 = 2 * 503
1007 = 19 * 53
1008 = 2^4 * 3^2 * 7
1010 = 2 * 5 * 101
■10000~10010について調べる■
【素数の一覧】
10007 10009
【素数でない数の素因数分解の結果】
10000 = 2^4 * 5^4
10001 = 73 * 137
10002 = 2 * 3 * 1667
10003 = 7 * 1429
10004 = 2^2 * 41 * 61
10005 = 3 * 5 * 23 * 29
10006 = 2 * 5003
10008 = 2^3 * 3^2 * 139
10010 = 2 * 5 * 7 * 11 * 13
■2~1100について調べる■
【素数の一覧】
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 211 223 227 229
233 239 241 251 257 263 269 271 277 281
283 293 307 311 313 317 331 337 347 349
353 359 367 373 379 383 389 397 401 409
419 421 431 433 439 443 449 457 461 463
467 479 487 491 499 503 509 521 523 541
547 557 563 569 571 577 587 593 599 601
607 613 617 619 631 641 643 647 653 659
661 673 677 683 691 701 709 719 727 733
739 743 751 757 761 769 773 787 797 809
811 821 823 827 829 839 853 857 859 863
877 881 883 887 907 911 919 929 937 941
947 953 967 971 977 983 991 997 1009 1013
1019 1021 1031 1033 1039 1049 1051 1061 1063 1069
1087 1091 1093 1097
【素数でない数の素因数分解の結果】
4 = 2^2
6 = 2 * 3
8 = 2^3
9 = 3^2
10 = 2 * 5
(中略)
1095 = 3 * 5 * 73
1096 = 2^3 * 137
1098 = 2 * 3^2 * 61
1099 = 7 * 157
1100 = 2^2 * 5^2 * 11