【问题标题】:Pseudorandom generator in Assembly Language汇编语言中的伪随机生成器
【发布时间】:2010-09-10 13:12:26
【问题描述】:

我需要一个伪随机数生成器算法用于课程中分配的汇编程序,我更喜欢简单的算法。但是,我不能使用外部库。

什么是一个好的、简单的汇编伪随机数生成器算法?

【问题讨论】:

  • 你能解释一下这是干什么用的吗?加密、游戏和随机算法确实有不同的要求和权衡。

标签: algorithm assembly prng


【解决方案1】:

用于测试的简单代码,不要与 Crypto 一起使用

来自测试计算机软件,第 138 页

使用 32 位数学,您不需要操作 MOD 2^32

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

【讨论】:

    【解决方案2】:

    使用masm615编译:

    delay_function macro
        mov cx,0ffffh
    .repeat
        push cx
        mov cx,0f00h
        .repeat
            dec  cx
            .until cx==0
        pop cx
        dec cx
        .until cx==0
    endm
    
    random_num macro
       mov  cx,64    ;assum we want to get 64 random numbers
       mov  si,0
    
    get_num:    
       push cx
       delay_function    ;since cpu clock is fast,so we use delay_function
       mov  ah,2ch  
       int  21h
       mov  ax,dx     ;get clock 1/100 sec
       div  num       ;assume we want to get a number from 0~num-1
       mov  arry[si],ah   ;save to array you set
       inc  si
       pop  cx
       loop get_num   ;here we finish the get_random number 
    

    【讨论】:

      【解决方案3】:

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

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

      您需要加密强度的 RNG 吗?在它重复之前需要多长时间?您是否必须绝对、肯定地保证所有位的均匀分布?

      这是我几年前使用的简单技巧。我在嵌入式工作,我需要在上电时测试 RAM,我想要非常小的、快速的代码和非常少的状态,我这样做了:

      • 从种子的任意 4 字节常量开始。
      • 计算这 4 个字节的 32 位 CRC。这给了你接下来的 4 个字节
      • 将这 4 个字节反馈到 CRC32 算法中,就好像它们已被附加一样。这 8 个字节的 CRC32 是下一个值。
      • 随意重复。

      这需要很少的代码(尽管您需要一个用于 crc32 函数的表)并且具有很少的状态,但是伪随机输出流在重复之前有很长的循环时间。此外,它不需要处理器上的 SSE。假设你手边有 CRC32 函数,实现起来很简单。

      【讨论】:

        【解决方案4】:

        嗯 - 由于我没有看到对旧的线性反馈移位寄存器的引用,我发布了一些基于 SSE 内在 C 代码。只是为了完整性。几个月前我写了那件事来再次提高我的 SSE 技能。

        #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 个数字之后重复。这比您通过主要方法和 32 位算术获得的要多得多。如果展开它也会更快。

        【讨论】:

          【解决方案5】:

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

          此算法称为linear congruential generator

          【讨论】:

          • 你不应该只是随机选择 2 个相对质数。有些对比其他对工作得更好。正如其他人所指出的,这种技术对于加密用途来说不够好。
          • 实际上很容易(当然不使用 asm)来反转 a 和 b 的值。我的加密课程让我这样做。
          【解决方案6】:

          @jjrv
          您所描述的实际上是一个线性同群生成器。最随机位是最高位。要从 0..N-1 中获得一个数字,您将整个值乘以 N(32 位乘以 32 位,得到 64 位)并使用高 32 位。

          您不应该只为 a 使用任何数字(从一个完整值到下一个完整值的乘数),Knuth 中推荐的数字(表 1 第 3.3.4 节 TAOCP vol 2 1981)是 1812433253 , 1566083941, 69069 和 1664525。

          您可以为 b 选择任何奇数。 (加法)。

          【讨论】:

          • LCG 使用模运算符。这会保留低位,而不是高位。
          • jjrv 的生成器是 x=(x*a+b) % (232)。 [模 232 由硬件隐式完成]。然后他返回 r=x % N。这只是范围缩小(如果他正在模拟骰子,N 可能是 6)。在提到的 Knuth (3.6 vi) 和维基百科(“另一个问题..”)中,最低位不是很随机
          【解决方案7】:

          线性同余 (X = AX+C mod M) PRNG 可能是分配给汇编程序课程的好方法,因为您的学生将不得不处理 2^31 以上的中间 AX 结果的进位位并计算模数。如果您是学生,它们在汇编程序中实现起来相当简单,并且可能是讲师的想法。

          【讨论】:

            【解决方案8】:

            The Art of Computer Programming 的第 2 卷有很多关于伪随机数生成的信息。这些算法在汇编程序中进行了演示,因此您可以自己查看汇编程序中最简单的算法。

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

            请注意,大多数伪随机数生成器对于加密来说是不安全的,因此如果您需要安全的随机数生成,则需要超越基本算法(并且可能应该利用特定于操作系统的加密 API )。

            【讨论】:

              【解决方案9】:

              您也可以在不同位之间使用 XOR 和元素来模拟移位寄存器,这将为您提供伪随机数字序列。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-03-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-05-18
                相关资源
                最近更新 更多