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



我正在使用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

我正在使用真实和真实*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

您发布的函数不会生成随机数,它仅通过将随机整数(从genrand_int32())限制为区间 [0,1),方法是除以 2^32(正好是 4294967296)或如果 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 个正数和 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等等。 然而,这更像是一个学术观点。

最新更新