Oxygen Basic
Programming => Example Code => Topic started by: Frankolinox on April 10, 2013, 01:49:06 AM
-
hi, I am looking for a simple "rnd(a,b)" command or function.
thanks, frank
-
Frank..
Peter create this and work very well.. ;)
Rand(min,max)
Function Rand(byval z1 as long, byval z2 as long) as long
Long rnd
mov eax,z2
sub eax,z1
Inc eax
imul edx,sys_Seed,0x8088405
Inc edx
mov sys_Seed,edx
mul edx
add edx,z1
mov rnd,edx
Function = rnd
End Function
-
a) thanks for little rand() function, aurel, but it doesn't work here. have you more details about that example?
b) I am looking for a random function for using two parameters with "rnd(min,max)".
but it's not very urgent. I wanted only to use it for different "height" parameter for some cubes in my openGL fog example :) I can change the example for having different height values for the cubes, no problem, but it would be easier to have a random function here.
sys a,b,y
a=1
b=100
y=rnd(a,b)
function random(sys min, max) as long
end function
for i = -25 to 25 step 10
for j = -25 to 25 step 10
height = Rand(5, 20)
'...
next
next
if anybody has an idea I am glad to see that one.
frank
X
-
Hi frank,
got this from Fasm and converted to Oxygen.
$ filename "rnd.exe"
#include "..\..\inc\RTL32.inc"
int Rnd(int max)
{
int a;
rdtsc ; call read time-stamp counter instruction
; returns timer value in edx:eax
cdq ; convert double word to quad word
; edx:eax <-- sign extension of EAX
idiv max ; divide edx:eax by max integer
; stores result in EAX <- Quotient, EDX <- Remainder
; EDX = edx:eax % max
cmp edx, 0 ; compare value to zero?
jge after ; jump if not less than to after: label
neg edx ; otherwise, change sign to positive
.after:
mov a, edx ; store random number in a
return a; // return random number
}
macro RndA(min,max)
rnd(max-min)+min
end macro
print Rnd(100)
print RndA(200,300)
-
Here is a copy in HighLevelAsm
int H_Rnd(int max)
{
rdtsc
cdq
idiv max
^ .if eax<0
^ ~edx
^ .endif
^ eax><edx
return eax
}
-
What... >:(
This time not work for me to...what a heck was heapend ???
-
Emil..
do you can show code without all this comments with
standard oxygen syntax without {} thingies ;)
Or maybe better to show us how create RND function with oxygen BASIC code?
-
Aurel ,
do you can show code without all this comments with
standard oxygen syntax without {} thingies
what is the problem with the comment , when coding in asm it is recommended to comment every step
you do for better understanding.
{} is prat of Oxygen , for example
function rnd(min as int, max as int) as int
equal to this
int rnd(int min,int max)
{
and
function = val
End function
is equal to
return val
}
so what is the problem here ??????
Or maybe better to show us how create RND function with oxygen BASIC code?
i think Oxygen basic still do not support quad value division so we cant make this with basic.
-
32bit Oxygen uses the FPU for quad (64bit signed integer) arithmetic.
-
thank you emil for your example! :) I haven't checked it, but I will try next hours, looks good if that's working I am very glad!
here's my result of explorations about "rand" and "rnd()" by charles and peter's example shown:
'first random() ' rand(a,b) ' peter
Long seed=0x12345678 'initial seed value
Function Rand(byval z1 as long, byval z2 as long) as long
long rnd
long sys_Seed=0x12345678
mov eax,z2
sub eax,z1
Inc eax
imul edx,sys_Seed,0x8088405
Inc edx
mov sys_Seed,edx
mul edx
add edx,z1
mov rnd,edx
Function = rnd
End Function
print Rand(64,255) /Log(10) '93.80760809
print Rand(64,255) '216
'second random() 'Rnd() ' charles
'-----------------------
Function Rnd() as single 'sys
'=======================
'
Static As Single f, d=1/0x7fffffff
mov eax,seed
rol eax,7
imul eax,eax,13
mov seed,eax
push eax
fild dWord [esp]
add esp,4
fmul dWord d
fstp dWord f
Function=f
End Function
print rnd() '0.657777..
the rand() example from peter is good, but it's not working correct for different values for my openGL cubes (or I have done something wrong), I already tried it.
I suppose that's not working as usual rnd(min,max) function because there's a fixed value with the "seed", but I am not sure about that one.
got this from Fasm and converted to Oxygen.
@emil: little question just for my curiosity, because I didn't know Fasm: is that a heavy job to convert from Fasm to oxygen? thanks!
best regards, frank
-
@emil: little question just for my curiosity, because I didn't know Fasm: is that a heavy job to convert from Fasm to oxygen? thanks!
fasm = flat assembler http://flatassembler.net/ (http://flatassembler.net/)
-
But Frank something is strange here:
Function Rand(byval z1 as INT, byval z2 as INT) as INT
INT rnd
INT sys_Seed=0x12345678
mov eax,z2
sub eax,z1
Inc eax
imul edx,sys_Seed,0x8088405
Inc edx
mov sys_Seed,edx
mul edx
add edx,z1
mov rnd,edx
Function = rnd
End Function
print Rand(1,100)
I always receive same result...what i do wrong ???
-
Peter
First ..i see that your new function is litlle bit different then old which i have.
Ok i get it that i first need to randomize.
I will try... ;)
by the way ,is there a way to create this func without asm code?
and what will be difference ?
thanks
-
Peter
This looks like nightmare...
I receive now result 1 ???
What kind of problem is now?
here is my test code:
! GetTickCount Lib "kernel32.dll" () as sys
sys seed
Function Randomize() as sys
seed = GetTickCount
End Function
Function Rand(sys z1,z2) as sys
pushad
sys rnd
mov eax,z2
sub eax,z1
inc eax
imul edx,seed,0x8088405
inc edx
mov seed,edx
mul edx
add edx,z1
mov rnd,edx
popad
Return rnd
End Function
print Rand(1,100)
I also found in from your old window.inc
this :
Declare Function timeGetTime Lib "winmm.dll" () As Long
sys sys_Seed
Sub Randomize()
sys_Seed = timeGetTime
End Sub
Function Rand(sys z1, z2) as sys
sys rnd
mov eax,z2
sub eax,z1
inc eax
imul edx,sys_Seed,0x8088405
inc edx
mov sys_Seed,edx
mul edx
add edx,z1
mov rnd,edx
return rnd
End Function
print Rand(1,100)
And again result is always 1 ...
this is really weird...
because i know that this function work in the past ::)
-
perhaps anybody can check this random() example I've done this morning with arrays:
basic
print "random test"
'-----------------------// test // ------------------
function rando(sys*max,sys*min) as long
sys p=@max
sys k=@min
rdtsc
cdq
idiv max
idiv min
cmp edx, 0
jge after
neg edx
.after:
mov edx,p 'mov a, edx
mov edx,k
return [edx+4] 'p 'max '
end function
print "ok"
indexbase 1
'sys aa[12]={50,52,53,54,55,56,57,58,59,60,61,62}
sys ab[21]={10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}
print "test random function"
print "ok2"
'print rando ab[3] ,ab[5] 'result: 15
print rando ab[6] ,ab[7] 'result: 17
print "ok3"
'print rando aa[8] ,aa[9] 'result: 60
'print rnd(100)
'-----------------------// test end // ------------------
both results are correct, but I can only run one example
either
rando ab[3] ,ab[5]) OR
print rando aa[8] ,aa[9] 'result: 60
I've used emil's code (one page before) from fasm and convert it into oxygen.
b) thanks peter for code example with randomize+gettickcount :)
best regards, frank
-
I try..
compile Ok
but when i run program after few message boxes ,program just crush ???
-
Finally.. it work fine :)
i do what Peter say ,so i call Randomize() inside function Rand(min,max)
! GetTickCount Lib "kernel32.dll" () as sys
sys seed
Function Randomize() as sys
seed = GetTickCount
End Function
Function Rand(sys z1,z2) as sys
Randomize
pushad
sys rnd
mov eax,z2
sub eax,z1
inc eax
imul edx,seed,0x8088405
inc edx
mov seed,edx
mul edx
add edx,z1
mov rnd,edx
popad
Return rnd
End Function
print Rand(1,100)
I am wondering is this posible to write without asm code?
-
1) here's my fixed version for random(a,b) with arrays :-)
that's only "one possible" approach for this task and this works fine here..
'
'random test with arrays by frankolinox for oxygenbasic, 11.april.2013
'
print "..new random(a,b) test follows.."
'-----------------------// test // ------------------
function rando(sys*max,sys*min) as long
'------------- max
sys p=@max
rdtsc
cdq
idiv max
cmp edx, 0
jge after
neg edx
.after:
mov edx,p
return [edx+4] 'max 'that's I fixed ;)
'------------- min
sys k=@min
rdtsc
cdq
idiv min
cmp edx, 0
jge after
neg edx
.after:
mov edx,k
return [edx+4]
end function
indexbase 0
sys aa[12]={100,200,300,400,500,600,700,800,900,1000,1100,1200}
sys ab[31]={10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}
print "test random function with arrays"
print "ok"
print rando aa[2] ,aa[4] 'result: 400 for indexbase 0
print "ok2"
print rando ab[3] ,ab[5] 'result: 14 for indexbase 0
print "ok3"
2) I am not sure, but I think that's peter example serves with no different values as random function should do. output gives in that example only first parameter back and not different (random) values.
best regards, frank
-
Hi Frank,
My i ask you a question .
why you do the job towis , one for max value and other one for min.
for the sake of speed , you can do only one time for a value (max-min) then add min to the result.
here is the example again
int Rnd(int max)
{
int a;
rdtsc ; call read time-stamp counter instruction
; returns timer value in edx:eax
cdq ; convert double word to quad word
; edx:eax <-- sign extension of EAX
idiv max ; divide edx:eax by max integer
; stores result in EAX <- Quotient, EDX <- Remainder
; EDX = edx:eax % max
cmp edx, 0 ; compare value to zero?
jge after ; jump if not less than to after: label
neg edx ; otherwise, change sign to positive
.after:
mov a, edx ; store random number in a
return a; // return random number
}
macro RndA(min,max)
rnd(max-min)+min
end macro
-
Hi Peter,
yes , jge is equal to jnl.
but Oxygen did not support jnl and many of jn... and i have told Mr Charles.
he will complete it.
-
@emil: the macro didn't work here this morning, I don't know why. therefore I tried another way. in this example I adept little for oxygen everything is working fine, I used instead of macro a function. your example didn't work for me at all, so I was searching for another way. now I have installed newer oxygen update and everything is going well and much better. the little devil hides in some details how so often ;)
$ filename "rnd2a.exe"
#include "inc\RTL32.inc" '#include "..\..\inc\RTL32.inc"
function rnd(int max)
int a
rdtsc
cdq
idiv max
cmp edx, 0
jge after
neg edx
.after:
mov a, edx
return a '[edx+4]
end function
'------------------- macro doesnt work here correctly ----- //
macro RndAll(min,max)
rnd(max-min)+min
end macro
'print RndAll(200,300) 'unidentified array or procedure error message!
'------------------- macro doesnt work here correctly ----- //
print "ok"
function rndAllgo(int min,max) 'function works fine!
return rnd(max-min)+min
end function
print "randomFunction 200-300: " +str(RndAllgo(200,300))
print "first: "+str(Rnd(100))
print "second: "+str(Rnd(500))
print "end of random example"
I am glad that's all working.
@peter: your example is working for me too. don't ask me why, I suppose it's belonging to an old oxygen.dll or my notebook has got a cold ;)
frank
-
Yeah Peter , Randomize ONCE -> work whole day.. ;D
Emil...
Because you like to add comments ,do you can comment this Peter code
for laics like me that will be interesting..
Function Rand(sys z1, z2) as sys
sys rnd
mov eax,z2 ; move z2 to eax
sub eax,z1 ; subtract eax - z1
inc eax ; increase eax
imul edx,sys_Seed,0x8088405 ; i(what? multiply / you can kill me if i know what is this /)
inc edx
mov sys_Seed,edx
mul edx
add edx,z1
mov rnd,edx
return rnd
End Function
Heh ...i just try.. :-\
-
I don't understand exactly how this algorithm works, except that the edx register is overwritten when a 32 bit multiply is performed. edx takes the upper 32 bits of the product (bits 32..63). so it is rather specific to x86 processors. Very clever though.
http://www.illmob.org/Sources/RobinHood.html
-
Aurel ,
here is the comments
first i will demonstrate it then adding the comments.
we have a Sys_seed variable that holds the returned value of Randomize function , it get a semi random value because it return the timer at any time.
we subtract min value from max value and add 1 to result . then we multiply this result by 0x8088405
then increasing it by 1 , we store it for next calling, add it to min value and return the rand value.
this is the concept of this code
here is the comments
Function Rand(sys z1, z2) as sys
sys rnd
mov eax,z2 ; Eax = max value
sub eax,z1 ; Eax = eax - min value
inc eax ; Eax = Eax + 1
imul edx,sys_Seed,0x8088405 ; edx = Sys_seed * 0x8088405
inc edx
mov sys_Seed,edx ; Sys_seed = EDX
mul edx ; Eax = Eax * edx
add edx,z1 ; eax = eax + min value
mov rnd,edx ; rnd = eax
return rnd
End Function
-
What I don't understand is how the result is confined within the upper range. Any ideas Emil, Peter?
-
hi Charles,
consider the following
imul op1 , op2 , imm
eg.
imul edx , ecx , 100
will be
(32 bit) edx = (32 bit) ecx * 100
that is deffer from this
mul op
eg.
mul ebx
will be
Edx:Eax = Eax * Ebx ------------ here edx is the upper result.
-
Aurel ,
here is Peter's code with High Level asm , may be better to understand
===============================
' Peter's function with HLA
===============================
Function H_Rand(sys z1,z2) as sys
^ eax = z2
^ eax -= z1
^ eax++
^ edx = seed * 0x8088405
^ edx++
^ seed = edx
^ eax *= edx
^ edx += z1
^ eax >< edx
Return eax
End Function
BTW i have made a litle change
-
Hi Peter
machine code isn't that easy, but for an Engineer is it easy.
BTW , I am Engineer , but civil Engineer . :)
-
Heh ..i try to convert Emil comments to pure Basic code
but it looks that i mess up ::)
'random basic
! GetTickCount Lib "kernel32.dll" () as sys
sys sys_Seed
Sub Randomize()
sys_Seed = GetTickCount
End Sub
Function Rand(sys z1, z2) as sys
Randomize()
sys rnd,ex,ed
ex = z2
ex = ex-z1
ex = ex+1
ed = sys_Seed * 0x8088405
ed = ed+1
sys_Seed = ed
ex = ex * ed
ex = ex + z1
rnd = ex
return rnd
End Function
print Rand(1,100)
Emil do you can fix this..?
-
Aurel ,
the problem is here
^ eax *= edx
this translated to that
Mul edx
so this asm instruction is better to presented like that
(64 bits) Edx:Eax = Eax * edx
then edx is the high Dowrd of the quad multiplication
in your basic code you took the lower Dword of quad multiplication.
really i do not know how to make it by basic
-
Aurel ,
here it is with basic and small asm code
===============================
' Aurel's function with basic
===============================
Function B_Rand(sys z1, z2) as sys
int Lex,Led
Lex = z2
Lex = Lex - z1
Lex = Lex + 1
Led = seed * 0x8088405
Led = Led + 1
seed = Led
mov eax , Lex
mul edx
Lex = edx + z1
return Lex
End Function
-
We can get close to an equivalent Basic rand :)
Peter's Orginal:
sys seed
Function Rnd(sys z1,z2) as sys
pushad
sys rand
mov eax,z2
sub eax,z1
inc eax
imul edx,seed,0x8088405
inc edx
mov seed,edx
mul edx
add edx,z1
mov rand,edx
popad
Return rand
End Function
Intermediate:
function rand(sys z1,z2) as sys
mov eax,z2
sub eax,z1
inc eax
imul edx,seed,0x8088405
inc edx
mov seed,edx
mul edx
add edx,z1
return edx
end function
Basic:
function brnd(sys z1,z2) as sys
seed*=0x8088405+1
eax=z2-z1+1 : mul seed
return edx+z1
end function
seed=12345 : print rnd 1,100 '39
seed=12345 : print rand 1,100 '39
seed=12345 : print brnd 1,100 '39
Charles
-
But Charles...
your code always return 1
function brnd(sys z1,z2) as sys
sys seed
seed*=0x8088405+1
eax=z2-z1+1 : mul seed
return edx+z1
end function
print brnd(1,100)
-
Charles did you ever see something like this :
This isn't asm, but works fine in vb. You get the idea.
Dim startIndex As New String("1234567890")
Dim random As New Random
Dim startIndex1 As New String("0987654321")
Dim random1 As New Random
startIndex = random.Next(startIndex)
startIndex1 = random1.Next(startIndex1)
Dim str1 As String = startIndex
Dim str2 As String = startIndex1
Dim str3 As String = (str1 + str2).Substring(0, 10)
TextBox2.Text = str3
End SubEnd Class
-
Hi Aurel, seed has to be global, not defined inside the brnd function. (sys seed)
-
Hi Aurel, seed has to be global,
Ok ...
But still return 1
sys seed
function brnd(sys z1,z2) as sys
seed*=0x8088405+1
eax=z2-z1+1 : mul seed
return edx+z1
end function
print brnd(1,100)
-
A seed of 0 wont work. You need to start with a large seed to saturate eax.
-
aurel take some simple values for seed and try the example again with for example
seed=12345
sys seed=12345
function brnd(sys z1,z2) as sys
seed*=0x8088405+1
eax=z2-z1+1 : mul seed
return edx+z1
end function
print brnd(1,100)
print brnd(1,100)
so you will get different values.
@charles: very good your short rnd code example ;) for my openGL fog test I've used longer rand() function and that's working very fine there.
frank
-
Ahhh..oh my i see now..
this work...
Declare Function GetTickCount Lib "kernel32.dll" () As Int
sys seed
seed = GetTickCount
function brnd(sys z1,z2) as sys
seed*=0x8088405+1
eax=z2-z1+1 : mul seed
return edx+z1
end function
print brnd(1,100)