Halton Sequence 原理和代码实现

Halton Sequence是一种随机序列,被用来生成均匀分布的随机数。最常被应用的地方就是Monte Carlo算法。因为最近在学习MapReduce算法,在看对PI的计算实现时了解到Halton Sequence,但惊讶地发现Google竟然搜不到多少介绍,不知道是已经没什么人用了,还是比较冷门呢。Anyway,hadoop计算PI用到了,所以我也就了解下啦。

Halton Sequence经常被用来选取空间中的均匀随机点。但其实我理解它不是一种随机选取算法,因为它更强调平均,是通过一定的算法让所选取的点精确地均匀分布在空间里。


算法

Halton算法其实不难,就是选取一个质数作为基数,然后不断地切分,从而形成一些不重复并且均匀的点,每个点的坐标都在0~1之间。

比如,在一个一维数轴上,取2作为基数。那么首先对(0,1)进行切分,得到1/2;然后对(0,1/2)和(1/2,1)进行切分,得到1/4和3/4;然后在对(0,1/4), (1/4, 1/2), (1/2, 3/4)和(3/4,1)进行切分...最终得到的数列为:

12143418583878116916,...

同理,以3为基数得到的数列为:

1323194979295989127,...


实现

算法的原理不难,但编程实现就不那么简单了。至少我观察了很久也没发现这一组数组该怎么快速实现,wiki上的伪码也太糙了,看不懂。查了很久,才查到一点简单的说明,琢磨了下,现在分享出来:

要取第n个数:

  • 首先要把n化为b进制数,其中b就是指定的基数。
  • 然后把转化后的数反转到小数点后,转化为小数。
  • 最后,再把这个b进制数转回成十进制数。

比如,以2为基数,取第6个数,首先转化为2进制数为110. 然后把110反转到小数点后成了0.011,这是二进制数。然后把二进制的0.011转化为十进制,就是 0.5*0 + 0.25*1 + 0.125*1=0.375 。所以第六个数就是0.375.


到这里其实就很清晰了,我们把第一步和第二步合并一下,就是:

第n个数 = 求和{ b进制 * 每一位的进位取负次方}

例如上面以2为基数的第6个数(110):

= 1 * 1/2^2 + 1 * 1/2^1 + 0*1/2^0. 


代码

下面是二维Halton Sequence的java代码实现。基数可以自己指定:


public class HaltonSequence {
	static int digit = 40;
	private int[] bases= new int[2];
	private double[] baseDigit = new double[2];
	private double[][] background = new double[2][digit];
	private long index;
	
	HaltonSequence(int[] base) {
		bases = base.clone();
		index = 0;

		for(int i=0; i



你可能感兴趣的:(其他)