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

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

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

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

530閲覧

n = pow(2, 54); --n; と n = pow(2, 54) - 1; の違い

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2020/01/31 06:07

C++に慣れるために素数判定の関数を書き、Pythonでは時間のかかったメルセンヌ素数の判定を試そうとしたのですが、2^n - 1を表現するところで理解のできない挙動に直面しました。

1)``unsigned long long n = 1;を用意してfor文内で2乗を繰り返す、2)あるいはfor文内でn = pow(2, i);を用意してから--n;をすると、2^n - 1が正しく表現されます。 ですが、3)for文内でn = pow(2, i) - 1;とすると、2^53 - 1までは正しく計算されるのですが、2^54 - 1以降は、2^n - 1ではなく2^n`になってしまいます。

C++ - C++のpow関数でおかしくなってるのか?|teratailという質問を読んで、doubleの表現範囲の限界として52-53桁あたりで問題が起きうるというのは何となく理解したのですが、(2)と(3)のやり方で差が出る理由が分かりません。
よろしくお願いします。

1: [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

C++

1#include <iostream> 2#include <string> 3using namespace std; 4 5int main() { 6 // works fine 7 unsigned long long n = 1; 8 for (int i = 1; i <= 64; ++i) { 9 n *= 2; 10 cout << "2^"s << i << "-1: "s << n - 1 << endl; 11 } 12}

2: [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

C++

1#include <iostream> 2#include <string> 3#include <cmath> 4using namespace std; 5 6int main() { 7 // works fine 8 for (int i = 1; i <= 64; ++i) { 9 unsigned long long n = pow(2, i); 10 cout << "2^"s << i << "-1: "s << n - 1 << endl; 11 } 12}

3: [Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

C++

1#include <iostream> 2#include <string> 3#include <cmath> 4using namespace std; 5 6int main() { 7 /* 8 * incorrect from 2^54 - 1 9 * 2^53-1: 9007199254740991 10 * 2^54-1: 18014398509481984 (should be 18014398509481983) 11 */ 12 for (int i = 1; i <= 64; ++i) { 13 unsigned long long n = pow(2, i) - 1; 14 cout << "2^"s << i << "-1: "s << n << endl; 15 } 16}

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

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

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

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

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

guest

回答3

0

浮動小数点数 - Wikipedia

倍精度浮動小数点数型式、では、実数部が52ビットしかありません
52ビットのオール1(pow(2,53)-1)は表現できますが、
53ビットのオール1(pow(2,54)-1)は表現できませんね

投稿2020/01/31 06:25

y_waiwai

総合スコア87749

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

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

0

ではここで、pow関数のプロトタイプを見てみましょう。

C

1double pow(double x, double y);

型がdoubleなので、浮動小数点数の限界までしか正しい値が表現できません。


もっとも、「2の累乗」であれば、1 << 40のように計算するのが手っ取り早いです。

投稿2020/01/31 06:20

maisumakun

総合スコア145183

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

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

0

ベストアンサー

こんにちは。

pow(2, 54) - 1 はdoubleで計算されるため、-1は桁あわせの際に有効桁数を越えるため丸められて0になっているのだろうと思います。

n = pow(2, 54); --n;とした場合は、nはunsigned long longなので恐らく64ビット長の整数型でしょうから、pow(2, 54)を正確に表現でき、1引いても問題ないのだと思います。

投稿2020/01/31 06:18

Chironian

総合スコア23272

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

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

退会済みユーザー

退会済みユーザー

2020/01/31 06:52

pow(2, 54)だけでなく、pow(2, 54) - 1全体がdoubleとして計算されるのですね、腑に落ちました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問