问候
我需要计算一个由16位字组成的信号的一阶熵(Markov源,就像在wiki上http://en.wikipedia.org/wiki/Entropy_(information_theory)。 这意味着,我必须计算在数据流中发生a-> b(符号b出现在a之后)的每个组合的频率。 当我只使用4个不太重要或4个更重要的位时,我使用了一个二维数组,其中第一维是第一个符号,第二维是第二个符号。
我的算法看起来像这样
然后,Array [a] [b]将表示符号b在流中出现符号a后的次数。
现在,我明白C中的数组是一个递增得到精确值的指针,比如从数组[10] [10]获取元素[3] [4]我必须将指针递增到数组[0] [0] by(3 * 10 + 4)(存储在数组中的变量的大小)。我理解问题必须是2 ^ 32个unsigned long类型的元素必须占用太多。
但是,有没有办法解决它?
或许还有另一种方法可以实现这一目标?
答案 0 :(得分:5)
具有32'000乘32'000个元素的二维整数数组(4字节)占用大约16 GB的RAM。你的机器有那么多内存吗?
无论如何,在超过10亿个数组元素中,只有极少数数组元素的数量不同于零。因此,使用某种稀疏存储可能会更好。
一种解决方案是使用字典,其中元组(a,b)是关键字,出现次数是值。
答案 1 :(得分:1)
也许您可以对数据进行多次传递。从符号X开始的对的熵贡献基本上独立于以任何其他符号开头的对(当然除了它们的总数),因此您可以计算所有这些对的熵,然后丢弃分布数据。最后,结合2 ^ 16个部分熵值得到总数。您不一定要对数据进行2 ^ 16次传递,您可以在一次传递中“感兴趣”尽可能多的初始字符,因为您有空间。
或者,如果您的数据小于2 ^ 32个样本,那么您肯定知道您不会看到所有可能的对,因此您实际上不需要为每个对分配计数。如果样本足够小,或者熵足够低,那么某种稀疏阵列将比完整的16GB矩阵使用更少的内存。
答案 2 :(得分:1)
在Ubuntu 10.10 x64上进行了快速测试
gt@thinkpad-T61p:~/test$ uname -a Linux thinkpad-T61p 2.6.35-25-generic #44-Ubuntu SMP Fri Jan 21 17:40:44 UTC 2011 x86_64 GNU/Linux gt@thinkpad-T61p:~/test$ cat mtest.c #include <stdio.h> #include <stdlib.h> short *big_array; int main(void) { if((big_array = (short *)malloc(4UL*1024*1024*1024*sizeof (short))) == NULL) { perror("malloc"); return 1; } big_array[0]++; big_array[100]++; big_array[1UL*1024*1024*1024]++; big_array[2UL*1024*1024*1024]++; big_array[3UL*1024*1024*1024]++; printf("array[100] = %d\narray[3G] = %d\n", big_array[100], big_array[3UL*1024*1024*1024]); return 0; } gt@thinkpad-T61p:~/test$ gcc -Wall mtest.c -o mtest gt@thinkpad-T61p:~/test$ ./mtest array[100] = 1 array[3G] = 1 gt@thinkpad-T61p:~/test$
只要你有足够的内存和/或交换,看起来linux上的虚拟内存系统可以胜任。
玩得开心!