2016-08-05 3 views
1

次のコードをFortran 90で実装しました。ここで、パラメータの対数を使用してパラメータtauを計算したい場合は、 OSXエルキャピタンでのgfortran 6.1 MacBook Airの2013年を使用してコンパイルするとき0の対数は、到達不可能な条件の場合でもエラーを発生させます

MODULE nrtype 
    INTEGER, PARAMETER :: SP=KIND(1.0) 
    INTEGER, PARAMETER :: DP=KIND(1.0d0) 
    INTEGER, PARAMETER :: I4B=SELECTED_INT_KIND(9) 
    INTEGER, PARAMETER :: I2B=SELECTED_INT_KIND(4) 
    INTEGER, PARAMETER :: I1B=SELECTED_INT_KIND(2) 
    INTEGER, PARAMETER :: SPC=KIND((1.0,1.0)) 
    INTEGER, PARAMETER :: DPC=KIND((1.0D0,1.0D0)) 
    INTEGER, PARAMETER :: LGT=KIND(.TRUE.) 
END MODULE 

MODULE parameters 
USE nrtype 
    REAL(DP), PARAMETER :: beta=.98_dp 
    REAL(DP), PARAMETER :: maxtol=1.0e-6_dp 
    REAL(DP), PARAMETER :: theta=1.0_dp 
    REAL(DP), PARAMETER :: delta=0.0_dp 
END MODULE 

PROGRAM mainp 
    USE parameters 
    USE nrtype 

    IMPLICIT NONE 

    INTEGER(I4B) :: tau 
    REAL(DP) :: taustar 

    IF (theta > 1.0_dp .AND. (delta > 0.0_dp .AND. delta < 1.0_dp)) THEN 
     taustar=LOG(maxtol/(beta*(1.0_dp-delta)*(theta-1.0_dp)))/LOG(beta*delta) 
     tau=CEILING(taustar,REAL(DP)) 
    ENDIF 

    IF (theta > 1.0_dp .AND. delta==0.0_dp) THEN 
     tau=1 
    ELSEIF (theta == 1.0_DP .OR. delta==1.0_DP) THEN 
     tau=0 
    ENDIF 

END PROGRAM main 

はしかし、私は次のエラーを取得する:私は、コードにどのような間違いを

program.f90:30:69: 

    taustar=LOG(maxtol/(beta*(1.0_dp-delta)*(theta-1.0_dp)))/LOG(beta*delta) 
                   1 
Error: Argument of LOG at (1) cannot be less than or equal to zero 

やっていますか? IF文が認識されていないかのように見えます。

+0

Fortranのすべての質問について、tag [tag:fortran]を使用してください。 –

+0

Fortran 90(30年近く)に自分自身を限定している理由は何ですか? Modern Fortranには、このような問題のロバスト性を向上させるための固有モジュール 'ieee_arithmetic'があります。 – jlokimlin

答えて

0

デルタが0の定数の場合、式LOG(beta*delta)はgfortranによって無効と見なされます。コードの到達不能な部分にあることは重要ではありません。無効です。 if条件や他の場所に置くことはできません。

deltaparameterと宣言していないか、プリプロセッサを使用している可能性があります。他のコンパイラがそれを受け入れるかもしれません(私はifortを試しました)。私は標準についてはわかりません。

+0

ありがとう、私は前にfortranタグを付け加えなかったことを謝ります。 –

+1

この結論にどうやって来ますか?私はこれをコンパイラのバグだと考えています。型を越えて、LOGへの実際の引数の値の制限は、プロシージャが呼び出されたときに適用されます。これは、プロシージャ参照を含む文の実行を必要とします。この例ではコンパイルできないようにするべき他の問題があります。 – IanH

+0

そのコンパイラでの私の経験から。これは可能ですが、コンパイラはそれを受け付けません。だから、すべての面倒な(回避策)は、http://stackoverflow.com/questions/31971836/having-parameter-constant-variable-with-nanvalue-in-fortran –

0

(これは長いコメントのようなものですが...)のgfortran-6.1マックOSX10.9上-fdump-fortran-originalまたは-fdump-fortran-optimizedでコンパイルした場合、以下の情報を与えた:

code: 
    IF .false. 
    ASSIGN mainp:taustar (/ log[(((/ 9.9999999999999995e-7_8 
          (parens (* (* 9.7999999999999998e-1_8 
          (parens 1.0000000000000000_8)) 
          (parens 0_8))))))] log[((0_8))]) 
    ASSIGN mainp:tau ceiling[((mainp:taustar) (8.00000000))] 
    ENDIF 
    IF .false. 
    ASSIGN mainp:tau 1 ELSE 
    IF .true. 
     ASSIGN mainp:tau 0 
    ENDIF 
    ENDIF 

結果はすべてのために同じでした-O0,-O2,-O3および-O5

ifort-14.0は到達不能なlog行に迷惑をかけずにプログラムをコンパイルしました(tau=CEILING(...)と不平を言っています)。 theta == 1.0_DP .OR. delta==1.0_DPに対応する第3のIFブロックが実行された。ブロックが実行された場合

taustar=LOG(maxtol/(beta*(1.0_dp-delta)*(theta-1.0_dp)))/LOG(beta*delta) 
       ^         ^ ^          
"test.f90", Line = 31, Column = 27: WARNING: A divisor of zero was detected in an expression.               
"test.f90", Line = 31, Column = 65: WARNING: Evaluation of this constant expression produced a NaN or other abnormal value. 
"test.f90", Line = 31, Column = 74: WARNING: The argument is not in the valid range for this intrinsic. 

が、再び第三:それはこのような警告を与えたので

オラクルFORTRAN 12.4は少し面白かったです。私は、通常の変数としてdeltaを宣言した場合CEILING(...)除去した後、ブロック(この行は異なる理由で問題と思われる)場合も

は、(ないPARAMETER属性で)のgfortranも三分の一を実行します。


この問題を回避するには、一度ローカル変数に定数を割り当て、LOG(...)/LOG(...)にそれらを渡すかもしれ(のgfortranをごまかすために、ある意味で!):

REAL(DP) :: arg1, arg2, tmp 

IF (theta > 1.0_dp .AND. (delta > 0.0_dp .AND. delta < 1.0_dp)) THEN 
    tmp = beta * (1.0_dp - delta) * (theta - 1.0_dp) 
    arg1 = maxtol/tmp 
    arg2 = beta * delta 
    taustar = LOG(arg1)/LOG(arg2) 
ENDIF 

これが動作しているようですときthetadelta上記のコーナーケースの値を持ち、他のケースに対して正しい結果を返します。前者の場合、gfortran -fdump-fortran-originalの出力は次のようになり:

code: 
IF .false. 
    ASSIGN mainp:tmp 0_8 
    ASSIGN mainp:arg1 (/ 9.9999999999999995e-7_8 mainp:tmp) 
    ASSIGN mainp:arg2 0_8 
    ASSIGN mainp:taustar (/ __log_r8[[((mainp:arg1))]] __log_r8[[((mainp:arg2))]]) 
ENDIF 
+0

こんにちは、ありがとう、私は最後にやったあなたが言及していることは、(ローカル変数に定数を割り当てる)。 –

0

このエラーは、実行時ではなく、コンパイル時にスローされています。

betaとdeltaは定数なので、コンパイラはショートカットをとり、プログラムが実行される前にログを評価しています。それはゼロのログであるため、エラーを投げています。

あなたは何をしようとしているのですか?コンパイラは正しく、これは常にゼロのログになります。デルタを定数にしてもよろしいですか?

+0

反対意見については、IanHのコメントを参照してください。私は正しい答えが何であるか分かりません。 –

関連する問題