恥ずかしい内容の質問になってしまいますが、お願いします。
ある計算をしていて、出力する計算式の中の変数の値を変えれば、結果も当然変わると思うのですが、変わらなくて困っています。
簡単に説明いたしますと、以下のようなことが起こります。(例ですが)
A=2;
B=5;
C=10;
として、
D=(A+C)/(1-A*B);
という計算で、A,B,Cを変えればDも変わるはずのところ、BとCの場合はいいのですが、Aの時だけ、値を変えてもDが全く変わりません。
つまりある変数だけ、いくらいじっても結果に全く影響しないということです。他の場所で、その変数を定義してるとかってこともありません。約分とかでその変数が出力式から消せるということもありません。コードはすべて並列的に書いていますし、特にその変数だけ特別な書き方をしているわけではありません。
何か原因として考えられることはありますでしょうか?
ちなみに実際は、A,B,Cは配列を含んだ計算式の形で、下に簡単に示します。
式中の配列の値は分かっています。
for(・・・){
・・・
A[j][x]=(I[0]*(M1[j][x]+I[4]*M2[j][x])-(M3[j][x]+I[4]*M4[j][x]));
B[j][x]=I[0]/(I[0]*(M1[j][x]+I[4]*M2[j][x]));
C[j][x]=(I[0]*(N1[j][x]+I[4]*N2[j][x])-(N3[j][x]+I[4]*N4[j][x]));
・・・
}
〜〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜
for(・・・){
・・・
D[j][x]=pow(abs((A[j][x]*C[j][x])/(1.0-A[j][x]*B[j][x])),2);
・・・
}
>何か原因として考えられることはありますでしょうか?
ありません。プログラムは書いたソースの通りにしか動きません。変わらないのはあなたのソースがそうなっているからです。まあバグの原因が分からないと、つい自分以外のせいにしたくなるのは初心者にありがちです。
一応ヒントとして
1、単なるソースの記述ミス
2、少数が必要な計算でdoubleじゃなくintを使ってる
3、intのつもりで実はアドレス(ポインタ)を計算してる
配列を使ってるようですので3の可能性もありますね。またCの配列は間違って記述してもそのままコンパイルが通って動いてしまうことがあるので注意がいります。そこら辺はVBと違ってやっかいな部分です。
…本当に中身の値を計算しているのかね?
とおりすがりさんの指摘の通り、ポインタを…な感じがする。
質問の答えではありませんが
>D[j][x]=pow(abs((A[j][x]*C[j][x])/(1.0-A[j][x]*B[j][x])),2);
pow(abs(...),2)はpow((...),2)で良いのでは?
Aの式をもう少し分割して適当な変数に代入しデバッガで値を確認しながら
動かしてはどうでしょう?
fprintfで値をファイルに落としてもいいと思います。
問題点を絞り込む術を身につけましょう
Temp1 = M1[j][x]+I[4]*M2[j][x] ;
Temp2 = I[0] * Temp1 ;
Temp3 = I[4] * M4[j][x] ;
Temp4 = M3[j][x] * Temp3 ;
A[j][x] = ...
ご返信ありがとうございます。
一つ分かったこと(これがまた疑問な点ではありますが)がありますのでご報告いたしますと、配列を宣言する順番によって計算結果が変わることがわかりました。例えば極端に書くと、
double A[81][21];
double B[81][21];
を、
double B[81][21];
double A[81][21];
という順序に変えるだけで、同じ計算をしていても値が違うのです。
そこで、問題としている「Aの値を変えても結果に影響しない」ということですが、計算式に用いている各配列(BとかCとか)の宣言の順番を変えたところ、計算結果が変わるのと同時に、それまでAがおかしかったのが、今度はBがおかしくなるというようになりました。つまり、参照されない変数(配列)が、宣言の順番によって変化するという現象が起こります。
以上より、新たな疑問点としまして、
①宣言の順番を、数行でも変えることによって、結果が異なること
②宣言の順番によって、参照されない変数(配列)も変わること
③必ずひとつ参照されない変数(配列)ができてしまうこと。
があげられます。
これらの現象と、アドレス指定とかの関係は何かあるのでしょうか?私は、宣言の箇所で、静的に確保していると思っているので、ポインタの概念は導入していないつもりではありますが・・
いろいろ書いてしまって申し訳ありません。ご教授いただけたらと思います。
開発環境はVC++2005,CLRです。
jとかxとかの取りうる範囲はどうなっていますか?
明らかにバッファオーバーした感じの現象です。Blueさんの指摘のようにjやxが81や21を超えてませんか?
>ポインタの概念は導入していないつもりではありますが
初心者向けに大幅に省略して説明すると配列=ポインタです。なので配列を使ってる=ポインタを使ってると思ってください。厳密には違うのですが、それは中級者や上級者になってから勉強し直してください。
まあどうみてもバッファ(添え字)オーバー等のイージーミスですよ。
少し原因が分かった気がします。
私は以前この掲示板で複素数に関する質問をさせていただいた者ですが、
そのとき複素数はメモリを実数の2倍食うということを教えていただきました。
ここで問題としている計算式は、全て複素数の計算なんですが、配列を宣言するときに、
complex<double> A[81][21];
complex<double> B[81][21];
というように宣言していたので、これがそもそもバッファフローの原因なのではないかと思います。配列で確保した部屋には、複素数は入れることができないのでは?と思います。実数で計算したらちゃんとできたので..
そこで、複素数を配列に入れる方法について、正しい記述の方法があるのでしょうか?ご存知の方いましたら教えていただきたいです。
お願いします。
>jとかxとかの取りうる範囲はどうなっていますか?
について回答もらえないのでしょうか?
すみません。
jは0から80の値を、xは0から20の値をとります。
>jは0から80の値を、xは0から20の値をとります。
それは自分がそう思っているだけで、実行時にはオーバーしているのではないですか?(というかバッファオーバーフローはそうやって起きます)
printf()を使ってjやxの中身を表示するなり、配列を使っている部分全てに
>assert( j>=0 && j<=80 );
のようなアサートを入れてチェックしてみて下さい。
とりあえず
double A[81][21];
などの配列を全て
double A[500][500];
位にして計算してみては?
>A,B,Cを変えればDも変わるはずのところ、BとCの場合はいいのですが
>Aの時だけ、値を変えてもDが全く変わりません。
と
>配列を宣言する順番によって計算結果が変わることがわかりました
からバッファオーバーフローという回答になっているのだと思います。
例えば適当に新規でプロジェクトを作って
{
int A[2];
int B[2];
int C[2];
for(int i=0;i<=2;i++) {
A[i] =2;
B[i] =5;
C[i] =10;
}
} <-ココでブレーク
ブレークして、A,B,Cの配列の中身を確認してみてください。
A[0]の値が書き換わっていませんか?
#もしかしたら変わるのはA[0]じゃないかも・・
この場合上記でA[i] =100;にしたとしても
A[0]+B[0]+C[0]
のような計算では結果が同じになると思います。
また定義の順番を変えると
B[0]の値がおかしくなるのが確認できると思います。
#上記のプログラムは実行続けるとアサートます。
#あくまで確認ということで・・
遅くなりましたが、解決しました!
なさんがおっしゃるように別プロジェクトで試しでいろいろやってみた結果、確かにわざとバッファオーバーフローさせると、ある値がおかしくなる現象が起こりました。
しかし、どこが原因か見つからず、計算過程を一つずつコメントアウトしていったら、ある配列の部分がバッファーオーバーしていることに気付き、そこを直したらうまくできました。
だいぶ時間がかかってしまいましたが、ご協力ありがとうございました。
とおりすがりさん、ん?さん、TT414さん、Blueさん、なさん、ありがとうございました。
ツイート | ![]() |