質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

793閲覧

c言語の累乗の計算について

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/12/13 13:36

初心者です。暗号化のプログラムを作っています。その中で、mのe乗を求めたいのですが正確な値が出ません。それよりも前の部分は正常に動いています。/暗号化/という部分です。どこを直せば良いのでしょうか。

c

1 #include<stdio.h> 2#include <stdlib.h> // rand, srand関数 3#include <time.h> // time関数 4#include <math.h> 5 6int gcd(int x, int y); // 最大公約数を求める関数 7 8 9 10 11 12int main(void){ 13 14 unsigned long long int p=0,q=0; 15 int i,l;//繰り返し用変数 16 int flag1=0,flag2=0; 17 int count=0; 18 unsigned long long int n; 19 unsigned long long int o;//オイラー関数 20 unsigned long long int E; 21 unsigned long long int num=0; 22 int x,y,r;//ユーグリッドの互除法で使う 23 int gcd_num=0;//最大公約数 24 unsigned long long int d=0; 25 unsigned long long int judge , k=0;//dを求める時に必要,dはあまり 26 unsigned long long int c; 27 int m=0;//平文 28 unsigned long long int me=0;//mのe乗 29 30 31 srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化 32 33 /*pの値を求める*/ 34 while(p<1000 || flag1==1 || p==0){//pの条件を満たしてない限り繰り返す 35 flag1=0; 36 p=rand()%10000;//以降の計算に時間がかかるため4桁に指定 37 for( l=2;l<p;++l ) { 38 if( p%l==0 ) {//割りきれる場合 39 flag1 = 1; 40 break;//繰り返し終了 41 } 42 } 43 } 44 printf("p:%llu\n",p);//pの値出力 45 46 /*qの値を求める*/ 47 while(q<1000 || flag2==1 || q==0){//qの条件を満たしてない限り繰り返す 48 flag2=0; 49 q=rand()%10000;//以降の計算に時間がかかるため4桁に指定 50 for( i=2;i<q;++i ) { 51 if( q%i==0 ) {//割りきれる場合 52 flag2 = 1; 53 break;//繰り返し終了 54 } 55 } 56 } 57 printf("q:%llu\n",q);//qの値出力 58 59 n=p*q; 60 61 o=(p-1)*(q-1);//オイラー関数 62 printf("φ:%llu\n",o); 63 64 /*eの値を求める*/ 65 while(gcd_num!=1 || E==0 ||E==1){ 66 E=rand()%100; 67 68 if(o<=E){//E,oのうち大きい方をx小さい方をyに設定 69 x=E; 70 y=o; 71 } 72 else{ 73 y=E; 74 x=o; 75 } 76 gcd_num = gcd(x, y); 77 } 78 printf( "e:%llu\n", E ); 79 80 81 /*dの値を求める*/ 82 while(judge!=0 || d>o ){ 83 d=rand()%99960004;//φの範囲:0~9998*9998 84 judge=(E*d-1)%o; 85 } 86 printf( "d:%llu\n", d ); 87 k=(E*d-1)/o; 88 89 printf("k:"); 90 if(E*d==k*o+1){//ed=φk+1か確認 91 printf("%llu\n", k ); 92 } 93 94 /*暗号化*/ 95 while(m==0){ 96 m=rand()%10;//mは2桁 97 } 98 printf("m:%d\n",m); 99 me=m*m; 100 for(i=1;i<E-1;i++){ 101 me=me*m; 102 } 103 printf("m^e:%llu\n", me ); 104 c=me%n; 105 printf("c:%llu\n",c); 106 107 108 109 110 return 0; 111} 112 113 114// 最大公約数を求める関数 115int gcd(int x, int y){ 116 int r; 117 118 119 // ユーグリッドの互除法 120 while((r = x % y) != 0) { // 割り切れるまでループ 121 x = y; 122 y = r; 123 } 124 return y; 125} 126 127 128 129 130

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/12/13 13:43

どういう値が出るんでしょうか
退会済みユーザー

退会済みユーザー

2019/12/13 13:47

例えば3^7の場合、67,585,198,634,817,523,235,520,443,624,317,923 ですが、このプログラムでは6,572,658,003,009,201,123と出力されます。
y_waiwai

2019/12/13 13:55

階乗じゃないんですか? それはなんの数字でしょうか
raccy

2019/12/13 14:00

67,585,198,634,817,523,235,520,443,624,317,923は3^73ですよね?
otn

2019/12/13 14:01

3の7乗 は 2187 では?
退会済みユーザー

退会済みユーザー

2019/12/13 14:12

そうです!すみません、間違えました3^73です。
guest

回答3

0

ベストアンサー

単純に桁溢れだと思います。ちなみに、これは他の部分を読む限り、RSA暗号あたりの暗号/復号のものでしょう。だとすると累乗計算はO(log N)の形にするのが適切です。以下、動作未確認。

C

1//巨大整数を扱う型をTとします。 2T power(T x, T n) 3{ 4 T temp; 5 if(0 == n){//0乗はxに関わらず1。 6 return 1; 7 }else if(1 == n){//1乗はxそのもの。 8 return x; 9 } 10 temp = power(x, n / 2);//再帰でx ^ (n / 2)を求めて一時変数へ。 11 return temp * temp * (n % 2 ? x : 1);//x ^ nを計算結果とする。 12} 13

このプログラムなら、nを半分しながら反復していくので計算量が対数オーダになります。

投稿2019/12/13 14:29

編集2019/12/13 14:34
HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

一般的なx86_64を含むほとんどの環境においてunsigned long long intの最大値は18446744073709551615です。meの値によってはこの最大値を超えてしまうため、その場合は正確な値がでることはありません。最大であり得る9の99乗の値(29512665430652752148753480226197736314359272517043832886063884637676943433478020332709411004889)が十分に入るような整数の型を考えるか、GNU MPのような多倍長整数ライブラリを使う必要があります。

投稿2019/12/13 13:58

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/12/13 14:18

回答ありがとうございます。 GNU MPというものを初めて聞いたのですが、調べてもいまいち理解できません。どのように使うのでしょうか。
raccy

2019/12/13 14:21

どのように使うのかと言われてもマニュアル https://gmplib.org/manual/ を読んでくださいとしか言いようがないです。
guest

0

細かい状況は分かりませんが、とりあえずバグとして考えられるのは

  1. eの値を求める際に低確率でgcdで0剰余演算が発生する(質問とは関係なさそうですが)
  2. eの値が低確率で1になるがmeとしてm^2が出力される
  3. meが割とオーバーフローしやすい

Eの詳しい算出方法は十分追い切れておりませんが恐らく3.が主な原因かと思います。
unsigned long long intの最大値が2^64-1として、例えばmが9の時eが20もあれば溢れます。

投稿2019/12/13 14:07

編集2019/12/13 14:08
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問