【问题标题】:How to seed to generate random numbers?如何播种以生成随机数?
【发布时间】:2015-03-27 07:15:14
【问题描述】:

它不会产生预期的随机性。

我认为从像 $66 这样的种子开始并异或最后两个低位和 ror 会给我下一个随机数等等,但它只显示 $B3 并且根本没有改变。

我该如何喂食? random 上面的行显示了 portc 上的数字,因为我希望两个数字一个接一个地显示。

我只使用 avr studio 4 for atmega 8535 at 1Mhz。

> ;Program to random numbers  on port C
> 
> ;Stack and Stack Pointer Addresses  .equ     SPH    =$3E             
> ;High Byte Stack Pointer Address   .equ     SPL    =$3D             
> ;Low Byte Stack Pointer Address 
> 
> .equ     RAMEND =$25F             ;Stack Address 
> 
> ;Port Addresses 
> 
> .equ     PORTC  =$15              ;Port C Output Address 
> 
> .equ     DDRC   =$14              ;Port C Data Direction Register
> Address 
> 
> .equ     numberoneddr=DDRC
> 
> .equ     numberoneport=portc
> 
> .equ     numbertwoddr=DDRC
> 
> .equ     numbertwoport=portc
> 
> .equ     delayCount=21
> 
> .equ    random1 =$66
> 
> ;Register Definitions 
> 
> .def    numberone   =r1               ;Register to store data pointed
> to by Z 
> 
> .def    numbertwo   =r2
> 
> .def     temp   =r16              ;Temporary storage register 
> 
> 
> 
> reset:
> 
> ; initialize stack pointer. Done automatically at reset on many AVRs
> 
>   ldi temp, low  (RAMEND)
> 
>   out spl, temp
> 
>   ldi temp, high (RAMEND)
> 
>   out sph, temp
> 
> 
> 
> 
> ;port initialisation
> 
> ldi temp,$FF
> 
> out numberoneddr,temp
> 
> out numberoneport,temp
> 
> out numbertwoddr,temp
> 
> out numbertwoport,temp
> 
> 
> 
> ;Program Initialisation 
> 
> ldi temp,$66
> 
> rcall random
> 
> mov   numberone, temp
> 
> out numberoneport,numberone
> 
> rcall random
> 
> mov   numbertwo, temp
> 
> out numberoneport,numbertwo
> 
> 
> 
> 
> random: mov r19,temp
> 
> ldi r17, 0x01
> 
> eor r19,r17
> 
> ror r19
> 
> mov temp,r19
> 
> ret
> 
> 
> 
> delay:
>         clr r20
> 
>       clr r21
> 
>       ldi r22, delayCount
> 
> loopDelay:
> 
>       dec r20
> 
>       brne loopDelay
> 
>       dec r21
> 
>       brne loopDelay
> 
>       dec r22
> 
>       brne loopDelay
> 
>         ret

【问题讨论】:

  • 对源代码使用代码块(或按 4 个空格),添加更多信息,例如什么 MCU,到底出了什么问题,...您的代码在 PC 上工作吗?如果不尝试跟踪它出了什么问题……并在它工作时移植到 MCU asm。如果您的 MCU 上有断点/跟踪功能,那么您可以跳过 PC 部分。现在,您的问题实际上是为什么这段代码不起作用,这是题外话,所以现在投票关闭
  • 它不会产生预期的随机性,我从像 $66 这样的种子开始教,然后异或最后两个低位和 ror 会给我下一个随机数等等,但它只显示 $B3 和完全没有任何帮助,我只使用 avr studio 4 for atmega 8535 at 1Mhz
  • 你在每次随机调用时都喂temp=$66,所以结果总是一样的......你应该只喂一次临时。我还会添加一个比特交换(不仅仅是ror),它通常会带来更好的随机性。还有 random: 标签上面的 3 行是做什么的...它们没有在 call random 上执行!!!
  • 我对播种位有点困惑,请你帮忙解释一下我是如何在不使用温度的情况下喂食的。 random 上面的行显示了 portc 上的数字,因为我希望两个数字一个接一个地显示
  • 在程序初始化时执行 ldi temp,$66 并将其从随机子程序中删除。 temp 也是一个坏名字......当你的程序增长时,尝试将它重命名为 random_tmp 例如

标签: assembly avr


【解决方案1】:

在搜索了我的古代 asm 源代码档案后,我发现了这个适用于我过去使用的 x86 MSDOS NASM 平台:

;.rnd       ;al=rnd num <0,ah>;

.rnd:   pusha
    mov cx,ax

.rnd0:  mov bx,[cs:.rnddat]

    mov ax,[cs:.rndtim]
    xor al,bh
    add ah,bh
    rcr ax,3
    xor al,bl
    rcl ax,2

.rnd2:  cmp al,ch
    jbe .rnde
    sub al,ch
    or  ch,ch
    jnz .rnd2
    sub al,al

.rnde:  mov ah,bl
    mov [cs:.rnddat],ax
    or  al,1

    xor ax,[fs:046Ch]
    add [cs:.rndtim],ax
    popa
    mov al,[cs:.rnddat]
    ret
.rnddat:db  0,0
.rndtim:dw  0

这个想法是让一些存储的数字执行一些基本的 ALU 操作,例如+,*,/,&lt;&lt;,&gt;&gt;,&amp;,^,但要确保不会发生饱和,并且通常会交换一些值的H,L,以控制随机性。所以将它移植到你的 asm,但我强烈建议对其进行编码并先在 PC 上尝试,看看随机性是否适合你的任务。

顺便说一句,您还可以使用程序存储器或任何 ROM 内容作为随机性的基础...这也利用了内部 RTC 块,因此您必须省略该部分或添加计时器或只是而是遍历一堆非空数据。

[0000:046C] are 4 Bytes master clock count (long integer) 0 = midnight and increments until a 24 hour equiv.

我发现了我的更旧的演示,称为 NoSignal(从 1997 年在 TASM 中),其中包含 rnd:

    .386P
    IDEAL
    MODEL TINY

    CODESEG
    STARTUPCODE
main:   mov ax,19   ;320*200*256
    int 16
    push 0A000h ;Video segment
    pop es      ;keyboard test,speaker delay v si=256

l0: ror ax,cl       ;rnd...ax
    add ax,di
    stosw       ;plot...
    loop r1     ;speaker delay...
    mov cx,si
    out 61h,al
r1: or di,di
    jnz l0
    push ax
    mov ah,1    ;test keyboard
    int 16h
    pop ax
    jz l0

ende:   sub ax,ax   ;turn off speaker and exit
    out 61h,al
    int 16h
    mov ax,3
    int 16
    ret
    END

它用白噪声填充屏幕和扬声器,就好像模拟电视中没有天线电缆一样。此版本长 44 字节,伪随机生成器从标签 l0: 开始

  • ax 是生成的号码(也是之前生成的号码,比如你的临时号码)
  • di 正在递增(类似于实际时间)...
  • cl 正在递减

所以如果我看对了它应该足够了:

    rnd:ror ax,cl       ;rnd...ax
        add ax,di
        inc di
        dec cl
        ret

如果需要,添加push/pop 存储寄存器/值。如果您需要更复杂的东西,请使用模素数算术。

[edit1] 简单的 C++ 伪随机生成器

WORD rnd_d0=0x66; // these are seed numbers if not selected right then the randomness is not good
WORD rnd_d1=0x5A; // these give fairly good results
WORD rnd_d2=0xC3;
WORD rnd()
    {
    rnd_d0^=rnd_d1|rnd_d2; // xor
    rnd_d1*=rnd_d2; // mul
    rnd_d2+=rnd_d1; // add
    rnd_d0=(rnd_d0<<8)|(rnd_d0>>8); // 8bit halves swap
    return rnd_d0;
    }

上述随机生成器被限制在 DOS 环境时间或特殊用途中。这个不是……随机性是这样的:

当我用它来填充 NoSignal 图像窗口时,结果是这样的:

这里还有 Gif 动画:

NoSignal填充码如下:

 for (int y=0;y<ys;y++)
  for (int x=0;x<xs;x++)
   pyx[y][x]=0x00010101*int(rnd()>>8);

所以只使用来自16bit 伪随机数的高8bit,乘法只是将此8bit 数字转换为灰度颜色。

  • xs,ys 是图片大小
  • pyx 是指向其行的直接图像指针

如果没有在 PC 上进行适当测试,请勿更改种子编号

错误选择的种子根本不会导致随机性。如果您想安全地播种(无需测试),请使用提供的常量播种,然后调用rnd() 的次数与您的新种子号一样多。现在解决了这个问题,所以可能会有更好的种子,这些只是我发现的第一个能产生相当好的结果的种子

这些种子也不错:

    WORD rnd_d0=0x37A6;
    WORD rnd_d1=0x377A;
    WORD rnd_d2=0x3BC3;

【讨论】:

  • @alex 有一点时间,所以我测试了我的旧随机生成器,没有 MSDOS 时间或特殊的使用方式,没有那么好,所以我创建了一些独立于平台和使用的东西,请参阅 [edit1 ] 它使用 16 位 ALU,所以如果没有任何来自 8 位 ALU 源代码的代码在 C++ 中,那么移植到 asm 应该没有任何问题。如果您需要更好的东西,请指定您需要的随机性属性
  • Rotate-through-carry (rcr/ rcl) 计数 > 1 在现代 x86 上相当慢:例如,Intel Haswell 上 8 uop,或 AMD Steamroller 上 15 m-ops。我猜这是针对代码大小而不是速度和/或更旧的 CPU 优化的。 (即使是像 PII 这样的早期 P6 CPU 也有更快的 rcr)。
  • @PeterCordes 更像是 AMD 80386 到 AMD K5... 是的,它针对代码长度进行了优化
猜你喜欢
  • 2013-09-24
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 2016-08-08
  • 2015-03-14
  • 2017-04-06
  • 1970-01-01
  • 2019-07-16
相关资源
最近更新 更多