• ベストアンサー

Fortran において変数の定義

現在Fortranを使いプログラムをしていますが、円の面積を計算するため変数を定義しているところでおかしな問題が出てきました。円周率を定義するところで自分でつけた変数名 PAI の値が入力データと違うことに気づきました。以下のように簡単なプログラムを作って試したのですが結果は同じくおかしな値が出てきました。 IMPLICIT REAL*8(A-Z) PAI=3.14159265 WRITE(*,1)PAI 1 FORMAT(E30.22) PAUSE END 結果は 0.3141592741012573000000E+01 とディスプレイに表示され、このあとにPAIを使った計算があるならこの値で計算されます。私としては、PAI=3.14159265と出力し、計算もしたいのですが... これは FORTRAN 自体の特有の性質なのでしょうか、それともソフト、ハード的な問題なのでしょうか? 尚、変数 PAI をファイルから読み込んだり、PAI=4.0*ATAN(1.0) (PAI=3.1415926535897930 となりますが)、PAI=3.14159265D+00などにすると正確に表示、計算出来ます。

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

  • ベストアンサー
  • uni050
  • ベストアンサー率26% (16/60)
回答No.1

こんにちはuni050というものです。 実際に試してみてわかった事を一つ。 i686、g77でコンパイルを行って試したところ実際にこの様になりました。で、次にalpha(OSF1)、g77で試してみたところ同じようになりました。そこで今度は、alpha、f77で試してみたら 0.3141592650000000208621E+01 となりました。そのほかにもいろいろ試してみたことから得られた結論として、数字がおかしくなるのはコンパイラの方の問題かと。 あと、ためしに double precision pai pai = 3.14159265 でg77でやってみたらうまくいきませんでした。おそらく入力する数字が単精度になっているから下の方の桁がうまく入らないのではないかと。これは推測なのであまり当てになさらずに。

gotkat
質問者

お礼

何かいろいろなコンパイラがあるみたいですね。 いろいろ調べてみた結果コンパイラにも「あまく」コンパイルするのもあるみたいですね。ありがとうございました。

その他の回答 (5)

noname#21649
noname#21649
回答No.6

IMPLICIT REAL*8(A-Z) より.単精度の宣言の宣言をしていますので.有効桁は7.2桁になります。 3.14159265 より.7.2桁を超える数値を指定していますから.この値は倍精度です。定数ですから.コンパイラーは7.2桁に丸めた数値を変数PAIに設定します。 (E30.22) より.E形式の出力を指定していますので.変数PAIの内容を単精度に換算して.その後に.30.22桁で表示します。 今のコンパイラーは型変換を自動でやってくれますから.このようなおかしな事になるのです(昔のコンパイラーでは型変換をせずメモリーから直接読み取るので.明らかに間違った答(0とか不の和とか)を出す)。簡単な方法としては IMPLICIT REAL*8(A-Z) を倍精度の宣言.たとえばダブルリアル(スペル忘却)宣言に直す方法があります。

gotkat
質問者

お礼

いやー質問の最初に書いておくべきだったんですけど、どうしてこのような問題が起こったかというと、WARKSTATION (CPU:R10000,64bit)でコンパイル(Fortran は古い)して走らせるちゃんとPAI=3.1415926540000・・・と結果が出てくるんですよ。やっぱりbit数の関係ですかねー.(でもコンパイラは64bit対応か解らないんですけど。) IMPLICIT REAL*8(A-Z)とIMPLICIT DOUBLE PRECISION(A-Z)は何か違うのですか?どちらも同じ意味と私は思っているんですけど。 どうもありがとうございました。

  • ymmasayan
  • ベストアンサー率30% (2593/8599)
回答No.5

> これは FORTRAN 自体の特有の性質なのでしょうか、それともソフト、ハード的な問題なのでしょうか? どれでもありません。数学の問題です。つまり、2進数と10進数の間で、小数点数の変換を行なうと(ほとんどの場合)わずかな誤差が出てしまうのです。これを完璧に防ぐ方法は(特殊な方法を使う以外)ありません。FORTRANなどの技術計算用言語では、極端に言うとこれをあきらめています。倍精度を使ってもそれ以上の精度を採用しても誤差が小さくなるだけで、ゼロには決してなりません。 特殊な方法というのは10進数で計算を行なうのです。汎用の大型計算機では10進計算のハード(命令語)をもっていますし、商業計算が得意なCOBOL言語では、ハードがなくてもソフトで10進計算をやっています。 質問の答えにはならないかも知れませんが、(歯がゆい事ながら)技術計算では、色々工夫しながらFORTRANやCを使っていくしかないと思います。

gotkat
質問者

お礼

確かに数学の話ですね。右辺を単精度で定義していたならこうなりますね。 10進数計算の話ですが最近は(昔からあるのかな?)BASIC にも2進数、10進数どちらでけいさんするのかを選ぶのもあるみたいですね。 どうもありがとうございました。

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.4

No.3 の回答に補足。 コンパイルオプションで、定数を倍精度で扱うコンパイラもある(→参考URL)ので、 そっちの方も気にして見てください。

参考URL:
http://www.compaq.co.jp/products/dvf/docs/vf-html/pg/pg04_01_31.htm
  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.3

> PAI=3.14159265 の右辺が *単精度* の表現であるから、なのだと思います。 コンパイラによっていろいろな表現があるのだと思いますが、例えば、参考URLに よれば、 > 倍精度(8バイト)の実数定数は,定数値_8 で与える。 とありますので、 PAI=3.14159265_8 とすると、お望みの結果になりそうです。 まずは、お手持ちのコンパイラのマニュアルでデータ型とか定数とかの項を 読むことをお勧めします。

参考URL:
http://www.media.kyoto-u.ac.jp/htomita/sec4.html#4.1.
gotkat
質問者

お礼

あまりマニュアルを信用していない私ですが、のぞいてみたところ確かにそのように書いてありました。(倍精度型実数にはDをつけると) どうもありがとうございました。

  • yfujii
  • ベストアンサー率17% (14/80)
回答No.2

PAI=3.14159265 の部分ですが左辺は倍精度実数、右辺は単精度実数(REAL*4) です。 単精度実数の場合10進数にした場合有効桁数が6桁強程度しかありません。 倍精度実数は有効桁数が10進数で13桁程度ありますので代入した場合、単精 度実数で表せない部分にごみがはいります。 これを避ける為には右辺も倍精度実数にする必要があり、それが後編で試された 内容です。 FORTRANに限りませんが(C言語も同じです)、代入時の型に注意しないとこの ような事がよくおこり原因不明の精度低下ということがあります。 なれると大丈夫なのですけどね。がんばって下さい。

gotkat
質問者

お礼

本当に変数の定義のときには注意が必要ですね。 今までの私のプログラムは倍精度実数にすることなく定義しているので、これから一時はそれを直すのに時間がかかりそうです。(大変だーー) どうもありがとうございます。

関連するQ&A

  • Fortran90/95の出力方法について

    Fortran90/95の出力方法について Fortran95において,変数の値をwrite文で出力した後に改行しない方法を教えてください. 具体的には次のProgram reiを用いて質問します. program rei implicit none integer i, n read(*,*) n do i = 1, n write(*,*) i end do end このプログラムを実行させnに3を代入すると次のように表示されます. 1 2 3 しかし,私としては次のように改行せずに表示させたいのです. 1 2 3 また,諸事情により配列は使用しません. プログラムをどのように改良すればよいのでしょうか.教えてください.

  • fortranからgnuplotへ

    gnuplot4.4.2を使って、グラフを書いております。 座標の情報は、ファイルから読み込みを行います。 ファイルの中身は、コンピュータで計算させたため、 0.1098998*10^-2 の表示が、 ( i ) 0.1098998D-02 となっております。 この表で書かれたデータがあまりにもたくさんあるため、すべてを ( i i ) 0.1098998e-2 と直すのは、正直面倒です。 そこで質問なのですが、 (1) 上記を表示のまま、gnuplotでグラフを書くためにはどうすればよいのでしょうか。 もし、( i ) の表記をどうしても (i i ) のようにしなければならな場合、コンピュータの計算の結果をそのままgnuplotで書きたいと思います。 (2) 現在fortran77 ( 実際は、fortran95 に対応しておりますが、77の範囲でプログラムを書いております ) を使って、計算をしております。 計算結果をそのままグラフにするためのプログラムはどのようにしたらよいのでしょうか。 どなたか、(1)か(2)の質問をヒントだけでもいいので教えてください。

  • fortranでのNaNについて

    お忙しい所、NaNについて回答お願い致します。 fortranでプログラムを使用して数値計算を行っていますが、計算途中で結果がNaNとなり困っています。 NaNは、0で除算を行なったり、負の数の指数を求めようとした時に出る無限大や定義できない値のようなのですが、式を見ても0で除算を行なったり、負の数の指数を求めようとしている所はありません。 もし同じような経験をされて見事解決された方、居られましたらその時の対処法をお聞かせ願えないでしょうか。 何卒よろしくお願い致します。

  • makeについて(FORTRAN)

    FORTRANでのプログラムについて質問させてください。 現在、一つのコードにsubroutineをいくつかまとめて、 計算を走らせています。 subroutineとmain programでの共有変数は、全て common/変数、変数/としているのですが、プログラムが複雑化するとこれでは計算速度が落ちるのでしょうか。 そこで、subroutine毎にコードを分けて、makeを使用してmakefileを作った方が、圧倒的に計算速度も作業効率も上がるのかどうか教えてください。

  • fortran90

    fortran90 現在 fortran90 で計算プログラムを作っております。 プログラムはかけたのですが、実行画面にエラーが出ます。 解決方法が分かりません。どなたか分かる方いらっしゃいますか。 プログラム implicit real*8 (a-h,o-z) parameter(n=900) open (1,file='004.txt',status='old') do 10 i=1,n read (1,*,end=11)xx,yy,zz,ww theta=acos(zz) phi1=acos(xx/sqrt(1-zz*zz)) phi2=asin(yy/sqrt(1-zz*zz)) write(*,*)theta,phi1,phi2 10 continue 11 end プログラム内容 あるフォルダーに保存してあるテキストファイルから4×4行列のデータを読み込み、そのデータからθの値とφ1、φ2のアタを求めるプログラムです。 実行分のエラー画面には、 acos: DOMAIN error です。

  • Fortranの変数の配列の設定値を計算中に設定するには?

    FortranでプログラムをつくるときAという変数にBの値の範囲で配列を設定する。A(B) このとき、プログラム作成時にはAには具体的な数値を設定しておかなくても良いですが、Bには具体的に配列の数を設定しておく必要があるように思います。  質問は、  プログラムが動く初めにはBに具体的な値を入れず、プログラム作動状況に応じてプログラム作動中にBの配列の範囲を設定できないものでしょうか?

  • gdbでFortranの名前つきcommonブロック内の変数の表示

    いまどきFortranなんてカテゴリーさえもないのですが、よろしくお願いします。 去年の暮れからLinuxを使って、Fortranで計算をしています。 質問は、Fortranの名前つきcommonブロック内のの配列変数をgbdを使ってデバッグしている時にprintコマンドで表示したいのですが、やり方がわかりません。 write文を使うというデバッグ方法には戻りたくないので、gdbで解決したいのですが、いかがなものでしょう?

  • FORTRANの問題

    今、大学でFORTRANを習っているのですが、先生の出した例題で、  N = 5 A = 1.1 A = A * N WRITE (*,*) N, A この場合、ディスプレー上に表示される変数Nと変数Aの値は各々5と0.0になる、この理由は? というのがありました。しかし、自分で勉強した限りはどうしても変数Nの値は5.5だと思うのですが…でもやり始めたばっかで自信もありません。どなたか教えていただけませんでしょうか?

  • LTspiceの変数の定義

    LTspiceでトランジェント解析を行っており、終了時間を指定する時に、波形二つ分のシミュレーションを行いたいと考えています。通常であれば周波数の逆数を自分で計算して値をstop timeに打つと思うのですが、周波数を振ってシミュレーションを行う為、いちいち打ち直すのが面倒です。 Hspiceでは .tran '1/freq' .param freq=100k と変数で定義していたのですが、LTspiceでは上手くいきません。 LTspiceでも正弦波を定義するところでは SINE(1 0.1 '{freq}*2') で認識してくれたのは確認しました。 stop timeで、変数の計算をする方法は何かありませんか?

  • fortran77教えてください

    fortran77の問題で次のプログラムの作成の仕方を教えてください 整数A,B,Cを読み込み、それを係数とする2次方程式Ax^2+Bx+C=0の解を計算して表示するプログラムを サブルーチン副プログラムを用いて作成せよ(複素数型を使うこと) メインプログラムでは整数A,B,Cの入力および解の出力および解の出力を行い解の計算はサブルーチン副プログラムで行うこと なお'keisan.txt'という名前のデータファイルに結果を出力するように 計算時は以下の3つの方程式を用いること x^2+3x+5=0 X^2+6x+4=0 x^2+x+1=0

専門家に質問してみよう