for文初期化で整数と実数を混在させると値が狂う

このQ&Aのポイント
  • C++のfor文で整数と実数を混在させると値が狂う問題について解説します。
  • for文の初期化処理で変数宣言を行う際、同時に他の初期化処理を記述すると、新たな変数として宣言されてしまうことが原因です。
  • この問題を回避するには、for文外で変数を宣言し、for文の初期化処理でその変数を使用するようにしましょう。
回答を見る
  • ベストアンサー

for文初期化で整数と実数を混在させると値が狂う

C++ではfor文の初期化時にカウンタ変数等の宣言ができますよね. 0°から360°を表示するプログラムの例なのですが,次のコードを見てください. int main(void) { const double drad = 2 * M_PI / 6; double rad; rad = 0.0; for (int i = 0; i <= 6; i++, rad+= drad) { // cout << "rad: " << rad << endl; cout << "deg: " << rad * 180.0 / M_PI << endl; } } このプログラムを実行すると,0°から60°ごとに360°まで表示されました. ここで,for文の初期化処理でradの初期化を行おうとして, for (int i = 0, rad = 0.0; i <= 6; i++, rad+= drad) とプログラムを書き換えたところ,表示値は deg: 57.2958 deg: 114.592 deg: 171.887 deg: 229.183 deg: 286.479 deg: 343.775 となりました. また,コメントアウトしてある行を有効にしてradの中身を直接表示させると, rad: 0 rad: 1 rad: 2 rad: 3 rad: 4 rad: 5 rad: 6 といったように,radが整数値に丸められています. int iをfor文の外で宣言して for (i = 0, rad = 0.0; i <= 6; i++, rad+= drad) としたときには,正しい角度の表示が行われました. これは,for文の初期化時に変数宣言を行うとき,同時にほかの初期化処理を記述してしまったらその変数も同じ型の新しい変数として宣言されてしまうということなのでしょうか? for (int i = 0, rad = 0.0;... →int i と int rad がスコープ内の変数として新しく宣言される?

質問者が選んだベストアンサー

  • ベストアンサー
  • maiko0318
  • ベストアンサー率21% (1483/6970)
回答No.1

>→int i と int rad がスコープ内の変数として新しく宣言される? 正解。 スコープ(forの終わりの}の外に出たらdoubleの値になります。

marriess
質問者

お礼

回答ありがとうございました. おかげ様でスッキリしました.

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

既に回答があるけど蛇足的に追加. for (あれ; これ; それ) なんか というのは, *だいたい* { あれ; while (これ) { なんか それ; } } と等価になります. つまり for (int i = 0, rad = 0.0; i <= 6; i++, rad+= drad) なんか は*だいたい* { int i = 0, rad = 0.0; while (i <= 6) { なんか i++, rad+= drad; } } と同じです. ちなみに C でもだいたい同じ.

marriess
質問者

お礼

今まではずっとCで書いてきており、今回はそれと同じ感覚で i=0;rad=0.0 while() {... となるものだと思っていました。 また、恥ずかしながら、 int A=0, B=1; といった宣言時に初期化をする書き方ができることを知りませんでした。今までは int A=0; int B=1; と書いてました^^; だから最初に気がつかなかったんですね 新しいことも知れてよかったです。 ありがとうございました。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

ついでに言うと doubleには誤差が含まれています。 rad += drad のように、doube+doubleを繰り返すと、誤差が溜まることがあります。 # たとえば、0.1+0.1+..... と100回繰り返した値!=10.0 と言う事が起こり得ます。 今回の場合は rad = drad * i とするのがよいでしょう。 詳しくは、「double 誤差」辺りで検索してください。

marriess
質問者

お礼

浮動小数点の計算誤差については少しだけ知ってはいましたが,なるほどこんな対処方法もあるんですね. これはいいことを聞きました.ありがとうございました.

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

>また,コメントアウトしてある行を有効にしてradの中身を直接表示させると, ループの外でいくつになっているのか? というのも確認してみるとよかったかも知れませんな。 http://www.ksky.ne.jp/~seahorse/cpp/loopvar.html とか。 VisualStudioなら… /Zc:forScopeオプションかな? いや、違うか??? まぁ、実際の仕様書にあたった方がいいでしょう。

marriess
質問者

お礼

>ループの外でいくつになっているのか?というのも確認してみるとよかったかも知れませんな。 確かにそうですね. 初期化部分でintを宣言したときに,ループが終わったあとのradを表示させたら,ループ前の値のままでした. これとは別に新しく変数がループ内に作られてこれが使用されていたということだったんですね. 回答ありがとうございました.

関連するQ&A

  • C++ for文からwhile文への変換方法

    まずは単刀直入にこのプログラムをご覧ください。 int two[6][10]; for(int j=0; j<net; j++){ for(int i=0; i<10; i++){ input_file >> two[j][i]; if(two[j][i]==0) break; } } for(int j=0; j<net; j++){ for(int i=0; i<10; i++){ cout << two[j][i] << " "; if(two[j][i]==0) break; } cout << endl; } このfor文をwhile文に置き換えて表示させるやりかたがよくわかりません。 今ゼミの課題でC++のプログラムに取り組んでおり、ファイル内の数字の配列を読み込んでそれを画面に表示させるプログラムを作ってるのですが、この部分がよくわからず苦戦しています。 ちなみに表示させる数字は以下の通りです。 9 11 8 0 1 10 6 0 8 2 4 10 0 5 8 7 2 0 1 3 10 4 0 2 4 12 0 どなたかご教授よろしくお願いします<(_ _)>

  • char型変数のアドレスを coutで表示するには

    #include <iostream> using namespace std; int main() { bool b; int i; short s; long l; float f; double d; char c; //上で宣言した変数のアドレスを表示 cout << "bool &b " << &b << endl; cout << "int &i " << &i << endl; cout << "short &s " << &s << endl; cout << "long &l " << &l << endl; cout << "float &f " << &f << endl; cout << "double &d " << &d << endl; cout << "char &c " << &c << endl; //「char &c 」とのみ表示される cout << '\n'; //char型のみ printf で再表示 printf("char &c %p\n", &c); //「char &c ********」と表示される return 0; } 上のプログラムを実行すると cout << "char &c " << &c << endl; のところだけ、アドレスが表示されません。 printfを使えば、char型の変数のアドレスも表示されるのですが…。 coutを使ってchar型のアドレスを表示させるにはどうすればいいのでしょうか。 よろしくお願いします。

  • integerクラスとMathクラス

    適当な整数numをキーボードから入力し、その回数だけ0から360までの整数をランダムに発生させ、その整数を角度(弧度法)とみなしたとき、その正接(tan)が最大のとなる整数を表示するプログラム を以下の手順で下記に作成した結果、角度が同じ値になります。これはどうしてですか?また、手順通りのプログラムにするにはどのようなプログラムて適切ですか?     手順      (1)最大値となる角度を代入する整数型の変数maxを初期値-90で定義する。      (2)乱数を発生させる回数を入力する。      (3)0から360までの整数を、乱数を使って1つ発生させ、整数型の変数degに保存。この値を表       示する。      (4)角度degをラジアンに変換し、実数型の変数radに代入し、表示する。変換は             rad = deg * Math.PI/180.0 (Math.PIは円周率を表す)       で行なうことができる。ただし、実際のプログラムでは上式をそのまま書くのではなく、変数       の型に注意して記述すること。      (5)radを用いて正接(tan)を計算する。      (6)maxから計算されるtanの値と比較し、(4)の結果の方が大きければmaxをdegに書き換え       る。      (7)(2)から(5)を入力した回数になるまで繰り返す      (8)maxを表示する。import java.io.*; class Kakudo3 { public static void main(String args[]) throws IOException { int max = -90; System.out.println("整数を入力"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str1 = br.readLine(); int num = Integer.parseInt(str1); int deg =(int)(Math.random()*360); for(int i=0; i<num; i++){ System.out.print(deg+","); } double rad = deg*Math.PI/180.0; Math.tan(rad); } }

    • ベストアンサー
    • Java
  • 角度の計算(C++)

    Theta cos(theta) sin(theta) 0.0    1.00     0.00 .    .     . .    .     . 上のような表示ができるプログラムを書いてます。角度は0度、5度、10度、15度、、、と5度毎に表示させないといけません。表示角度は角度は0-360度までです。 下のように書いてみましたがエラーが出てしまいます。何が問題なんでしょうか? int main(){ const double PI = 3.1415; double r = PI /180; cout<<setw(5)<<"theta"<<setw(13)<<"cos(theta)"<<setw(13)<<"sin(theta)"<<endl; for( int theta=0; theta<=360; <<theta += 5) cout<<setw(5)<<setprecision(1)<<(double)theta <<setw(14)<<setprecision(2)<<sin(theta * r) <<setw(10)<<cos(theta * r)<<endl; return 0; }

  • C++のfor文について

    C++では for ( int i = 0, j = 0; i < 10; i++ ) { } みたいな感じでforのなかで変数の宣言ができます。 ところで上の例ですとint型のiとjを2つ宣言していますが、 もしint型とchar型を宣言したい場合などは char j; for ( int i = 0; i < 10; i++ ) { } みたいにしないといけないのでしょうか? for ( int i = 0, char j; i < 10; i++ ) { } みたいにできると思ってやったらエラーになってしまうので・・。

  • java for文、if文を使っての三角形

    例:1 23 456 78910 ・・・・・・のようにひょうじさせるプログラムを作成するのに、for文とIf文を使っての三角形を   作成したいのですが、If文の条件式が分からないのとどうしたら、上記のようなプログラムが   出来るのか教えてください。お願いします。 public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ // 行に表示させる個数を表現するための変数がないため今回、新たに変数を用意する。 int a = 1; //行の終わりを改行して1増やすための変数がないため今回、新たに変数を用意する。 int b = 1; // 1~100までの数字を用意する。 for (int i = 1; i <= 100; i++) { //変数iをSystem.out.printを使って変数iをコンソールの中に出力させる。 System.out.print(i); //System.out.println("")を使って改行する。 System.out.println(" "); //変数iに1増加して数字を順番にする。 i++; if(a <= i){ System.out.print(a);

  • C++言語のプログラムをfortranに変換

    const int N = 100; const double q = 10.0, dt = 0.00001, Dm = 30.0, t0 = 2.0, K = 1.0, pi = 3.141592, f = 3.0; double C[N], dC[N]; double dx = q/N; for (int i = 0; i < N; ++i) C[i] = 0; // 初期条件 for (double t = 0; t < t0; t += dt) {  C[0] = 0; // 境界条件1  C[N - 1] = K*sin(2*pi*f*t); // 境界条件2  for (int i = 1; i < N - 1; ++i) dC[i] = (Dm*(C[i + 1] - 2*C[i] + C[i - 1])/(dx*dx))*dt;  for (int i = 1; i < N - 1; ++i) C[i] += dC[i]; } for (int i = 0; i < N; ++i) cout << C[i] << endl; // t = t0 このプログラムをfortranに変換できる方いますか?

  • 簡単なfor文

    #include <stdio.h> int main(void) { int n; int i; for(n=0 ;n<10;n++){ for(i=0; i<=n ;i++){ printf("*"); } printf("\n"); } return(0); } こういったプログラムを実行すると、以下のように表示されるのですがなんででしょうか? * ** *** 以下略 自分の考えですと、*は毎回一つしか表示されずに改行されると思うのですが・・・ * * * * 以下略 i個分の*を表示するなどという指示をプログラムはなされていないと思うのですがなぜなんでしょうか? 一つ目のfor文では10回ループが繰り返され改行 二つ目のfor文で*を永遠に表示 といった僕の解釈ではおかしいですよね。 当方C言語初心者で、周りに聞く人がいないため教えていただけると非常に助かりますm(__)m

  • 拡張for文の型変換について

    Javaでプログラミングを勉強しております。 拡張for文で変数宣言をする時についての質問です。 argsに数字を入れてString型をInt型に変換する時、変数宣言はどう書けばいいのでしょうか? 拡張for文に入れる前に Int num = Integer.parseInt(args[0]); と宣言してから for(int num : array){ 処理 } とするのか for(int num : array){ num = Integer.parseInt(args[0]) …ほかの処理 } みたいにfor文の中に埋め込むのか分かりません。 argsのString型を拡張for文でInt型にするにはどう書いたらいいでしょうか

  • 100x100行列の平均値を求めたい

    const int SIZE=100; for(int i=0; i< SIZE; i++){ for(int j=0; j< SIZE; j++){ fin >> array[i][j]; } } double sum=0.0; double ave=0.0; int J =3; for(int i=0; i< SIZE; i++){ sum += array[i][J]; } ave = sum / SIZE; cout << sum << endl; cout << ave << endl; 100x100行のファイルを読み込んで、すべての行の足し算および平均値を求めたいと思います。上のようある列(または行)を固定して求めることは出来るのですが、一度に0~99までの足し算および平均値を求めるやり方はどのようにしたらよろしいのでしょうか?たぶんfor文を使えば、できるのかなとは思うのですが、なかなか思うように行きません。 アドバイスよろしくお願いいたします。

専門家に質問してみよう