RandomBit() or how to get random yes or no behavior.

Share your advanced PureBasic knowledge/code with the community.
freak
PureBasic Team
PureBasic Team
Posts: 5944
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Note that you only get 64bits on x64 as the returntype is integer.

I am thinking it may be better to add a separate function for this and keep the Random() range to the signed numbers. This is one of the reasons why this trick isn't documented yet.

Or maybe something like this to generate any size of buffer with random data:

Code: Select all

RandomBuffer(*Buffer, Size)
quidquid Latine dictum sit altum videtur
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Rescator wrote: Oh and SFSxOI?
That video you rented was registered in the store's computer, which synced up to the corporate server using the internet most likely, which caused a bunch of routers to handle the traffic, which influence the timing of other routers, which might have delayed your computer's clock update by a fraction of a second, which caused a change in the CPU cycles, which might have caused the LSB of the TSC to go 1 or 0 when it could have been the other way around. :P
see, told ya so :)
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

freak wrote:Note that you only get 64bits on x64 as the returntype is integer.

I am thinking it may be better to add a separate function for this and keep the Random() range to the signed numbers. This is one of the reasons why this trick isn't documented yet.

Or maybe something like this to generate any size of buffer with random data:

Code: Select all

RandomBuffer(*Buffer, Size)
I like that idea. Would RandomBuffer() have about the same speed as Random($FFFFFFFF) for example?

See, what I find brilliant with a full integer width of bits is that say on x86 (or x64 with the upper half ignored)
is it would give you a 32bit random state bank.
A game could simply check if bit 1 is set or not, a different part could check if bit 32 was set or not, etc.

It would be as if 32 coin tosses was done at once, but using only a single call to Random()

A RandomBuffer() would be even more flexible as you said, a 1KB random state bank would be very useful indeed.

I'm posting a feature request for that one ;)
User avatar
idle
Always Here
Always Here
Posts: 5917
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

While I know that were probably better off sticking to the PB functions which are well established and studied, this is interesting simply out of curiosity.

This appears to be random.

Code: Select all

EnableExplicit

Procedure.i RandomBit()
 !RDTSC ;Read the CPU Time Stamp Counter
  ProcedureReturn ;Return the EAX register  
EndProcedure

Procedure RRandom(val)
 
 Protected n.f, num, a,bit,nb    
 n = Log(val)/Log(2)
  
  For a = 0 To n
    bit=Randombit()
    num ! bit << 3 >> 2 
  Next 
 
 ProcedureReturn (num) % (val) 

EndProcedure

Procedure draw(hdc)

Protected a,x,y 

While a < 255*255
    
    x = rRandom(255)
    y = rRandom(255)
    SetPixel_(hdc,x,y,RGB(0,0,0))  
    a+1
Wend 
EndProcedure 


Define b.i,st.i,et.i,hdc,x,y,a,id

OpenWindow(0,0,0,255,255,"random test",#PB_Window_WindowCentered| #PB_Window_SystemMenu | #PB_Window_TitleBar)
hdc = GetDC_(WindowID(0))


CreateThread(@draw(),hdc)
 
Repeat 
Until WaitWindowEvent() = 16 
  
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

With the PureBasic's current Random() there is not a random distribution of bits. Here's some code, just for fun, to demonstrate:

Code: Select all

#sWidth = 1024
#sHeight = 768

InitSprite()
InitKeyboard()
OpenScreen( #sWidth, #sHeight, 32, "RandomDemo1" )
Dim vert(#sWidth - 1)

Repeat
  ExamineKeyboard()
  ;cycle through rangegenerated
  For n = 0 To #sWidth - 1
    r = Random($FFFFFFFF) ;use maximum for an unsigned long
    vert(n) + ((r & $1)  - (r & $2) / $2) ;add the lowest bit of the random number while subtracting the second bit
  Next

  StartDrawing(ScreenOutput())
    Box(0,0,#sWidth,#sHeight)
    FrontColor(RGB(0,128,255))
    For n = 0 To #sWidth - 1
      length = Abs(vert(n)) / (#sWidth / 16)
      Select length
        Case 0
          FrontColor(RGB(255,0,128))
        Case 1
          FrontColor(RGB(128,255,0))
        Case 2
          FrontColor(RGB(0,128,255))
        Case 3
          FrontColor(RGB(0,255,128))
        Case 4
          FrontColor(RGB(192,64,64))
        Case 5
          FrontColor(RGB(192,64,192))
        Case 6
          FrontColor(RGB(64,192,192))
        Case 7
          FrontColor(RGB(64,64,192))
      EndSelect
       Line(n, #sHeight/2 - 1, 0, -vert(n))
    Next
  StopDrawing()
  Delay(0)
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
This cycles through 1024 entries and adds 1 to the value for bit 1 and subtracts 1 for bit 2. It then draws a vertical line representing the value and colors it based on its length.

When you run it you will notice some lines get longer, some don't, and some just fidget. If you have the time to let it run a while you will notice this doesn't change much. Most of the lines continue to get longer and there are a portion of them that are very resistant to changing size at all. I would think that all of the lines would fidget around the center point and that if they because long, they would later become short, or if they were positive (in the top half) they would later become negative (in the bottom half). This doesn't seem to happen.

All this indicates to me is that the bits aren't as random. Even though we are using a different random number for each line the same bits are used for all.

By the way if you want the demo to run as fast as possible just comment out the innocent Delay(0) line. :wink:
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Actually, if you are expecting it to be "mostly balanced" then that is not random.
Cryptographic RNG's need that (or close to that at least).
But "natural" RNG's behave like you see.

Just like in real life when you toss a coin, you can not expect a even distribution of 1's and 0's. Some people will just have shit luck and almost never get tails for example. :P
The very nature of random means that abnormalities are just as likely as repeating patterns.

Now, if weird biases are the same even with a different seed then something is very wrong indeed.

Try and add this to the start of the code:

Code: Select all

Procedure.i RandomSource() ;alternatively use QueryPerformanceCounter())
 !RDTSC ;Read the CPU Time Stamp Counter
 ProcedureReturn ;Return the EAX register content.
EndProcedure
RandomSeed(RandomSource())
Another idea might be to XOR that with ElapsedMilliseconds() before re-initing the seed etc.

Reseeding at random intervals like this should ensure a highly random behaviour.

Then again, some games/apps rely on being able to use a constant seed to re-create an environment or chain of events, in which case one can't do this "improvement".
User avatar
idle
Always Here
Always Here
Posts: 5917
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

This may have legs in it yet, though it may be effected by the clock frequency between systems regarding the magnitude of the shifts.

It's looking random on my system and it's reasonably fast, though you may see angled bands appearing.

first and second codes

left side RDTSC gen
right side Random()

third code back to RandomBit and RandomBuffer

I'm starting to think that with a bit of tweaking this could possibly pass the Nist tests as a TRNG


Enable ASM in options
Disable debugger

Code: Select all

EnableExplicit

Global w,h,hdc
Global rVal,bset 

Procedure.i RandomNum(num,Range)
 
 RDTSC ;Read the CPU Time Stamp Counter
 SHL eax, 6   ; << 5 
 XOR eax, num  ;xor result 
 SHR eax, 2    ; >> 2
 MOV ebx, Range ;do test for odd or even   
 AND ebx,1
 AND ebx,ebx
 JE  ED                  ; 
 MOV ebx, Range
 XOR edx,edx   ;do mod zero edx
 DIV ebx      ;num % Range
 INC edx
 MOV eax,edx
! ED:
 MOV ebx, Range ;get val   
 INC ebx        ;val +1
 XOR edx,edx    ;do mod zero edx   
 DIV ebx        ;num % Range
 MOV eax,edx    ;
 DEC eax        ;num - 1
   
 ProcedureReturn
EndProcedure

Procedure RRandom(Range)
   
  If bset = 0   
    Protected a 
    While a < 3
      rval = RandomNum(rval,Range) 
      a+1
    Wend
    bset = 1
  Else
    rval = RandomNum(rval,Range)
  EndIf
 
  ProcedureReturn rval 
     
EndProcedure

Procedure draw(hdc)

Protected a,x,y,st,et,Strt.s
Strt = "Random Test "
st = GetTickCount_()
While a < w*h
    x = rRandom(w/2)
    y = rRandom(h)
    SetPixel_(hdc,x,y,RGB(0,0,0)) 
    a+1
Wend
et = GetTickCount_()-st
strt + "RDTSC " + Str(et) + " "
SetWindowTitle(0,Strt)
a = 0
 
st = GetTickCount_()

While a < w*h
    x = Random(w/2)+w/2
    y = Random(h)
    SetPixel_(hdc,x,y,RGB(0,0,0)) 
    a+1
Wend
et = GetTickCount_()-st
strt + " Random " + Str(et)
SetWindowTitle(0,strt)



EndProcedure
 
w=640
h=480

OpenWindow(0,0,0,w,h,"Random Test",#PB_Window_WindowCentered| #PB_Window_SystemMenu | #PB_Window_TitleBar)
hdc = GetDC_(WindowID(0))
SetWinBackgroundColor(WindowID(0),RGB(255,255,255))
Delay(100)
 
CreateThread(@draw(),hdc)
 
Repeat
Until WaitWindowEvent() = 16      
  
 

looks a bit blotchy on the left!

Code: Select all


EnableExplicit

Global w,h,hdc
Global rVal,bset  

Procedure.i RandomNum(num,Range)
 
 RDTSC ;Read the CPU Time Stamp Counter
 SHL eax, 6   ; << 5  
 XOR eax, num  ;xor result  
 SHR eax, 2    ; >> 2 
 MOV ebx, Range ;do test for odd or even   
 AND ebx,1
 AND ebx,ebx
 JE  ED                  ;  
 MOV ebx, Range
 XOR edx,edx   ;do mod zero edx 
 DIV ebx      ;num % Range 
 INC edx 
 MOV eax,edx
! ED:
 MOV ebx, Range ;get val   
 INC ebx        ;val +1 
 XOR edx,edx    ;do mod zero edx   
 DIV ebx        ;num % Range
 MOV eax,edx    ; 
 DEC eax        ;num - 1
   
 ProcedureReturn 
EndProcedure

Procedure RRandom(Range)
   
  If bset = 0   
    Protected a  
    While a < 3
      rval = RandomNum(rval,Range)  
      a+1
    Wend
    bset = 1 
  Else 
    rval = RandomNum(rval,Range) 
  EndIf 
  
  ProcedureReturn rval  
     
EndProcedure

Procedure draw(hdc)

Protected a,x,y,st,et,Strt.s,*px.long,offset,pitch    
Strt = "Random Test "

SetFrameRate(25)

While 1

  StartDrawing(ScreenOutput())
  hdc= DrawingBuffer() 
  Pitch  = DrawingBufferPitch()
  a=0
  While a < w/2*h/2 
      x = rRandom(w/2)
      y = rRandom(h)
      offset = (x*4 + (y * pitch))
      *px = hdc + offset
      *px\l = rRandom(16777215)

      x = Random((w)/2)+w/2
      y = Random(h)
      offset = (x*4 + (y * pitch))
      *px = hdc + offset
      *px\l = Random(16777215)
      a+1
  Wend 
   
  StopDrawing()
  FlipBuffers()  
  ClearScreen(RGB(0,0,0))

Wend 

EndProcedure 
 
w=640 
h=480
InitSprite()
OpenWindow(0,0,0,w,h,"Random Test",#PB_Window_WindowCentered| #PB_Window_SystemMenu | #PB_Window_TitleBar)
OpenWindowedScreen(WindowID(0),0,0,w,h,0,0,0)

w-1
h-1

hdc = GetDC_(WindowID(0))
SetWinBackgroundColor(WindowID(0),RGB(255,255,255))
Delay(100)
 
CreateThread(@draw(),hdc)
 
Repeat 
Until WaitWindowEvent() = 16           
   

And back to RandomBit() and RandomBuffer()

haven't looked at the results from these yet

Code: Select all

 

Procedure SetBit(*num,bit)
   Protected of.i
   of = bit >> 3
   PokeB(*num+of,(PeekB(*num+of) | (1 << (bit % 8))))
EndProcedure

Procedure GetBit(*buffer,index)
   Protected mf
   mf = (index % 8)
   ProcedureReturn (PeekB(*buffer+(index>>3)) & (1 << mf)) >> mf
EndProcedure

Procedure.i RandomBit()
 
 Static num
 
 RDTSC ;Read the CPU Time Stamp Counter
 SHL eax, 6   ; << 5  
 XOR eax, num  ;xor result  
 SHR eax, 2    ; >> 2 
 MOV num,eax 
 AND eax, $1  
 ProcedureReturn 
EndProcedure

Procedure RandomBuffer(*buffer,size)
 
 Protected n.f, num, a,bit   
 Static bset 
 
  If bset = 0   
     
    While a < 3
      Randombit()  
      a+1
    Wend
    bset = 1 
  EndIf 
 
  For a = 1 To size*8  
    bit=RandomBit()
    If bit
      setbit(*buffer,a) 
    EndIf
  Next
  
EndProcedure

Define bit.i, num.i,a.i,b.i

For b = 1 To 100   ;get a random bit 
   Debug Randombit()
Next 

*rbuf = AllocateMemory(1024)   ;fill a buffer 
randombuffer(*rbuf,1024)      

For a = 0 To 1024*8    ;get bits   
   Debug getbit(*rbuf,a) 
Next 
a = 0 

While a < 1024  
  Debug (PeekB(*rbuf+a) & $F0) 
  a+1
Wend    
User avatar
idle
Always Here
Always Here
Posts: 5917
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

A visual test combining the methods

Randombit() - get a randombit
Randombuffer() -fill a random buffer number of bits
RRandom() - get a Random Number

RDTSC Gen RRandom() left half vs Random() Right half

RandomBit() top row text

Percentage of odd even bits

Randombuffer() bottom row text as bits

Really need to get feedback on this as I'm a bit concerned that the clock frequency between systems may effect the results.

While a stationary image may look ok, it's only by animating it that you really notice any cycles or anomalies.

The Resultant static noise should be indistinguishable to the Pseudo Random Generated noise on the right half of the window.

The RandomBit should converge nicely ~ 50%



Enable inline ASM in compiler options
Disable debugger



Code: Select all



;idle TRGN experiment based on Rescator's Idea of using the CPU time stamp Counter
;Results may vary on different systems due to clock speeds which could require the magnitude of the bit shifts to be changed 
;It apears that the output from the CPU time stamp can be used effectivly to generate a Random Bit with Rescators first example but you need 
;a delay between calls to the function, without a delay I found it generated patterns and didn't conform to a normal distributuon.  
;The issue was how to use it without a delay to obtain a normal distribution, so while the algorithim appears to look random it still may not 
;be totaly random due to the mixing and XOR which may add cyclic trends.  
 
EnableExplicit

Global w,h,hdc
Global rVal,bset  

;hacky method to set any bit in a var or buffer given it's offset in bits
Procedure SetBit(*num,bit)  
   Protected of.i
   of = bit >> 3
   PokeB(*num+of,(PeekB(*num+of) | (1 << (bit % 8))))
EndProcedure
;hacky method to get any bit from a var or buffer given its offset in bits 
Procedure GetBit(*buffer,index)
   Protected mf
   mf = (index % 8)
   ProcedureReturn (PeekB(*buffer+(index>>3)) & (1 << mf)) >> mf
EndProcedure

;get a random bit from the CPU Time Stamp Counter 
Procedure.i RandomBit()
 
 Static num
 RDTSC ;Read the CPU Time Stamp Counter
 SHL eax, 6    ; << 6  
 XOR eax, num  ;xor result  
 SHR eax, 2    ; >> 2 
 MOV num,eax 
 AND eax, $1  
 ProcedureReturn 
EndProcedure

;Random Buffer fill a buffer with random bits, size in bytes 
Procedure RandomBuffer(*buffer,size)
 
 Protected n.f, num, a,bit   
 Static bset 
  
  ZeroMemory_(*buffer,size)
  
  If bset = 0   
     
    While a < 3
      Randombit()  
      a+1
    Wend
    bset = 1 
  EndIf 
 
  For a = 1 To size*8  
    bit=RandomBit()
    If bit
      setbit(*buffer,a) 
    EndIf
  Next
  
EndProcedure

;Internal method to get random number called from RRandom()
Procedure.i RandomNum(num,Range)
 
 RDTSC ;Read the CPU Time Stamp Counter
 SHL eax, 6   ; << 6  
 XOR eax, num  ;xor result  
 SHR eax, 2    ; >> 2 
 MOV ebx, Range ;do test for odd or even   
 AND ebx,1
 AND ebx,ebx
 JE  ED                  ;  
 MOV ebx, Range
 XOR edx,edx   ;do mod zero edx 
 DIV ebx      ;num % Range 
 INC edx 
 MOV eax,edx
! ED:
 MOV ebx, Range ;get val   
 INC ebx        ;val +1 
 XOR edx,edx    ;do mod zero edx   
 DIV ebx        ;num % Range
 MOV eax,edx    ; 
 DEC eax        ;num - 1
   
 ProcedureReturn 
EndProcedure

;Get a TRGN number   
Procedure RRandom(Range)
   
  If bset = 0   
    Protected a  
    While a < 3
      rval = RandomNum(rval,Range)  
      a+1
    Wend
    bset = 1 
  Else 
    rval = RandomNum(rval,Range) 
  EndIf 
  
  ProcedureReturn rval  
     
EndProcedure


Procedure draw(hdc)

Protected a,x,y,st,et,Strt.s,*px.long,offset,pitch,strb.s ,ct,cta,tb,sout.s,*rbuf,bb ,strc.s,ctb,ct1 
Strt = "Random Test "
ct=1
cta=1
ctb=1
ct=1
SetFrameRate(25)

*rbuf = AllocateMemory(128/8) ;allocate a buffer want 128 bits 
randombuffer(*rbuf,128/8)     ;fill random buffer want 128 bits 

While 1

  StartDrawing(ScreenOutput())
  hdc= DrawingBuffer() 
  Pitch  = DrawingBufferPitch()
  a=0
  ;get TRGN number draw on the left 
  ;get PB Random number draw on the right 
  While a < w/2*h/2 
      x = rRandom(w/2)
      y = rRandom(h)
      offset = (x*4 + (y * pitch))
      *px = hdc + offset
      *px\l = rRandom(16777215)

      x = Random((w)/2)+w/2
      y = Random(h)
      offset = (x*4 + (y * pitch))
      *px = hdc + offset
      *px\l = Random(16777215)
      a+1
  Wend 
  
  ;Get a Random bit 
  tb = randomBit()  
  If tb = 1 
    cta + 1 
  EndIf 
  ct+1 
  
  If Len(strb)<110
    ;write out random bit 
    strb + Str(tb) + " " 
    ;write out a bit from the random buffer, alternativly use use peekB peekW PeekL and mask if you want unsigned vals   
    ;strc + Str(getbit(*rbuf,bb)) + " "
    tb = getbit(*rbuf,bb)
    If tb = 1 
      ctb+1
    EndIf
    ct1+1   
    strc + Str(tb) + " "
    bb+1
  Else 
    strb = Str(tb) + " " 
    ;refill the random buffer 
    randombuffer(*rbuf,128) 
    strc = ""
    bb=0
  EndIf  
  DrawText(0,0,strb,RGB(0,255,0),RGB(0,0,0)) 
  
  sout = "Percent " + StrF(((cta/ct)*100),2)
  DrawText(0,20,sout,RGB(0,255,0),RGB(0,0,0))  
  
  sout = strc 
  DrawText(0,40,sout,RGB(0,255,0),RGB(0,0,0))
  
  sout = "Percent " + StrF(((ctb/ct1)*100),2)
  DrawText(0,60,sout,RGB(0,255,0),RGB(0,0,0)) 
  
  StopDrawing()
  FlipBuffers()  
  ClearScreen(RGB(0,0,0))

Wend 

EndProcedure 
 
w=640 
h=480
InitSprite()
OpenWindow(0,0,0,w,h,"Random Test",#PB_Window_WindowCentered| #PB_Window_SystemMenu | #PB_Window_TitleBar)
OpenWindowedScreen(WindowID(0),0,0,w,h,0,0,0)

w-1
h-1

hdc = GetDC_(WindowID(0))
 
Delay(100)
 
CreateThread(@draw(),hdc)
 
Repeat 
Until WaitWindowEvent() = 16       
 
[/b]
Last edited by idle on Tue Jun 09, 2009 1:54 am, edited 2 times in total.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

First of all, the function you use to set the window background do not exist with PB 4.31
And the way you use asm doesn't work either, so I had to fiddle around to make it work.

Anyway, the top text at first run hovered around 50,
the bottom text took a run for it up to 60+ then crawled down to around 50 and stayed closer to 5 than the top text.

The second run was odder, both started out close to 50% but seemed to crawl slowly downwards.
User avatar
idle
Always Here
Always Here
Posts: 5917
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

Rescator wrote:First of all, the function you use to set the window background do not exist with PB 4.31
And the way you use asm doesn't work either, so I had to fiddle around to make it work.
I'm using 4.31, I deleted the set background was left over from when I was drawing in GDI.

You need to enable inline ASM in compiler options!

Also would probably be better to run it with the debugger off.

Send me the asm I'll add it in.

You should get some variances though it should be between 45-55%
the main thing to look for is that the static noise should look the same on the left and right.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

@Demivec
love your test.
I tweaked it a little, some nice fps stats and RNG per sec and RNG total info.
I also use the TSC to reseed PureBasic's Random() once per second (aprox.)
After the total RNG passed 100 million I still saw no conclusive bias.
Stopping the test and running it again would produce a completely different image.
Looks to me like freak did a pretty good job on Random()

Ideally the reseeding in this example should be done at random intervals as well, or use multiple sources that it switches between.
Obviously as far as PRNG's go this is no longer useful as there is no way to re-create the random sequence.

PS! Make sure to compile this with the debugger from the compile menu for best speed.
The framerate started at 110+ here but ends up crawling below 50 by the time I reach 100+ million RNG, I haven't bothered to find out why the code does this.

Code: Select all

DisableDebugger
ExamineDesktops()
sWidth = DesktopWidth(0)
sHeight = DesktopHeight(0)
sDepth = DesktopDepth(0)
sRefresh = DesktopFrequency(0)

Procedure.i RandomSource()
 !RDTSC ;Read the CPU Time Stamp Counter
 ProcedureReturn ;Return the EAX register content.
EndProcedure

InitSprite()
InitKeyboard()
SetRefreshRate(sRefresh)
OpenScreen( sWidth, sHeight, sDepth, "RandomDemo2" )
Dim vert(sWidth - 1)

timeBeginPeriod_(1)
Define last.l,time.l,fps.i,lastfps$,oldfps.i,rnd.i,seed.i,total.q
last=timeGetTime_()
now=last
Repeat
  now=timeGetTime_()
  ExamineKeyboard()
  For n = 0 To sWidth - 1
    r = Random(-1)&%1
    rnd+1
     If r
      vert(n)+1
     Else
      vert(n)-1
     EndIf
  Next

  StartDrawing(ScreenOutput())
    Box(0,0,sWidth,sHeight,0)
    If (now-last)>999
     last=now
     total+rnd
     lastfps$=Str(fps)+" Frames/s, "+Str(rnd)+" RND/s, Total "+Str(total)+" RND"
     fps=0
     rnd=0
     seed=RandomSource()
     RandomSeed(seed)
    EndIf
    DrawText(0,0,lastfps$,$FFFFFF,$0)
    FrontColor(RGB(0,128,255))
    For n = 0 To sWidth - 1
      length = Abs(vert(n)) / (sWidth / 16)
      Select length
        Case 0
          FrontColor(RGB(255,0,128))
        Case 1
          FrontColor(RGB(128,255,0))
        Case 2
          FrontColor(RGB(0,128,255))
        Case 3
          FrontColor(RGB(0,255,128))
        Case 4
          FrontColor(RGB(192,64,64))
        Case 5
          FrontColor(RGB(192,64,192))
        Case 6
          FrontColor(RGB(64,192,192))
        Case 7
          FrontColor(RGB(64,64,192))
      EndSelect
       Line(n, sHeight/2 - 1, 0, -vert(n))
    Next
  StopDrawing()
  Delay(0)
  FlipBuffers(#PB_Screen_NoSynchronization)
  fps+1
Until KeyboardPushed(#PB_Key_Escape)
timeEndPeriod_(1)
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

idle wrote:You should get some variances though it should be between 45-55%
the main thing to look for is that the static noise should look the same on the left and right.
It did, it looked as messy regardless of where I looked, felt like I was getting a tunnel syndrome in the end.
So in that respect Demivec's code is more easy on the eyes :P
User avatar
idle
Always Here
Always Here
Posts: 5917
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

Wouldn't want you to throw up your dinner, Demivec's is much easier on the eyes!

The side by side comparison is easiest way to compare the functions.
left half is my attempt of TRNG right side is PB's PRNG

so while you're looking for a practical solution, I've been running with your original premise and attempting to support it. Maybe I should toss it in a new thread, if I'm lagging behind the topic?

I liked the idea of TRNG and it's been challenging and while I think it's starting to look ok it's probably not but will undoubtedly take some time to test it properly.
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Rescator wrote:@Demivec
love your test.
I tweaked it a little, some nice fps stats and RNG per sec and RNG total info.
I also use the TSC to reseed PureBasic's Random() once per second (aprox.)
After the total RNG passed 100 million I still saw no conclusive bias.
Stopping the test and running it again would produce a completely different image.
Looks to me like freak did a pretty good job on Random()
Thank you, I made some variations that were even more peculiar that may end up as a PurePunch. :wink:

Freak did a great job. My comment on bias is an observation and is not meant as a criticism.

The bias that I noticed was that most of the lines get longer and longer, either more negative or more positive. This means that as the code cycles through 1024 possibilities and uses a single bit to either add or subtract from a line length, the bit is set to the same value at the same point in the cycle. What this means is that in general that bit will more often than not always have the same value every 1024 numbers or so. It may cause unwanted effects depending on how it is used. This occurs even with your reseeding the generator. I've measured the overall randomness by adding up the lengths of the lines and they hang around +/-3000 which tells me things are OK as a whole. I think what appeared to be a bias was due instead to bad logic.
Rescator wrote:The framerate started at 110+ here but ends up crawling below 50 by the time I reach 100+ million RNG, I haven't bothered to find out why the code does this.
The decrease in framerate is due to the lines getting longer, they're drawn each frame.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

"The decrease in framerate is due to the lines getting longer, they're drawn each frame."

So then even this is not random because you can predict the outcome. You know the lines are going to get longer and you know they are going to be drawn every frame.
Post Reply