装配NASM

时间:2018-12-02 13:47:43

标签: assembly random nasm

我正在为一个组装nasm的大学项目工作。唯一的问题是我无法生成介于162和278之间的偶数。我尝试了许多算法,但似乎无法将数字限制在范围内。

是否有小技巧或调整以获取所需范围内的数字?目的是在屏幕上随机显示水果(主要是蛇游戏)。

4 个答案:

答案 0 :(得分:4)

我在这篇文章中看起来有点:nasm random number generator function。 也许您可以尝试(rdtsc%(278-162)/ 2 + 162/2)* 2。 希望对您有帮助:)

答案 1 :(得分:3)

  

生成一个介于162和278之间的偶数随机数

步骤1

“生成随机数”
在蛇游戏中显示水果的任务并不是很苛刻,因此我认为使用TimeStampCounter是可以的。您将继续在EAX中找到低位双字。

-

rdtsc                        ; -> EDX:EAX

步骤2

“ 162和278之间的数字”
要将数字限制在所需的[162,278]范围内,请计算
(RandomNumber mod NumbersInTheRange) + StartOfTheRange

  • RandomNumber是第一步中的EAX寄存器。
  • NumbersInTheRange是upper bound - lower bound + 1别忘了+1。
  • StartOfTheRange是其下界。

-

xor     edx, edx             ; Required because there's no division of EAX solely
mov     ecx, 278 - 162 + 1   ; 117 possible values
div     ecx                  ; EDX:EAX / ECX --> EAX quotient, EDX remainder
mov     eax, edx             ; -> EAX = [0,116]
add     eax, 162             ; -> EAX = [162,278]

步骤3

“偶数”
降低数字的最低位,使数字偶数

-

and     eax, -2              ; -> EAX = {162,164,...,276,278}

答案 2 :(得分:1)

如我评论中所述,您可以使用

 ((random_number % 59) + 81) * 2

布兰登的下一个2-1的幂很简单,但是您需要选择并实现一个随机数生成器。这些随机数生成器中的很多都是LCG,它们使用2的乘方幂加模,但是,可以专门为59的某些乘方或整数乘幂而生成一个,这样就无需丢弃太大的数字。重复随机数序列。 Wiki文章。

https://en.wikipedia.org/wiki/Linear_congruential_generator

另一种选择是非二进制Galois LFSR:

https://en.wikipedia.org/wiki/Linear-feedback_shift_register#Non-binary_Galois_LFSR

但是,LFSR不包含0,因此它们产生q ^ m-1个值。可以检查LFSR何时返回其初始状态,并在该点返回零以结束q ^ m值。

由于59是质数,因此LFSR可以基于原始多项式1x ^ 2 + 1x + 2(GF(59 ^ 2)还有许多其他原始多项式)使用GF(59 ^ 2)将工作)。这将循环显示所有3480个非零值。每次LFSR循环回到其初始状态时,都可以输出一个零,以3481(59 ^ 2)值结束。此LFSR的Ascii艺术版本看起来像(所有数学运算都是%59):

1x^2  1x     2

→    *1     *2 
↑     ↓      ↓
↑     +      +  
←   ┌━┐ ← ┌━┐
    └━┘   └━┘

我这样做了,并使用低阶项(ax + b中的b值)生成了一组3481值,如以下链接到文本文件所示:

http://rcgldr.net/misc/x3481.txt

如果您想要更长的周期(12117360个周期+ 1个周期为零),则可以基于原始多项式1x ^ 4 + 1x + 14使用GF(59 ^ 4):

1x^4 0x^3  0x^2   1x     14

→    →      →     *1    *14 
↑                  ↓      ↓  
↑                  +      +  
←   ┌━┐ ← ┌━┐ ← ┌━┐ ← ┌━┐
    └━┘   └━┘   └━┘   └━┘

注意-我使用蛮力搜索程序找到原始多项式,以找到需要q ^ m-1个周期才能重复的LFSR。

答案 3 :(得分:-1)

首先;理解(对于随机数生成)以“非2的幂”为模将导致偏差,应避免。例如,如果您想要一个从0到2的数字并以4位随机数开头(值0、1、2,..,14、15),则在“取模3”之后,值将变为0、0 ,0、1、1、1,...,4、4、4、5),而值5的可能性将比其他任何值都要小。

解决“由非2的幂的模引起的偏差”的最简单方法是将(AND与)掩码为2的下一个最高幂减1,然后舍弃该数字,如果该值仍然超出该值,则重试。范围。例如,如果您想要一个从0到2的数字并以32位随机数开头;您将执行“ number = number&(4-1)”(因为4是2的次幂),然后如果该数字大于2,则将其丢弃并再次获得一个新的随机数。

现在...

如果您要避免“由于非2的幂的模引起的偏差”;如果该数字恰好是162到278范围内的偶数,为什么还不重试?

例如(在C中):

#define MAX_VALUE         500
#define NEXT_POWER_OF_2   512

int getNumber(void) {
    int number;

    do {
        number = rand();
        number = number & (NEXT_POWER_OF_2 - 1);
    } while( (number > MAX_VALUE) || ((number >= 162) && (number <= 278) && (number & 1 == 0)) );
}

用于组装:

;Input
; none
;
;Output
; eax = random number in range from 0 to MAX_NUMBER that is not an even number from 168 to 278

%define MAX_VALUE         500
%define NEXT_POWER_OF_2   512

getNumber:
    call getRandomDword         ;eax = random 32-bit value
    and eax,NEXT_POWER_OF_2-1   ;eax = random N-bit value
    cmp eax,MAX_VALUE           ;Is it too large?
    ja getNumber                ; yes, retry
    cmp eax,278                 ;Is it larger than the "not even" range?
    ja .done                    ; yes, allow the number
    cmp eax,162                 ;Is it smaller than the "not even" range?
    jb .done                    ; yes, allow the number
    test al,1                   ;Is it even?
    je getNumber                ; yes, retry

.done:
    ret

注意:我不知道您是否要使用16位,32位或64位代码,或者该代码是否必须在哪些CPU上运行,或者随机源是什么。例如,最近的CPU支持相对较慢的rdrand指令(它是为加密而不是速度而设计的,但可用于定期“重新设置”伪随机数生成器),但是如果您需要确保代码在旧的80386上工作正常,然后...