我正在为一个组装nasm的大学项目工作。唯一的问题是我无法生成介于162和278之间的偶数。我尝试了许多算法,但似乎无法将数字限制在范围内。
是否有小技巧或调整以获取所需范围内的数字?目的是在屏幕上随机显示水果(主要是蛇游戏)。
答案 0 :(得分:4)
我在这篇文章中看起来有点:nasm random number generator function。 也许您可以尝试(rdtsc%(278-162)/ 2 + 162/2)* 2。 希望对您有帮助:)
答案 1 :(得分:3)
生成一个介于162和278之间的偶数随机数
“生成随机数”
在蛇游戏中显示水果的任务并不是很苛刻,因此我认为使用TimeStampCounter是可以的。您将继续在EAX
中找到低位双字。
-
rdtsc ; -> EDX:EAX
“ 162和278之间的数字”
要将数字限制在所需的[162,278]范围内,请计算
(RandomNumber mod NumbersInTheRange) + StartOfTheRange
。
EAX
寄存器。 upper bound - lower bound + 1
。 别忘了+1。 -
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]
“偶数”
降低数字的最低位,使数字偶数。
-
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上工作正常,然后...