ページ 11

c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 02:11
by wai
c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

桁が大きすぎるのか、x=37をいれると95乗が-1028680659で割ったものを-272という結果になり、マイナスがついてしまいます。
さらにx=250をいれると全て0になってしまいます。
1.この桁数の多さ?は解決する手段はないのでしょうか?
2.また、以下に表したプログラムでintからlongにする場合、全てのintをlongにするのですか?
わからないことが多くて困っています。ちなみに使ってるのはmicrosoft visualC++の2010です。
-----------------------------------------------------------
#include "stdafx.h"
#include <math.h>
#include <stdio.h>

int Power(int x, int y); //プロトタイプ宣言

int main(void)
{
int xi,yi,zi;

printf("整数を入力してください:");
scanf("%d",&xi);
yi=95;
zi=Power(xi,yi)%323;

printf("%dの%d乗は%dで、それを323で割った余りは%dです\n",xi,yi,Power(xi,yi),zi);
printf("十六進数表示は%xです",zi);

return 0;

}

int Power(int x, int y)
{
int i,result;
for( i=1, result = 1; i <= y; i++) {
result *= x;
}
return result;
}
---------------------------------------------------------------
結果

整数を入力してください:37
37の95乗は-102868059で、それを323で割ったあまりは-272です。
十六進数表示はfffffef0です

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 02:58
by h2so5
wai さんが書きました: 1.この桁数の多さ?は解決する手段はないのでしょうか?
ヒント: (x ^ 95) % 323 = ((((((((x * x) % 323) * x) % 323) * x) % 323) * x) ... ) % 323
x ^ 95 という巨大な数を直接求める必要はありません
wai さんが書きました: 2.また、以下に表したプログラムでintからlongにする場合、全てのintをlongにするのですか?
わからないことが多くて困っています。ちなみに使ってるのはmicrosoft visualC++の2010です。
そうです。ただし、VisualC++では int も long int も32bitですのでどちらでも扱える整数の範囲は同じです。

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 08:04
by box
まともに計算したらダメです、というか、
xが大きいと95乗を計算できないのは
今回の現象のとおりです。

「合同式」「剰余系」あたりについて研究してみてください。

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 08:33
by みけCAT
wai さんが書きました:また、以下に表したプログラムでintからlongにする場合、全てのintをlongにするのですか?
違います。main関数の戻り値はlongではなくintを使うべきです。
また、もちろん「printf」に含まれる「int」もlongにしてはいけません。
テキストエディタの置換機能を使用するとよくあるミスなので、気をつけるべきです。

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 08:37
by みけCAT
wai さんが書きました:この桁数の多さ?は解決する手段はないのでしょうか?
桁数は変わりませんが、GNU MPというライブラリを使用すれば、オーバーフローするという問題は解決できます。
ただし、ライブラリのライセンスがLesser General Public License version 3なので、公開時には注意が必要かもしれません。

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 08:42
by みけCAT
h2so5 さんが書きました:ヒント: (x ^ 95) % 323 = ((((((((x * x) % 323) * x) % 323) * x) % 323) * x) ... ) % 323
x ^ 95 という巨大な数を直接求める必要はありません
さらにヒント : x=76543でテストしましょう。答えは10進数で121(16進数に直すと0x79)です。

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 09:04
by box
考え方を少し変えてみると、うまくいくかもしれません。
例えば、x = 2の場合を考えてみます。

(1乗から7乗までは省略)
2^8 = 256を323で割ったあまりは、256です。
2^9 = 512を323で割ったあまりは、189です。
さて、次の2^10を323で割ったあまりを求める際、
2^10 = 1024をまともに計算するのではなく、
先に求めた189に2をかけた378を323で割ったあまりである55とするのです。
実際、2^10 = 1024を323で割ったあまりは55になりますね。
先ほどの回答で書いた合同式でいうと、
378 ≡ 1024 (mod 323)
378と1024は、323を法として合同である、と読みます。
378も1024も、323で割ったあまりは等しいという意味です。
1024を扱うよりは378を扱う方が、数値が小さくてすみますね。
べき乗の数値が大きくなっていくほど、10乗の場合における378と1024の違いが
さらに際立ってくるはずです。
xが大きくなれば、なおさらです。

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 09:51
by sql
今回のトピックの主題は最終的な値が桁溢れしない数なのでh2so5さんのやり方でいいと思います・・・・が!
wai さんが書きました:1.この桁数の多さ?は解決する手段はないのでしょうか?
とあり、例えば次に、「入力したxの95乗を求めて出力しろ」という課題が出たら詰むと思います。(調べればいい話なのですが・・・)
ですので調べたら「このようなページ」を見つけたので貼っておきます。(コメント欄まで読んだほうがいいかもです)

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月16日(日) 11:59
by zeek

Re: c言語のプログラムで、「xの95乗を323で割った余りを16進数に直す」というものを作りたいです

Posted: 2014年2月18日(火) 19:02
by かずま
zeek さんが書きました:マルチポストだね。
http://detail.chiebukuro.yahoo.co.jp/qa ... 1121105256
あっちで解答がついているので、もうこっちは見ないでしょう。

x の 95乗も求めないといけないのなら、多倍長計算ですね。
x < 10000 という制限付きですが。

コード:

#include <stdio.h>
 
#define B 10000  // 万進法 (Base = 100)
#define N 100    // 万進100桁, 十進400桁

int mul(int *a, int b)  // a *= b, return carry
{
    int i, t, c = 0;
    for (i = 0; i < N; i++) t = a[i] * b + c, c = t / B, a[i] = t % B;
    return c;
}

int mod(const int *a, int b) // return a % b 
{
    int i = N, r = 0;
    while (--i >= 0) r = (a[i] + r * B) % b;
    return r;
}

void print(const int *a) 
{
    int i= N;
    while (--i > 0 && a[i] == 0) ;
    printf("%d", a[i]);
    while (--i >= 0) printf("%04d", a[i]);
}

int main(void)
{
    int i, x, r, a[N] = { 1 };
    printf("整数を入力してください: "); 
    if (scanf("%d", &x) != 1 || x < 0 || x >= B) return 1;
    for (i = 0; i < 95; i++) if (mul(a, x)) return 1;
    r = mod(a, 323);
    printf("%d の 95乗は ", x); 
    print(a);
    printf(" で、\nそれを 323で割った余りは %d です\n16進数表示は %x です\n", r, r); 
    return 0;
}