2016-07-21 14 views
0

も最小限の標準的な使用式乱数発生器内のオーバーフローと4バイトの対8バイト整数

x(i+1)=16807*x(i) mod (2^31-1) 

として知られている有名な線形合同乱数ジェネレータ私はこの使用のFortranを実装したいです。

しかし、「数値レシピ」で指摘されているように、デフォルトの整数型(32ビット)の式を直接実装すると16807*x(i)がオーバーフローします。

したがって、Schrageのアルゴリズムは、mの近似分解に基づいています。このメソッドは、デフォルトの整数型で実装できます。

しかし、私は、Fortranが実際にその範囲16807*x(i)は可能性よりもはるかに大きいです9,223,372,036,854,775,807から-9,223,372,036,854,775,808あるInteger(8)タイプを持っている疑問に思って。

しかし本も次の文

式(7.1.2)を実装することは不可能であり、前記(7.1.3)高級言語で直接 、Aの生成以来m - 1は、32ビット整数の最大値の を超えています。

なぜ、Integer(8)タイプを直接使用して式を直接実装できないのですか?

+0

'整数(8)は8バイト整数ではなく、8種の整数を意味します。同じではありません。http://stackoverflow.com/questions/3170239/fortran-integer4-vs-integer4-vs- integerkind-4 –

+0

数字レシピについては、http://www.uwyo.edu/buerkle/misc/wnotnr.htmlを参照してください。単にこれを信じてはいけません。それは古い本ですが、書かれていてもそれほど良いものではありませんでした。 –

答えて

2

8バイト整数を使用できるかどうかは、コンパイラーとシステムによって異なります。 selected_int_kindメソッドを使用すると、ある範囲のint型を取得できます。このコードは私の64ビットコンピュータでコンパイルされ、正常に動作します。

program ran 
    implicit none 
    integer, parameter :: i8 = selected_int_kind(R=18) 
    integer(kind=i8) :: x 
    integer :: i 
    x = 100 
    do i = 1, 100 
     x = my_rand(x) 
     write(*, *) x 
    end do 

    contains 
     function my_rand(x) 
      implicit none 
      integer(kind=i8), intent(in) :: x 
      integer(kind=i8) :: my_rand 
      my_rand = mod(16807_i8 * x, 2_i8**31 - 1) 
     end function my_rand 
end program ran 
+0

ありがとう、chw21。だから、この本の言い方は間違っています。フォーミュラは直接fortranに実装できますよね? – user15964

+0

@ user15964はい、できます。 8バイトを直接選択するには、 'kind = int64'を使用することができます。ここで' int64'は組み込みモジュール 'iso_fortran_env'で定義されています。 –

0

はい。最も簡単な方法は、_8を整数定数に追加して8バイトにすることです。私はそれが "古いスタイル"のFortranだが、移植性があり、曖昧ではないことを知っている。もし書き込み方法によって

16807*x mod (2^31-1) 

この16807*xの結果を取得し、すべてのビットが符号ビットを除いいずれかに設定されている32ビットマスクでandを使用することと等価です。高価なMOD機能を回避することにより、それを書くために 効率的な方法は次のとおりです。

iand(16807_8*x, Z'7FFFFFFF') 

更新コメント後:

または

iand(16807_8*x, 2147483647_8) 

あなたのスーパー現代のコンパイラは、後方互換性を持っていない場合。

+0

ポータブルではありません。 '_8'は' 1,2,3'という種類のコンパイラでは受け入れられません。 '_8'は8バイトを意味するものではなく、' kind = 8'を意味します。 http://stackoverflow.com/questions/3170239/fortran-integer4-vs-integer4-vs-integerkind-4そして古いスタイルではありません(Fortran 90以降でしか動作しません)。それはちょっとしたスタイルです。 –

+0

私はあなたの 'iand(16807_8 * x、Z'7FFFFFFF ')'にも問題があると強く確信しています。 BOZ定数の使用法はFortran 2008で変更されましたが、現在はより一般的ですが、あなたの例のBOZ定数は(私のコンパイラでは)四倍精度であり、この方法で混合することはできません。 –

+0

OK。修正をありがとう。 Fortran90からずっと離れているようです。それはPython2とPython3の競合を思い出させます。 –

関連する問題