ページ 1 / 2
格納
Posted: 2015年10月23日(金) 13:30
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, sum;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
int suretu = sum + get_rand();
if (i > 0) putchar(',');
printf("%d", suretu);
sum =sum+suretu;
printf("%d",sum+suretu);
}
putchar('\n');
return 0;
}
sumで出した数列をその出た数列を全て足し合わせたのを二つ表示させたいのですがうまくいきません。
どこを直せばいいでしょうか?printf("%d",sum+suretu);これではダメなのでしょうか?
また出力された10個ある数列を1つ1つ格納するにはどうすればいいでしょうか?
Re: 格納
Posted: 2015年10月23日(金) 16:55
by みけCAT
数列の作成のコードと酷似しています。
万が一同一人物であるのであれば、名前の統一をお願いします。
[hr]
ライトニング さんが書きました:sumで出した数列をその出た数列を全て足し合わせたのを二つ表示させたいのですがうまくいきません。
どこを直せばいいでしょうか?
意味がよくわかりませんが、出力の仕方を直せばいいと思います。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, sum;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
int suretu = sum + get_rand();
sum = sum + suretu;
printf("%d %d\n", suretu, sum);
}
return 0;
}
ライトニング さんが書きました:printf("%d",sum+suretu);これではダメなのでしょうか?
書く位置にもよりますが、このコードだとsuretuの加算が被るのでダメな気がします。
ライトニング さんが書きました:また出力された10個ある数列を1つ1つ格納するにはどうすればいいでしょうか?
数列の要素を格納するなら、普通に格納する場所を用意して格納すればいいでしょう。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, sum;
int kakunou[NUM];
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
int suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
return 0;
}
数列を格納する場合でも、普通に格納する場所を用意して格納すればいいでしょう。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM_OF_SEQ 10
#define NUM_OF_ELEM 20
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, j, sum;
int kakunou[NUM_OF_SEQ][NUM_OF_ELEM];
srand((unsigned int)time(NULL));
for (i = 0; i < NUM_OF_SEQ; i++)
{
sum = 0;
for (j = 0; j < NUM_OF_ELEM; j++) {
int suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i][j] = suretu;
}
}
return 0;
}
Re: 格納
Posted: 2015年10月24日(土) 13:53
by ライトニング
ご回答ありがとうございます!格納されたものを実行しようとしたんですが何もでないのですがどうすれば格納されたものがでるんでしょうか?
またこの格納された数列全体に同じ値などを*たり+などの計算は可能ですかね?
Re: 格納
Posted: 2015年10月24日(土) 14:09
by softya(ソフト屋)
drakeさんですよね?
同じ方は同じ名前を使い続けるなど統一をお願いしております。
理由としては、回答者は前回の質問内容などの理解度を回答の参考にしているため、回答者に余計な手間を取らせることにつながりますので、ご協力ください。
質問者も同じ説明を受けずに済んだり、理解度に合わせて回答がもらえるのでメリットも多いです。
フォーラムルールに記載がありますので、お読み下さい。
http://dixq.net/board/board.html
Re: 格納
Posted: 2015年10月24日(土) 14:13
by ライトニング
すいません格納されたものを表示する事はできした。この出した数列全体に同じ値を掛け合わせたり 2つ目と4つ目の値を足し合わせたりなどは可能ですか?
Re: 格納
Posted: 2015年10月24日(土) 14:16
by ライトニング
ご指摘ありがとうございます。課題のため即急にしなくてはならなくてお力が欲しくて安易に聞いてしまって申し訳ないです。
Re: 格納
Posted: 2015年10月24日(土) 14:35
by softya(ソフト屋)
ライトニング さんが書きました:ご指摘ありがとうございます。課題のため即急にしなくてはならなくてお力が欲しくて安易に聞いてしまって申し訳ないです。
みけCATさんなど前回、回答してくれた人に謝りましょう。
全部正直に、、何時までにどの様な課題をやらないと行けないか記載して下さい。
あと分からなところはちゃんと聞きましょう。
色々小出しにしたり、後回しで話がややこしくなるだけです。
Re: 格納
Posted: 2015年10月24日(土) 14:52
by ライトニング
前回回答してくださった方など迷惑をかけてしまって申し訳ないです。softyaさんも申し訳ございませんでした。
来週までにMH暗号というのを作らないといけなくてそれにてこずっており何度も質問させていただいてる状況です。
自分が今やりたい事はこの出てきた数列の合計の出た値を(例数列の合計1000なら1000以上の素数(例1009)などをを見つけその素数以下の数字(例100mod1009)を数列にかけたその数列を表示させるというのをやりたい状況です。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, x,sum;
x=10;
int kakunou[NUM];
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
int suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("%d",suretu);
printf("%d,",suretu*x);
}
return 0;
}
とりあえず自分でこの数列に10という数字をかけて表示させようとしたのですが、10をかけた数字しかでてこず元の数列が出てこないという状況です。
kakunou[2]+kakunou[3]などをして数列の二つ目と三つ目の値を足しあわようとしてるのですがエラーがでてしまう状況です。
もし指摘くださる方がいらっしゃればお願いします。
本当に色々な迷惑をかけて本当に申し訳ありませんでした。
Re: 格納
Posted: 2015年10月24日(土) 15:56
by みけCAT
ライトニング さんが書きました:自分が今やりたい事はこの出てきた数列の合計の出た値を(例数列の合計1000なら1000以上の素数(例1009)などをを見つけその素数以下の数字(例100mod1009)を数列にかけたその数列を表示させるというのをやりたい状況です。
素数や「その素数以下の数字」は具体的にどのようにして選びますか?(最大/最小のもの、ランダムなど)
ライトニング さんが書きました:とりあえず自分でこの数列に10という数字をかけて表示させようとしたのですが、10をかけた数字しかでてこず元の数列が出てこないという状況です。
適当に実行してみましたが、きちんと両方の値が出力されました。
処理系の不都合を疑ってください。
※1~10の乱数を出しているので、数列の初項が77になることは無いはずです
ライトニング さんが書きました:kakunou[2]+kakunou[3]などをして数列の二つ目と三つ目の値を足しあわようとしてるのですがエラーがでてしまう状況です。
具体的にどのようなエラーですか?
エラーメッセージが出ている場合は、それをそのまま(パスなどにユーザー名などの個人情報が出ている場合は、そこだけを伏せて)提示してください。
とりあえず、全角の2や+をC言語のコードのコメントや文字列以外の場所に置くのは不正です。
また、kakunou[2]およびkakunou[3]は、初項を1番目とした場合それぞれ3番目と4番目の項です。
Re: 格納
Posted: 2015年10月24日(土) 19:19
by ライトニング
素数は出た数列を全て足し合わせた合計以上の中での素数なら何でもいいです。その素数を法xとしたときx>yとなるようなy決めるような感じです。
そのxmodyを数列全体に掛け合わせ新たな数列を作るのがやりたい状況です。
10掛けた数列を出すことは無事出来ました。ありがとうございます。
このようにやってみたのですがこれを実行するとわけのわからない数列が羅列されてしまうという状況です。
printf("%d %d %d\n",suretu,suretu*x);これだけだと綺麗に数列と数列を10倍したものが出力されるのですが、
これの下にprintf("%d",kakunou[2]+kakunou[3]);これをつけるとおかしくなるという状況です。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, x,sum;
x=10;
int kakunou[NUM];
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
int suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("%d %d %d\n",suretu,suretu*x);
printf("%d",kakunou[2]+kakunou[3]);
}
return 0;
}
Re: 格納
Posted: 2015年10月24日(土) 19:49
by みけCAT
ライトニング さんが書きました:このようにやってみたのですがこれを実行するとわけのわからない数列が羅列されてしまうという状況です。
printf("%d %d %d\n",suretu,suretu*x);これだけだと綺麗に数列と数列を10倍したものが出力されるのですが、
これの下にprintf("%d",kakunou[2]+kakunou[3]);これをつけるとおかしくなるという状況です。
- 連続して出力しているので数字が繋がって見えてしまいます。書式に適当な区切り文字を追加してください。
- i=0, 1, 2のとき、未初期化の不定の値を参照しています。適当に初期化するか、条件分岐で未初期化の値やそれを用いた計算結果を出力しないようにしてください。
- そもそも最初のprintfに渡すデータが足りていません。本当に綺麗に出力されるのですか?
Re: 格納
Posted: 2015年10月24日(土) 20:29
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, x,sum;
int kakunou[NUM];
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
int y;
int suretu = sum + get_rand();
int x = sum + suretu;
sum = sum + suretu;
kakunou[i] = suretu;
printf("%d,%d\n",suretu,x);
if(y>x)
scanf("%d",y);
printf("増加数列にyを掛け合わせたものは%dです\n",suretu*y);
else
printf("xの合計値よりyが数列の合計より小さいです。");
}
return 0;
}
「31行目」で記述エラーを発見しました。
「identifier」を付け忘れています。
全て足し合わせた数列に自分で入力した値を掛けてだすのをやりたかったのですが
試しにやってみたのですがこのようなエラーがでました。
また数列の(1,5,10,21,....)なら始めの1をkakunou[1]に5をkakunou[2]に10をkakunou[3]にして
kakunou[1]+kakunou[2]=6見たいなのは無理なのでしょうか?
kakunou
をどの用に変えてもうまくいきません....
Re: 格納
Posted: 2015年10月24日(土) 21:26
by みけCAT
ライトニング さんが書きました:「31行目」で記述エラーを発見しました。
「identifier」を付け忘れています。
elseがあるのに、対応するifが無いのでエラーになっています。
ライトニング さんが書きました:また数列の(1,5,10,21,....)なら始めの1をkakunou[1]に5をkakunou[2]に10をkakunou[3]にして
kakunou[1]+kakunou[2]=6見たいなのは無理なのでしょうか?.
「kakunou[1]+kakunou[2]」に6を代入するのは無理ですが、kakunou[1]+kakunou[2]の計算ならもちろんできます。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void)
{
return rand() % 10 + 1;
}
int main(void)
{
int i, x,sum;
int kakunou[NUM + 1]; /* 余計な要素を置き、NUMまでの添字を安全に使えるように */
srand((unsigned int)time(NULL));
sum = 0;
for (i = 1; i <= NUM; i++) /* 1~NUMに格納するように変更 */
{
int y = 0; /* yの値はどうやって決める? */
int suretu = sum + get_rand();
int x = sum + suretu;
sum = sum + suretu;
kakunou[i] = suretu;
printf("%d,%d\n",suretu,x);
if(y>x) { /* ブロックにする */
scanf("%d",&y); /* ポインタを渡さないとダメ */
printf("増加数列にyを掛け合わせたものは%dです\n",suretu*y);
}
else
printf("xの合計値よりyが数列の合計より小さいです。");
}
printf("kakunou[1]+kakunou[2] = %d\n", kakunou[1]+kakunou[2]);
return 0;
}
Re: 格納
Posted: 2015年10月24日(土) 21:38
by みけCAT
ライトニング さんが書きました:素数は出た数列を全て足し合わせた合計以上の中での素数なら何でもいいです。その素数を法xとしたときx>yとなるようなy決めるような感じです。
そのxmodyを数列全体に掛け合わせ新たな数列を作るのがやりたい状況です。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int is_prime(int x); /* xが素数かを判定する */
void print_seq(const char *title, const int *seq, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int seq[NUM], newseq[NUM];
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
int elem = sum + get_rand();
sum = sum + elem;
seq[i] = elem;
}
/* 数列の全要素の合計以上の最小の素数を探す */
for (x = sum; !is_prime(x); x++);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newseq[i] = seq[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_seq("数列: ", seq, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_seq("新たな数列: ", newseq, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int is_prime(int x)
{
/* ここにxが素数なら1(真)を、素数でないから0(偽)を返すプログラムを書いてください */
return 1;
}
void print_seq(const char *title, const int *seq, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", seq[i]);
}
putchar('\n');
}
Re: 格納
Posted: 2015年10月25日(日) 16:31
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int is_prime(int x); /* xが素数かを判定する */
void print_suretu(const char *title, const int *seq, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM],suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
int elem = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を探す */
for (x = sum; !is_prime(x); x++);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", suretu, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int is_prime(int x)
{
/* ここにxが素数なら1(真)を、素数でないから0(偽)を返すプログラムを書いてください */
if(sum>x) {
scanf("%d",&x);
printf("増加数列にxを掛け合わせたものは%dです\n",suretu*x);
return 1;
}
else
printf("sumの合計値よりxが小さいです。");
return 0;
}
void print_seq(const char *title, const int *seq, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", seq[i]);
}
putchar('\n');
}
ご丁寧にこのうようなプログラミングを作っていただきありがとうございます。
自分で分かりやすいようにseq→kakunou elem→suretuに直したのですがなぜか上手くいかないです。これを実行したところsumが定義されていないとでます。int sumなどをつけてもうまくいかないです。どこが原因なのでしょうか?元々seqとelemの意味を履き違えていますかね?
また素数は数列の合計値を見て自分でその数列以上の素数を自分で打って数列に掛けて新たな数列を表示させるようにしたいのですが
みけCATがここに書いてくださいの所に書いてみたのですがあっていますでしょうか?
Re: 格納
Posted: 2015年10月25日(日) 17:02
by みけCAT
ライトニング さんが書きました:ご丁寧にこのうようなプログラミングを作っていただきありがとうございます。
プログラムを作っただけで、プログラミング(プログラムを書くこと)は作ってません。
ライトニング さんが書きました:自分で分かりやすいようにseq→kakunou elem→suretuに直したのですがなぜか上手くいかないです。
- elemを1箇所直しそこねています。
- print_seq関数の定義での名前を変えそこねています。
- suretuは数列ではなくその要素なので、print_suretu関数に単体で渡しても数列を出力することはできません。
ライトニング さんが書きました:これを実行したところsumが定義されていないとでます。int sumなどをつけてもうまくいかないです。どこが原因なのでしょうか?
sumが定義されていないのが原因です。
ライトニング さんが書きました:また素数は数列の合計値を見て自分でその数列以上の素数を自分で打って数列に掛けて新たな数列を表示させるようにしたいのですが
みけCATがここに書いてくださいの所に書いてみたのですがあっていますでしょうか?
sumを適切に渡しても間違っています。suretuも定義されていないですし、main関数のローカル変数suretuをグローバルにしたとしてもsuretu*xは増加数列にxを掛け合わせたものではありません。
さらに、sum>xという条件式もおかしいです。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int get_prime(int sum); /* sum以上の素数を得る */
void print_suretu(const char *title, const int *kakunou, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を得る */
x = get_prime(sum);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", kakunou, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
if (scanf("%d",&x) != 1)
{
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
Re: 格納
Posted: 2015年10月26日(月) 14:17
by ライトニング
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
コード:
int i;
int flag=0;
if (x >= sum)
for( i=2;i<x;++i ) {
if( x%i==0 ) {
flag = 1;
break;
else
puts("xは素数ではありません。");
みけCATさんが書いてくれたプログラミングのここの部分に自分のおもう素数判定をつくってみたのですが
「73行目」で記述エラーを発見しました。
「identifier」を付け忘れています
というエラーがでてしまいます。何故でしょうか?
Re: 格納
Posted: 2015年10月26日(月) 17:07
by みけCAT
ライトニング さんが書きました:「73行目」で記述エラーを発見しました。
「identifier」を付け忘れています
というエラーがでてしまいます。何故でしょうか?
おそらくelseに対応するifが無いからですね。
中かっこの対応に注意してください。
Re: 格納
Posted: 2015年10月26日(月) 18:04
by ライトニング
コード:
int i,flag;
for( i=2;i<x;++i ) {
if( x%i==0 ) {
flag = 1;
break;
}
}
if( flag==0 )
printf("%d は素数です。\n",x);
else
printf("%d は素数ではありません。\n",x);
このようにかいてみたのですがこれだと全然関係ないところの
「81行目」で記述エラーを発見しました。
「;」を付け忘れていますとエラーが
おきてしまいます。int i;の宣言場所が悪いのでしょうか?
Re: 格納
Posted: 2015年10月26日(月) 18:35
by Rittai_3D
全体のコードが無いと何行目と書かれても分からないので、全体のコードを載せてください。
ライトニング さんが書きました:int i;の宣言場所が悪いのでしょうか?
ぱっと見は問題が無いように思います。
どうしてそのように思われたのですか?
オフトピック
ブロックの省略はバグのもとですので、一行だから、と省略しないで書いた方がよいと思います。
Re: 格納
Posted: 2015年10月26日(月) 22:38
by みけCAT
ライトニング さんが書きました:コード:
int i,flag;
for( i=2;i<x;++i ) {
if( x%i==0 ) {
flag = 1;
break;
}
}
if( flag==0 )
printf("%d は素数です。\n",x);
else
printf("%d は素数ではありません。\n",x);
このようにかいてみたのですがこれだと全然関係ないところの
「81行目」で記述エラーを発見しました。
「;」を付け忘れていますとエラーが
おきてしまいます。int i;の宣言場所が悪いのでしょうか?
周りの状況がわからないのでわかりません。
とりあえず、警告をエラーとみなさなければコンパイルエラーにはならないはずですが、flagを初期化しないのはまずいと思います。
Re: 格納
Posted: 2015年10月26日(月) 22:48
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int get_prime(int sum); /* sum以上の素数を得る */
void print_suretu(const char *title, const int *kakunou, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を得る */
x = get_prime(sum);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", kakunou, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
if (scanf("%d",&x) != 1)
{
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
int i,flag;
for( i=2;i<x;++i ) {
if( x%i==0 ) {
flag = 1;
break;
}
}
if( flag==0 )
printf("%d は素数です。\n",x);
else
printf("%d は素数ではありません。\n",x);
}
void print_suretu(const char *title, const int *kakunou, int num)
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
「81行目」で記述エラーを発見しました。
「;」を付け忘れています。
今の状態はこの様な状況です。int iを下にも宣言してるのでint iの宣言場所が悪いのではないかと思いました。
Re: 格納
Posted: 2015年10月27日(火) 00:16
by かずま
インデントがぐちゃぐちゃなので、これをちゃんとすると、
コード:
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;) {
if (scanf("%d", &x) != 1) {
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
int i, flag;
for (i = 2; i < x; ++i) {
if (x % i == 0) {
flag = 1;
break;
}
}
if (flag == 0)
printf("%d は素数です。\n", x);
else
printf("%d は素数ではありません。\n", x);
}
void print_suretu(const char *title, const int *kakunou, int num)
int i;
for (i = 0; i < num; i++) {
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
22~24行目を次のように修正してみてください。
コード:
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
Re: 格納
Posted: 2015年10月27日(火) 00:20
by みけCAT
- get_prime関数内のiの宣言位置はC99以降であれば問題ありません。
- printf("%d は素数ではありません。\n",x);の後にfor文の{に対応する}が抜けています。
- void print_suretu(const char *title, const int *kakunou, int num)の後に{が抜けています。
Re: 格納
Posted: 2015年10月27日(火) 17:33
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int get_prime(int sum); /* sum以上の素数を得る */
void print_suretu(const char *title, const int *kakunou, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を得る */
x = get_prime(sum);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", kakunou, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;) {
if (scanf("%d", &x) != 1) {
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
int i, flag;
for (i = 2; i < x; ++i) {
if (x % i == 0) {
flag = 1;
break;
}
}
if (flag == 0)
printf("%d は素数です。\n", x);
else
printf("%d は素数ではありません。\n", x);
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++) {
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
ご指摘ありがとうございます。手直しをし動かしてみたのですが素数を入力してもどの数字も素数ではありませんとされてしまいます。
素数判定できていないということでしょうか?
Re: 格納
Posted: 2015年10月27日(火) 17:47
by box
ライトニング さんが書きました:
ご指摘ありがとうございます。手直しをし動かしてみたのですが素数を入力してもどの数字も素数ではありませんとされてしまいます。
素数判定できていないということでしょうか?
うそ~ん。それ以前の問題で、最後に投稿されたコードはコンパイルできないはずです。
なぜなら、
ライトニング さんが書きました:コード:
void print_suretu(const char *title, const int *kakunou, int num)
void print_suretu(const char *title, const int *kakunou, int num)
print_suretu関数の定義が複数あるからです。
質問者さんのところで「素数を入力してもどの数字も素数ではありません」という現象が起きるコードを
正しく貼ってください。
Re: 格納
Posted: 2015年10月27日(火) 17:58
by usao
No21の回答で
>flagを初期化しないのはまずいと思います。
と指摘されています.
適切に初期化してみてはいかがでしょう.
Re: 格納
Posted: 2015年10月27日(火) 22:28
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int get_prime(int sum); /* sum以上の素数を得る */
void print_suretu(const char *title, const int *kakunou, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を得る */
x = get_prime(sum);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", kakunou, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;) {
if (scanf("%d", &x) != 1) {
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
int i, flag;
for (i = 2; i < x; ++i) {
if (x % i == 0) {
flag = 1;
break;
}
}
if (flag == 0)
printf("%d は素数です。\n", x);
else
printf("%d は素数ではありません。\n", x);
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++) {
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
この状態でコンパイル出来たのですがおかしいですかね?
Re: 格納
Posted: 2015年10月27日(火) 22:43
by box
ライトニング さんが書きました:
この状態でコンパイル出来たのですがおかしいですかね?
おかしいと思います。
全く同じ関数が2個あってコンパイルが通るなんて話は聞いたことがありません。
ついでに、インデントもおかしいと思います。
Re: 格納
Posted: 2015年10月27日(火) 22:50
by box
くだんのコードは、結局 ↓ と同じことをしているわけですが、コンパイルは通りません。
少なくとも当方のところでは。
コード:
#include <stdio.h>
void f(void);
void f(void)
{
printf("f() was called.\n");
}
void f(void)
{
printf("f() was called.\n");
}
int main(void)
{
f();
return 0;
}
Re: 格納
Posted: 2015年10月27日(火) 23:08
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int get_prime(int sum); /* sum以上の素数を得る */
void print_suretu(const char *title, const int *kakunou, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を得る */
x = get_prime(sum);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", kakunou, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;) {
if (scanf("%d", &x) != 1) {
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
int i, flag;
for (i = 2; i < x; ++i) {
if (x % i == 0) {
flag = 1;
break;
}
}
if (flag == 0)
printf("%d は素数です。\n", x);
else
printf("%d は素数ではありません。\n", x);
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++) {
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
こういうことでしょうか?
Re: 格納
Posted: 2015年10月29日(木) 14:11
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void); /* 数列作成用の乱数を得る */
int get_prime(int sum); /* sum以上の素数を得る */
void print_suretu(const char *title, const int *kakunou, int num); /* 数列を出力する */
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
/* 数列を生成する */
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
/* 数列の全要素の合計以上の最小の素数を得る */
x = get_prime(sum);
/* yを適当に決める */
y = rand() % (x - 1) + 1; /* 1以上(x-1)以下の乱数を生成する */
/* 新たな数列を作る */
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
/* 作った数列とパラメータを出力する */
print_suretu("数列: ", kakunou, NUM);
printf("sum = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("新たな数列: ", newkakunou, NUM);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
if (scanf("%d",&x) != 1)
{
/* 入力エラー */
exit(1);
}
/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
int i, flag;
flag = 0;
for (i = 2; i < x; ++i) {
if (x % i == 0) {
flag = 1;
break;
}
}
if (flag == 0)
printf("%d は素数です。\n", x);
else
printf("%d は素数ではありません。\n", x);
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
何とか素数判定は出来ました。
けれど素数判定をするだけになってしまいその素数を数列にかけられないのですがどうすればよいでしょうか?
Re: 格納
Posted: 2015年10月29日(木) 15:33
by usao
>/* ここにxが素数かどうかを判定し、素数でないなら返さないようにするプログラムを書くとよい */
素数でないなら返さない ということですが,
だったら 素数である場合 はどうするんでしょうね?
あと,get_prime()の用途としては,
>/* 数列の全要素の合計以上の最小の素数を得る */
ということですから,get_prime()内での判定処理は「素数かどうか」だけでは不十分ですよね? きっと.
オフトピック
ご自身でやるべきことを注釈で書いてるわけですから
とりあえずその内容を実装すればいいんじゃないですか?
必要な処理に対応するコードをまだ書いてない段階で
>素数判定をするだけになってしまい
…とか言われても,そりゃそうでしょ,としか.
Re: 格納
Posted: 2015年10月29日(木) 16:30
by ライトニング
コード:
int i, flag;
flag = 0;
for (i = 2; i < x; ++i) {
if (x % i == 0) {
flag = 1;
break;
}
}
if (flag == 0)
printf("%d は素数をかけた数列は。\n",kakunou[NUM]* x);
else
printf("%d は素数ではありません。\n", x);
判定した素数をkakunou[NUM]にかけるようにしたいのですが、このようにしたのですがkakunouが宣言されていないとエラーをはかれたのですが
これより上に書いてあるプログラミンのkakunouには反映されるためにはどのようにしたらいいのでしょうか?素数判定の場所が悪いということでしょうか?
Re: 格納
Posted: 2015年10月29日(木) 17:51
by みけCAT
usao さんが書きました:あと,get_prime()の用途としては,
>/* 数列の全要素の合計以上の最小の素数を得る */
ということですから,get_prime()内での判定処理は「素数かどうか」だけでは不十分ですよね? きっと.
申し訳ありません。自分のコメントの更新し忘れです。
「最小の」は無視してください。
ライトニング さんが書きました:判定した素数をkakunou[NUM]にかけるようにしたいのですが
まずこのままではkakunou[NUM]は範囲外なので、判定した素数をkakunou[NUM]にかけるにはkakunouの要素数をNUM+1以上に修正してください。kakunou[NUM]の初期化もするべきです。
ライトニング さんが書きました:このようにしたのですがkakunouが宣言されていないとエラーをはかれたのですが
これより上に書いてあるプログラミンのkakunouには反映されるためにはどのようにしたらいいのでしょうか?
「プログラミン」が何かはよくわかりませんが、main関数のkakunouに反映させるためには、
素数をmain関数にget_prime関数の戻り値として渡し、main関数にkakunouに反映されるプログラムを追加するといいでしょう。
推奨はしませんが、kakunou(の先頭の要素のアドレス)をget_primeに渡してそれを使って反映されるプログラムを書いてもできます。
ライトニング さんが書きました:素数判定の場所が悪いということでしょうか?
いいえ。
オフトピック
usao さんが書きました:ご自身でやるべきことを注釈で書いてるわけですから
とりあえずその内容を実装すればいいんじゃないですか?
その注釈は、本当に「ご自身」で書いたものですか?
Re: 格納
Posted: 2015年10月29日(木) 18:36
by ライトニング
要素数を1上げるというのは#define NUM 10を#define NUMNUM 11にするということでしょうか?
またkakunou[NUM]の初期化はどこですべきでしょうか?
Re: 格納
Posted: 2015年10月29日(木) 19:09
by みけCAT
ライトニング さんが書きました:要素数を1上げるというのは#define NUM 10を#define NUMNUM 11にするということでしょうか?
全然違います。
- 名前をNUMからNUMNUMに変えてはいけません。
- 名前と置き換える内容の区切りを全角スペースにしてはいけません。
- NUMの値を変えても意味無いです。int kakunou[NUM]をint kakunou[NUM + 1]にするといいでしょう。
ライトニング さんが書きました:またkakunou[NUM]の初期化はどこですべきでしょうか?
「判定した素数をkakunou[NUM]にかける」前の適当なところですればいいでしょう。
Re: 格納
Posted: 2015年10月29日(木) 22:29
by ライトニング
kakunou[NUM+1]にし
kakunou[NUM]=0;
にしてみたのですがkakunouが定義されていませんとでてしまいます....
Re: 格納
Posted: 2015年10月30日(金) 14:24
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("",sum);
}
x = get_prime(sum);
scanf("%d",&y);
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
print_suretu("秘密鍵: ", kakunou, NUM);
printf("合計 = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("公開鍵: ", newkakunou, NUM);
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
28行目のscanf("%d",&y);の所の%dの前に値は?などをするとyの値が変な値になり自分で入力することができないようになってしまいます。
後x,yの素数判定とxmodyをかけた数列にxmodyの逆元をかけるようにしたいのですがどうすればいいでしょうか?
本当に質問ばかりで荒らしみたいになってますが
今週中にはどうしても完成させなくてはいけなくて自分の力では間に合いそうにならずお力を貸して頂きたいです。
よろしくお願いいたします。
あまりにも邪魔なようでしたらトピックを削除して頂いても構いません。
Re: 格納
Posted: 2015年10月30日(金) 17:16
by みけCAT
ライトニング さんが書きました:28行目のscanf("%d",&y);の所の%dの前に値は?などをするとyの値が変な値になり自分で入力することができないようになってしまいます。
本当ですか?
そのしたやつを入力しても変な値になりますか?
(例:scanf("値は?%d",&y);と書き換えたなら、「値は?37」と入力する(鍵括弧は含まない))
プロンプトを表示したいなら、scanfではなくprintfなどの出力用の関数で出力するといいでしょう。
ライトニング さんが書きました:後x,yの素数判定とxmodyをかけた数列にxmodyの逆元をかけるようにしたいのですがどうすればいいでしょうか?
そういう処理をするコードを書いてコンパイルすればいいです。
(コードを書き換えても保存し、コンパイル(アセンブルやリンクを含む)をしないと実行形式ファイルに反映されません。私もよくミスっています…。)
Re: 格納
Posted: 2015年10月30日(金) 21:14
by ライトニング
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("",sum);
}
x = get_prime(sum);
scanf("値は?%d",&y);
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
print_suretu("秘密鍵: ", kakunou, NUM);
printf("合計 = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("公開鍵: ", newkakunou, NUM);
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
これにするとxを入力したら勝手にyが出されてyが変な値になってしまいます...値は?をつけただけです。
またxを入力するときに値は?などを聞きたい場合どこにいれればいいのでしょうか?
Re: 格納
Posted: 2015年10月30日(金) 22:27
by みけCAT
ライトニング さんが書きました:これにするとxを入力したら勝手にyが出されてyが変な値になってしまいます...値は?をつけただけです。
scanfの書式指定文字列に余計な文字列を入れてはいけません。値は?を消してください。
ライトニング さんが書きました:またxを入力するときに値は?などを聞きたい場合どこにいれればいいのでしょうか?
xの入力を読み込む文の直前あたりにいれればいいでしょう。
Re: 格納
Posted: 2015年10月31日(土) 17:45
by ライトニング
ではyの値を入力するときに何か文字をつけるのは駄目って事でしょうか?
初歩的申し訳ないのですがこの中でxを入力するよう書かれているのはどの部分なのでしょうか?
x = get_prime(sum);この部分でしょうか?
Re: 格納
Posted: 2015年10月31日(土) 17:57
by かずま
ライトニング さんが書きました:コード:
printf("",sum);
}
x = get_prime(sum);
scanf("値は?%d",&y);
無茶苦茶ですね。
コード:
printf("%d\n", sum);
}
x = get_prime(sum);
printf("値は?"); scanf("%d", &y);
Wikipediaの
Merkle-Hellmanナップサック暗号に書いてる通りに実装してみたつもりですが、
すべてのビットが 1 の場合に復号できません。
コード:
#include <stdio.h>
#include <stdlib.h>
#define N 10
int gcd(int a, int b)
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
void print_array(const char *name, int a[N])
{
int i;
printf("%s = [", name);
for (i = 0; i < N; i++) printf(" %d", a[i]);
printf(" ]\n");
}
void print_bin(const char *name, int b)
{
int i;
printf("%s = [", name);
for (i = N; --i >= 0; ) printf(" %d", b >> i & 1);
printf(" ]\n");
}
int input_data(const char *name, int *a)
{
int i = 0;
char buf[256];
printf("\nEnter %d binary digits\n", N);
printf("%.*s\n", N, "123456789.123456789.123456789.12");
if (!fgets(buf, sizeof buf, stdin)) exit(1);
*a = 0;
for (i = 0; i < N && buf[i] == '0' || buf[i] == '1'; i++)
if (buf[i] == '1') *a |= 1 << (N - i - 1);
return i == N;
}
void create_keys(int b[N], int w[N], int *q, int *r)
{
int i, sum = 0;
for (i = 0; i < N; i++)
sum += w[i] = sum + 1 + rand() % 3;
*q = sum;
print_array(" w", w);
printf(" q = %d\n", *q);
while (1) {
printf("Enter r: ");
if (scanf("%d", r) != 1) exit(1);
if (gcd(*r, *q) == 1) break;
printf("not coprime\n");
}
while (getchar() != '\n') ;
for (i = 0; i < N; i++)
b[i] = (long long)*r * w[i] % *q;
}
int encrypt(int a, int b[N])
{
int i, c = 0;
for (i = 0; i < N; i++)
if (a >> (N - i - 1) & 1) c += b[i];
return c;
}
int decrypt(const int c, const int w[N], int q, int r)
{
int i, s = 0, c1 = (long long)c * inverse(r, q) % q;
for (i = N; --i >= 0; )
if (c1 >= w[i]) {
c1 -= w[i];
s |= 1 << (N - i - 1);
}
return s;
}
int main(void)
{
int w[N], q, r; // public key
int b[N]; // public key
int a; // input data
int c; // encrypted data
int s; // decrypted data
create_keys(b, w, &q, &r);
printf("Public key\n");
print_array(" w", w);
printf(" q = %d\n r = %d\n", q, r);
printf("Private key\n");
print_array(" b", b);
while (input_data("a", &a)) {
print_bin(" a", a);
c = encrypt(a, b);
print_bin(" c", c);
s = decrypt(c, w, q, r);
print_bin(" s", s);
}
return 0;
}
N は、あまり大きくするとオーバーフローします。
多倍長計算が必要でしょう。
Re: 格納
Posted: 2015年10月31日(土) 18:03
by みけCAT
ライトニング さんが書きました:ではyの値を入力するときに何か文字をつけるのは駄目って事でしょうか?
「何か文字をつける」とはどういうことですか?プログラムの話ですか?それとも実行時の入力の話ですか?
ライトニング さんが書きました:この中でxを入力するよう書かれているのはどの部分なのでしょうか?
コード:
if (scanf("%d",&x) != 1)
{
exit(1);
}
この部分です。
Re: 格納
Posted: 2015年10月31日(土) 18:15
by かずま
すみません。Public key と Private key が間違っていました。
コード:
int main(void)
{
int w[N], q, r; // private key <-- ここ訂正
int b[N]; // public key
int a; // input data
int c; // encrypted data
int s; // decrypted data
create_keys(b, w, &q, &r);
printf("Private key\n"); // <-- ここ訂正
print_array(" w", w);
printf(" q = %d\n r = %d\n", q, r);
printf("Public key\n"); // <-- ここ訂正
print_array(" b", b);
Re: 格納
Posted: 2015年10月31日(土) 23:17
by かずま
訂正です。
ナップサック暗号のプログラムの 47行目、括弧を追加してください。
コード:
for (i = 0; i < N && (buf[i] == '0' || buf[i] == '1'); i++)
Re: 格納
Posted: 2015年11月01日(日) 09:40
by かずま
57行目の *q = sum; を *q = sum + 1 + rand() % 4; に変更したら、
すべてのビットが 1 の場合も復号できました。
Re: 格納
Posted: 2015年11月01日(日) 14:49
by ライトニング
if (scanf("%d",&x) != 1) このxの実行のときの入力時に値は?などを聞く場合はどうしたらいいのでしょうか?
かずまさんご回答ありがとうございます。
自分のC言語の理解が乏しすぎてかずまさんのソースの理解が全く追いついてない状況です...
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("",sum);
}
x = get_prime(sum);
printf("値は?"); scanf("%d", &y);
xmody = x % y;
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
}
print_suretu("秘密鍵: ", kakunou, NUM);
printf("合計 = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("公開鍵: ", newkakunou, NUM);
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
かずまさん的にここから素数判定しnewkakunouを復号するのはは難しいでしょうか?
Re: 格納
Posted: 2015年11月01日(日) 14:55
by みけCAT
ライトニング さんが書きました:if (scanf("%d",&x) != 1) このxの実行のときの入力時に値は?などを聞く場合はどうしたらいいのでしょうか?
そういうコードに書き換え、その書き換えたプログラムをコンパイル及び実行すればいいでしょう。
if文の前にprintfで質問文を出力する処理を入れれば多分それっぽくなるでしょう。
Re: 格納
Posted: 2015年11月01日(日) 15:46
by ライトニング
出来ました。ありがとうございました。
コード:
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
後疑問に思っていたのですがこの部分は何を表しているのでしょうか?constは調べて定数にしたいという意味が分かったのですが
char*titleや i==0? の?などの部分がよくわかりません....
Re: 格納
Posted: 2015年11月01日(日) 15:56
by みけCAT
ライトニング さんが書きました:後疑問に思っていたのですがこの部分は何を表しているのでしょうか?
titleという見出しを付けて配列kakunouの要素をnum個出力する処理を表しています。
ライトニング さんが書きました:char*titleや i==0? の?などの部分がよくわかりません....
char*titleはchar型のデータを指すポインタのtitleという引数です。
?は三項演算子であり、A ? B : CはAが真の時はBの値になり、Aが偽の時はCの値になります。
Re: 格納
Posted: 2015年11月01日(日) 16:15
by かずま
ライトニング さんが書きました:if (scanf("%d",&x) != 1) このxの実行のときの入力時に値は?などを聞く場合はどうしたらいいのでしょうか?
No.44 の次の回答は見ていないのですか?
かずま さんが書きました:ライトニング さんが書きました:コード:
printf("",sum);
}
x = get_prime(sum);
scanf("値は?%d",&y);
無茶苦茶ですね。
コード:
printf("%d\n", sum);
}
x = get_prime(sum);
printf("値は?"); scanf("%d", &y);
ライトニング さんが書きました:かずまさん的にここから素数判定しnewkakunouを復号するのはは難しいでしょうか?
難しくありませんが、その前に、次の [2], [5], [9] の意味を説明してください。
ライトニング さんが書きました: コード:
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
Re: 格納
Posted: 2015年11月01日(日) 16:25
by かずま
かずま さんが書きました:難しくありませんが、その前に、次の [2], [5], [9] の意味を説明してください。
それから、あなたのプログラムの入力と、期待する出力がどういうもの
であるかも示してください。いくつかのサンプルもお願いします。
Re: 格納
Posted: 2015年11月01日(日) 17:42
by かずま
とりあえず、復号してみました。
素数判定の代わりに、互いに素かどうかの判定をしています。もちろん、
x が素数であれば、x と y は互いに素になりますが、そこまでしたいですか?
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
#if 1 // 追加
int gcd(int a, int b);
int inverse(int a, int b);
#endif
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("",sum);
}
x = get_prime(sum);
#if 0
printf("値は?"); scanf("%d", &y);
#else // 修正
while (1) {
printf("y の値は? "); scanf("%d", &y);
if (gcd(x, y) == 1) break;
printf("x と y が互いに素ではありません。\n");
}
#endif
//xmody = x % y; // <- 削除
for (i = 0; i < NUM; i++)
{
#if 0
newkakunou[i] = kakunou[i] * xmody;
#else // 修正
newkakunou[i] = (long long)kakunou[i] * y % x;
#endif
}
print_suretu("秘密鍵: ", kakunou, NUM);
printf("合計 = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("公開鍵: ", newkakunou, NUM);
#if 0
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
#else // 修正
xmody = newkakunou[2]+newkakunou[5]+newkakunou[9];
printf("暗号: %d\n", xmody);
xmody = (long long)xmody * inverse(y, x) % x;
printf("復号:");
for (i = NUM; --i >= 0; ) {
if (xmody >= kakunou[i]) {
xmody -= kakunou[i];
printf(" [%d]", i);
}
}
printf("\n");
#endif
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
printf("x の値は? ");
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
#if 1 // 追加
int gcd(int a, int b)
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
#endif
実行結果
コード:
数列の項の合計 = 4881
x の値は? 4883
y の値は?1234
秘密鍵: 2, 11, 18, 41, 74, 155, 302, 611, 1223, 2444
合計 = 4881, x = 4883, y = 1234
公開鍵: 2468, 3808, 2680, 1764, 3422, 833, 1560, 1992, 335, 3085
暗号: 6598
復号: [9] [5] [2]
Re: 格納
Posted: 2015年11月01日(日) 19:03
by ライトニング
ご回答ありがとうございます。No.44 の回答をみてyの値は?はできることができました。
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
は自分(送信者)で任意で数列の要素のどれかを選び合計値を作ります。2,5,9でなくても何でも大丈夫です。
その合計値を受信者は数列の要素を組み合わせてその送信者が選んだ合計値を当てる?というのが目的です。
復号はnewkakunouにxmodyの逆元をかけてkakunouに戻してこの場合だと2,5,9の値を足し早あわせた値を入力して合計値を当てれば復号完了と言う状態です。
説明が下手で申し訳ないです。
Re: 格納
Posted: 2015年11月01日(日) 19:49
by かずま
ライトニング さんが書きました:ご回答ありがとうございます。No.44 の回答をみてyの値は?はできることができました。
でも、No.49 でまた同じ質問をしていますよ。今度は x の値ですが。
ライトニング さんが書きました:復号はnewkakunouにxmodyの逆元をかけてkakunouに戻して
そうじゃないでしょ。
(mod x) の合同における「y の逆元」を掛けて、さらにその結果を x で割った余りが、
「 選ばれた kakunou
の和」になるんですよ。
Re: 格納
Posted: 2015年11月01日(日) 21:02
by ライトニング
xのほうもできました。すいません。
自分のイメージとしては
コード:
int x=newkakunou[2]+newkakunou[5]+newkakunou[9];
int z;
scanf("%d",&z);
if(x=z);
printf("復号成功");
else
printf("失敗");
自分のイメージとしてはこういう状態で復号したいと思ってるのですが....
Re: 格納
Posted: 2015年11月01日(日) 21:34
by みけCAT
ライトニング さんが書きました:自分のイメージとしては
コード:
int x=newkakunou[2]+newkakunou[5]+newkakunou[9];
int z;
scanf("%d",&z);
if(x=z);
printf("復号成功");
else
printf("失敗");
自分のイメージとしてはこういう状態で復号したいと思ってるのですが....
- if文の中で比較ではなく代入をしている
- if文の後に余計なセミコロンがついているので、常に「復号成功」が表示されると見せかけて余計なelseがあるのでコンパイルエラーになる
というようなひどいバグがある状態で復号したいということですか?
Re: 格納
Posted: 2015年11月02日(月) 04:07
by かずま
ライトニング さんが書きました:コード:
int x=newkakunou[2]+newkakunou[5]+newkakunou[9];
int z;
scanf("%d",&z);
if(x=z);
printf("復号成功");
else
printf("失敗");
自分のイメージとしてはこういう状態で復号したいと思ってるのですが....
そのイメージには、復号の処理が全くありません。
10ビットのデータを暗号化して送信したい時に使用する
公開鍵の newkakunou は、10個の数値から成ります。
暗号化して送信したい 10ビットのデータが 0010010001 の時、
先頭を 0番目として、2番目、5番目、9番目が 1 なので
公開鍵を使って、暗号化されたデータ x を作っています。
z の値を入力させて、それを暗号化データと比較するだけでどうして
復号が成功か失敗か判定できるんですか?
もう提出期限が過ぎたのかもしれませんが、これは何かの課題なのでしょう?
その全文を提示してもらえませんか?
Re: 格納
Posted: 2015年11月02日(月) 13:11
by ライトニング
課題の内容はMH暗号を作るという課題です。
すいません自分のなかでのMH暗号の解釈が大分間違っているのかもしれません。
かずまさんが正しい復号だと思います。申し訳ないです。
ほとんど今までも丸投げ質問でしたが最後の復号部分の作り方を教えていただけないでしょうか?
C言語の参考書などを読んでるのですがMH暗号を理解するのも難しくそれをプログラミングで作ってみるというのもとても難しく
苦戦してる状態です。
Re: 格納
Posted: 2015年11月03日(火) 17:53
by かずま
ライトニング さんが書きました:課題の内容はMH暗号を作るという課題です。
「MH暗号を作る」が課題の全文ですか?
こういう入力に対して、こういう出力が表示されるように、
などの指定はないんですか?
プログラミング言語の指定もないんですか?
ライトニング さんが書きました:ほとんど今までも丸投げ質問でしたが最後の復号部分の作り方を教えていただけないでしょうか?
No. 44 のプログラムの 79~88行目と、No.55 のプログラムの 59~67行目で既に
作り方を教えたはずなのですが、見ていないのですか?
分からないところは質問してくれれば、なんでも答えるつもりでいるんですけど。
Re: 格納
Posted: 2015年11月03日(火) 18:05
by かずま
ライトニング さんが書きました:
C言語の参考書などを読んでるのですがMH暗号を理解するのも難しく
Wikipediaの
Merkle-Hellmanナップサック暗号 のページの左側に「他言語版」が
あって「English」を選ぶと、そこには、小学生でもわかりそうな具体的な例が
載っていて、詳しく解説されています。
Re: 格納
Posted: 2015年11月04日(水) 02:12
by かずま
No.44 のプログラムに、間違い発見。
暗号データを 2進 10ビットで表示していますが、これは公開鍵 b の部分和なので
もっと大きな数です。表示を改めます。
また、r の値をユーザが入力するのではなく、内部で求めるようにしました。
コード:
#include <stdio.h>
#include <stdlib.h>
#define N 10
int gcd(int a, int b)
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
void print_array(const char *name, int a[N])
{
int i;
printf("%s = [", name);
for (i = 0; i < N; i++) printf(" %d", a[i]);
printf(" ]\n");
}
void print_bin(const char *name, int b)
{
int i;
printf("%s = [", name);
for (i = N; --i >= 0; ) printf(" %d", b >> i & 1);
printf(" ]\n");
}
int input_data(const char *name, int *a)
{
int i = 0;
char buf[256];
printf("\nEnter %d binary digits\n", N);
printf("%.*s\n", N, "123456789.123456789.123456789.12");
if (!fgets(buf, sizeof buf, stdin)) exit(1);
*a = 0;
for (i = 0; i < N; i++)
if (buf[i] == '1') *a |= 1 << (N - i - 1);
else if (buf[i] != '0') break;
return i == N;
}
void generate_keys(int b[N], int w[N], int *q, int *r)
{
int i, sum = 0;
for (i = 0; i < N; i++)
sum += w[i] = sum + 1 + rand() % 10;
*q = sum + 1 + rand() % 10;
print_array(" w", w);
printf(" sum = %d\n", sum);
for (*r = *q /2; gcd(*r, *q) != 1; ++*r) ;
for (i = 0; i < N; i++)
b[i] = (long long)*r * w[i] % *q;
}
int encrypt(int a, int b[N])
{
int i, c = 0;
for (i = 0; i < N; i++)
if (a >> (N - i - 1) & 1) c += b[i];
return c;
}
int decrypt(const int c, const int w[N], int q, int r)
{
int i, s = 0, c1 = (long long)c * inverse(r, q) % q;
for (i = N; --i >= 0; )
if (c1 >= w[i]) {
c1 -= w[i];
s |= 1 << (N - i - 1);
}
return s;
}
int main(void)
{
int w[N], q, r; // private key
int b[N]; // public key
int a; // input data
int c; // encrypted data
int s; // decrypted data
generate_keys(b, w, &q, &r);
printf("Private key\n");
print_array(" w", w);
printf(" q = %d\n r = %d\n", q, r);
printf("Public key\n");
print_array(" b", b);
while (input_data("a", &a)) {
print_bin(" a", a);
c = encrypt(a, b);
printf(" c = %d\n", c);
s = decrypt(c, w, q, r);
print_bin(" s", s);
}
return 0;
}
10ビットの 2進数をいろいろ入力してみてください。
Re: 格納
Posted: 2015年11月04日(水) 13:43
by ライトニング
指定されたのはC言語です。
内容はとりあえずMH暗号を作れとの事です。
後実行してみたのですが
warning: format string is empty [-Wformat-zero-length]
printf("",sum);
^~
こういうエラーを吐かれてしまったのですがどう直せばいいのでしょうか?
Re: 格納
Posted: 2015年11月04日(水) 15:47
by かずま
ライトニング さんが書きました:後実行してみたのですが
warning: format string is empty [-Wformat-zero-length]
printf("",sum);
^~
こういうエラーを吐かれてしまったのですがどう直せばいいのでしょうか?
プログラムは複数あります。
どのプログラムを実行したのか書きましょう。
エラーメッセージは、出たものをそのままコピペしましょう。
ファイル名と「行番号」があるはずです。
英語だからといって、内容を読まないのですか?
「警告: 書式文字列がカラです。printf("",sum);」
どう直せばいいかは、No.44 で回答済みです。見ていないんですか?
Re: 格納
Posted: 2015年11月09日(月) 14:17
by ライトニング
すいませんNo44の通りやったら治りました。すいません。
また復号は公開鍵の中から自分で何か部分和を作りその部分和にxmodyの逆元をかけると秘密鍵の数列の要素の部分和になっているみたいです。
その部分和を秘密鍵の大きい値から順番に引けるか判定をしていき最終的に0になればいいみたいです。
それをNo.55の回答でうまくだしたいのですがどうすればいいのでしょうか?
Re: 格納
Posted: 2015年11月09日(月) 14:18
by ライトニング
すいませんNo44の通りやったら治りました。すいません。
また復号は公開鍵の中から自分で何か部分和を作りその部分和にxmodyの逆元をかけると秘密鍵の数列の要素の部分和になっているみたいです。
その部分和を秘密鍵の大きい値から順番に引けるか判定をしていき最終的に0になればいいみたいです。
それをNo.55の回答でうまくだしたいのですがどうすればいいのでしょうか?
Re: 格納
Posted: 2015年11月09日(月) 17:38
by かずま
ライトニング さんが書きました:
また復号は公開鍵の中から自分で何か部分和を作りその部分和にxmodyの逆元をかけると秘密鍵の数列の要素の部分和になっているみたいです。
「公開鍵の中から自分で何か部分和を作り」ですか。「何か」はないでしょう。
暗号化したい 10ビットのデータ(これを平文と言います)のうち、1の立っている
ビットが何番目にあるかで、公開鍵の何番目の数値を使うかを決めるんです。
そうしてできた部分和が暗号化データ(暗号文と言います)です。
ここからが復号です。
「xmodyの逆元」という意味不明の用語を使わないでください。
「x を法とする合同の y の逆元」とか「モジュロ x の y の逆元」とか
「mod x における y の逆元」と言いましょう。
暗号データ(部分和)にその「y の逆元」を掛けて、x で割った余りが
秘密鍵の部分和になります。
ライトニング さんが書きました:
その部分和を秘密鍵の大きい値から順番に引けるか判定をしていき最終的に0になればいいみたいです。
0 にはなるんです。もっと重要なのは、何番目が引けたかということで、それに
よって 10ビットのデータの何番目が 1 なのかが分かり、元の平文が復号できた
ことになります。
ライトニング さんが書きました:
それをNo.55の回答でうまくだしたいのですがどうすればいいのでしょうか?
[9] [5] [2] とうまく出てるじゃないですか。
0010010001 と表示したいということですか?
No.44 の訂正版である No.64 のプログラムの中の decrypt() や print_bin()
を参考にすればいいだけのことでは?
それとも、全部引き終わったらゼロになったことを確認したいのですか?
それなら、No.64 のプログラムでは復号の最後で if (c1 == 0) printf("OK\n");。
No.55 のプログラムなら、if (xmody == 0) printf("OK\n"); でいいのでは?
Re: 格納
Posted: 2015年11月11日(水) 13:24
by ライトニング
復号結果の[9] [5] [2] はどのような判定をしてこれが出力されたのでしょうか?
また何箇所か理解できない部分があるんですが
1.(long long)kakunou
2.for (i = NUM; --i >= 0; ) {
if (xmody >= kakunou) {
xmody -= kakunou;
printf(" [%d]", i);
3.for (;;)
4.while (b)
r = a % b, a = b, b = r;
5.int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
この辺りのプログラミングの内容がよくわからないのですがどういう事なのでしょうか?
Re: 格納
Posted: 2015年11月12日(木) 02:14
by かずま
ライトニング さんが書きました:復号結果の[9] [5] [2] はどのような判定をしてこれが出力されたのでしょうか?
No.55 のプログラムですね。
コード:
printf("暗号: %d\n", xmody);
xmody = (long long)xmody * inverse(y, x) % x;
printf("復号:");
for (i = NUM; --i >= 0; ) {
if (xmody >= kakunou[i]) {
xmody -= kakunou[i];
printf(" [%d]", i);
}
}
printf("\n");
最初の xmody は暗号文です。
これに、(mod x) における y の逆元である inverse(y, x) を掛けて、
その結果を x で割った余りが、秘密鍵である kakunou の部分和です。
ここでは、それをまた xmody に代入しています。
超増加列である kakunou の項の大きいほうから順に、すなわち
kakunou[N-1], kakunou[N-2], ..., kakunou[0] を xmody から、
引けるなら引いて、その位置を表示しています。
これが、MHナップサック暗号の復号手順で、復号した平文の
1の立っているビットの位置だけを表示したものです。
ライトニング さんが書きました:1.(long long)kakunou
コード:
#else // 修正
newkakunou[i] = (long long)kakunou[i] * y % x;
#endif
公開鍵を作るところですね。
NUM が 10 の場合、kakunou
や y は 1万未満の値なので kakunou * y は
1億未満の値となり、32ビットの int でオーバーフローしませんが、たとえば、
NUM が 20 の場合、kakunou や y は 1億未満の値なので kakunou * y は
32ビットの int の最大値である 2147483647 を超えてしまいます。
そこで、掛け算をする前に kakunou の値を (long long) すなわち 64ビットの
int に変換して、y を掛けてもオーバーフローしないようにしています。その
掛け算の結果を y で割ると、また 32ビットの int に収まる小さな値になります。
ライトニング さんが書きました:2.for (i = NUM; --i >= 0; ) {
if (xmody >= kakunou) {
xmody -= kakunou;
printf(" [%d]", i);
既に説明しました。
ライトニング さんが書きました:3.for (;;)
コード:
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
printf("x の値は? ");
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
「for(;;) 文」は「while (1) 文」と同様に、文を繰り返し実行します。
その無限ループからは、return文や break文や exit関数の呼び出しなどで
抜けだします。
ライトニング さんが書きました:4.while (b)
r = a % b, a = b, b = r;
コード:
int gcd(int a, int b)
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
最大公約数を求めるところですね。
次のように書いても同じです。これは説明不要ですよね。
コード:
int gcd(int a, int b)
{
int r;
while (b != 0) {
r = a % b;
a = b;
b = r;
}
return a;
}
ライトニング さんが書きました:5.int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
コード:
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
(mod b) における a の逆元を求めるところですね。
#define STEP(a, b) は関数型マクロと言って、これ以降に、STEP という名前が
出てくるところはすべて (t = a - q * b, a = b, b = t) の文字列に置き換え
ますが、引数の a, b は与えられた引数に置き換えます。
ということで次のようになります。
コード:
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
q = z1 / z2,
(t = x1 - q * x2, x1 = x2, x2 = t),
(t = y1 - q * y2, y1 = y2, y2 = t),
(t = z1 - q * z2, z1 = z2, z2 = t);
return x2 < 0 ? x2 + b : x2;
}
さらに 三項演算子 ? : を if文に置き換えて、分かりやすくすると、
コード:
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1) {
q = z1 / z2;
t = x1 - q * x2, x1 = x2, x2 = t;
t = y1 - q * y2, y1 = y2, y2 = t;
t = z1 - q * z2, z1 = z2, z2 = t;
}
if (x2 < 0)
return x2 + b;
else
return x2;
}
Re: 格納
Posted: 2015年11月12日(木) 04:03
by かずま
かずま さんが書きました:#define STEP(a, b) は関数型マクロと言って、
「関数型マクロ」を「関数形式マクロ」に訂正します。
なお、#define NUM 10 のようなマクロを「オブジェクト形式
マクロ」と言います。これらは、JIS の規格書の用語です。
ISO では、object-like macro と function-like macro でした。
Re: 格納
Posted: 2015年11月21日(土) 21:40
by かずま
かずま さんが書きました:
コード:
#else // 修正
newkakunou[i] = (long long)kakunou[i] * y % x;
#endif
公開鍵を作るところですね。
NUM が 10 の場合、kakunou
や y は 1万未満の値なので kakunou * y は
1億未満の値となり、32ビットの int でオーバーフローしませんが、たとえば、
NUM が 20 の場合、kakunou や y は 1億未満の値なので kakunou * y は
32ビットの int の最大値である 2147483647 を超えてしまいます。
そこで、掛け算をする前に kakunou の値を (long long) すなわち 64ビットの
int に変換して、y を掛けてもオーバーフローしないようにしています。その
掛け算の結果を y で割ると、また 32ビットの int に収まる小さな値になります。
最後の文を次のように訂正します。
「その掛け算の結果を x で割ると、その余りは 32ビットの int に収まる小さな値になります。」
ところで、このトピックは解決にはならないんでしょうか?
少なくとも次のトピックは解決になっていいと思うんですが。
数列の作成 と mody逆演算
Re: 格納
Posted: 2015年11月25日(水) 22:13
by ライトニング
分かり易い説明ありがとうございます。
intget_primeやintgcdやint inverse のintの後の部分はどのような名前に変えてもいいんですかね?
関数?との見分けが出来てない部分が何個かありまして...
同様に(long long)xmodyのlong longの部分
void print_suretu(const char *title, const int *kakunou, int num)
const title const int
なども問題ないのでしょうか?
Re: 格納
Posted: 2015年11月25日(水) 22:24
by みけCAT
ライトニング さんが書きました:intget_primeやintgcdやint inverse のintの後の部分はどのような名前に変えてもいいんですかね?
C言語の識別子として有効な名前で、他の名前と被らなければいいでしょう。
ライトニング さんが書きました:同様に(long long)xmodyのlong longの部分
void print_suretu(const char *title, const int *kakunou, int num)
const title const int
なども問題ないのでしょうか?
はい。
typedefを用いてC言語の識別子として許される範囲で好きな名前をつけることができます。
Re: 格納
Posted: 2015年11月25日(水) 23:55
by ライトニング
int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int gcd(int a, int b);
int inverse(int a, int b);
ちなみに最初のこの部分を全部消しても動いたのですが
この部分自体も別に分かりやすく書いてるだけでいらないということでしょうか?
Re: 格納
Posted: 2015年11月26日(木) 00:09
by みけCAT
ライトニング さんが書きました:int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int gcd(int a, int b);
int inverse(int a, int b);
ちなみに最初のこの部分を全部消しても動いたのですが
この部分自体も別に分かりやすく書いてるだけでいらないということでしょうか?
NO: 55のコードなら、代わりにmain関数を一番下に持ってくれば、消してもいいでしょう。
Re: 格納
Posted: 2015年11月26日(木) 03:35
by かずま
ライトニング さんが書きました:
intget_primeやintgcdやint inverse のintの後の部分はどのような名前に変えてもいいんですかね?
関数?との見分けが出来てない部分が何個かありまして...
intget_prime ではなく、int get_prime ですね。質問は正確に書きましょう。
これは int に関連する名前を宣言しているところです。
名前は、英字で始まり英数字が続くという規則に従えば何でも構いません。
英字には、下線を含みます。だから、get_prime は OK。
int get_prime; と書けば、get_prime は int型の変数です。
int get_prime(int sum); と書けば、get_prime は、int型の値を返す関数です。
これらの宣言で、名前が変数名か関数名か、が分かります。
名前の後に ( がついている宣言の時は、その名前は関数名です。
見分けができてない部分とは具体的にどこでしょうか?
ライトニング さんが書きました:
同様に(long long)xmodyのlong longの部分
同様にというのは、long long の部分をどのような名前に書き換えてもよいか、
ということでしょうか?
それはダメです。long long は C のキーワードであり、型名です。
No.55 のプログラムでは、int が 32ビット、long long が 64ビットであるもの
と仮定しています。たいていのコンパイラは、そのようになっていますが、
int が 16ビットのものや、long が 64ビットのものもあります。
ライトニング さんが書きました:
void print_suretu(const char *title, const int *kakunou, int num)
const title const int
なども問題ないのでしょうか?
これは、質問が不明確です。const title const int って何ですか?
const char *title の const char * は型を表すので変更できません。
title は名前ですから、変更してかまいません。
Re: 格納
Posted: 2015年11月26日(木) 03:47
by かずま
ライトニング さんが書きました:int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int gcd(int a, int b);
int inverse(int a, int b);
ちなみに最初のこの部分を全部消しても動いたのですが
この部分自体も別に分かりやすく書いてるだけでいらないということでしょうか?
動きますが、コンパイル時に警告が出るでしょう。
VC++ なら、
コード:
C:\tmp>cl hm2.c
Microsoft(R) C/C++ Optimizing Compiler Version 18.00.31101 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
hm2.c
hm2.c(97) : error C2371: 'print_suretu' : 再定義されています。異なる基本型です。
cygwin の gcc なら、
コード:
C:\tmp>gcc hm2.c
hm2.c:96:6: 警告: 'print_suretu' と型が競合しています
void print_suretu(const char *title, const int *kakunou, int num)
^
hm2.c:51:5: 備考: 前の 'print_suretu' の暗黙的な宣言はここです
print_suretu("秘密鍵: ", kakunou, NUM);
あなたの使っているコンパイラは何ですか?
あなたは,他にも、回答者からの多くの質問を無視して答えていませんね。
できるだけ答えてください。
それから、No.64 のプログラムは、ちゃんと見ていますか?
Wikipediaの
Merkle-Hellmanナップサック暗号に書いてる通りに
実装しているつもりなので、分かりやすいはずです。
No.55 のプログラムは、変数名が kakunou、newkakunou、x、y、xmody と
意味不明のものばかりで、よくないと思いませんか?
暗号化する平文がプログラムの中に埋め込まれているし、
その埋め込み方も結果の表示もビット列ではなく、
1のビットの番号だけというのは変だと思いませんか?
Re: 格納
Posted: 2015年12月01日(火) 11:51
by ライトニング
すみません自分の中で勝手に回答したつもりでした。
コンパイラはC言語のフリーソフト?みたいなのと
gcc でターミナルでやっています。
No64の回答していただいのは自分の理解力がなくてどの部分がどういう動きになってるのかよくわからなくて
またコンパイルした後何をしたらいいのかもよくわからなくて...
後一つ数列の合計値は?までに出てくる最初の数列と
xの値とyの値を入力した後に出てくる秘密鍵の数列が変わってしまうのですがどうすれば良いのでしょうか?
Re: 格納
Posted: 2015年12月01日(火) 13:47
by ライトニング
またライブラリを使って大きい桁でやってみたいのですがどこの値を変えたらたくさんの乱数を生成できるのでしょうか?
Re: 格納
Posted: 2015年12月01日(火) 13:55
by ライトニング
NTLというライブラリを使って実行してみたのですが
#define NUM 10を#define NUM 30に
return rand() % 10 + 1;をreturn rand() % 30 + 1;
に変えて実行してみたのですが合計値が−になりうまくきいきませんでした
Re: 格納
Posted: 2015年12月01日(火) 23:56
by かずま
ライトニング さんが書きました:
コンパイラはC言語のフリーソフト?みたいなのと
gcc でターミナルでやっています。
答えはそれだけですか?
あなたは、No.55 のプログラムで、先頭の「関数の宣言」を削除しても
動いたので、これは要らないということか、と聞いてきました。
でも削除するとコンパイラが警告を出すはずなのに、それは書いていません。
だから、どんなコンパイラを使っているのかと尋ねたのです。
そしたら、gcc だという。
質問です。警告は出なかったのですか?
警告は出たけれど、動けばいいと判断したのでしょうか?
ライトニング さんが書きました:No64の回答していただいのは自分の理解力がなくてどの部分がどういう動きになってるのかよくわからなくて
またコンパイルした後何をしたらいいのかもよくわからなくて...
コンパイルした後は、実行でしょう。
実行例
コード:
w = [ 2 10 17 30 69 133 270 540 1074 2150 ]
sum = 4295
Private key
w = [ 2 10 17 30 69 133 270 540 1074 2150 ]
q = 4301
r = 2150
Public key
b = [ 4300 4296 2142 4286 2116 2084 4166 4031 3764 3226 ]
Enter 10 binary digits
123456789.
0011010110
a = [ 0 0 1 1 0 1 0 1 1 0 ]
c = 16307
s = [ 0 0 1 1 0 1 0 1 1 0 ]
Enter 10 binary digits
123456789.
0000101101
a = [ 0 0 0 0 1 0 1 1 0 1 ]
c = 13539
s = [ 0 0 0 0 1 0 1 1 0 1 ]
Enter 10 binary digits
123456789.
.
実行すると、超増加列とその合計値を表示し、
さらに秘密鍵と公開鍵を生成して表示します。そして
Enter 10 binary digits
123456789.
と表示して、10個の2進数字を入力せよと言ってきます。
123456789. は間違いなく 10個の数字(0 か 1) を入力するためのガイドです。
10ビットの 2進数を入力すると、それを平文 a として表示し、
暗号化して、c の値として表示し、復号して s を表示します。
a から c へは公開鍵を使って暗号化され、
c から s へは秘密鍵を使って復号されています。
で、質問です。No.64 のプログラムは見てもよくわからないから、
実行してみなかったのですか?
ライトニング さんが書きました:後一つ数列の合計値は?までに出てくる最初の数列と
xの値とyの値を入力した後に出てくる秘密鍵の数列が変わってしまうのですがどうすれば良いのでしょうか?
これはどのプログラムのことを言っていますか?
No.55 も No.64 も「数列の合計値は?」とは表示しません。
最初の数列とは何ですか?
新しいプログラムなら、それを提示してください。また実行経過を
[ code=text] と [ /code] で挟んで提示してください。
具体的なデータを示してもらわないと、数列が変わってしまうといわれても
何のことかわかりません。
Re: 格納
Posted: 2015年12月02日(水) 00:06
by かずま
ライトニング さんが書きました:またライブラリを使って大きい桁でやってみたいのですがどこの値を変えたらたくさんの乱数を生成できるのでしょうか?
「大きい桁」とは何桁ぐらい?
「どこの値を変えたら」というのは、No.55 のプログラムで、
と言っているのですか?
Re: 格納
Posted: 2015年12月02日(水) 00:11
by かずま
ライトニング さんが書きました:NTLというライブラリを使って実行してみたのですが
実行したプログラムを提示してくれないことには、何も言えません。
質問です。NTL は C++ のライブラリなのではありませんか?
int や long long では桁数が少ないので、新しい型と演算子を定義して
提供するライブラリではないのですか?
Re: 格納
Posted: 2015年12月02日(水) 03:33
by かずま
ライトニング さんが書きました:
No64の回答していただいのは自分の理解力がなくてどの部分がどういう動きになってるのかよくわからなくて
No.64 のプログラムが理解されないのは、
入力データである 10個の 1 と 0 を本当の 10ビットのデータに変換して
int の a に入れるビット操作が分かりにくいのだと考えました。
そこで、int a[N]; と配列にして、その要素に 1 か 0 を入れることにしました。
以後は、Wikipediaの
Merkle-Hellmanナップサック暗号 を参照しながら、
次のプログラムをよく読んでみてください。
コード:
#include <stdio.h> // fgets, printf
#include <stdlib.h> // rand, srand
#include <time.h> // time
#define N 10
int gcd(int a, int b) // 最大公約数
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
int inverse(int a, int b) // b を法とする整数の合同における a の逆元
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
void print_array(const char *name, const int a[N]) // 配列の表示
{
int i;
printf("%s = [", name);
for (i = 0; i < N; i++) printf(" %d", a[i]);
printf(" ]\n");
}
int input_data(int a[N]) // データの入力
{
int i;
char buf[256];
printf("\nEnter %d binary digits\n", N);
printf("%.*s\n", N, "123456789.123456789.123456789.12");
if (!fgets(buf, sizeof buf, stdin)) return 0;
for (i = 0; i < N; i++)
if (buf[i] == '1') a[i] = 1;
else if (buf[i] == '0') a[i] = 0;
else break;
return i == N; // i が N だったら 1 を、そうでなかったら 0 を返す
}
void generate_keys(int b[N], int w[N], int *q, int *r) // 鍵の生成
{
int i, sum = 0;
for (i = 0; i < N; i++) // 超増加列(秘密鍵)の生成
sum += w[i] = sum + 1 + rand() % 10;
print_array(" w", w);
printf(" sum = %d\n", sum);
*q = sum + 1 + rand() % 10; // 秘密鍵 q の生成
for (*r = *q /2; gcd(*r, *q) != 1; ++*r) ; // 秘密鍵 r の生成
for (i = 0; i < N; i++) // 公開鍵の生成
b[i] = (long long)*r * w[i] % *q;
}
int encrypt(const int a[N], const int b[N]) // 暗号化
{
int i, c = 0;
for (i = 0; i < N; i++)
if (a[i] == 1) c += b[i];
return c;
}
int decrypt(int c, const int w[N], int q, int r, int s[N]) // 復号
{
int i, sum = (long long)c * inverse(r, q) % q;
for (i = N; --i >= 0; ) {
if (sum >= w[i])
sum -= w[i], s[i] = 1;
else
s[i] = 0;
}
return sum; // 復号できれば 0、そうでなければ正の値を返す
}
int main(void)
{
int w[N], q, r; // 秘密鍵
int b[N]; // 公開鍵
int a[N]; // 暗号化する前のデータ
int c; // 暗号化されたデータ
int s[N]; // 復号されたデータ
srand(time(0));
generate_keys(b, w, &q, &r); // 鍵の生成
printf("Private key\n");
print_array(" w", w);
printf(" q = %d\n r = %d\n", q, r);
printf("Public key\n");
print_array(" b", b);
while (input_data(a)) { // データの入力
print_array(" a", a); // 入力データの表示
c = encrypt(a, b); // 暗号化
printf(" c = %d\n", c); // 暗号化されたデータの表示
decrypt(c, w, q, r, s); // 復号
print_array(" s", s); // 復号されたデータの表示
}
return 0;
}
分からないところは質問してください。
inverse() の中身は分からなくてかまいません。
Re: 格納
Posted: 2015年12月03日(木) 13:32
by ライトニング
コード:
#include<NTL/zz.h>
using namespace std;
using namespace NTL;
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
zz get_rand(void);
zz get_prime(zz sum);
void print_suretu(const char *title, const int *kakunou, int num);
zz gcd(int a, int b);
zz inverse(int a, int b);
void main()
{
zz i, sum;
zz kakunou[NUM], newkakunou[NUM], suretu;
zz x, y, xmody;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
}
x = get_prime(sum);
while (1) {
printf("y の値は? "); scanf("%d", &y);
if (gcd(x, y) == 1) break;
printf("x と y が互いに素ではありません。\n");
}
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
newkakunou[i] = (long long)kakunou[i] * y % x;
}
print_suretu("秘密鍵: ", kakunou, NUM);
printf("合計 = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("公開鍵: ", newkakunou, NUM);
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
xmody = newkakunou[2]+newkakunou[5]+newkakunou[9];
printf("暗号: %d\n", xmody);
xmody = (long long)xmody * inverse(y, x) % x;
printf("復号:");
for (i = NUM; --i >= 0; ) {
if (xmody >= kakunou[i]) {
xmody -= kakunou[i];
printf(" [%d]", i);
}
}
printf("\n");
return 0;
}
zz get_rand(void)
{
return rand() % 10 + 1;
}
zz get_prime(int sum)
{
zz x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
printf("x の値は? ");
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
zz i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
zz gcd(int a, int b)
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
zz inverse(zz a, zz b)
{
zz x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
これをNTLライブラリを使って実行したのですが
zz get_rand(void);
^
mhangou.cpp:12:1: error: unknown type name 'zz'
zz get_prime(zz sum);
^
mhangou.cpp:12:14: error: unknown type name 'zz'
zz get_prime(zz sum);
^
mhangou.cpp:15:1: error: unknown type name 'zz'
zz gcd(int a, int b);
^
mhangou.cpp:16:1: error: unknown type name 'zz'
zz inverse(int a, int b);
^
mhangou.cpp:19:1: error: 'main' must return 'int'
void main()
^~~~
int
mhangou.cpp:21:5: error: unknown type name 'zz'
zz i, sum;
^
mhangou.cpp:22:5: error: unknown type name 'zz'
zz kakunou[NUM], newkakunou[NUM], suretu;
^
mhangou.cpp:23:5: error: unknown type name 'zz'
zz x, y, xmody;
^
mhangou.cpp:27:5: error: use of undeclared identifier 'sum'
sum = 0;
^
mhangou.cpp:30:9: error: use of undeclared identifier 'suretu'
suretu = sum + get_rand();
^
mhangou.cpp:30:18: error: use of undeclared identifier 'sum'; did you mean
'sub'?
suretu = sum + get_rand();
^~~
sub
/usr/local/include/NTL/zz.h:322:13: note: 'sub' declared here
inline void sub(ZZ& x, const ZZ& a, const ZZ& b)
^
mhangou.cpp:30:22: error: arithmetic on a pointer to the function type 'void
(NTL::ZZ &, const NTL::ZZ &, const NTL::ZZ &)'
suretu = sum + get_rand();
~~~ ^
mhangou.cpp:31:9: error: use of undeclared identifier 'sum'
sum = sum + suretu;
^
mhangou.cpp:31:15: error: use of undeclared identifier 'sum'; did you mean
'sub'?
sum = sum + suretu;
^~~
sub
/usr/local/include/NTL/zz.h:322:13: note: 'sub' declared here
inline void sub(ZZ& x, const ZZ& a, const ZZ& b)
^
mhangou.cpp:31:21: error: use of undeclared identifier 'suretu'
sum = sum + suretu;
^
mhangou.cpp:32:22: error: use of undeclared identifier 'suretu'
kakunou
= suretu;
^
mhangou.cpp:34:20: error: use of undeclared identifier 'sum'; did you mean
'sub'?
x = get_prime(sum);
^~~
sub
/usr/local/include/NTL/zz.h:322:13: note: 'sub' declared here
inline void sub(ZZ& x, const ZZ& a, const ZZ& b)
^
mhangou.cpp:34:10: error: no matching function for call to 'get_prime'
x = get_prime(sum);
^~~~~~~~~
mhangou.cpp:12:4: note: candidate function not viable: no known conversion from
'void (NTL::ZZ &, const NTL::ZZ &, const NTL::ZZ &)' to 'int' for 1st
argument
zz get_prime(zz sum);
このようなエラーが出ました。C++との違いがよくわからないのですがzzという型数を宣言したのですがうまくいきません。
大きい桁というとはとりあえず50ビット?くらいで試してみたい状況です。
Re: 格納
Posted: 2015年12月03日(木) 18:17
by よもやま
ライトニング さんが書きました:コード:
zz get_rand(void);
^
mhangou.cpp:12:1: error: unknown type name 'zz'
NTLライブラリのリファレンスやサンプルを参照していないように見受けられます。
zzではなくZZでは。
Re: 格納
Posted: 2015年12月06日(日) 04:56
by かずま
コード:
#include <iostream> // cin, cout
#include <cstdlib> // rand, srand
#include <ctime> // time
#include <NTL/ZZ.h>
using namespace std;
using namespace NTL;
#define N 128
ZZ gcd(ZZ a, ZZ b) // 最大公約数
{
ZZ r;
while (b != 0)
r = a % b, a = b, b = r;
return a;
}
ZZ inverse(ZZ a, ZZ b) // b を法とする整数の合同における a の逆元
{
ZZ x1, y1, z1 = a, x2, y2, z2 = b, q, t;
x1 = 1, y1 = 0, x2 = 0, y2 = 1;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
void print_array(const char *name, const ZZ *a, int n) // 配列の表示
{
cout << name << " = [";
if (n > 10) n = 10;
for (int i = 0; i < n; i++) cout << ' ' << a[i];
cout << " ... ]\n";
}
void print_bin(const char *name, const int *a, int n) // 配列の表示
{
cout << name << " = [";
for (int i = 0; i < n; i++) cout << a[i];
cout << " ]\n";
}
int input_data(int *a) // データの入力
{
string buf;
cout << "\nEnter less than " << N << " binary digits\n";
if (!getline(cin, buf)) return 0;
size_t i, n = buf.size();
if (n >= N) return 0;
for (i = 0; i < n; i++)
if (buf[i] == '1') a[i] = 1;
else if (buf[i] == '0') a[i] = 0;
else break;
if (i != n) return 0;
return n; // ビット数を返す
}
void generate_keys(ZZ *b, ZZ *w, ZZ& q, ZZ& r) // 鍵の生成
{
ZZ sum;
sum = 0;
for (int i = 0; i < N; i++) // 超増加列(秘密鍵)の生成
sum += w[i] = sum + 1 + rand() % 10;
print_array(" w", w, N);
cout << " sum = " << sum << endl;
q = sum + 1 + rand() % 10; // 秘密鍵 q の生成
for (r = q / 2; gcd(r, q) != 1; ++r) ; // 秘密鍵 r の生成
for (int i = 0; i < N; i++) // 公開鍵の生成
b[i] = r * w[i] % q;
}
ZZ encrypt(int n, const int *a, const ZZ *b) // 暗号化
{
ZZ c;
c = 0;
for (int i = 0; i < n; i++)
if (a[i] == 1) c += b[i];
return c;
}
int decrypt(int n, ZZ c, const ZZ *w, ZZ q, ZZ r, int *s) // 復号
{
ZZ sum = c * inverse(r, q) % q;
for (int i = n; --i >= 0; ) {
if (sum >= w[i])
sum -= w[i], s[i] = 1;
else
s[i] = 0;
}
return sum != 0; // 復号できれば 0、そうでなければ 1 を返す
}
int main(void)
{
ZZ w[N], q, r; // 秘密鍵
ZZ b[N]; // 公開鍵
int a[N]; // 暗号化する前のデータ
ZZ c; // 暗号化されたデータ
int s[N]; // 復号されたデータ
int n; // ビット数
srand(time(0));
generate_keys(b, w, q, r); // 鍵の生成
cout << "Private key\n";
print_array(" w", w, N);
cout << " q = " << q << "\n r = " << r << endl;
cout << "Public key\n";
print_array(" b", b, N);
while (n = input_data(a)) { // データの入力
print_bin(" a", a, n); // 入力データの表示
c = encrypt(n, a, b); // 暗号化
cout << " c = " << c << endl; // 暗号化されたデータの表示
decrypt(n, c, w, q, r, s); // 復号
print_bin(" s", s, n); // 復号されたデータの表示
}
return 0;
}
実行結果
コード:
w = [ 8 14 31 57 114 233 458 917 1839 3672 ... ]
sum = 2442393501432829254771146219802651424984
Private key
w = [ 8 14 31 57 114 233 458 917 1839 3672 ... ]
q = 2442393501432829254771146219802651424992
r = 1221196750716414627385573109901325712497
Public key
b = [ 8 14 1221196750716414627385573109901325712527 1221196750716414627385573109901325712553 114 1221196750716414627385573109901325712729 458 1221196750716414627385573109901325713413 1221196750716414627385573109901325714335 3672 ... ]
Enter less than 128 binary digits
0011010100001111010101010011
a = [0011010100001111010101010011 ]
c = 10990770756447731646470157989113456852191
s = [0011010100001111010101010011 ]
Enter less than 128 binary digits
1111111111111111000000000000000000010101010
a = [1111111111111111000000000000000000010101010 ]
c = 14654361008596975528626877339778500203434
s = [1111111111111111000000000000000000010101010 ]
Enter less than 128 binary digits
.
No.83 の質問(?が付いているもの)にすべて答えていただけない場合、
これ以上の質問を受け付けません。
また、以前のトピックを解決にするかどうかも教えてください。
さらに、NTL に関する質問をするなら、
「NTL を使用する Merkle-Hellmanナップサック暗号」という件名の
新しいトピックを立ててください。
Re: 格納
Posted: 2015年12月06日(日) 22:42
by ライトニング
自宅ではEasyIDECと言うのを使用しておりそれで先頭の「関数の宣言」を消しては実行できました。
学校ので使ってるのEmacsをターミナルでコンパイルするとかずまんの言われたとおり警告が出てしまいました。
なので先頭の「関数の宣言」は消さない事にしました。報告を忘れていました。
No64の実行をしてみたのですがその後どのような値を入力するのか分からないのが謎でした。
けれど10bitを何かうつというのをようやく理解でき実行部分までは理解することができました。
実行したのはこのプログラミングです
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 10
int get_rand(void);
int get_prime(int sum);
void print_suretu(const char *title, const int *kakunou, int num);
int gcd(int a, int b);
int inverse(int a, int b);
int main(void)
{
int i, sum;
int kakunou[NUM], newkakunou[NUM], suretu;
int x, y, xmody;
srand((unsigned int)time(NULL));
sum = 0;
for (i = 0; i < NUM; i++)
{
suretu = sum + get_rand();
sum = sum + suretu;
kakunou[i] = suretu;
printf("%d\n",sum);
}
x = get_prime(sum);
while (1) {
printf("y の値は? "); scanf("%d", &y);
if (gcd(x, y) == 1) break;
printf("x と y が互いに素ではありません。\n");
}
for (i = 0; i < NUM; i++)
{
newkakunou[i] = kakunou[i] * xmody;
newkakunou[i] = (long long)kakunou[i] * y % x;
}
print_suretu("秘密鍵: ", kakunou, NUM);
printf("合計 = %d, x = %d, y = %d\n", sum, x, y);
print_suretu("公開鍵: ", newkakunou, NUM);
printf("暗号%d",newkakunou[2]+newkakunou[5]+newkakunou[9]);
xmody = newkakunou[2]+newkakunou[5]+newkakunou[9];
printf("暗号: %d\n", xmody);
xmody = (long long)xmody * inverse(y, x) % x;
printf("復号:");
for (i = NUM; --i >= 0; ) {
if (xmody >= kakunou[i]) {
xmody -= kakunou[i];
printf(" [%d]", i);
}
}
printf("\n");
return 0;
}
int get_rand(void)
{
return rand() % 10 + 1;
}
int get_prime(int sum)
{
int x;
printf("数列の項の合計 = %d\n", sum);
for (;;)
{
printf("x の値は? ");
if (scanf("%d",&x) != 1)
{
exit(1);
}
if (x >= sum)
return x;
else
puts("数列の合計値よりxが小さいです。");
}
}
void print_suretu(const char *title, const int *kakunou, int num)
{
int i;
for (i = 0; i < num; i++)
{
printf("%s%d", i == 0 ? title : ", ", kakunou[i]);
}
putchar('\n');
}
int gcd(int a, int b)
{
int r;
while (b)
r = a % b, a = b, b = r;
return a;
}
int inverse(int a, int b)
{
int x1 = 1, y1 = 0, z1 = a, x2 = 0, y2 = 1, z2 = b, q, t;
while (z2 > 1)
#define STEP(a, b) (t = a - q * b, a = b, b = t)
q = z1 / z2, STEP(x1, x2), STEP(y1, y2), STEP(z1, z2);
return x2 < 0 ? x2 + b : x2;
}
以前に質問した29行目のprintf("",sum)だとエラーをはかれてしまったのでprintf("%d\n",sum)を治したらこのようになってしまい
[ code=text]
6
17
42
92
193
394
791
1589
3185
6379
数列の合計 = 6379
xの値は? 7000
yの値は? 699
秘密鍵 6,11,25,50,101,397,798,1596,3194
合計=6379 x = 7000 y=6999
公開鍵 6994,6989,6975,6950,6899 6799 6603 6202 5450 3806
暗号 17580 暗号:17580
復号:[9][5][2]
[ /code]
のように少し変になってしました。
すいません。NTLのことも色々聞きたいので新しいトピックを作らせてもらいます。そちらでよろしくお願いします。
Re: 格納
Posted: 2015年12月06日(日) 22:44
by みけCAT
オフトピック
ライトニング さんが書きました:学校ので使ってるのEmacsをターミナルでコンパイルするとかずまんの言われたとおり警告が出てしまいました。
Emacsをコンパイルした…?どうして…?
ライトニング さんが書きました:実行したのはこのプログラミングです
これはプログラミングではありません。プログラムです。
Re: 格納
Posted: 2015年12月06日(日) 22:46
by ライトニング
すいません誤字・脱字がありました。
かずまさんの言われた通り警告が出てしました。
EasyIDEXでは実行できたので勝手にEmacs作ったもの保存したものをgccでもコンパイルできると思い込んでいました。
そのため先頭の関数宣言は消さずにそのままにしておきました。
10bitの何かではなく10個の2進数字を入力をするというのが分かったので実行方法までは分かりました。
Re: 格納
Posted: 2015年12月06日(日) 22:49
by ライトニング
すいません何て言えばいいのか分からないのですが
Emacsで作ったプログラムをターミナルを使ってgccでコンパイルしましたと言えばいいのでしょうか?説明が下手で申し訳ないです。
すいません実行したプログラムです。
Re: 格納
Posted: 2015年12月07日(月) 02:38
by かずま
ライトニング さんが書きました:自宅ではEasyIDECと言うのを使用しておりそれで先頭の「関数の宣言」を消しては実行できました。
私のところで、EasyIDEC Ver 0.0.9.0 を起動し、No.90 のプログラムをコピペして、
「プログラム実行」を押すと、次のようにエラーになりました。
コード:
ファイル「C:/EasyIDEC/project/default/main.c」の
「89行目」で記述エラーを発見しました。
「print_suretu」が再定義されています。以前と同じ名前を使っていないか、関数の記述順番は正しいかどうかを確認してください。
gcc では警告だけで実行はできたのに、EasyIDEC ではエラーで実行できません。
EasyIDEC のバージョンが違うのでしょうか?
ライトニング さんが書きました:No64の実行をしてみたのですがその後どのような値を入力するのか分からないのが謎でした。
けれど10bitを何かうつというのをようやく理解でき実行部分までは理解することができました。
No.64 の改良版の No.86 なら中身を理解できますか?
分からないところは質問してください。
No.89 は、これの NTL版です。
ライトニング さんが書きました:実行したのはこのプログラミングです
以前に質問した29行目のprintf("",sum)だとエラーをはかれてしまったのでprintf("%d\n",sum)を治したらこのようになってしまい
コード:
6
17
42
92
193
394
791
1589
3185
6379
数列の合計 = 6379
xの値は? 7000
yの値は? 699
秘密鍵 6,11,25,50,101,397,798,1596,3194
合計=6379 x = 7000 y=6999
公開鍵 6994,6989,6975,6950,6899 6799 6603 6202 5450 3806
暗号 17580 暗号:17580
復号:[9][5][2]
のように少し変になってしました。
何も変ではありません。
6 17 42 92 というのは sum の値です。
6 11 25 50 というのは、kakunou
の値です。
17 = 6 + 11
42 = 6 + 11 + 25
92 = 6 + 11 + 25 + 50
となるのは当然です。プログラムをそうなるように書いているのですから。
Re: 格納
Posted: 2015年12月07日(月) 10:14
by かずま
かずま さんが書きました:私のところで、EasyIDEC Ver 0.0.9.0 を起動し、No.90 のプログラムをコピペして、
「プログラム実行」を押すと、次のようにエラーになりました。
次のように訂正します。
私のところで、EasyIDEC Ver 0.0.9.0 を起動し、No.90 のプログラムをコピペして、
「関数の宣言」を削除して、「プログラム実行」を押すと、次のようにエラーになりました。
Re: 格納
Posted: 2015年12月08日(火) 22:37
by ライトニング
自分ももう一度改めて実行してみたところかずまさんと同じようなエラーをはかれてしまいました
自分でも何故以前実行できたのか分からない状態です....
またNo.89のプログラムで質問したいことがあるのですがここで質問していいでしょうか?一応NTLトピックをたてたのですが...
Re: 格納
Posted: 2015年12月09日(水) 06:15
by かずま
ライトニング さんが書きました:自分ももう一度改めて実行してみたところかずまさんと同じようなエラーをはかれてしまいました
自分でも何故以前実行できたのか分からない状態です....
No.94 の「EasyIDEC のバージョンが違うのでしょうか?」という質問に
答えてもらっていません。
ライトニング さんが書きました:またNo.89のプログラムで質問したいことがあるのですがここで質問していいでしょうか?
No.94 の「No.64 の改良版の No.86 なら中身を理解できますか?」に
答えてもらっていません。
No.89 のプログラムは、No.86 を元に NTL を使うようにしたものなので、
そちらの理解が先です。
ライトニング さんが書きました:一応NTLトピックをたてたのですが...
No.89 で、「さらに、NTL に関する質問をするなら、
「NTL を使用する Merkle-Hellmanナップサック暗号」という件名の
新しいトピックを立ててください。」とお願いしたのに、そうなっていません。
何度同じ間違いをしたら気が済むのですか?
10/04~10/07
「mod計算?」
10/08~10/14
「数列の作成」
10/23~現在
「格納」
10/29~10/31
「mody逆元計算」
どれも、不明確な質問をし、回答者が疑問を持ってから、Wikipedia の
「Merkle-Hellmanナップサック暗号」へのリンクを持ち出しています。
12/06
「NTLの使い方」
ライトニング さんが書きました:
これをNTLでうまく実装させたいのですがどの部分を直せばいいでしょうか?
うか?NTLのオリジナル?の関数なのでしょうか?
これを見た人はどう思いますか?
・このプログラムは何だろうか?
・NTL って何だろうか?
・なぜ直さないといけないんだろうか?
と疑問がいっぱいです。
ちゃんとこれまでの経緯を説明し、少なくとも「格納」へのリンクを張るべきです。
ライトニング さんが書きました:
またCとC++の違いがよくわからないのですがcoutと言うのはC++関数なのでしょうか?NTLのオリジナル?の関数なのでしょうか?
C++ を全く学習していないことが分かります。
せめて 30分だけでも C++ の入門ページを見てください。
Re: 格納
Posted: 2015年12月09日(水) 14:32
by ライトニング
EasyIDEC のバージョンは一緒でした。
No.86のプログラムを理解できていない状態なのでそちらを聞いてもいいでしょうか?
トピックのタイトルは完全に忘れていました。申し訳ないです。
どれも自分の説明不足で結果的にナップサック暗号のリンクを持ち出してしまってる形になっているのはすいません。
確かにまたNTLのトピックも同じように自分の説明不足でNTLが何のかなども分からない事だらけだと思います。
格納のリンクを貼るべきでした
C++の入門を少し拝見しcoutがC++の関数ということも分かりました。
Re: 格納
Posted: 2015年12月09日(水) 21:34
by みけCAT
ライトニング さんが書きました:C++の入門を少し拝見しcoutがC++の関数ということも分かりました。
どこでそんなことを知ったのですか?coutは関数ではありません。
c++ - cout and cin are not functions, so what are they? - Stack Overflow
Re: 格納
Posted: 2015年12月10日(木) 06:21
by かずま
ライトニング さんが書きました:No.86のプログラムを理解できていない状態なのでそちらを聞いてもいいでしょうか?
はい、聞かれたことはなんでも答えるつもりです。
ライトニング さんが書きました:どれも自分の説明不足で結果的にナップサック暗号のリンクを持ち出してしまってる形になっているのはすいません。
そうです。最初にリンクを示し、自分がどんな問題で困っているのかを説明するべきでした。
ライトニング さんが書きました:確かにまたNTLのトピックも同じように自分の説明不足でNTLが何のかなども分からない事だらけだと思います。
NTL は、どこで知ったのですか?
前の課題は、「C言語で MH暗号を作れ」だったと思いますが、
今度の課題は、「C++ で、NTL を使って MH暗号を作れ」になったんですか?
ライトニング さんが書きました:格納のリンクを貼るべきでした
「NTLの使い方」にそのトピックができたいきさつを説明し、リンクを貼ってください。
ライトニング さんが書きました:C++の入門を少し拝見しcoutがC++の関数ということも分かりました。
cout は、オブジェクトです。ostreamクラスのインスタンスです。
と言っても、わからないでしょう。cout は、変数だと思ってください。
cout << "abc" は、operator<<(cout, "abc") のことで、operator<< が関数です。
これは C の fputs("abc", stdout) に相当します。