汇编语言中的伪随机生成器

时间:2020-03-06 14:20:04  来源:igfitidea点击:

对于在课程中分配的汇编程序,我需要伪随机数生成器算法,并且我希望使用简单的算法。但是,我不能使用外部库。

什么是用于汇编的良好,简单的伪随机数生成器算法?

解决方案

一种简单的方法是只选择两个相对大的素数a和b,然后将随机数乘以a并加b。使用取模运算符将低位保留为随机数,并保留下一个迭代的完整值。

该算法称为线性同余生成器。

我们也可能会在异位之间使用XOR和元素模拟移位寄存器,这将为我们提供伪随机数字序列。

《计算机编程艺术》第2卷中有许多有关伪随机数生成的信息。这些算法在汇编器中进行了演示,因此我们可以亲自了解汇编器中最简单的算法。

但是,如果可以链接到外部库或者目标文件,那将是最好的选择。然后,我们可以链接到例如Mersenne Twister。

请注意,大多数伪随机数生成器对于密码术而言并不安全,因此,如果需要安全的随机数生成,则需要超越基本算法的范围(并且可能应使用特定于OS的加密API)。

简单的测试代码,请勿与Crypto一起使用

从测试计算机软件,第138页

使用32位数学运算,我们无需执行`MOD 2 ^ 32'操作。

RNG = (69069*RNG + 69069) MOD 2^32

线性同余(X = AX + C mod M)PRNG可能是分配汇编课程的一个好方法,因为学生将不得不处理2到31之间的中间AX结果的进位并计算模数。如果我们是学生,那么他们很容易在汇编器中实现,并且可能是讲师所考虑的。

#include <emmintrin.h>

static __m128i LFSR;

void InitRandom (int Seed)
{
  LFSR = _mm_cvtsi32_si128 (Seed);
}

int GetRandom (int NumBits)
{
  __m128i seed = LFSR;
  __m128i one  = _mm_cvtsi32_si128(1);
  __m128i mask; 
  int i;

  for (i=0; i<NumBits; i++)
  {

    // generate xor of adjecting bits
    __m128i temp = _mm_xor_si128(seed, _mm_srli_epi64(seed,1));

    // generate xor of feedback bits 5,6 and 62,61
    __m128i NewBit = _mm_xor_si128( _mm_srli_epi64(temp,5),
                                    _mm_srli_epi64(temp,61));

    // Mask out single bit: 
    NewBit = _mm_and_si128 (NewBit, one);

    // Shift & insert new result bit:
    seed = _mm_or_si128 (NewBit, _mm_add_epi64 (seed,seed));
  }

  // Write back seed...
  LFSR = seed;

  // generate mask of NumBit ones.
  mask = _mm_srli_epi64 (_mm_cmpeq_epi8(seed, seed), 64-NumBits);

  // return random number:
  return _mm_cvtsi128_si32 (_mm_and_si128(seed,mask));
}

将此代码转换为汇编器是微不足道的。只需用真正的SSE指令替换内部函数,并在其周围添加一个循环即可。

在此代码生成的序列之间,在4.61169E + 18数字之后重复。这远远超出了我们通过prime方法和32位算术获得的结果。如果展开,它也会更快。

为什么不使用外部库???那个轮子已经被发明了数百次,那又为什么要重复呢?

如果我们需要自己实施RNG,是否需要按需生成数字-即我们是要实现rand()函数-还是需要产生随机数流-例如用于内存测试?

我们是否需要具有加密强度的RNG?重复需要多长时间?我们是否必须绝对肯定地保证所有位的均匀分布?

这是我几年前使用的简单技巧。我当时在嵌入式系统中工作,我需要在加电时测试RAM,我想要很小的,快速的代码和很少的状态,我做到了:

  • 从种子的任意4字节常量开始。
  • 计算这4个字节的32位CRC。那给你接下来的4个字节
  • 将这4个字节反馈回CRC32算法,就好像它们已被追加一样。下一个值是这8个字节的CRC32.
  • 只要我们想重复即可。

这需要很少的代码(尽管crc32函数需要一个表)并且状态很少,但是psuedorandom输出流在重复之前有很长的循环时间。而且,它不需要处理器上的SSE。并假设我们拥有方便的CRC32函数,实现起来很简单。

标题数量不匹配