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

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

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

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

Q&A

解決済

4回答

3292閲覧

標準入力から与えらる正整数 m を読み取り、m 番目のメルセンヌ数を書き出すプログラムを組みたいです

Taka787

総合スコア23

C

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

0グッド

0クリップ

投稿2018/05/22 05:15

前提・実現したいこと

標準入力から与えらる正整数 m を読み取り、m 番目のメルセンヌ数を書き出すプログラムを組みたいです。
※メルセンヌ数とは、 2^m-1 です。

発生している問題・エラーメッセージ

標準入力に100を入れ実行すると、1267650600228229401496703205376 になります。 正解は1267650600228229401496703205375 なのですが・・・ 54以降はなぜか、1足されたものが出力されます。

該当のソースコード

C言語

1#include <stdio.h> 2#include <math.h> 3 4int main(int argc, char *argv[]) { 5 double m; 6 double a; 7 double b; 8 9 scanf("%lf", &m); 10 11 a = pow(2,m); 12 b = (a-1); 13 14 printf("%.0f", b); 15 printf("\n"); 16 return 0; 17}

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

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

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

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

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

guest

回答4

0

doubleは浮動小数点数型です。

浮動小数点数というのはざっくり言うと
(+/-)1.aaaa x 2^bbbb
というような数値表現です。例えば1.01001 x 2^5のように。

そして、doubleの場合、aaaaの部分(仮数部)は52ビット、2進数で52桁と決まっています。
1.の部分も合わせると、53桁になります。

(2^53)-1 は2進数で1111111..11(1が合計53個)ですから、
doubleで誤差なく表すことができるメルセンヌ数はm=53までとなります。

投稿2018/05/22 05:42

ozwk

総合スコア13521

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

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

Taka787

2018/05/22 05:44

m=53以上の値を求めるにはどのようにすればよいのでしょうか?
nob.

2018/05/22 05:49

そういうのを「多倍長整数」といいます。 多倍長整数を扱うライブラリを探してください。 無ければ自分で作りましょう。
Taka787

2018/05/22 10:25

皆さん分かりやすい回答ありがとうございます。 解決できました。
guest

0

ベストアンサー

こんにちは

まず初めに

他の方もおっしゃるとおり

倍精度浮動小数点数 任意精度演算

で実装するのがいいと思います。
質問欄にあるソースコードを見て、質問者もその方針で進めていると思います。

しかし、他の方法を思いついたのでその方法を説明したいと思います。
あまり参考にならないかもしれませんが、
一応、求めたいものは求まったので少しでも参考になれば幸いです。

どんな方法で実装するのか?

そもそもintlongではなくdoubleで求めたかを考えるとそれは
結果がとても大きな自然数であり、intlongではオーバーフローしてしまうからです。
そこで考えたのは各桁をそれぞれ配列に格納すればいいと思いました。
各桁の数字は0以上9以下なのでintで十分に収まります。

(i)初期化として、配列の0番目を1それ以外は0とする。
(ii)配列に格納されている数字をそれぞれ2倍する。
(iii)配列に格納されている数字が10を超えた場合、次の桁へ繰り上げる。
(iv) (ii),(iii)をそれぞれn回繰り返す。
(v) 一桁目(配列の0番目)を1引く.

以下、私が書いたソースコードを載せておきます。

注意

(i)今回は100番目のメルセンヌ数を求めたいので、配列の要素数は31くらいでいいですが、
もっと大きなメルセンヌ数を求めたい場合を考え,配列の要素数を100にしています。

(ii) n桁目の数字は配列のn - 1番目に格納されていますが、表示するときは、逆順にする必要があります。

例えば、1桁目の数字は配列の0番目に格納されていますが、1桁目は数字の一番右にあります。
しかし、for文で回すときカウントする数字を0から回すと1桁目が1一番左に表示されます。
そのため、、for文で回すときカウントする数字を(桁数 - 1)から回す必要があります。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4#define BUFSIZE 256 5#define MAX_NUMBER 100 6 7void Mersenne_primes(int); 8 9int main(void) { 10 11 char buf[BUFSIZE]; 12 int n; 13 14 fgets(buf,sizeof(buf),stdin); 15 n = atoi(buf); 16 Mersenne_primes(n); 17 18 return 0; 19} 20 21void Mersenne_primes(int n) 22{ 23 int answer[MAX_NUMBER]; 24 int carry = 0; //桁上がり 25 int digit = 1; //現在の桁数 26 int i,j; 27 int num; 28 for(i = 0; i < MAX_NUMBER; i++){ 29 answer[i] = 0; 30 } 31 answer[0] = 1; 32 33 for(i = 0; i < n; i++){ 34 for(j = 0; j <= digit; j++){ 35 num = answer[j] * 2 + carry; 36 carry = num / 10; 37 answer[j] = num % 10; 38 if(carry > 0 && j + 1 > digit){ 39 digit++; 40 } 41 } 42 carry = 0; 43 } 44 answer[0]--; 45 46 for(i = digit; i >= 0; i--){ 47 printf("%d",answer[i]); 48 } 49}

<結果>
イメージ説明

投稿2018/05/22 07:16

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Taka787

2018/05/22 10:23

詳しい回答ありがとうございました。 おかげさまで理解できました!
退会済みユーザー

退会済みユーザー

2018/05/22 11:53

質問内容とは全く別の方針だったのですが、役に立ったので良かったです。 ちなみに私は最初,質問のタイトルを見てメルセンヌ素数と勘違いをしました。(笑)
退会済みユーザー

退会済みユーザー

2018/05/22 11:56 編集

ちなみに計算したところ,配列の要素数が100(つまり100桁)で求めることができるの自然数の最大値は2^332 - 1です。
Taka787

2018/05/23 22:20

勘違いさせてすみません( ;∀;) 有難うございました。( ´∀` )
退会済みユーザー

退会済みユーザー

2018/05/24 03:07 編集

いえいえ、これは、私の勘違いなので....(おそらく数学のメルセンヌ素数と完全数が好きなのが原因)
guest

0

double ではなくて long などで試せばおかしな値になってしまうのでわかりやすいのですが、コレは double 計算精度を超える値を使っていることによる丸め誤差ですね。
たとえば、 a が巨大な数になった時、大きな値を表現するためのビットに対して -1 などの小さな値は決められた数のビット数では表現できません。

c

1a = 10000000000000000; 2b = a - 1;

もし具体的にこれらの値を計算したい場合は、「任意精度演算」などを参照すると良いと思います。

投稿2018/05/22 05:58

mather

総合スコア6753

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

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

Taka787

2018/05/22 10:24

初めて知りました。とても参考になりました。ありがとうございます。
guest

0

倍精度浮動小数点数

これをみて、2の100乗という数値がどういう表現になるか考えてみましょう。
そして、そこから1を引く、ということがどういうことかを考えると、おのずと理解できるかと。

投稿2018/05/22 05:39

y_waiwai

総合スコア87749

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

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

Taka787

2018/05/22 10:26

なるほどです。よく理解できました。有難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問