双精度舍入为单精度:强制上限

Rounding of double precision to single precision: Forcing an upper bound

我正在使用 Mersenne Twister 实现,它为我提供双精度数字。

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/fortran.html(Tsuyoshi Tada 在 Fortran 77 中的实现,我使用的是 genrand_real2)

但是,为了避免在将具有不同精度的数字相乘时出现警告,我的应用程序需要一个单精度随机数。 所以,我写了一个小函数来在两种数据类型之间进行转换:

    function genrand_real()

    real   genrand_real
    real*8 genrand_real2

    genrand_real = real(genrand_real2())

    return
    end

我使用 real 和 real*8 来与我正在处理的代码保持一致。 它在大多数情况下都运行良好(除了事实上我不确定 real() 有多快),但是它改变了我的 RNG 的上限,因为转换将 [0,1) 更改为 [0, 1].在遇到问题之前,我从未想过这一点。

我的问题是,如何以有效的方式确保上限,甚至如何编写类似于 genrand_real2(原始函数)的函数来为我提供单精度实数。我的猜测是我只需要替换除数 4294967296.d0 但我不知道用哪个数字

  function genrand_real2()

  double precision genrand_real2,r
  integer genrand_int32
  r=dble(genrand_int32())
  if(r.lt.0.d0)r=r+2.d0**32
  genrand_real2=r/4294967296.d0

  return
  end

您发布的函数不会生成随机数,它只会通过除以 2^32(正好是 4294967296)或添加将随机整数(从 genrand_int32())限制在区间 [0,1) 内如果 int 为负数,则首先为 2^32。 2^32是一个标准整数所能容纳的值的个数,一半为负,一半为正(大约在正端少1),因此来自函数genrand_int32().

假设您有从 -10 到 10 的数字,并且想将它们限制在区间 [0,1] 内。最简单的解决方案是将负数加 20(因此正数保持 0-10,负数变为 10-20),然后除以 20。 这正是函数正在做的,只是用 2^31 而不是 10.

如果您想知道为什么函数的区间是 [0, 1]: 由于数字 0 也需要一个点,并且位表示只能存储 2^32 个数字,因此不能有 2^31 个负数和 2^31 个正数 AND 0。解决方案是省略值 +2^ 31(最高正数)因此 1 被排除在您的间隔之外。

所以要将整个事情简化为单精度:

function genrand_real2()

real genrand_real2,r
integer genrand_int32
r=real(genrand_int32())
if(r.lt.0)r=r+2**32
genrand_real2=r/4294967296

return
end

幻数必须保持不变,因为它们与整数相关,而不是实数。

编辑: 你自己已经说过了,所以我只是对其他人重复一遍:为了可移植性,在技术上使用默认类型而不指定精度不是一个好主意。所以你应该在某处做 sp = selected_real_kind(6, 37)sp 用于单精度)然后 real(kind=sp)...2.0_sp 等等。 不过,这更像是一个学术观点。