均匀分布位但密度增加的算法

Algorithm to distribute bits evenly but with increasing density

我正在寻找一种算法来生成一系列位,使得系列开始时的密度非常低(即大部分为 0),而系列末尾的密度非常高(即大部分1 秒)。我通过改变随机数落在一个范围内的概率来实现这一点,但我想找到一种更结构化的[阅读:确定性]算法,比如某种稳步增加 1s 密度的方法.

有人知道类似的东西吗?或者也许是关于这些主题的一些阅读?事实证明,考虑起来很有趣,但也很有挑战性(除非我遗漏了一些简单的东西)!

有多种方法可以做到这一点,这取决于您想要的发行版。这是一个非常简单的示例,我认为它应该适合您的目的:

for (i=0; i<end; i++)
  value = rand(0,1) * (2*i/end) * (2*(end-i)/end);
  if(i>end/2)
    value = 1 - value;

其中 rand(0,1) 生成一个介于 0 和 1 之间的值。最后您必须对结果进行舍入。

编辑:我快速实现了算法并模拟了 50 次(end = 500)。它显示了 1 和 0 的分布(四舍五入前)。

如果 0 和 1 设置完美,那么你可以在中间划分结果,左半部分应该有 1/3 与右半部分相比(换句话说:左半部分有 1/4所有的,右半部分有 3/4)。所以我们可以使用这个想法来生成位。

private static boolean[] res;

public static boolean[] generate(int len) {
    res = new boolean[len];
    generate(0, len, len / 2);
    return res;
}

private static void generate(int start, int len, int bits) {
    if (bits == len)
        for (int i = start; i < start + len; i++)
            res[i] = true;
    else if (bits > 0) {
        int l1 = len / 2, l2 = len - l1, b1 = (bits + 2) / 4, b2 = bits - b1;
        if (l2 < b2) {
            b2 = l2;
            b1 = bits - b2;
        }
        generate(start, l1, b1);
        generate(start + l1, l2, b2);
    }
}

63、64 和 65 位的输出:

000000100000001000100010001011100010001000111111111111111111111
0000000100000001000100010001011100010001010111111111111111111111
00000001000000010001000100010111000100010001111111111111111111111

您可以使用在许多应用程序中被广泛使用的高斯分布。

我使用了 Matlab,因为它对于这种应用程序来说很容易,但它应该很容易转换成另一种语言。

那么,假设您要根据您要求的条件创建一个包含 20 个值的数组。

len = 20;
x = 1:len; 
y = normdist(x, len, len/5);  % you can play with mean and standard deviation.
plot(x,y)

然后,将随机性添加到等式中,并根据需要添加阈值。

rn = rand(1,len);
res = y.*rn; 

并添加一个阈值,假设低于平均值的为零。

您可以使用这些值并根据需要获取一组值。

一种非常灵活的方法是使用 logistic function 来计算生成 1 与 0 的概率。这假设您知道序列的长度 先验 ,但在提升速率以及获得 1 的最小和最大概率方面为您提供了很大的灵活性。

由于您没有指定语言,我在 Ruby 中制作了原型:

# Creates an array of desired length whose values are symmetric
# about the mid-point of the array, are bounded below and above
# by min & max, and have a ramp up rate determined by steepness.
def logistic_function(length, min, max, steepness)
  mid = 0.5 * (length - 1)
  range = max - min
  # create, initialize elements via logistic fn, and return resulting array
  Array.new(length) { |x| min + range / (1 + Math.exp(-steepness * (x - mid))) }
end

length = 80
# 80 probabilities will vary from 0.1 to 0.9, with a relatively slow ramp-up
probability = logistic_function(length, 0.1, 0.9, 0.1)

# Create an array of bits where each entry's probability of being 1
# is determined by the logistic function we generated
bits = Array.new(length) { |i| rand <= probability[i] ? 1 : 0 }
puts bits.join

来自 运行 的示例输出两次:

00000000011000001000001100001101001010000011001011001111000111011111101011111011
10100000000000000000010000010111000000110110111011111000111011111111111110111111

结果是随机的,但您可以通过 minmaxsteepness.[=18=(随机地)控制 1 的密度和转换率]

注意,根据logistic函数的对称性,1位的整体比例具有期望值(min + max) / 2。对于我在示例中使用的参数化,这是 0.5。为了说明这一点,我计算了一组 80 位中 1 的数量,并重复 generating/counting 进行 10,000 次试验。由于预期比例为 0.5,因此每次试验中 1 的预期数量为 40。以下是实证结果:

确定性地(无随机数)执行此操作的一种非常通用的方法是使用 sigma-delta 调制器。

选择一个从 0 开始到 1 结束的平滑递增函数。然后使用调制器算法以 0 和 1 逼近。

注意:Sigma-delta 调制器在电子产品中非常普遍,用于将模拟信号(声音、视频等)转换为 1/0 比特流。

为了说明,我将在 100 的周期内采用从 0 到 1 的斜坡,并使用一阶转换器。但是你可以选择任何你喜欢的曲线。例如,hyperbolic tangent 水平缩放会给出更小的开始和结束坡度,中间变化更快。二阶转换器可能会提供 "nicer" 模式。他们往往不太规律。

这是一个非常简单的算法。在 C:

#include <stdio.h>

int main(void) {
  int x_max = 99;
  double vn = 0;
  for (int x = 0; x <= x_max; ++x) {
    double xn = (double) x / x_max; // linear ramp from 0 to 1.
    int yn = vn > 0.5;
    printf("%d", yn);
    vn += xn - yn;
  }
  printf("\n");
  return 0;
}

如您所见,它是确定性的。它也非常简单和快速:没有三角函数、指数等。这就是为什么它有利于硬件实现。

输出分为 2 行以便于查看:

00000000000100000010000100010001001001001010100101
01010110101011011011011101110111101111110111111111

Here 是一篇关于 sigma-delta 转换的开创性论文。上面程序中的变量与图8匹配。图13显示了一个二阶图,如果你想试试的话。

为了好玩,这里有一个间隔为 1000 的 运行:

00000000000000000000000000000000010000000000000000
00000010000000000000001000000000000100000000001000
00000010000000010000000100000001000000010000001000
00010000010000010000010000010000010000100001000010
00010000100001000010001000010001000100001000100010
00100010001000100100010001001000100100010010001001
00010010010010010001001001001001001001001001001001
00101001001001001010010010100100101001010010010100
10100101010010100101001010100101010010101010010101
01001010101010100101010101010101010010101010101010
10101010101010101101010101010101010110101010101011
01010101101010101101010110101011010110101101010110
10110101101101011010110110101101101011011011011010
11011011011011011011011011011011011101101101101101
11011011101101110110111011011101110110111011101110
11101110111011110111011101111011101111011110111101
11101111011110111101111101111101111101111101111101
11111011111101111111011111110111111101111111101111
11111011111111110111111111111011111111111111101111
11111111111111111101111111111111111111111111111111