
No.1ベストアンサー
- 回答日時:
int factorial(int n) {
int i, fact;
for (i = 0; i <= n; i++) {
if (i == 0) {
fact = 1;
} else {
fact *= i;
}
}
return fact;
}
int combination(int n, int r) {
if (r <= 0) {
return 1;
} else {
return factorial(n) / (factorial(r) * factorial(n - r));
}
}
この回答へのお礼
お礼日時:2020/12/15 15:00
投稿者です。
作成完了したんですけど、20C10みたいな大きい数字だと計算できないのですが、その理由を教えていただきたいです!!
No.11
- 回答日時:
C の場合
・int は -(2^15-1)~(2^15-1)
・long は -(2^31-1)~(2^31-1)
・ついでに long long は -(2^63-1)~(2^63-1)
が規格上の最小範囲>#10. だから, 「一番狭い」処理系を考えると 8! ですでに範囲を超えてしまう... というか, この場合の「ロジックと全く関係ないトコで計算テクニックが必要」は「多倍長演算を自動でやってくれない」すべての言語の「問題」で, ことさら C だけあげつらう理由もないんではないかと. 強いていえばカテゴリーくらい?
ちなみにいうと #7 の指摘はいい線をついていて, たとえば
・順序を逆にして割り算を先にする
・めんどくさいので 1つの文にする
なんてやると指摘されている通りの現象が発生します. 約分してから処理するなら, 2つの文に分ければ順序はどっちでもいいんだけど (ただし 1つの文にしちゃうと相変わらず問題が発生する).
あと修正感謝>#9.
No.10
- 回答日時:
> 20C10みたいな大きい数字だと計算できないのですが、その理由を教えていただきたいです!!
1つは、factorialがかなり速く大きくなるから、ですよね。
一応ロジック自体は書いた通りなんですが、C言語の厄介なトコは、「ロジックと全く関係ないトコで計算テクニックが必要」な辺りです。初学者に向かない理由がその辺なんですよねぇ。
例えば、
1*2*3*4*5*6*7*8*9*10
とたった10個の数だけ、で計算結果が3628800、と7桁、にも達します。11をこれに掛けるだけで8桁突破するのも分かりますよね?10の位を超えた数を今後かけていくと、最低でも桁がひとつづつ増えていって、コンピュータ(っつーかC言語)じゃなかなか扱いづらい桁数へと突入していきます。
実際は、C言語の仕様上、intがどこまで扱えるのか、ってのは実装依存になってたと思います。1つの解決策としてはintを使わずに、もっと桁数が大きく扱えるlongを使う事。また、正の整数しか扱わない、と言う前提で、符号なしの整数にしてしまう、と言う手があります(unsigned long)。
あと、combinationの計算としては
factorial(n) / (factorial(r) * factorial(n - r))
が公式通り、なんですが、この計算をする際、結果の数は小さいにせよ、factorial(n)やfactorial(r) * factorial(n-r)がデカくなる可能性があるんですよね。
良くあるこれらの肥大化の避け方、と言うのに、対数に変換して計算する、ってテクニックがあります。
つまり、
combination(n, r) = factorial(n) / (factorial(r) * factorial(n - r))
なので、両辺対数を取れば
ln|combination(n, r)| = ln|factorial(n) / (factorial(r) * factorial(n - r))|
= ln|factorial(n)|-ln|factorial(r) * factorial(n - r)|
= ln|factorial(n)|-(ln|factorial(r)|+ln|factorial(n - r)|)
= ln|factorial(n)|-ln|factorial(r)|-ln|factorial(n - r)|
になるので、これを利用利用してプログラミングします。そして、結果を返す前に指数関数で元に戻して計算結果の数の肥大化を防ぐ、ってのが割にありきたりなテクニックにはなりますね。
No.9
- 回答日時:
No2です
No.6の方法でプログラミングしてみました
int combination(int a, intb )
{
int i,s;
s=1;
for(i=0; i<b; i++) {
s *= (a-i);
s /= (i+1);
}
return s;
}
No.8
- 回答日時:
No7です
>でも計算途中で割り切れずに分数表現が必要になってしまいそうな気がしますが大丈夫でしょうか?
No6さんの計算方法では、
nCi (i=1,2,...)を計算し続けるので、必ず割り切れ整数になる
ので大丈夫ですね。
失礼しました。
No.7
- 回答日時:
>1 からはじめて
>(n-i) を掛けて i で割る
>って書けばオーバーフローしにくくなる. しないわけじゃないけど.
確かに!
でも計算途中で割り切れずに分数表現が必要になってしまいそうな気がしますが大丈夫でしょうか?
分子と分母の数列を記憶する配列を用意し、
分子にn!の計算に必要な数値1,2,・・、n を書き込み,
分母に(n-r)! / r!、 の計算に必要な数値1,2,・・、(n-r),1,2,..,rを書き込み
分子分母で約分できる部分を見つけ約分し、
(この段階で分母は全て1に約分出来ているはずなので)、
分子をかけ合わせて答えにする
のが正解かしら
No.6
- 回答日時:
1 からはじめて
(n-i) を掛けて i で割る
って書けばオーバーフローしにくくなる. しないわけじゃないけど.
もっと頑張って
(n-i)/i を約分して分母で割ってから分子を掛ける
ようにすれば, さらにオーバーフローしにくくなる... ここまでやればオーバーフローしないようになってるかなぁ.
No.5
- 回答日時:
今気がついたのですが、
bunnsi の初期値がa-b+1なのに、
bunnsiのforループが i= a-b+1から
始まってます?
a-b+1を2回かけたりしてないですか?
No.4
- 回答日時:
nCr = n! / (n-r)! / r!
combination(a,b)
= a! / (a-b)! / b!
= {1 から a までの総積}/{1 から a-b までの総積}/{1 から b までの総積}
= {(a-b)+1 から a までの総積} / {1 から b までの総積}
= 1 * (a-b+1) * (a-b+2) * ... * a / 1 / 2 / ... / b
c = 1;
for (i = a-b+1; i <= a; i++) c *= i;
for (i = 1; i <= b; i++) c /= i;
No.3
- 回答日時:
return combi; の手前に
combi = bunnsi / bunnbo;
を入れればいいだけだと思います。
(int 同士の除算は「小数点以下切り捨て」
になる。)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
65536は2の何乗なのでしょうか?
-
VBAの再計算が反映されない件に...
-
matlabで計算終了
-
モジュラス103の計算とは何でし...
-
エクセルで特定のセルのみを任...
-
Vba Cells.Findについて教えて...
-
排他的論理和 BCC(水平パリテ...
-
バッチファイルでウインドウを...
-
なぜオーバーフローになるので...
-
エクセル以外で麻雀の成績を管...
-
Perlで時間の計算
-
2次元ラプラス方程式を差分法で...
-
数値計算の高速化 (cos, sin, exp)
-
傾いた四角形内の範囲の条件式
-
科学技術計算の仕事について
-
WEBページ上で計算をさせるには...
-
VBAで一時的にオーバーフローを...
-
VBでReplace
-
ExcelのVBAで複素数は扱えない...
-
Excel VBAにてFFT
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
65536は2の何乗なのでしょうか?
-
VBAの再計算が反映されない件に...
-
EXCELなどで「返す」という表現
-
matlabで計算終了
-
排他的論理和 BCC(水平パリテ...
-
変化させるセルが変化しない
-
モジュラス103の計算とは何でし...
-
傾いた四角形内の範囲の条件式
-
VBAで関数をつくる
-
[急募]Pythonについてです。
-
数値計算の高速化 (cos, sin, exp)
-
C言語についての質問です。 ル...
-
切り上げたい
-
DLL(VC++で作った)で稼動中の...
-
CとFORTRANの計算速度はどちら...
-
趣味で「乗換案内」みたいなソ...
-
CGIの実行権限(ディスク容...
-
エクセルで特定のセルのみを任...
-
functionを含んだプログラムを...
-
時間差を求める
おすすめ情報