用户将 MATLAB 算法翻译成 Python,在调试过程中,为了同步两个语言之间的种子,他必须重写几个与随机数相关的函数。即使随机生成的数字(表面上)相同,他仍然发现两个代码之间存在收敛差异。他将错误追溯到重写的 randn() 函数,该函数需要从标准正态分布中返回 2 个数字。以下是使用 Box-Müller 方法重写的 Matlab 和 Python 版本的 randn() 函数:
function output = newRandn(input)
output=zeros(input,1);
for i = 1:input
output(i) = sqrt(-2*log(rand())) * cos(2*pi*rand());
end
def newRandn(size):
x = np.arange(0.0, size)
for i in xrange(0,size,1):
x[i] = math.sqrt(-2*math.log(numpy.random.rand())) * math.cos(2*math.pi*numpy.random.rand())
return x
这两个代码都使用相同的种子同步。可以使用以下命令设置种子:
rng('default')
rng(3530723506)
numpy.random.seed(3530723506)
分别用于 MATLAB 和 Python。
通过一个简单的 for 循环查看这两个函数的输出,用户发现了一个差异(以粗体显示),在这个例子中,在第 21 次迭代时,第一个数字的小数点后出现了差异:
Matlab:
1.10773989463900091045900353492470458149909973144531
0.16119915478508828332593338927836157381534576416016
Python:
1.10773989463900113250360845995601266622543334960938
0.16119915478508828332593338927836157381534576416016
代码如下:
rng('default')
rng(3530723506)
for i = 1:50
temp = newRandn(2);
fprintf('%d\n %.50f\n %.50f\n', i, temp(1), temp(2))
end
import numpy
import math
numpy.random.seed(3530723506)
for i in xrange(1, 26, 1):
temp = newRandn(2);
print i
print " %.50f"%temp[0]
print " %.50f"%temp[1]
后面的迭代基本正确,但一些数字也包含精度的错误,例如这个数字。用户无法理解为什么有些数字是正确的(至少在显示的精度范围内),而另一些数字不正确。
用户尝试调整 pi 的精度(例如,创建一个变量 mypi = 3.14),但是没有效果。在某些情况下,算法使用 pi = 3.14 在两个版本之间会收敛到类似的结果,但其他种子反而会失败。
用户想知道这些精度误差来自哪里以及如何克服它们。
2、解决方案
为了解决这个问题,用户可以尝试以下方法:
- 确保 MATLAB 和 Python 中的随机数生成器使用相同的种子。可以在 MATLAB 中使用 rng('default') rng(3530723506) 命令,在 Python 中使用 numpy.random.seed(3530723506) 命令来设置种子。
- 确保 MATLAB 和 Python 中的随机数生成器使用相同的算法。MATLAB 中的默认随机数生成器是 Mersenne Twister,Python 中的默认随机数生成器是 Mersenne Twister 或 Xorshift,具体取决于 Python 版本。如果需要在两种语言中使用相同的算法,可以尝试使用第三方库,例如 NumPy 或 SciPy。
- 使用更高精度的随机数生成器。MATLAB 和 Python 中都提供了更高精度的随机数生成器,例如 MATLAB 中的 randn('state', 'with-seed') 和 Python 中的 numpy.random.RandomState(seed).rand()。
- 使用不同的随机数生成器。MATLAB 和 Python 中都提供了不同的随机数生成器,例如 MATLAB 中的 Halton 和 Python 中的 Permuted Congruential。尝试使用不同的随机数生成器可能会提高随机数的精度。
- 使用替代方法生成随机数。如果以上方法都无法解决问题,可以尝试使用替代方法生成随机数,例如使用 Box-Muller 方法或 Ziggurat 方法。