News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

noob about nrandom...yes I searched

Started by sydetys, October 07, 2008, 11:58:47 PM

Previous topic - Next topic

sydetys

I am sorry to bother you, don´t answer at all if this irritates.

I have searched and tried many variations but I can´t make this work, everytime I run this program it gives SAME values.

start:


invoke nrandom, 0ffffh
        mov ebx, eax
       
print str$(ebx)

invoke nrandom, 0fffffffh
        mov esi, ebx

print str$(esi)


xor ebx, ebx
xor eax, eax
xor esi, esi
invoke ExitProcess, 0
end start

what´s wrong? eventually I want to make a loop which makes different numbers everytime...but that´s AFTER this is solved..

thank you

BTW I know there should be line feed between prints, but main thing is, no randomness, and there was in some thread that "I have to feed this again, so I wouldn´t lose randomness", I assume feed means, putting other value after nrandom syntax, but noo

MichaelW

Like most pseudo-random generators nrandom produces a predetermined sequence, and the starting seed determines where in the sequence the generator starts. When you call nrandom without first setting the seed, the generator starts with the default seed. To start at a different location in the sequence you must change the starting seed. One common way of doing this would be to use the return value from GetTickCount as the starting seed:


invoke GetTickCount
invoke nseed, eax


Note that frequent reseeding of the generator tends to destroy the randomness of the generated sequence.


eschew obfuscation

raymond

QuoteI have searched and tried many variations but I can´t make this work, everytime I run this program it gives SAME values.

Assuming you get a value such as "1234" when you run the program a first time, do you mean you are always getting that same "1234" if you run the program several more times???

Quotestart:

invoke nrandom, 0ffffh
        mov ebx, eax
       
print str$(ebx)

invoke nrandom, 0fffffffh
        mov esi, ebx

print str$(esi)

When you run the above code, it's obvious that both values being printed will ALWAYS be identical. You transfer the first random number to EBX which you print out then call for another random number but transfer the value of EBX (which should not have changed) to ESI and print it out again!!!
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

sydetys

You mean like this?, I simplified that thing:

start:
main proc

invoke GetTickCount
invoke nseed, eax

invoke nrandom, 2000
        add ebx, eax
       
print str$(eax)

print chr$(10)

print str$(ebx)

ret
main endp
invoke ExitProcess, 0
end start

so I get TWO random numbers? I assume that after that I have to use SVAL syntax to change eax and ebx into real numbers....
Can you explain what kind of numbers those RAW numbers are? unsigned?
Because my english skill sucks in technical things so, I feel I didn´t understand what differrence is between unsigned and signed numbers from manual, can you assist?

Masm32 help wasn´t that good to explain what that "base" number represents. In my code above it´s 2000, is that same as "0 - 2000 random number will be calculated"?

PS. I noticed that I can´t play with decimal number like 0.12,  how is it done in assembler

If I make this:

main proc

LOCAL nro:DWORD
LOCAL nro2:DWORD

mov nro, input("Enter a number : ")
mov nro2, sval(nro)
print chr$(10)


mov eax, nro2
mov ebx, 10

add eax, ebx
print str$(eax)

EBX register can´t be decimal number and I assume same thing is number in variable "nro"
Any hints?

thanks for patience

MichaelW

The nrandom procedure returns (in EAX) a 32-bit integer that at least normally would be treated as an unsigned value. The base parameter specifies the "range" of the returned values, meaning that the return value will be >= 0 and < base. So for example, this snippet:

    mov ebx, 100
  looper:
    invoke nrandom, 10
    print str$(eax), 9
    dec ebx
    jnz looper


Will produce this output:

4       1       4       2       6       3       3       9       6       3
9       1       6       4       6       8       8       9       8       2
5       4       7       3       9       3       6       0       0       9
7       1       6       9       7       6       8       2       6       7
2       3       0       2       4       8       8       5       9       8
9       0       2       5       1       2       0       3       0       5
1       9       4       3       3       5       8       1       0       0
8       3       6       9       0       6       9       8       7       3
5       2       3       9       3       0       0       8       3       2
8       4       3       9       7       3       6       3       6       6


As you can see, the minimum value is 0 and the maximum value is base - 1.

To illustrate the points I was trying to make in my post above, if you create an EXE from this code:

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    ;invoke GetTickCount
    ;invoke nseed, eax

    mov ebx, 100
  looper:
    invoke nrandom, 10
    print str$(eax), 9
    dec ebx
    jnz looper

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


It will produce the same output, as shown above, each time it is run. If you uncomment the first 2 statements and recreate the EXE, it will then produce a different output each time it is run (or put another way, the output will vary from run to run).
eschew obfuscation

RaZiel

I'll try help you out. I can't really help you a lot with specific masm syntax, but I do have a lot of experience from other languages.

Yes, you get two. But one is the actual random number from nrandom returned in eax. The other is adding the result eax to ebx (which is uninitialized according to your code), which may give unexpected results.
If you want to initialize it, you write "xor ebx, ebx". Why they don't write "mov ebx, 0", is most likely because using xor saves cpu cycles. But if you initialize it, you'll get the same result printed twice.

The numbers are unsigned. Which means they are only positive numbers. Signed numbers can be both negative and positive, which is indicated by the datatype you use. I'm not sure about the names for all the datatypes in masm.
But you want to use a datatype equal to INT.

A DWORD for example is an unsigned datatype for numbers. You can still do arithmatic like subtracting, but the result will always be a positive number. Subtracting beyond 0 will result in a number that's not negative, but still positive. The remaining value subtracted beyond 0, is actually subtracted from the maximum value a DWORD can have. When you increment the last value or decrement the first value, the result wraps around the beginning or end of the range.

Example:
Max value for DWORD is 2^32 = 4294967295. In hex it's 0xFFFFFFFF. 2^32 because it's a 32bit datatype, which also means it takes 32/8bits= 4 bytes of memory.
If you initialize a DWORD with 0, and subtract 12. You'll get 4294967284.
If you initialize a DWORD with 11, and subtract 12. You'll get 4294967295.

An INT datatype is signed. It's also 32 bit. So it can store 2^32 values. But the range is -2147483648..2147483647. While DWORD is 0..4294967295.
How do you know if it's a positive or negative number? It's decided by the MSB (most significant bit) if it's set or not.

QuoteIn my code above it´s 2000, is that same as "0 - 2000 random number will be calculated"?
Yep. If you want negative values too. You can use take the result and subtract by half. Like 2000 - 1000. Then you'll actually have a range from -1000 to 1000.

To use decimal numbers, you'll have to declare you variables as floats, and check if the functions you use supports that datatype. Or do it manually. Get an integer value, devide it, and cast the result as a float.

I hope this helped :)




NightWare

here some random number routines (faster than nrandom) :
.DATA
ALIGN 16
Seed DWORD ?


.CODE
ALIGN 16
;
; Initialise the random numbers
;
; syntax :
; call InitRndmNbr
;
; Return:
; eax = number of ticks since the computer started, and Seed defined
;
InitRndmNbr PROC
push ecx
push edx

invoke GetTickCount
test eax,eax ; ) to be sure it's not zero (it's possible ! if you launch the program 48 days after you've started the computer, lol)
jnz Label1 ; ) (and depending of the radom number routine, some really don't like zeros...)
mov eax,123456789 ; )
Label1: mov Seed,eax ; save the seed

pop edx
pop ecx
ret
InitRndmNbr ENDP


ALIGN 16
;
; generate a random number
;
; syntax :
; mov ebx,Range
; call GetRndmNbr
;
; Return :
; eax = desired random number
;
GetRndmNbr PROC
push edx

mov eax,987654321 ; a x value
mul Seed ; multiply eax by your Seed
bswap eax ; swap bytes (to not have a too easy suit)
xor eax,078787878h ; apply a mask
mov Seed,eax ; save the new RndmNbr as Seed, for next use
; a range ?
inc ebx
jz Label2 ; if not jump Label2
; here a range :
mul ebx ; mul by range+1
mov eax,edx ; return the result in eax
; exit
Label2: dec ebx ; restore ebx

pop edx
ret
GetRndmNbr ENDP


Quote from: RaZiel on October 08, 2008, 01:37:10 PM
Get an integer value, devide it, and cast the result as a float.

hey ! don't give bad habits to noobs  :lol, you just need to generate a 8 digits random number, and MULTIPLY it by 0.00000001f  :wink

dsouza123

invoke nrandom, 2000   ; the result range is 0..1999 in eax
; if you subtract 1000 it has a range of -1000..0..999

fild eax  ; loads eax as a signed value into st(0)
          ; auto converted to real, double, extended
          ; that is a 32 bit, 64 bit, 80 bit real format

A 32 bit register can hold a value of
0..4294967295 unsigned
0..2147483647  2147483648..4294967295 unsigned
0..2147483647 -2147483648..-1 signed

0..0FFFFFFFFh unsigned hex
0..7FFFFFFFh   80000000h..0FFFFFFFFh unsigned hex

There are many other values that could mapped on a 32 bit register,
fixed point (implied decimal/binary point), four ascii characters etc.

MichaelW

AFAIK the only FPU instruction that can directly access a CPU register is FSTSW, which can store the FPU status word in AX. Instead of fild eax, you could use:

push eax
fild DWORD PTR [esp]
pop eax

eschew obfuscation

jj2007

Quote from: MichaelW on October 08, 2008, 11:09:01 PM
AFAIK the only FPU instruction that can directly access a CPU register is FSTSW, which can store the FPU status word in AX. Instead of fild eax, ...

Indeed, fild eax does not assemble under Masm. It is not a good habit to post code that has not been tested, especially not in the Campus :naughty:

Here is a full-fledged FPU program.

include \masm32\include\masm32rt.inc

.data
MyNum dd 12345678
MyDiv REAL8 1234.5678
MyResult dd 0

.code
start:
; mov eax, offset MyNum   < possible but unnecessarily
; fild dword ptr [eax]    < complicated

fild MyNum
fld MyDiv
fdiv
fistp MyResult

MsgBox 0, str$(MyResult), "The FPU is cool:", MB_OK

exit

end start

NightWare

damn... i'm sure i've said MUL...  :'(

jj2007

Quote from: NightWare on October 09, 2008, 01:35:18 AM
damn... i'm sure i've said MUL...  :'(
In case you mean my fdiv: This was just an illustrative example for the correct use of fld/fild, in reply to dsouza's inexistant fild eax :wink
Since we are in the Campus here: It is good practice to replace a division by a multiplication with 1/x, because it's a lot faster.

sydetys

O-right-o, now I only have this digest and test this, thanks