Funções "RANDOM" não funcionam!

Projeto [x]Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

Ladinilson Sousa
Usuário Nível 1
Usuário Nível 1
Mensagens: 35
Registrado em: 09 Fev 2015 11:41
Localização: Belém/PA

Funções "RANDOM" não funcionam!

Mensagem por Ladinilson Sousa »

Fiz vários testes com nRANDOM(), RANDOM(),  HB_RandomInt(), etc e todas elas NÃO FUNCIONARAM nas suas totalidades ou seja, todas deixaram de fornecer alguns números em uma de range 999999 e estou com muita dificuldade em encontrar uma solução para isso já que em se tratando de sorteios, nenhum número pode faltar ou se repetir.

Algum de vocês tem alguma rotina própria criada para esta função que eu consiga testar?

Obrigado
lucimauro
Usuário Nível 3
Usuário Nível 3
Mensagens: 465
Registrado em: 21 Set 2004 21:02
Localização: Sobral-CE

Funções "RANDOM" não funcionam!

Mensagem por lucimauro »

Bom dia,
eu uso assim

result:=hb_random(1,999999)
Avatar do usuário
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Funções "RANDOM" não funcionam!

Mensagem por Vlademiro »

As funções simulam a geração aleatória de números, não tem como impedir a repetição. É como lançar um dado. Não tem como garantir a "não repetição" de números. Vc pode até usar a função para fazer o que vc deseja, mas vai ter que completar via código mesmo.

Pensei aqui em uma solução mas já vi que está incompleta. Mas vou descrever, quem sabe alguém complete ou faça melhor.

(1) O valor sorteado vai ter que ser armazenado em um array. AADD( aArray , valor sorteado )

(2) Sorteia o valor com HB_RandomInt(1,max) // Aqui está o problema, no final eu digo

(3) Verifica se o número sorteado está no array com ASCAN

(4) Se tiver sorteia outro (passo 2)

(5) Se nao tiver exibe

O problema é no passo 2, porque quando os números vão se esgotando a probabilidade de HB_RandomInt retornar um número não sorteado vai diminuir e a função pode demorar demais. Uma alternativa é : caso o número já tenha sido sorteado, vai percorrendo o array até encontrar o superior (ou inferior) não sorteado.

Outra coisa, se for uma função, o array que conterá os números precisa ser STATIC para evitar que ele fique zerado a cada chamada do sorteio

Espero ter ajudado, vamos aguardar alguém melhorar ou trazer outra solução que resolva o seu problema.
Avatar do usuário
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Funções "RANDOM" não funcionam!

Mensagem por Vlademiro »

Fiz esse aqui mas não testei muito, usa a linha de comando para testar. Acho que está ok, se eu realmente entendi o seu problema corretamente.

Código: Selecionar todos



PROCEDURE MAIN( n )

    LOCAL x
    
    IF n == NIL
        ? "informe o valor maximo via linha de comando. ex: ex01 10"
        quit
    endif    
    n := VAL( n )
    FOR x := 1 TO n
    
        ? x, Sorteio( n )
        
    NEXT


    RETURN
    
FUNCTION Sorteio( nMax )

    LOCAL nSorteio
    STATIC aSorteio := {}
    
    nSorteio := HB_RandomInt( 1 , nMax )
    
    DO WHILE .T. 
        IF Ascan( aSorteio , nSorteio ) == 0 // NAO ACHEI
            AADD( aSorteio , nSorteio ) // ADICIONO PARA NAO REPETIR
            EXIT
        ENDIF
        
        IF ++nSorteio > nMAX
            nSorteio := 1
        ENDIF   
        IF LEN( aSorteio ) == nMax // ACABOU 
            EXIT 
        ENDIF    
    ENDDO    
    
    

RETURN nSorteio    
Ladinilson Sousa
Usuário Nível 1
Usuário Nível 1
Mensagens: 35
Registrado em: 09 Fev 2015 11:41
Localização: Belém/PA

Funções "RANDOM" não funcionam!

Mensagem por Ladinilson Sousa »

Obrigado meus amigos mas no forum internacional me deram uma solução onde "força" a função a refazer e se testar pois somente ela não resolve.

o teste ficou assim....

Código: Selecionar todos

function RandomList()

   local aList    := Array( 999999 )
   local nAt, aRandom := {}

   AEval( aList, { |u,i| aList[ i ] := i } )

   do while Len( aList ) > 0
      nAt      := HB_RandomInt( 1, Len( aList ) )
      AAdd( aRandom, aList[ nAt ] )
      ADel( aList, nAt, .t. )
   enddo

   XBROWSER aRandom SHOW RECID

return nil
Valeu
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Funções "RANDOM" não funcionam!

Mensagem por JoséQuintas »

Vlademiro escreveu:As funções simulam a geração aleatória de números, não tem como impedir a repetição.
Deixou passar isto
Ladinilson Sousa escreveu: todas deixaram de fornecer alguns números... já que em se tratando de sorteios, nenhum número pode faltar ou se repetir.
Talvez algo mais simples:

Funciona de 0 a 9?

Se funciona, sorteia um dígito de cada vez, e junta no final
E no caso do número final repetido, despreza e faz outro.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Adalberto
Usuário Nível 3
Usuário Nível 3
Mensagens: 343
Registrado em: 01 Set 2007 01:09
Localização: Santa Cruz de la Sierra - Bolivia

Funções "RANDOM" não funcionam!

Mensagem por Adalberto »

Amigo, buenas tardes

Hace algunos años tomé una función RAMDOM de Internet, créditos y agradecimientos al autor, mil disculpas por no recordar que creó esa función.

Tal Vez te sea de utilidad.

Código: Selecionar todos

FUNCTION RandInt(nDesde, nHasta)
LOCAL nUltimo, nRandom:= 0, nMult:= INT(SECONDS())
LOCAL nNumero:= (nHasta - nDesde)
LOCAL nLen:= LEN(ALLTRIM(STR(nNumero)))
//
SET DECIMAL TO 16
IF ((VALTYPE(nUltimo) <> "N") .OR. EMPTY(nUltimo))
	nUltimo:= ((nMult * ((SECONDS() - INT(SECONDS())) * 100)) % 335544319)
ENDIF
nUltimo:= ((nMult * nUltimo) % 335544319)
nRandom:= VAL(RIGHT(STR(nUltimo / 335544319), nLen))
IF (nRandom > nNumero)
	nRandom:= (nNumero - VAL(RIGHT(STR(nRandom), LEN(ALLTRIM(STR(nNumero))) - 1)))
ENDIF
SET DECIMAL TO 2
RETURN(nDesde + INT(nRandom))
Un abrazo, Dios te cuide siempre.

Adalberto
Avatar do usuário
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Funções "RANDOM" não funcionam!

Mensagem por Vlademiro »

Quintas, eu tinha visto, mas creio que essa informação não procede. O que pode ter acontecido é não ter tido tempo suficiente para o número ser sorteado.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Funções "RANDOM" não funcionam!

Mensagem por JoséQuintas »

Só não dá pra esperar terminar.
Com 3 dígitos demora pra sair o último número do sorteio de 1.000 números
Acima de 3 dígitos, vai longe.
Mas não vai sortear tanto número assim.

Código: Selecionar todos

#include "inkey.ch"
#define NUM_LIMITE 999999
#define NUM_DIGITOS 6

PROCEDURE Main

   LOCAL aList := {}, nCont, nKey

   SetMode( 30, 100 )
   CLS
   FOR nCont = 1 TO NUM_LIMITE
      IF nKey == K_ESC .OR. Len( aList ) = NUM_LIMITE
         EXIT
      ENDIF
      Sorteia( aList, @nKey )
   NEXT

   Inkey(0)

   RETURN

STATIC FUNCTION Sorteia( aList, nKey )

   LOCAL nCont, cNumero

   DO WHILE .T.
      nKey := Inkey()
      IF nKey == K_ESC
         EXIT
      ENDIF
      cNumero := ""
      FOR nCont = 1 TO NUM_DIGITOS
         cNumero += Str( hb_Random( 0, 9 ), 1 )
      NEXT
      IF hb_ASCan( aList, Val( cNumero ) ) == 0
         AAdd( aList, Val( cNumero ) )
         ? Time(), Len( aList ), Val( cNumero )
         EXIT
      ENDIF
   ENDDO

   RETURN NIL
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Funções "RANDOM" não funcionam!

Mensagem por JoséQuintas »

Outra opção seria criar um array com todos os números e ir sorteando só os que tem:

Vou tentar enquanto digito no fórum, pode conter erros, algo do tipo

Código: Selecionar todos

LOCAL aList := {}, nKey := 0

FOR nCont = 1 TO 999999
   AAdd( aList, nCont )
NEXT
DO WHILE .T.
   nKey := Inkey()
   IF Len( aList ) == 0 .OR. nKey == K_ESC
      EXIT
   ENDIF
   nPos := hb_Random( 1, Len( nCont ) )
   ? aList[ nPos )
   hb_Adel( aList, nPos, .T. )
ENDDO

RETURN
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Funções "RANDOM" não funcionam!

Mensagem por JoséQuintas »

Testado/Testando:

Código: Selecionar todos


#include "inkey.ch"

PROCEDURE Main

   LOCAL aList := {}, nKey := 0, cTime, nCont, nPos

   SetMode( 25, 80 )
   CLS
   cTime     := Time()
   FOR nCont = 1 TO 999999
      AAdd( aList, nCont )
   NEXT
   DO WHILE nKey != K_ESC
      nKey := Inkey()
      IF Len( aList ) == 0
         EXIT
      ENDIF
      nPos := hb_Random( 1, Len( aList ) )
      IF Mod( Len( aList ), 1000 ) == 0
         ? Time(), Len( aList ), aList[ nPos ]
      ENDIF
      hb_Adel( aList, nPos, .T. )
   ENDDO
   ? cTime, Time()
   Inkey(0)

   RETURN
sorteio.png
média de 1.000 números a cada 4 segundos
Não vou esperar terminar
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Funções "RANDOM" não funcionam!

Mensagem por JoséQuintas »

Esse último pode não ser bom.
Depende de uma coisa:

Notou que certos números não saem.
São sempre os mesmos?

Se forem sempre os mesmos, então pode deixar todo sorteio viciado.
Se cada vez que roda, são números diferentes, aí sim, sem problema.

Criando o array, o sorteio vai ser somente do intervalo de elementos do array, e de números que não foram sorteados ainda.
Com certeza o resultado final é sortear todos os números existentes.

No primeiro sorteio o random retorna 1 a 999999
no segundo, 1 a 999998
e assim por diante

o número sorteado não vai ser o randômico, mas o elemento do array que corresponde à posição sorteada.

Pode até criar outra rotina que gera os números de forma randômica no array, antes de começar a sortear, pra deixar mais embaralhado ainda.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Funções "RANDOM" não funcionam!

Mensagem por Claudio Soto »

JoséQuintas escreveu: Notou que certos números não saem.
São sempre os mesmos?
Probaste reiniciar cada tanto la "semilla" del generador de números pseudoaleatorios llamando:
HB_RandomSeed()

En un loop tan grande como la generación de los números es con una función matemática cuyo resultado depende del numero anterior puede que entre en un espiral de repetición
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Ladinilson Sousa
Usuário Nível 1
Usuário Nível 1
Mensagens: 35
Registrado em: 09 Fev 2015 11:41
Localização: Belém/PA

Funções "RANDOM" não funcionam!

Mensagem por Ladinilson Sousa »

Obrigado pelo debate.

No caso seria para criação de cartelas tipo rifas que vão de 1 a 999999 ou seja, seis dígitos e as funções testadas não se obtém TODOS os números aleatórios de 1 a 999999 sempre deixavam alguns faltando.
Pois bem, fiz um DBF de 1 a 999999 e usava a função hb_randomint() para mudar o ponteiro aleatoriamente e "catar" esses números e mesmo assim falhavam.

A função apresentada pelo fórum Internacional supriu este problema usando ARRAY que tem a mesma idéia do que fiz com DBF mas de maneira a "forçar" a função a não "falhar".

No fórum Internacional tem uma observação sobre as funções RANDOM e parecem que funcionam apenas para 4 dígitos no máximo ou seja, até 9999.

Abraços
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Funções "RANDOM" não funcionam!

Mensagem por Claudio Soto »

Todas las funciones que generan números aleatorios generan un numero decimal entre 0 y 1. Luego para generar un numero aleatorio entero se hace asi:
Nro entero = INT (NroMax * AleatorioDecimal0y1 + NroMin)

En consecuencia los números generados van a depender de la precisión decimal del numero aleatorio generado entre 0 y 1

Por ejemplo si la precisión fuera de 1 dígito decimal sólo se podrán generar:
0, 0.1, 0.2, ... ,0.9, 1.0

Si con la formula anterior queremos generar un numero entre 1 y 100,
Solo generaran 1,10,20, ... 90, 100
jamás podremos tener 23, 34, 67, etc.
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Responder