• ベストアンサー
  • 困ってます

プログラミングのエラー修正

  • 質問No.5620237
  • 閲覧数142
  • ありがとう数1
  • 回答数4

お礼率 22% (4/18)

抵抗R、コイルL、コンデンサCの値を与え、これらRLC直列回路の複素インピーダンスを共振周波数の1/10~10倍程度の範囲で数値計算し、データの組として出力するプログラムを作成するために、

#include <stdio.h>

double resonance(double x,double y)
{
return(1/2*3.14*(x*y)^(1/2);
}
int main(void) {
double r,l,c;
double r_abs,l_abs,c_abs;
double R;
double f0;

printf("put r");
fflush(stdout);
scanf("%lf",&r);

printf("put l");
fflush(stdout);
scanf("%lf",&l);

printf("put c");
fflush(stdout);
scanf("%lf",&c);


if(l==0||c==0){
R=0,X=0;
}
if(l<0){
r_abs=r;
l_abs=-l;
c_abs=c;
}
if(c<0){
r_abs=r;
l_abs=l;
c_abs=-c;
}
if(r<0&&c<0){
r_abs=r;
l_abs=-l;
c_abs=-c;
}
f0=resonance(l_abs,c_abs);

double n[]={f0/10,f0*2/10,f0*3/10,f0*4/10,f0*5/10,f0/10,f0*6/10,f0*7/10,f0*8/10,f0*9/10,f0,f0*2,f0*3,f0*4,f0*5,f0*6,f0*7,f0*8,f0*9,f0*10};

R=r_abs;

double X[]=(n[]*2*3.14*l_abs)-1/(l_abs*)*c_abs;

printf("周波数%d,Z=%lf+j%lf",n[],R,X[]);





return 0;
}
のようなプログラムを書いたのですが、if(l==0||c==0){
R=0,X=0;
}
double n[]={f0/10,f0*2/10,f0*3/10,f0*4/10,f0*5/10,f0/10,f0*6/10,f0*7/10,f0*8/10,f0*9/10,f0,f0*2,f0*3,f0*4,f0*5,f0*6,f0*7,f0*8,f0*9,f0*10};
double X[]=(n[]*2*3.14*l_abs)-1/(l_abs*)*c_abs;
printf("周波数%d,Z=%lf+j%lf",n[],R,X[]);return(1/2*3.14*(x*y)^(1/2);
にエラーが出てしまうのですがなぜだかわからないので、教えていただけませんか?

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

  • 回答No.4
  • ベストアンサー

ベストアンサー率 55% (1857/3366)

#3です。
新しいのを見たら、いろいろおかしな所に気づきました
> double f=(1/2)*3.14*a;
ここが0になります。
(1/2)が (intの1)/(intの2) = 0.5の切り捨て=0
となってしまうからです。
double f=(1.0/2.0)*3.14*a;
と小数点を付けたり、
double f=((double)1/(double)2)*3.14*a;
とキャストしたりして、doubleであることを明記する必要があります。
他の数値もdoubleとしたいところは小数点を付けた方がよいでしょう。

>if(isalpha(r)!=0||isalpha(l)!=0||isalpha(c)!=0){

doubleをisalphaで判定するのは無意味です。むしろ、誤動作の原因となります。

> if(l<0){ (以下略)

ここもおかしいです。
おそらく、それぞれの絶対値をいれようとしているのだと思いますが。
例えば、 l=-1. r= 1, c = -1 のときどうなるか

if(l<0){ なので l_abs=-l(=1)
if(c<0){ なので l_abs=l(=-1)
if(r<0&&c<0){ ではないので elseの l_abs=l (=-1)
とl_absはlの絶対値になりません

変数一つに一つのifを使う
if ( l < 0 ) { l_abs = -l ;} else { l_abs=1;}
か、fabs関数を使うかです
l_abs = fabs(l);

>double n[19];
>double X[19];
Cの配列は、宣言した個数だけの領域が用意されます。添字は0から始まるため、有効な添字は 0~(宣言した個数-1)となります。上の場合は n[0]~n[18], X[0]~X[18]の19個です。
さらに、Cでは、添字が範囲内かどうかのチェックは行いません。n[19]としてもなにくわぬ顔でコンパイルできてしまいます。
しかし、実行時には、関係ない場所を参照したり書き換えたりするので、正常に動作しません。最悪、致命的なエラーとなります。
(むしろ、エラーになった方がわかりやすいくらいで、たまたま動いているように見えてしまう事もあり、やっかいです)

修正方法は2通りです
1)添字を0~18にして、forループも0~18にする
2)宣言を n[20] X[20] のようにし、n[19] X[19]を有効な添字にする。

あと、気になったのが
>X[i] = n[i]*2*3.14*l_abs - 1/n[i]*c_abs;
ですが1/n[i]*c_abs の c_absって分子側、つまり 1.0/(n[i]*c_abs) だったような気がするんですが(このあたりのLCR回路、ちょっと苦手だったもので...)

πの精度も3.14程度でいいのですね?

その他の回答 (全3件)

  • 回答No.3

ベストアンサー率 55% (1857/3366)

まず確認しますが、これ、Cですか?

とりあえず、Cだと仮定してgccでコンパイルしてみましたが、確かに、エラーが出ます。
で、エラーメッセージをちゃんと読んでますか?
例えば、
R=0,X=0;
については、Xが定義されてない、とわかりやすいエラーですよ。

return(1/2*3.14*(x*y)^(1/2);
→まず、括弧があってません。
^演算子は Cでは「ビット毎の排他的論理和(XOR)」です。
よく、べき乗の上付き文字を表すのに使用されますが、Cではべき乗演算には使えません。

double X[]=(n[]*2*3.14*l_abs)-1/(l_abs*)*c_abs;
→おそらく、すべてのnに対してのXを求めて配列にしようとしているのだと思いますが、Cでは、こんな単純な記述ではでません。
直接書くにしろ、ループで処理するにしろ、添字をちゃんと指定して一つずつ計算する必要があります。

printf("周波数%d,Z=%lf+j%lf",n[],R,X[]);
→これも同じです。配列を指定したら、自動で全要素に対して実行してくれる、なんてことはCではやりません。
補足コメント
red_smith

お礼率 22% (4/18)

#include <stdio.h>
#include <ctype.h>


double resonance(double x,double y)
{
double a=sqrt(x*y);
double f=(1/2)*3.14*a;
return f;
}
int main(void) {
double r,l,c;
double r_abs,l_abs,c_abs;
double R;
double f0;
int i,p;


printf("put r");
fflush(stdout);
scanf("%lf",&r);

printf("put l");
fflush(stdout);
scanf("%lf",&l);

printf("put c");
fflush(stdout);
scanf("%lf",&c);

if(isalpha(r)!=0||isalpha(l)!=0||isalpha(c)!=0){
printf("error");
return 0;
}
if(l==0||c==0){
printf("error");
return 0;
}
if(l<0){
r_abs=r;
l_abs=-l;
c_abs=c;
}
if(c<0){
r_abs=r;
l_abs=l;
c_abs=-c;
}
if(r<0&&c<0){
r_abs=r;
l_abs=-l;
c_abs=-c;
}
else{
r_abs=r;
l_abs=l;
c_abs=c;
}
f0=resonance(l_abs,c_abs);

double n[19];
n[1]=f0/10;
n[2]=f0*2/10;
n[3]=f0*3/10;
n[4]=f0*4/10;
n[5]=f0*5/10;
n[6]=f0*6/10;
n[7]=f0*7/10;
n[8]=f0*8/10;
n[9]=f0*9/10;
n[10]=f0;
n[11]=f0*2;
n[12]=f0*3;
n[13]=f0*4;
n[14]=f0*5;
n[15]=f0*6;
n[16]=f0*7;
n[17]=f0*8;
n[18]=f0*9;
n[19]=f0*10;

R=r_abs;
double X[19];
for (i = 1; i < 20; i++){
X[i] = n[i]*2*3.14*l_abs - 1/n[i]*c_abs;
}
for (p = 1; p < 20; p++){
printf("周波数%lf,Z=%lf+j%lf\n",n[p],R,X[p]);
}

return 0;
}
のように変更したのですが、
double a=sqrt(x*y);
double f=(1/2)*3.14*a;
return f;
のところなんですが最終的に f=(1/2)*3.14*(x*y)^(1/2);にしたいんですがどうしたらいいですか?
後、プログラミングコンパイル段階には、問題は発生しないのですが、答えの数と答えのX=0000000になるのはなぜでしょうか?
投稿日時:2010/01/25 11:50
  • 回答No.2

ベストアンサー率 55% (492/894)

行列を使うプログラムを書くのに配列を使っているんだと思いますが、配列と行列は透過ではありません。配列の要素は一つ一つ参照したり更新したりする必要があり、まとめて参照、更新はできません。
red_smith さんはそれを誤解されていると思います。

例えば、配列を使うには配列の要素数を予め宣言しておき、その宣言量以上使うことは出きません。
なお、配列の宣言は関数の最初のところで行いますので、途中で出しているdouble n[]={f0/10,f0*2/10,f0*3/10,f0*4/10,f0*5/10,f0/10,f0*6/10,f0*7/10,f0*8/10,f0*9/10,f0,f0*2,f0*3,f0*4,f0*5,f0*6,f0*7,f0*8,f0*9,f0*10};はエラーとなります。
また、配列の中身は固定値しか設定できないため、上記のような宣言は出きません。

さらに、配列の中身を更新するにはその要素一つ一つにたいして行う必要があり、全部をいっぺんに更新することは出きません。
これが原因でdouble X[]=(n[]*2*3.14*l_abs)-1/(l_abs*)*c_abs;はエラーとなります。
また、表示も要素一つ一つに対して行わなくてはなりません。

つまり、
double f0;
の直後にdouble n[20], X[20], R[20];と宣言する必要があります。
そして、更新に使うためのカウンタとしてint i;などと宣言しておきます。
また、n,X,Rの更新は次のような形で行います。
例えばR=r_abs;とするところは、
for (i = 0; i < 20; i++)
R[i] = r_abs;
としなくてはいけません。
また、double X[]=(n[]*2*3.14*l_abs)-1/(l_abs*)*c_abs;は
for (i = 0; i < 20; i++)
X[i] = n[i]*2*3.14*l_abs - 1/l_abs*c_abs;と書かなくてはいけません。
...l_abs*はl_absの書き間違いだと思いますが。

表示のところも、同様です。

おそらくはC言語を使うよりも、MatlabやMaple Vなど行列を行列として扱えるプログラミング言語を使うほうがやりたいことを素直に表せるような気がします。...C言語で書く必然性があれば別ですが。
お礼コメント
red_smith

お礼率 22% (4/18)

ご丁寧な説明、ありがとうございます。
もう一度しっかり勉強しなおします。
投稿日時:2010/01/25 10:46
  • 回答No.1

ベストアンサー率 32% (1695/5289)

他カテゴリのカテゴリマスター
何をしたときに(コンパイル時?実行時?)、
そんなエラーが出るか(エラーメッセージの内容は?)を
具体的に示してください。
関連するQ&A

その他の関連するQ&Aをキーワードで探す

ピックアップ

ページ先頭へ