人に聞けない痔の悩み、これでスッキリ >>

c言語のmまたはnが13以上となる場合に正しい解を求めることができない、なぜなら、13の階乗は6,227,020,800であり、この値はint型変数で扱うことのできる範囲をこえてしまっているからである。以下のプログラムを改良しなるべく大きなmやnの値でも正しく解を求めることができるプログラムをおしえてください。しかし、変数はあくまでint型を用い、floatやdouble型は使用しない方法でお願いします
int add( int a, int b )
{
int i;
int d = ( b>0 ? 1 : -1 );
int n = ( b>0 ? b : -b );
for( i=0; i<n; ++i )
{ a += d; }

return a;
}

int mul( int a, int b )
{
int i;
int r = 0;
int n = ( b>0 ? b : -b );
for( i=0; i<n; ++i )
{ r = add( r, a ); }

return ( b>0 ? r : -r );
}

int fn( int kitten )
{
return ( kitten>1 ? mul( kitten, fn(kitten-1) ) : 1 );
}

A 回答 (2件)

質問の意図に反しますか、double型は2^53までの整数を、誤差無しで


保持出来ることは知っておいた方が良いでしょう。

多倍長演算は随分色々作りましたが、ここでちょろっと教えられるようなコード量
ではないです。検索しましょう。
Javaやpythonなら、何も作らず利用出来ます。
    • good
    • 0
この回答へのお礼

ありがとうございます

お礼日時:2017/07/07 23:19

log_2(13!)≒32.54なので、 intが33bit以上ある処理系を使えば解決。


intが64bitなら、20!まで正しく求められます。

C言語の規格では、 intのビット幅は決まっていません。
あなたが使っているものが、たまたま int=32bitなだけです。


これって、 関数fn が、 階乗を求める関数ですよね?
ということは、int型を返す 関数fn では、どんなに中で正しく計算できても、 fn()は 32bitまでしか正しく返すことはできません。
つまり、intをやめない限り、 fn(13) は正しく求められません。


どこにも m ,n が出てきていませんが、もしかして順列 (nPm) または組合せ(nCm) を求めるために、階乗を使っているのでしょうか?
それなら、階乗を使った公式ではなく、別の計算方法を使います。

nPm なら n・(n-1)・…・'(n-m+1) を計算する。
nCm なら、 分子と分母に分けて、オーバーフローしないように掛けて、約分して既約分数にしてを繰り返す。

それでも、組合せの性質上、nは大して大きくできませんが。
    • good
    • 4

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aと関連する良く見られている質問

Qプログラムの改良

人の作ったプログラムを改良することになりました。
Visual C++ は初めてですが、CやC++は一通り勉強しています。

そこで、いろいろ調べているのですが、
例えば
「MFCは使わずに,Win32API SDKを用いた方法」
などという説明があります。

自分が対応しているプログラムが、そのどちらであるか、あるいはほかの方法で作られているか
というのはどうしたら分かるのでしょうか?

Aベストアンサー

No1です
私はC++は全然触ったこと無いので
あまり的確な回答は期待しないでくださいね

Q1.いいんじゃないでしょうか?
MSDNのOnPoint↓
https://msdn.microsoft.com/ja-jp/library/01c9aaty.aspx

OnPointクラス(Cwndクラス)
https://msdn.microsoft.com/ja-jp/library/1xb05f0h.aspx
このページの一番最初に
「Microsoft Foundation Class ライブラリにあるすべてのウィンドウ クラスの基本機能が用意されています。」と書いてありますから
そういうことですね

Q2.なんでもいいと思いますけど
そもそもあなたが対応するプログラムが
きちんとWin32のみで、もしくはMFCのみで書かれているとは限らないですからね
適当に作られて、両方が混在している可能性だってありますし

Q3.そこからですか
そこは調べればすぐ出てくるかと思いますが
MFCというのはWin32をラッピングしたものです

Q4.作った本人に聞く
仕様書とかがあるならそれを見る

No1です
私はC++は全然触ったこと無いので
あまり的確な回答は期待しないでくださいね

Q1.いいんじゃないでしょうか?
MSDNのOnPoint↓
https://msdn.microsoft.com/ja-jp/library/01c9aaty.aspx

OnPointクラス(Cwndクラス)
https://msdn.microsoft.com/ja-jp/library/1xb05f0h.aspx
このページの一番最初に
「Microsoft Foundation Class ライブラリにあるすべてのウィンドウ クラスの基本機能が用意されています。」と書いてありますから
そういうことですね

Q2.なんでもいいと思いますけど
そもそもあなたが...続きを読む

QプログラミングC言語

急募



行列の計算(xとyとx*y)を表示するプログラムを作成したのですが、デバックなしで実行はできたがプログラムが、表示されません。
どなたか、プログラムの間違えているところ、間違えているところの正しい答えを教えていただけないでしょうか


#include<stdio.h>

int main(void)

{
int i,j,k;

int x[2][3]={{3,0,3},{4,5,6}};
int y[3][2]={{1,5},{5,3},{8,1}};
int z[2][2]={0};

for(i=0; i<3; i++){
for(j=0; j=2; j++){
for(k=0; k<2; k++)

z[i][j]+=x[i][k]*y[k][j];
}
}

printf("行列X=\n");

for(i=0; i<2; i++){
for(j=0; j<3; j++)
printf("%3d",x[i][j]);
putchar('\n');

}

printf("行列Y=\n");

for(i=0; i<3; i++){
for(j=0; j<2; j++)
printf("%3d",y[i][j]);
putchar('\n');
}


printf("\nx*y=\n");

for(i=0; i<2; i++){
for(j=0; j<2; j++)
printf("%3d",z[i][j]);
putchar('\n');
}



return 0;
}

急募



行列の計算(xとyとx*y)を表示するプログラムを作成したのですが、デバックなしで実行はできたがプログラムが、表示されません。
どなたか、プログラムの間違えているところ、間違えているところの正しい答えを教えていただけないでしょうか


#include<stdio.h>

int main(void)

{
int i,j,k;

int x[2][3]={{3,0,3},{4,5,6}};
int y[3][2]={{1,5},{5,3},{8,1}};
int z[2][2]={0};

for(i=0; i<3; i++){
for(j=0; j=2; j++){
for(k=0; k<2; k++)

z[i][j]+=x[i][k]...続きを読む

Aベストアンサー

とりあえず、1っ箇所修正しました。
//修正・・・とコメントを入れておきます。

#include<stdio.h>

int main(void)

{
int i,j,k;

int x[2][3]={{3,0,3},{4,5,6}};
int y[3][2]={{1,5},{5,3},{8,1}};
int z[2][2]={0};

for(i=0; i<3; i++){
for(j=0; j<2; j++){ //修正
for(k=0; k<2; k++)

z[i][j]+=x[i][k]*y[k][j];
}
}

printf("行列X=\n");

for(i=0; i<2; i++){
for(j=0; j<3; j++)
printf("%3d",x[i][j]);
putchar('\n');

}

printf("行列Y=\n");

for(i=0; i<3; i++){
for(j=0; j<2; j++)
printf("%3d",y[i][j]);
putchar('\n');
}


printf("\nx*y=\n");

for(i=0; i<2; i++){
for(j=0; j<2; j++)
printf("%3d",z[i][j]);
putchar('\n');
}



return 0;
}

とりあえず、1っ箇所修正しました。
//修正・・・とコメントを入れておきます。

#include<stdio.h>

int main(void)

{
int i,j,k;

int x[2][3]={{3,0,3},{4,5,6}};
int y[3][2]={{1,5},{5,3},{8,1}};
int z[2][2]={0};

for(i=0; i<3; i++){
for(j=0; j<2; j++){ //修正
for(k=0; k<2; k++)

z[i][j]+=x[i][k]*y[k][j];
}
}

printf("行列X=\n");

for(i=0; i<2; i++){
for(j=0; j<3; j++)
printf("%3d",x[i][j]);
putchar('\n');

}

printf("行列Y=\n");

for(i=0; i<3; i++){
for(j=0; j<2; j+...続きを読む

Qプログラミング初心者です!このエラーの意味があまりよくわからないのですがどういう意味なのでしょうか?

このプログラムのエラーの用語?みたいなやつの意味がよくわからないので教えてください!

Aベストアンサー

すみません、画像が不鮮明で、詳細まではわかりません。

class Class1 {}
でよろしいでしょうか?
文法通りに解釈すれば、これでClass1の定義は終了です。
ここで区切られなければならないならない筈が、なんか続きっぽく書いてある、ということでエラーになっています。

その後に続く { 以降は、Class1の外です。
本当は、この後の部分が Class1の内容ではないでしょうか?
だとすると、Class1直後の{} が不要です。


エラーメッセージは、コンピュータの解釈した内容で表示されます。
本当の原因が、エラーメッセージの通りであるとは限りません。
表示された行より前を確認しましょう


また、エラーメッセージが沢山出てもあわてないことです。
一つ間違いがあると、本来正しい箇所まで間違っていると判断されてしまうことがよくあります。
そんなときは、その一つを治すだけで一気にエラーが無くなります。

QC言語 昇順・降順 ソート

C言語の勉強をしている者です。
課題を解くのに行き詰っているのですが、
どのように解くことが好ましいでしょうか。

よろしくお願いします。
___________________________

・パラメータ1に降順か昇順か数字を入力させる。
 例)降順0昇順1
 0か1以外の入力はエラー表示。

・パラメータ2~10の数字チェック、数字以外はエラー表示し終了。

・動的メモリを取得しパラメータ2~10の数字を動的メモリに格納する
 取得できない場合はエラー表示し終了。

・動的メモリ上のパラメータ2~10の数字を
パラメータ1(降順・昇順)に従いソートし表示する。

・動的メモリを開放し終了。
___________________________

[注1]パラメータ2~10の数字は1~999までとする。

Aベストアンサー

main関数の引数*argc, *argvがポインタになっている意味を考えるか、引数の個数を何度か変えてはデバッガを使ってポインタの中身をチェックすれば、引数の数を可変にしているやり方が見えてくる。
引数の個数に合わせて、データ型に応じた適切なサイズのメモリをアロケートし、配列なり、リストなりを使ってデータを格納し、処理終了時にメモリを忘れずに解放。
ソートの仕方に関しては、たいていのアルゴリズム解説本にプログラミング言語が違っていても記してあるから、読んで参考にするだけ。

QCのプログラムに無性にイライラするのはおかしいですか?

CQ出版のインタフェース 2017-5 の記事のプログラム例に
for( i=0; i<256; i++){
 for( y =0; y < Y; y++ ){
  for( x = 0; x < X; x++){
   p[0] = img -> imageData[img->widthStep* y + x*3 ]; //B(青色)
   if(p[0]==i){hn[i]++;}
  }
 }
}
がありました。このリストを見て、無性にイライラするのは私だけでしょうか?

なぜ、i,y,x の3重のループで処理しないといけないのか、y,xの2重ループで十分ではないかと思います。

for( y =0; y < Y; y++ ){
 for( x = 0; x < X; x++){
  p[0] = img -> imageData[img->widthStep* y + x*3 ];  //B(青色)
  hn[ p[0] ]++;
 }
}

3重にするならせめて、y,x,i の順にしてp[0]への代入は1回で済ませればと思います。

for( y =0; y < Y; y++ ){
 for( x = 0; x < X; x++){
  p[0] = img -> imageData[img->widthStep* y + x*3 ];  //B(青色)
  for( i=0; i<256; i++){
     if(p[0]==i){hn[i]++;}
  }
 }
}

最近のコンパイラの最適化では、私の書いたようなコーディング(修正?)は無意味なのでしょうか?

CQ出版のインタフェース 2017-5 の記事のプログラム例に
for( i=0; i<256; i++){
 for( y =0; y < Y; y++ ){
  for( x = 0; x < X; x++){
   p[0] = img -> imageData[img->widthStep* y + x*3 ]; //B(青色)
   if(p[0]==i){hn[i]++;}
  }
 }
}
がありました。このリストを見て、無性にイライラするのは私だけでしょうか?

なぜ、i,y,x の3重のループで処理しないといけないのか、y,xの2重ループで十分ではないかと思います。

for( y =0; y < Y; y++ ){
 for( x = 0; x < X; x++)...続きを読む

Aベストアンサー

利点を考えてみました


これを並列処理したときに
スレッド0: hn[0] に p[0] = 0 をカウント
スレッド1: hn[1] に p[0] = 1 をカウント
...
とすれば、
・img -> imageData は読み出すだけなので衝突しない
・hn[i] でアクセスする領域は、スレッド毎に i が違うので、同じ箇所に書き込まれることはない。
となり、排他処理が不要となります。
(もちろん、x,y,i,p[0]はスレッドでローカルな変数とします)

ただ、並列処理のオーバーヘッドや同時並列処理数等を考えると、こんな並列処理はしない方が効率的です。


あるいは、hn[]がシークに時間がかかる領域の場合、
hn[p[0]) で毎回違う位置を探しに行って、その時間が無視できないほどだったら、
先にhnを決めてしまった方が速くなるでしょう。

こちらも、非現実的です。

Qこれがどーゆープログラムなのかわかりません。 教えてください

これがどーゆープログラムなのかわかりません。
教えてください

Aベストアンサー

No.1さんの通りなので、私にベストアンサーは不要ですが、補足で。
書いてある通り素直に読めばいいだけでなんのトリッキーなアルゴリズムでもないですよ。

aが1~9の間以下を繰り返す。
bが1~9の間以下を繰り返す。
cにaとbの乗算結果を代入して出力する。
bが9まで繰り返したら1行改行する。
aが9まで繰り返したら処理結果0を設定してプログラムを終了する。

流れで言えば、
aが1で、bが1,2,3 ... 9と動いていくので、c=1*1 , c=1*2 , c=1*3 .... c=1*9の次
aが2で、bが1,2,3 ... 9と動いていくので、c=2*1 , c=2*2 ...

C言語を日本語にしただけですが、どのあたりで悩んでいるのか書いてくれれば違った回答があるかと。
それともC言語がわからないということでしょうか?
includeとかmainとかわかりますか?

Qプログラミング C言語

多重ループを用いて、クラス数、生徒数,生徒の点数を入力したときに、各クラスの平均点,
及びクラス全体の平均点を算出するプログラムを作成しているのですが、どこが間違えているかわかりません。どなたか間違えているところ、答えを教えて頂けないでしょうか。

これが、自分で作成したプログラムです。


#include<stdio.h>

int main(void){
int a,b,c=0,i,j,sum=0;
double ave=0;

printf("クラス数を入力してください:"); scanf("%d",&a);
printf("生徒数を入力してください:"); scanf("%d",&b);


for(i=1; i<=a; i++){
for(j=1; j<=b; j++){
printf("クラス%d:%d人目の点数を入力してください:",i,j,c); scanf("%d",&c);
sum=sum+c;

}

printf("クラス%dの平均点は%fです。\n",i,ave=sum/b);


}

printf("クラス全体の平均は%dです。",i,ave/a);

return 0;
}

多重ループを用いて、クラス数、生徒数,生徒の点数を入力したときに、各クラスの平均点,
及びクラス全体の平均点を算出するプログラムを作成しているのですが、どこが間違えているかわかりません。どなたか間違えているところ、答えを教えて頂けないでしょうか。

これが、自分で作成したプログラムです。


#include<stdio.h>

int main(void){
int a,b,c=0,i,j,sum=0;
double ave=0;

printf("クラス数を入力してください:"); scanf("%d",&a);
printf("生徒数を入力...続きを読む

Aベストアンサー

とりあえず、追加、修正した箇所にコメントいれてあります。

#include<stdio.h>

int main(void){
int a,b,c=0,i,j,sum=0;
int allsum = 0; //追加
double ave=0;

printf("クラス数を入力してください:"); scanf("%d",&a);
printf("生徒数を入力してください:"); scanf("%d",&b);


for(i=1; i<=a; i++){
sum = 0; //追加
for(j=1; j<=b; j++){
printf("クラス%d:%d人目の点数を入力してください:",i,j,c); scanf("%d",&c);
sum=sum+c;
allsum=allsum+c; //追加

}

printf("クラス%dの平均点は%fです。\n",i,ave=sum/b);


}

printf("クラス全体の平均は%fです。\n",ave=allsum/(a*b)); //修正

return 0;
}

とりあえず、追加、修正した箇所にコメントいれてあります。

#include<stdio.h>

int main(void){
int a,b,c=0,i,j,sum=0;
int allsum = 0; //追加
double ave=0;

printf("クラス数を入力してください:"); scanf("%d",&a);
printf("生徒数を入力してください:"); scanf("%d",&b);


for(i=1; i<=a; i++){
sum = 0; //追加
for(j=1; j<=b; j++){
printf("クラス%d:%d人目の点数を入力してください:",i,j,c); scanf("%d",&c);
sum=sum+c;
allsum=allsum+c; //追加

}

printf("クラス%d...続きを読む

QC言語 a * b / c の計算

特に困っているわけではないのですが、エレガントな方法が見つからないので質問します。

a,c は32ビット、bは8ビット、0<a≦c、0<b がわかっているとします。
このとき、8ビットの整数計算値 a * b / c を「最大32ビットの範囲」で計算する方法、教えてください。
一応C言語で考えていますので、以下の***の部分の具体的な計算方法がわかればうれしいです。

int a,c; // 32bit 符号付き整数
signed char b,d; // 8bit 符号付き整数
if(a<2^(32-8)) d = a * b /c;
else **** ← この部分のプログラム

Aベストアンサー

決してエレガントではありませんが、a, cは正でありしかし符号付の型だという前提で a * b / c の整数の商を求めるのであれば、最初にa - cを求めて一時変数に代入しておき、bの数だけループし、ループ中に一時変数にaを加え、それがc以上になったらdを1加えて一時変数からcを引き去ることを繰り返せば、間違いなくすべての数値は32ビット以内に収まると思います。CPUにALUしかない時代の発想で、歳がばれますね・・・

Qこの答えって4じゃないんですか?

この答えって4じゃないんですか?

Aベストアンサー

i を 1から5まで変化させてくりかえす。

i ÷ 2 の余りが 0のとき、sum に i を足す。

なので、
i = 2,
i = 4
のときに加算されるから、6

Q構造体とポインタ

他人のコードに以下のようなものがありした。

struct coma{
char a[5]......


char *p=(char *)(&coma);

Q1
(&coma)はcoma[0]のアドレスなので

(char *)(&coma)はcoma.a[0].のアドレスの中身、すなわちcoma.a[0]ということですか?
それともpのアドレスがcoma.a[0]のアドレスということですか?

Q2
おそらく、上記の解答は後者であるとして、
char *p=coma;
ではいけないのでしょうか?

あえて上記のように書く理由は何かありますか?

Aベストアンサー

>具体的な理由を指摘していただけると幸いです。
構造体の仕様変更例
struct coma{
int id; // 仕様追加
char a[5];
float b[20];
.....
}

コーディング内で、特定の構造体メンバー(coma[0])を示す目的で
>char *p=(char *)(&coma);
の様な使い方をしている場合には、それを知らないプログラマーが、上記の
様な構造体の仕様変更をした場合、動作不良を起こします。
#(char *)で、キャスト(型変換)しているので、コンパイル事にはエラー
#にならない。

>それなりの会社に発注したものなので
たまに頭が良い人が「自分にはこんなすごいテクニックを駆使したプログ
ラムが作れるんだ!!」と言わんばかりに自慢げに作ったプログラムの中
には、並のプログラマーには十分理解できず修正・変更ができない、又は解釈
を間違えた結果、トラブルを起こす場合が有ります。
#一般的な注意点。今回分はNo2へのお礼が有ったので撤回します。

No.2の回答へのお礼
>なお、ソケット通信で受け取ったデータがpに入っていて、
>それを comaに代入するための準備コードです。
できれば、これを先に出して欲しかった...
これだと、coma構造体の先頭アドレスを、char *pに渡す意味になります。
特定の構造体メンバー(coma[0])を示す意味では有りません。
今回のソケット通信では、構造体にセットしたデータを、指定されたバイト
数(構造体サイズ)単位で、通信を行っているようです。

>具体的な理由を指摘していただけると幸いです。
構造体の仕様変更例
struct coma{
int id; // 仕様追加
char a[5];
float b[20];
.....
}

コーディング内で、特定の構造体メンバー(coma[0])を示す目的で
>char *p=(char *)(&coma);
の様な使い方をしている場合には、それを知らないプログラマーが、上記の
様な構造体の仕様変更をした場合、動作不良を起こします。
#(char *)で、キャスト(型変換)しているので、コンパイル事にはエラー
#にならない。

>それなりの会社に発注したものなので
...続きを読む


人気Q&Aランキング