今fortranのプログラムをやっているのですが、
図形の面積を求めたいのですがどうやったらいいのでしょうか?
とりあえず小さな区間に区切って足し算を行うようにしているのですが、うまく動きません・・・。
DOループをまわし過ぎなのでしょうか???
一応下にプログラムの一部を書いておきます。

DO 444 J= 1,5000
T=FLOAT(J)*0.1

IF (T.GE.281)THEN
GL3 = -0.01105*T+4.104972
ELSE
   GL3 = -0.01105*T-2.1050
ENDIF
    ・
    ・
    ・
444 CONTINUE

誰か助けてください!
宜しくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (6件)

質問者本人抜きの議論は、ここでは御法度ですが、質問者の理解の助けに


なると信じ、実数の比較の話に決着をつけます。

ubonoti01 さんの理解は、理由を抜きに「実数の比較が危ないらしい」と
いう風になっているのがまずい。

今回の質問のプログラム

DO 444 J= 1,5000
 T=FLOAT(J)*0.1
 IF (T.GE.281)THEN

であれば、EQUAL を含めて、問題なく判定されます。問題が出るのは、

T = 0.0
DO 444 J = 1, 5000
 T = T + 0.1
 IF (T .GE. 281.0) THEN

となっている場合。でも、同様の書き方でも

T = 0.0
DO 444 J = 1, 5000
 T = T + 0.5
 IF (T .GE. 281.0) THEN

であれば、問題なく動く計算機が *多い* です。

どうしてこんなことになるかというと、(Fortran で扱う)実数が二進数で
表現されている(正確にいえば、二進数の指数表現)からです。

0.1 は、十進数で書くと切りが良いですが二進数で表現すると無限小数に
なります。だから二進数の世界では

  0.1 × 10 ≠ 0.1 + … + 0.1 (10回足す)

となってしまいます。

先ほど例に出した 0.5 は、二進数の世界でも無限小数ではありません。
だから、

  0.5 × 10 = 0.5 + … + 0.5 (10回足す)

が成立します。

で、このへんの話は「実数を二進数で表現すること」の問題なので、
Fortran 固有の問題ではなく、C でも同様の問題を抱えます。

bob> 実数の大小比較に信頼性がない

のではなく、演算結果が等しいかどうかを判断するときに実数演算の
誤差を考慮しなくてはいけない、と言うことです。

ubonoti01> IF (J.GE.2810)THEN の方が好ましい

とあるのは、その「考慮」のやりかたのひとつです。



(補足 その1)
先程、0.5 を足して行くケースで「問題なく動く計算機が *多い* です」と
いう表現を使いました。それは、実数の表現が二進数表現ではない計算機が
あるからです。いわゆる IBM Format と呼ばれる実数表現では 16進数の
指数形式で表現されます。

なので、多分 0.5 では 0.1 と同様の問題が出るはずで、0.0625 (1÷16)なら
問題は発生しません。

(補足 その2)
COBOL では、ふつう実数は BCD コードで桁数を指定して扱います。なので、
オーバフローやアンダーフローが無いように桁を決めてあげれば、こういった
問題は出ません。
    • good
    • 0

便乗質問になってしまいますが、私は基本的にCプログラマでFortranでの計算はあまりやったことがないのでFortran独特のくせは確かによく知らないので、一応質問させていただきます。


実数の大小比較に信頼性がないということは、そのままとるとFortranは実数が使えないというのと同義です。主に科学技術計算に使われてきたFortranの歴史からいくとちょっと信じがたいのですが、これは本当なのでしょうか?
    • good
    • 0

再度ubonoti01です。


わたしがIF (T.GE.281)THEN は、IF (J.GE.2810)THEN の方が好ましいと申したのは、
・IF文の中でREAL同士を比較するのは危険と言う意味です。IF文の中での値の比較はINTEGER同士の比較であるべきです。出所が別のREAL同士の比較では、本来一致する筈が真でなく偽と判定されるケースが多いからです。これはコンピュータ内部での数値の扱いに起因します。
    • good
    • 0

やはり、最初に問題の説明が不足していることを指摘しておきます。


この質問内容では推測による回答しかできません。

で、推測に基づく回答ですが、やっていることは数値積分ですね。おそらく1次式で表わされる2直線とx軸(t軸)とy軸(gl3軸)で囲まれる部分の面積を求めようとしているのだと思われます。

で、予想される問題点ですが、多分変数Tに掛けている定数-0.1105のうちどちらか(多分後者)は符号が逆でしょう。切片も-2.1050ではなくて2.1050では?

if分岐の条件についてですが、ubonoti01さんと意見が割れますが、この場合は積分変数による分岐なのでTで分岐する方で良いと思われます。
おそらく意味的にもっといいのは各式を関数化しておいて、IF([2式].GE.[1式])THENと書いてしまうことです。計算量は若干多くなりますが、281という一見意味不明なパラメータを直接書く必要はなくなります。

そして、おそらく一番決定的な問題は積分の和をとってないことです。先頭にS=0をいれて、CONTINUEの前にS=S+GL3を入れるか、GL3を初期化しておいて2つの式をGL3=GL3+...にする必要があると思われます。

最後に、ループの終了条件がJ=5000というのはちょっと怪しいと思われます。この時GL3はゼロを割り込んでいます。おそらく3715以下の数値になると思われます。
    • good
    • 0

もう少し背景なり状況なりを示した質問をすべきと思いますが・・・・・・。

プログラムだけを見た範囲では、a-kumaさんのご指摘のほかに、
IF (T.GE.281)THEN
は、
IF (J.GE.2810)THEN
の方が好ましいと思います。
    • good
    • 0

どう上手くいかないんですかね?



コンパイルができない、期待している数字と結果が違う、計算に時間がかかり
過ぎる、etc ...

このコードの断片だけを見ると、コンパイルはできそうだし、ぎざぎざの
のこぎりのような形の面積を求めたいのかな、位しか想像つきません。

もしそうだとしたら、GL3 の初期化がされていないところと、Tの判断条件
のところが怪しいかな、くらいを思い付きます。

   GL3 = 0.0 ← ★ 必要なし?
   DO 444 J= 1,5000
    T=FLOAT(J)*0.1
    
    IF (T.GE.281)THEN ← ★ 281? 28.1? 不等号の向きは合ってる?
     GL3 = -0.01105*T+4.104972 ← ★ 右下がりで
    ELSE
     GL3 = -0.01105*T-2.1050 ← ★ こっちも右下がり?
    ENDIF ← ★ 終わっちゃっていいの?
        ・ ← ★ 続いているみたいだけど
        ・
        ・
 444 CONTINUE

ぎざぎざな形の面積だったら、こんな感じになるんじゃない?

IF (T .LT. 100.0) THEN
 GL3 = ...
ELSE IF (T .LT. 200.0) THEN
 GL3 = ...
ELSE IF (T .LT. 300.0) THEN
 ・
 ・
ENDIF
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

Q「for next」文と「if then else」文

両方とも「くり返し」をさせるものですけど、
for nextにできてif then elseにできないことって
ありますでしょうか?

僕は無いと思うのです。
その理由は
for next文は等差数列に関係したくり返しをさせるものであり
if then else文は等差数列とは関係の無い繰り返しもできるし、等差数列に関係あるくり返しもできるからです。

for nextの「等差数列に関係のあるくり返し」とは
例えば
for i=1 to 100 step 2
のような場合、
これは、初項1、公差2、末項100
の等差数列を用意したことを意味しますよね?

つまりfor next文では「等差数列を使ったくり返し」しか出来ないのに対し、
if then else文は等差数列に関係なく、「一般的なくり返し」が出来るものだと思うのです。

つまり、for next文は存在理由が無いと思うのです。
こういう理解であっていますでしょうか?
よろしくおねがいします。

Aベストアンサー

長文で、まことにすみません。
自分の意見としては、あなたの言うとおり、for next文が存在しなくてもプログラムは組めます。
とは、言っても実際に「ソフトウェアを作りたい」というときには、for next文を使用しないで作ると、かなりわかりにくくなってしまうのでfor next文が存在しているのです。

(例)「1」から「変数N(値:1~100)」までの値をすべて足した時の答えを出すプログラムです。((1)と(2)は同じプログラム)
(1)for next文を使わない場合
10 S = 0
20 I = 1
30 N = 0
40 N = N + 1
40 S = S + I
50 I = I + 1
60 IF I <= N THEN 40 ELSE 70
70 PRINT S
80 IF N <= 100 THEN 40
90 END

(1)for next文を使う場合
10 S = 0
20 I = 1
30 N = 0
40 FOR N = 1 TO 100
50 FOR I = 1 TO N
60 S = S + I
70 NEXT I
80 PRINT S
90 NEXT N
90 END

/////////////////////////////
>for next文では「等差数列を使ったくり返し」しか出来ない
(例)
10 FOR I = 1 TO 3
20 INPUT"あなたの名前は";N$
30 NEXT I
40 END
↑絶対に3回までしか繰り返しができない。

>if then else文は等差数列に関係なく、「一般的なくり返し」が出来るもの
(例1)等差数列を使用する場合
10 I = 1
20 INPUT"あなたの名前は";N$
30 I = I + 1
40 IF I <= 3 THEN 20
50 END
↑3回までしか繰り返しができない。

(例2)等差数列を使用しない場合
10 INPUT"あなたの名前は";N$
20 IF N$ = "END" THEN 30 ELSE 10
30 END
↑とある条件が発生するまで(上のは「END」が入力されるまで)繰り返す。

長文で、まことにすみません。
自分の意見としては、あなたの言うとおり、for next文が存在しなくてもプログラムは組めます。
とは、言っても実際に「ソフトウェアを作りたい」というときには、for next文を使用しないで作ると、かなりわかりにくくなってしまうのでfor next文が存在しているのです。

(例)「1」から「変数N(値:1~100)」までの値をすべて足した時の答えを出すプログラムです。((1)と(2)は同じプログラム)
(1)for next文を使わない場合
10 S = 0
20 I = 1
30 N = 0
40 N = N + 1
40 S = ...続きを読む

QCプログラムの条件文  if,else if ,elseについて教えてください。

 こんにちは。課題でどうしても解らないところがあるので教えてください。
 次のプログラムは一桁の数(0~9)が偶数(EVEN)か奇数(ODD)かを表示するものです。

 #include <stdio.h>

main() {
int num;
printf("please enter a number[0~9]:");
scanf("%d",&num);
if (num % 2 ==0)
printf("%d is an EVEN. \n", num);
else
printf("%d is an ODD. \n", num);
}
というプログラムをコンパイルして実行すると、ちゃんと実行されるのですが、10以上の数や負数を入力しても動作してしまうんです。

 そこで0~9の範囲以外の数が入力されていないかを確認して、その場合を偶数、奇数の判断や表示をせず、エラーメッセージだけを表示して終了するプログラムに書き換えなくてはならないのですが、まず
 (1)判断する条件式(変数numの内容が0~9の範囲にあるか)で、num >= 0 && num <= 9 をどこに入れればいいか。
 (2)please enter a number[0~9]: 8
8 is an EVEN.  (←例えば8を入れると普通こうなるのですが)
  please enter a number[0~9]:12
  ERROR:12 is in out of range!!  (←0~9以外ののものだったら、この様にエラー表示にしたいのです。

 私が考えたプログラムは
 #include <stdio.h>

main() {
int num;
printf("please enter a number[0~9]:");
scanf("%d",&num);
if (num % 2 ==0)
printf("%d is an EVEN. \n", num);
if else
printf("%d is an ODD. \n", num);
else(num >= 0 && num <= 9)
printf("ERROR:%d is in out of range!! \n",num);

}
という風に考えたのですがコンパイルできません。プログラミング初心者なので、書いている内容も解りにくいんですが、どうかよろしくお願いします。

 こんにちは。課題でどうしても解らないところがあるので教えてください。
 次のプログラムは一桁の数(0~9)が偶数(EVEN)か奇数(ODD)かを表示するものです。

 #include <stdio.h>

main() {
int num;
printf("please enter a number[0~9]:");
scanf("%d",&num);
if (num % 2 ==0)
printf("%d is an EVEN. \n", num);
else
printf("%d is an ODD. \n", num);
}
というプログラムをコンパイルして実行すると、ちゃんと実行されるのですが、10以上の数や負数を入...続きを読む

Aベストアンサー

コンパイルエラーが出ていたと思います。エラーになんて書いてあったか読みましたか?どこの行でエラーになっているかコンパイラが教えてくれますよ。

さて、コンパイルが通らない原因ですが、

printf("%d is an EVEN. \n", num);
if else
printf("%d is an ODD. \n", num);

犯人はこの、if else です。書くなら else if にしましょう。

しかし、コンパイルが通ってもこのままではプログラムは希望通りには動きません。なぜなら、エラーチェックを入れる部分が拙いからです。

エラーチェックは出来る限り前に持ってきましょう。エラーチェックが済んだ後で正常系の処理に進むのが定石です。それに、
else(num >= 0 && num <= 9)
も拙いですね。

私なら、

#include <stdio.h>
#include <stdlib.h>

int main(void) {
int num;
printf("please enter a number[0~9]:");
scanf("%d",&num);

/* エラーチェック:0~9以外の数字が入力されたら
 エラーメッセージを出してプログラムを終了する。
*/
if( (num < 0) || (9 < num) ){
printf("ERROR:%d is in out of range!! \n",num);
exit( EXIT_FAILURE );
}

/* 以下、正常系の処理を続ける。*/
if(0 == (num % 2))
printf("%d is an EVEN. \n", num);
else
printf("%d is an ODD. \n", num);

return 0;
}

コンパイルエラーが出ていたと思います。エラーになんて書いてあったか読みましたか?どこの行でエラーになっているかコンパイラが教えてくれますよ。

さて、コンパイルが通らない原因ですが、

printf("%d is an EVEN. \n", num);
if else
printf("%d is an ODD. \n", num);

犯人はこの、if else です。書くなら else if にしましょう。

しかし、コンパイルが通ってもこのままではプログラムは希望通りには動きません。なぜなら、エラーチェックを入れる部分が拙いからです。

エラーチェックは出...続きを読む

QRGB値をL*a*b*に変換したい

VC++で画像処理のプログラムを組んでいます。
RGB値からL*a*b*への変換式はネット上にあるんですが、
実際コーディングして、出た値が正しいのかどうかを確かめるすべがないので困っています。
任意のRGB値を入力して、Lab値を取得する手段はないでしょうか?
ちなみに私の研究室にはフォトショとイラレはあります。
このへんのツールを使うとできたりするんでしょうか?

Aベストアンサー

バージョンによるかもしれませんが、フィトショのカラーピッカー(描画色をクリックすると出るやつ)にLabが表示されているので、RGBを入力すればLabの値が得られます。
なんらかの補正がかかっているかどうかは良くわかりません。

QRuby while line = DATA.gets と DATA.each do |line| の違い

DATA.each do |line|
if /code,(.+)/=~line
code=$1
elsif /name,(.+)/=~line
puts "code=#{code} name=#{$1}"
end
end
__END__
code,001
name,ipp
code,002
name,opp

上記実行結果は以下の様に変数codeの値が出力されません。
code= name=ipp
code= name=opp

ところがプログラムの一行目をwhile line = DATA.getsに変更すると、以下の様に値が出力されます。
code=001 name=ipp
code=002 name=opp

どういう理屈なんでしょうか? 教えていただけませんか?
また、DATA.each do |line|の書式で、変数code(DATAの一行前で代入した値)を有効にする方法はあるのでしょうか?

Aベストアンサー

eachはスコープを生成するので、
code=$1はeachブロック内のローカル変数と見なされます。
そのため、code=$1を通らないときはcodeに対する代入が行われていないと見なされ、
code==nilとなります。

Rubyリファレンスマニュアル - trap::スコープ、制御構造
http://www.ruby-lang.org/ja/man/?cmd=view;name=trap%3A%3A%A5%B9%A5%B3%A1%BC%A5%D7%A1%A2%C0%A9%B8%E6%B9%BD%C2%A4
より引用
| while や for がスコープを作らないのに対し、loop や each などのイテレータはスコープを作ります。


> DATA.each do |line|の書式で、変数code(DATAの一行前で代入した値)を有効にする方法はあるのでしょうか?
----
code=""
DATA.each do |line|
#後略
----
のように、あらかじめ変数codeを宣言(代入)しておけばよいです。


[参考]
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-list/8472?8393-8678

eachはスコープを生成するので、
code=$1はeachブロック内のローカル変数と見なされます。
そのため、code=$1を通らないときはcodeに対する代入が行われていないと見なされ、
code==nilとなります。

Rubyリファレンスマニュアル - trap::スコープ、制御構造
http://www.ruby-lang.org/ja/man/?cmd=view;name=trap%3A%3A%A5%B9%A5%B3%A1%BC%A5%D7%A1%A2%C0%A9%B8%E6%B9%BD%C2%A4
より引用
| while や for がスコープを作らないのに対し、loop や each などのイテレータはスコープを作ります。


> DATA...続きを読む

QIF文の先のCONTINUEの意味(フォートラン)

フォートランのプログラムコードで下記の記述を見ました。
IF( Y(5,1).LT.1) GO TO 21
21 CONTINUE

この場合、CONTINUEに何らかの意味はあるのでしょうか?

Aベストアンサー

CONTINUE は何もしません。
通常、この文のようにラベル(例では21)をくっつけるための何もしない命令文です。


人気Q&Aランキング

おすすめ情報