Clipper On Line • Ver Tópico - Funções "RANDOM" não funcionam!
Página 1 de 2

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

MensagemEnviado: 07 Ago 2020 10:21
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

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

MensagemEnviado: 07 Ago 2020 11:21
por lucimauro
Bom dia,
eu uso assim

result:=hb_random(1,999999)

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

MensagemEnviado: 07 Ago 2020 11:33
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.

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

MensagemEnviado: 07 Ago 2020 11:56
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.



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   

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

MensagemEnviado: 07 Ago 2020 12:14
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....

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

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

MensagemEnviado: 07 Ago 2020 12:47
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.

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

MensagemEnviado: 07 Ago 2020 12:53
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.
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

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

MensagemEnviado: 07 Ago 2020 12:54
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.

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

MensagemEnviado: 07 Ago 2020 13:02
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.

#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

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

MensagemEnviado: 07 Ago 2020 13:07
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

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

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

MensagemEnviado: 07 Ago 2020 13:19
por JoséQuintas
Testado/Testando:


#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

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

MensagemEnviado: 07 Ago 2020 13:33
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.

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

MensagemEnviado: 07 Ago 2020 14:18
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

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

MensagemEnviado: 07 Ago 2020 16:01
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

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

MensagemEnviado: 07 Ago 2020 16:28
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.

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

MensagemEnviado: 07 Ago 2020 17:04
por JoséQuintas
Então parece que aquela rotina de gerar um número de cada vez pode ser a mais adequada.

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

MensagemEnviado: 07 Ago 2020 18:22
por Claudio Soto
Si es lo mas seguro, porque a pesar que en C:
float : 7 dígitos de precisión decimal
double : 15 dígitos

Hay diferentes funciones para generar números pseudoaleatorios y hay que ver si la función realmente recorre todo el espectro de presicion decimal o entra en un loop más o menos infinito y luego de una determinado número de cálculo vuelve a empezar del inicio de la serie.

Se llaman pseudoaleatorios porque no son verdaderamente aleatorios, siempre la funcion parte de un valor inicial y si siempre se da el mismo valor inicial ("semilla") siempre arroja la misma secuencia de números.
Generalmente como semilla se usa la hora y la fecha actual del sistema en segundos o milisegundos para asegurarse que la secuencia de números sea diferente en cada corrida.

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

MensagemEnviado: 07 Ago 2020 18:47
por alxsts
Olá!

Provavelmente trocando o uso de arrays pelo de hashes torne o processo mais rápido

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

MensagemEnviado: 03 Set 2020 11:07
por Linguagemclipper
Eu uso a seguinte função para gerar números aleatórios para nomes de arquivos temporários:
function Ran( nLimite )
  static nGuarda:= 1

  local I
  local nResult

  if ValType( nLimite ) # [N]
    nLimite:= 100
  endif

  I:= Seconds()

  while nLimite > I
    I:= I * 100 +Seconds()
  enddo

  nGuarda:= (nGuarda +I) / (nResult:= nGuarda * I % nLimite +1)
  nResult:= Int( nResult )
return nResult

Essa função retorna um número de 0 até o número passado como parâmetro para ela.
Exemplo:
cRANDOM  := ALLTRIM(STR(RAN(9999)))
fINDEX   := xTEMP+"TEMP" + cRANDOM

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

MensagemEnviado: 20 Set 2020 20:03
por Eduardo Pinho
Talvez o debate já tenha se encerrado, mas se der tempo, tenho uma funcao aqui que pra mim funciona bem.
Baixei na net nao sei onde, e só fiz adaptacao pra parametros de intervalo.
Fiz muitos testes nela, e nunca vi falha, distribuicao irregular, essas coisas...



func RND && ( Min, Max )
* Esta funcao gera um numero aleatorio entre min e max (inclusive).
*
* Returns a floating-point pseudo-random number (PRN) between 0 and maxval
* (left-inclusive), with maxval defaulting to 1. If maxval is in the same
* order of size as the generator's period, the distribution of the
* resulting PRNs will be irregular, but since PERIOD is 2147483647, that
* should not be a problem in practice; people doing astrophysics or monte
* carlo simulation using Clipper deserve everything they get, anyway .
*
* Adaptada para o Harbour com 2 parametros: limite min e maximo,
* mantendo maxval sempre 1.
* Sem os parametros min e max retorna o random como foi gerado.
*
* Esta funcao nao funciona se RND_SEED nao puder ir se modificando a cada chamada.
* Portanto, um executavel gerando um unico PRN e sendo chamado varias vezes em um
* arquivo BAT, por exemplo, irá gerar uma distruibuicao irregular que em nada se
* parecerá com numeros aleatorios.
*
* Para gerar numeros aleatorios seguidamente, use esta funcao seguidamente no mesmo
* executavel.
*

para min,max
private nRandom,nmaxval,range

IF TYPE([RND_PERIOD])#[N]
   PUBLIC RND_PERIOD,RND_FACTOR,RND_SEED
   RND_PERIOD=2147483647
   RND_FACTOR=16807
   rnd_seed = 0
ENDIF

do while rnd_Seed = 0
   rnd_Seed = Seconds()
   rnd_Seed = ( rnd_Seed * 12345 ) % RND_PERIOD
enddo

rnd_Seed = RND_FACTOR * rnd_Seed - Int(RND_FACTOR * rnd_Seed / RND_PERIOD ) * RND_PERIOD

nRandom = (rnd_Seed / RND_PERIOD)

if pcount()=2
   range=max-min+1
   nrandom = int(nrandom*range+min)
endif

RETURN nRandom


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

MensagemEnviado: 20 Set 2020 21:21
por Vlademiro
Até o momento, a única forma que eu encontrei para garantir a não repetição de valores foi através de uma variável Static.

Static nVal := 0

nValorFinal := hb_randomint(1000,9999) + nVal++

Return nValorFinal

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

MensagemEnviado: 20 Set 2020 21:24
por Vlademiro
Eduardo, essa sua da certo tb, é o mesmo princípio.

Valeu.