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

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

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

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

Q&A

解決済

2回答

1828閲覧

pow関数が上手く動作しない、setに謎の値が入ってしまう。

subaru-k

総合スコア19

C++

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

0グッド

0クリップ

投稿2020/05/09 06:30

X以下の最大のべき乗数を出力するプログラムを作りたい。

問題のリンク:Atcoder097B

制約

・1 <= x <= 1000
・xは整数
・べき乗数とは、ある1以上の整数bと2以上の整数pを使ってb^pとかける整数のことを指すこととします。


この問題を解くために以下のプログラムを実装しました。

c++

1#include<bits/stdc++.h> 2using namespace std; 3int main(){ 4 int x; 5 cin>>x; 6 set<int> s; 7 8 //setに1000以下のべき乗数を全て用意 9 for(int i=1;i<=31;i++){ 10 for(int j=2;j<=9;j++){ 11 int a=pow(i,j); 12 if(1000<a) break; 13 s.insert(a); 14 } 15 } 16 17 //x以下の最大べき乗数を出力する 18 auto itr = s.end(); 19 while (itr != s.begin()) { 20 if(*itr<=x){ cout<<*itr; return 0; } 21 itr--; 22 } 23} 24

しかし、実行結果が以下のようになってしまい、上手くいきません。
(入力が10の時は上手くいった。)
入力:1 --> 出力:何も出てこない
入力:999 --> 出力:41

そこでsetの中身を、スペースで区切って末尾のイテレータから出力すると、以下のような結果になりました。

41 1000 960 899 840 783 729 675 624 576 528 512 483 440 399 361 343 324 289 256 243 224 216 196 168 144 128 124 120 99 81 64 49 36 32 27 24 16 9 8 4

ここで、以下の疑問点が浮かび上がりました。

・なぜ41という値が入っているのか?
・41がなぜ一番最初に出力されるのか?
・なぜ10^2や5^2の値がpow関数で正しく計算されていないのか?
・なぜ1^2や1^3の値がsetに入っていないのか?

これらの疑問点について、回答していただけると幸いです。

環境

OS:windows10
エディタ:atom
コンパイラ:MinGW

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

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

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

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

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

guest

回答2

0

ベストアンサー

itr.end()は最後の要素の次なので、

C++

1 auto itr = s.end(); 2 while(true){ 3 itr--; 4 if(*itr<=x){ cout<<*itr; return 0; } 5 if(itr == s.begin()) break; 6 }

でしょうか。

・なぜ41という値が入っているのか?
・41がなぜ一番最初に出力されるのか?

*(s.end())は個数のようです。

・なぜ10^2や5^2の値がpow関数で正しく計算されていないのか?

powは指数関数や対数関数を使うので、正確に計算できません。
切り捨て前に、+0.5して四捨五入にしましょう。
あるいは、整数で掛け算のループをしてべき乗を求めるか。

・なぜ1^2や1^3の値がsetに入っていないのか?

setには入ってますが、*(s.begin())を見て無いから表示されてないだけです。

投稿2020/05/09 07:18

otn

総合スコア84533

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

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

subaru-k

2020/05/09 07:56

丁寧なご回答ありがとうございます。 おかげで疑問点が解決しました。
guest

0

・なぜ41という値が入っているのか?
・41がなぜ一番最初に出力されるのか?
*s.end()は要素を指さないからです。s.end()の一つ前がsetの最後の要素です。
なので、while ループを回すならs.begin()から回す必要があります。

cpp

1 auto itr = s.begin(); 2 while (itr != s.end()) {

・なぜ10^2や5^2の値がpow関数で正しく計算されていないのか?
浮動小数点数をそのままintにキャストすると、誤差が生じて正しい値になりません。
例えば、pow(10,2) = 99.99999... を int にキャストすると 99 になってしまいます。
なので、int a=pow(10,2) + 1e-7; として 100.00000... にするか。
最初から int で累乗を計算すると解決します。

・なぜ1^2や1^3の値がsetに入っていないのか?
これは、*s.begin()が1^2=1^3=1ですが、出力する前にbreakしているためです。

あと質問とは関係ないですが気になったこととして、
int a=pow(i,j);
で、pow(i,j)の値が最大31^9になっています。
31^9をintにキャストすると、intの値の範囲 2,147,483,647 を越えオーバーフローしてしまいます。

投稿2020/05/09 06:50

minaminao

総合スコア249

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

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

subaru-k

2020/05/09 07:56

丁寧なご回答ありがとうございます。 おかげで疑問点が解決しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問