2016-10-11 8 views
1

組み込み関数 'CEILING'を使用しようとしていますが、丸め誤差により時々必要なものを得るのが難しくなります。丸め誤差の影響を受けずにCEILINGを使用

PROGRAM MAIN 

    IMPLICIT NONE 

    INTEGER, PARAMETER  ::  ppm_kind_double = KIND(1.0D0) 
    REAL(ppm_kind_double)  ::  before,after,dx 

    before = -0.112 
    dx = 0.008 
    after = CEILING(before/dx) 

    WRITE(*,*) before, dx, before/dx, after 

    END 

そして、私は結果を得た:サンプルコードはちょうど非常に簡単ですenter image description here

コードで、私は「前」に与える値と 'dxはただのデモンストレーションのためです。たとえば/ dx = -13.5以前の場合は、CEILINGを使用して-13を取得します。しかし私が示す写真の場合、私は実際に-14を得たいと思っています。私はいくつかの引数を使用することを検討しました

しかし、それは単に美しくはありません。これを行うための良い方法はありますか?

アップデート:私はppm_kind_doubleの定数に変数を設定した場合、問題が発生しないことを知って驚いた

。この丸め誤差は、使用するマシンの丸め精度の桁数がppm_kind_doubleで定義されているもの以上の場合にのみ発生します。私は実際に私のプログラム(このデモコードではありません)をクラスタ上で実行していますが、マシンの精度についてはわかりません。だから多分問題の原因となるのはマシンの4倍の精度ですか?

私は倍精度に定数を設定した後:

before = -0.112_ppm_kind_double 
dx = 0.008_ppm_kind_double 

enter image description here

+0

あなたは-14を望んで私を少し捨てました。 -0.112/0.008が正確に-14であることに気付くまでにはしばらく時間がかかりましたが、丸め誤差のために結果はやや多くなり、CEILINGはこの小さな誤差を増幅します。 – chw21

+0

@ chw21、実際に私はあなたの以前のコメントを見て、それを見つけるのを待っていました。 :) – Ruizhi

+2

ここでは精度が問題の一部ですが、リテラル定数は単精度のみであることには注意してください。 '-0.112'は' -0.112_ppm_kind_double'と書くべきでしょう。この変更によって根本的な問題は解決されません。 – IanH

答えて

0

丸め誤差がどこから来るあなたが知っていることはありませんので、これは、少しトリッキーです。 dx0.008よりも少し小さい場合、before/dxの部分は同じ値に丸められますが、今度は-13が正しい答えになります。

私が見てきた最も一般的な方法は、ちょうどを先読みすることです。反対の方向に少し前の値に戻します。このような何か:

program sign_test 
    use iso_fortran_env 
    implicit none 
    real(kind=real64) :: a, b 
    integer(kind=int32) :: c 
    a = -0.112 
    b = 0.008 
    c = my_ceiling(a/b) 
    print*, a, b, c 
contains 
    function my_ceiling(v) 
     implicit none 
     real(kind=real64), intent(in) :: v 
     integer(kind=int32) :: my_ceiling 
     my_ceiling = ceiling(v - 1d-6, kind=int32) 
    end function my_ceiling 
end program sign_test 

これは、値の大多数への影響はありませんが、意図したより多くので切り上げてしまいますいくつかの値が存在することになります。

+0

ありがとうchw21、最初の推測を与える合理的なシフトも良い方法です。 – Ruizhi

0

ノートでは、あなたの実数は、指定された精度に「正確な」概念上であれば、あなたはこのような何かを行う可能性があります:

after=nint(1000*before)/nint(1000*dx) 

あなたは両方のために期待するものと述べていない。これはあなたの例のために働きます値が正の値なので、少し作業する必要があります。

関連する問題