※ 私はあまり数学は得意ではないです...
CやC++でやっています。(主にBetterCというやつです)
C言語(もしくはC++)でlong longを超える値を扱う場合、どのようにすべきでしょうか。
例えば (xのn乗)を計算する Test::factorial関数があるとして、これの型をどうするかです。
ある処理(例えば暗号等)をするライブラリを組んでいて、データ列(std::stringやstd::vector etc.)
の長さを指定したい時があります。
例えば暗号であれば「平文の長さは1~(2の64乗)とする」等のような場合で
Cipherクラスがあるとして Cipher::maxPlainTextLength() で(要求する平文の)最大の長さを返したい...とかです。
その場合、私のイメージでは
TYPE Cipher::maxPlainTextLength()
と考えています。(TYPEには型名が入りますが...)
ですが、実際に最小単位のサンプルコードで試すと 2^64 を計算するだけでもオーバーフローを起こします。
桁あふれをさせずに表示できないものでしょうか。
出来れば外部ライブラリは入れたくないのですが...
一応のコード。
C++
1// 必要なヘッダはインクルードしているとします... 2 3namespace Test{ 4 // 型が不明なため... 5 using TYPE = int; 6 7 // ans = x^n 8 Test::TYPE factorial( Test::TYPE x, Test::TYPE n ){ 9 Test::TYPE tmp = 1; 10 /* 11 計算式: 12 (2の3乗) = 2 * 2 * 2 = 8 13 (2の64乗) = 2 * 2 * 2 ... = 18446744073709551616 14 */ 15 for( int i = 0; i < (int)n; i++ ){ 16 tmp *= x; 17 //cout << i << ":" << tmp << endl; 18 } 19 return tmp; 20 } 21} 22 23int main( void ){ 24 Test::TYPE ans = Test::factorial( 2, 64 ); 25 std::cout << ans << std::endl; 26return 0; 27}
上記のコードを実行すると、なぜか0となります。
factorial 内のfor中で表示させると i = 30 辺りから負の数、
それ以降は 0になっているみたいです。
そして、ProgrammingPlace Plus というサイトでは(C言語編の第19章の整数型辺り)
まず、符号無し整数型の方ですが、0 になりました。
これはつまり、最小値に戻ってきているということですが、
正確にいえば、表現できる最大値 + 1 で割った余りになっています。
と書かれています。
一応型の種類を別のもの(例えばlongやlong longとか)に変えてみればいいかなぁと思い、
試してみました。
[int] -> (i = 29) 辺りまでしか対応していない模様 [long] -> 同上 [long long] -> (i = 61) 辺りまでしか対応していない模様 (だいぶマシになった方...) [double] -> (i = 18) まではいいが、(i = 19) 辺りからは 1.04858e+06 のような数値になる [long double] -> 同上
思いつく型すべて試してみました。(charとかは別...)
それでもだいぶマシなものでも (2の64乗) の計算では i = 61 までしか表現できそうにもありません...
やはり自分でクラスなりを作るべきでしょうか。
コンパイル時は C++11 としてやっています。
(多分、C++17として使おうと思えばできるだろうけど...)
Cpprefference.com のオフライン版でチェックしてみましたが、
一番近そうなものがauto, std::any, std::varriant ぐらいでした...
(流石にautoはあり得ないし、std::anyは(加算とかで)加工して使うには
別の型(longとか)に変換しないといけないようだし..
追記:
調べてみると(unsigned long long int)と言う型を見つけたので
試してみました。
すると i = 63 で 0 に戻っていました。(= オーバーフローを起こしている)
追記:
できれば外部ライブラリに頼ることなく、(xのn乗) を表現できたらなぁ...と思っているのですが...
[追記2]
皆様、ご回答ありがとうございます。
どの回答をBAにするか悩みましたが、Amazing_GraceさんのをBAとさせて頂きます。
(できれば他の方々にもBAにしたいのですが...)
ちょっと今回の問題は私にはハードルが高かったかもしれません。(回答を読むと、私の苦手な範囲が使われていたりして...)
もうちょっと調べてから再挑戦することにします。
ありがとうございました。
回答4件
あなたの回答
tips
プレビュー