New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Criar a zzaleatorio, para substituir o $RANDOM #75

Closed
aureliojargas opened this Issue Mar 12, 2013 · 18 comments

Comments

Projects
None yet
3 participants
@aureliojargas
Member

aureliojargas commented Mar 12, 2013

A $RANDOM não é 100% portável. É exclusivo do Bash, não funciona em outros shells. Por enquanto nossa meta é ser Bash-only, então não há problema.

A lista de funções que a utilizam hoje.

$ grep -l RANDOM *
zzcnpj.sh
zzcpf.sh
zzlinha.sh
zzmat.sh
zzpalpite.sh
zzsenha.sh
zzshuffle.sh
zzss.sh
zzsubway.sh

Não há pressa, mas no futuro podemos seria bom ter uma solução portável pra gerar números aleatórios.

Eu imagino o uso assim: zzaleatorio [número-inicial] número-final.

Exemplos:

$ zzaleatorio 10           # me dê um núm entre 1 e 10
7
$ zzaleatorio 5 15         # me dê um núm entre 5 e 15
11

Bem simples, sem firulas, sem opções, somente para números inteiros.

O mais trabalhoso no momento é encontrar uma solução 100% portável para gerar um número aleatório. Talvez com expr, talvez awk, não sei, ainda não pesquisei.

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 12, 2013

Contributor

Que tal essa sugestão?

#71 (comment)

Contributor

itamarnet commented Mar 12, 2013

Que tal essa sugestão?

#71 (comment)

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 15, 2013

Contributor

Usei o awk, como havia citado no comentário anterior. Acho que ficou aceitável, mas gostaria que avaliassem como foi feita a solução, e se realmente está funcionando em outros shell. Comigo, em todos funcionaram bem.

Contributor

itamarnet commented Mar 15, 2013

Usei o awk, como havia citado no comentário anterior. Acho que ficou aceitável, mas gostaria que avaliassem como foi feita a solução, e se realmente está funcionando em outros shell. Comigo, em todos funcionaram bem.

@itamarnet itamarnet closed this Mar 15, 2013

@gmgall

This comment has been minimized.

Show comment
Hide comment
@gmgall

gmgall Mar 15, 2013

Contributor

Fiz um teste rápido aqui e parece tudo certo no bash, dash e pdksh.

Contributor

gmgall commented Mar 15, 2013

Fiz um teste rápido aqui e parece tudo certo no bash, dash e pdksh.

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 15, 2013

Contributor

Obrigado pelo feedeback! De toda maneira qq sugestão ainda é muito bem vinda.

Contributor

itamarnet commented Mar 15, 2013

Obrigado pelo feedeback! De toda maneira qq sugestão ainda é muito bem vinda.

@aureliojargas

This comment has been minimized.

Show comment
Hide comment
@aureliojargas

aureliojargas Mar 15, 2013

Member

Aqui no BSD o comando date não reconhece esse %N:

$ date +%N
N
$
Member

aureliojargas commented Mar 15, 2013

Aqui no BSD o comando date não reconhece esse %N:

$ date +%N
N
$
@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 16, 2013

Contributor

date +%s funciona retornando os segundos desde 01/01/1970 no BSD?? Se sim vou usar esse comando especificamente para substituir quando date +%N não funcionar.
É uma pena pois o %N retorna nanosegundos, na qual eu usava para ter uma "semente" mais aleatória possível. Por padrão no awk, o srand() usa a data e o tempo do dia como "semente", para o uso do rand(), mas usando num laço como while ou for, os resultado ficam repetitivos. Para evitar esse tipo de coisa, no zzmat aleatorio uso uma pausa (sleep 1), para evitar esse problema, talvez tenha que usar esse recurso para suprir essa limitação.
Alguma sugestão para contornar isso?

Contributor

itamarnet commented Mar 16, 2013

date +%s funciona retornando os segundos desde 01/01/1970 no BSD?? Se sim vou usar esse comando especificamente para substituir quando date +%N não funcionar.
É uma pena pois o %N retorna nanosegundos, na qual eu usava para ter uma "semente" mais aleatória possível. Por padrão no awk, o srand() usa a data e o tempo do dia como "semente", para o uso do rand(), mas usando num laço como while ou for, os resultado ficam repetitivos. Para evitar esse tipo de coisa, no zzmat aleatorio uso uma pausa (sleep 1), para evitar esse problema, talvez tenha que usar esse recurso para suprir essa limitação.
Alguma sugestão para contornar isso?

@aureliojargas

This comment has been minimized.

Show comment
Hide comment
@aureliojargas

aureliojargas Mar 17, 2013

Member

Estou longe do computador agora, depois vou testar, mas tenho quase certeza que o %s funciona. Eu já tinha pensado nele mas desisti por causa desse problema de acessos repetidos dentro do mesmo segundo.

Se for dentro de um loop, talvez a semente poderia ser o %s somando de um contador incremental. Mas isso não resolve o problema de acessos simultâneos por processos diferentes, tipo dois terminais rodando a zzaleatorio ao mesmo tempo.

Tem também o /dev/random, se não me falha a memória. Mas também tem que ver se ele está presente em sistemas mais antigos.

Enfim, longe do computador não consigo testar nem confirmar nada. Mas quis jogar umas idéias aqui por enquanto. Ah, e vou reabri este issue, pois a função precisa ser portável, ok?

Member

aureliojargas commented Mar 17, 2013

Estou longe do computador agora, depois vou testar, mas tenho quase certeza que o %s funciona. Eu já tinha pensado nele mas desisti por causa desse problema de acessos repetidos dentro do mesmo segundo.

Se for dentro de um loop, talvez a semente poderia ser o %s somando de um contador incremental. Mas isso não resolve o problema de acessos simultâneos por processos diferentes, tipo dois terminais rodando a zzaleatorio ao mesmo tempo.

Tem também o /dev/random, se não me falha a memória. Mas também tem que ver se ele está presente em sistemas mais antigos.

Enfim, longe do computador não consigo testar nem confirmar nada. Mas quis jogar umas idéias aqui por enquanto. Ah, e vou reabri este issue, pois a função precisa ser portável, ok?

@aureliojargas aureliojargas reopened this Mar 17, 2013

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 17, 2013

Contributor

Bem lembrado, isso até me deu uma idéia:

$ od -An -N2 -i /dev/random

Mas também não sei se é portável, mas tenho quase certeza que o od existe em todos os sabores de unixes.
Eu acho que o /dev/random também está presente em vários unixes, com algumas diferenças apenas na maneira como é implementado, mas acredito que sempre esteja presente
Se for isso mesmo acho que podemos usa-lo diretamente ou como a "semente".

Fico no aguardo.

Contributor

itamarnet commented Mar 17, 2013

Bem lembrado, isso até me deu uma idéia:

$ od -An -N2 -i /dev/random

Mas também não sei se é portável, mas tenho quase certeza que o od existe em todos os sabores de unixes.
Eu acho que o /dev/random também está presente em vários unixes, com algumas diferenças apenas na maneira como é implementado, mas acredito que sempre esteja presente
Se for isso mesmo acho que podemos usa-lo diretamente ou como a "semente".

Fico no aguardo.

@aureliojargas

This comment has been minimized.

Show comment
Hide comment
@aureliojargas

aureliojargas Mar 17, 2013

Member

O od está presente desde sempre, porém suas opções e formato da saída variam :/

Não é maravilhosa a vida de de programador? :)

Member

aureliojargas commented Mar 17, 2013

O od está presente desde sempre, porém suas opções e formato da saída variam :/

Não é maravilhosa a vida de de programador? :)

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 17, 2013

Contributor

Realmente é um grande problema.
Opções e formatos que variam acabam sendo uma baita dor de cabeça para manter compatibilidade.
Vou fazer um commit, com uma solução que vai testar várias possibilidades.

Não é das mais elegantes, mas acho que pode funcionar.

Contributor

itamarnet commented Mar 17, 2013

Realmente é um grande problema.
Opções e formatos que variam acabam sendo uma baita dor de cabeça para manter compatibilidade.
Vou fazer um commit, com uma solução que vai testar várias possibilidades.

Não é das mais elegantes, mas acho que pode funcionar.

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 18, 2013

Contributor

Confabulando com um colega de serviço, ele me deu algumas idéias baseado no que viu em outras zz's
Acha que essa solução seria plausível e portável?

Inluir a variavel cache:
local cache="$ZZTMP.aleatorio"

Incluir na atual linha 47:
[ -s "$cache" ] && v_temp=$(cat "$cache")

E na atual linha 48, mudar para:
zztool testa_numero $v_temp || v_temp=$(od -An -N2 -i /dev/urandom)

Incluir na atual linha 60:
echo "$v_temp" | zzmd5 | sed 's/[^0-9]+//g;s/./&+/g' | sed 's/^+//;s/+$//' | bc > "$cache"

Contributor

itamarnet commented Mar 18, 2013

Confabulando com um colega de serviço, ele me deu algumas idéias baseado no que viu em outras zz's
Acha que essa solução seria plausível e portável?

Inluir a variavel cache:
local cache="$ZZTMP.aleatorio"

Incluir na atual linha 47:
[ -s "$cache" ] && v_temp=$(cat "$cache")

E na atual linha 48, mudar para:
zztool testa_numero $v_temp || v_temp=$(od -An -N2 -i /dev/urandom)

Incluir na atual linha 60:
echo "$v_temp" | zzmd5 | sed 's/[^0-9]+//g;s/./&+/g' | sed 's/^+//;s/+$//' | bc > "$cache"

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 18, 2013

Contributor

Esqueça o comentário anterior, a idéia parecia boa, mas ocorre repetição e deixa de ser aleatório numa mesma seção.
De volta ao planejamento :/

Contributor

itamarnet commented Mar 18, 2013

Esqueça o comentário anterior, a idéia parecia boa, mas ocorre repetição e deixa de ser aleatório numa mesma seção.
De volta ao planejamento :/

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 19, 2013

Contributor

Não descobri outra maneira para uma solução melhor.
Usando um arquivo cache gera uma repetição de padrão, e não encontrei algo confiável que pudesse dar uma confiança na função ser mesmo randômica.
O uso de qualquer artífice se mostrou ineficiente e ao mesmo tempo nada ágil. Infelizmente a solução já usado no zzmat aleatório, com uma pausa de 1 segundo, mostrou-se a mais adequada, mas lenta por isso.
Se tiver alguma idéia nova, favor avisar, as minhas esgotaram...

Contributor

itamarnet commented Mar 19, 2013

Não descobri outra maneira para uma solução melhor.
Usando um arquivo cache gera uma repetição de padrão, e não encontrei algo confiável que pudesse dar uma confiança na função ser mesmo randômica.
O uso de qualquer artífice se mostrou ineficiente e ao mesmo tempo nada ágil. Infelizmente a solução já usado no zzmat aleatório, com uma pausa de 1 segundo, mostrou-se a mais adequada, mas lenta por isso.
Se tiver alguma idéia nova, favor avisar, as minhas esgotaram...

@aureliojargas

This comment has been minimized.

Show comment
Hide comment
@aureliojargas

aureliojargas Mar 22, 2013

Member

Testei aqui e sim, existe o /dev/random. O od aqui funcionou com as opções que você indicou, e retornou duas linhas, a segunda vazia e a primeira cheias de espaços e com um número de 5 dígitos no meio:

prompt$ od -An -N2 -i /dev/random | sed -n l
                    44065                                                $
$
prompt$ od -An -N2 -i /dev/random | sed -n l
                    23733                                                $
$
prompt$ 

Acho que temos um vencedor! Um tr pra limpar a saída e está pronto (ignore o echo no final):

prompt$ od -An -N2 -i /dev/random | tr -d -c '[0-9]' ; echo
18598
prompt$ od -An -N2 -i /dev/random | tr -d -c '[0-9]' ; echo
37609
prompt$ od -An -N2 -i /dev/random | tr -d -c '[0-9]' ; echo
25501
Member

aureliojargas commented Mar 22, 2013

Testei aqui e sim, existe o /dev/random. O od aqui funcionou com as opções que você indicou, e retornou duas linhas, a segunda vazia e a primeira cheias de espaços e com um número de 5 dígitos no meio:

prompt$ od -An -N2 -i /dev/random | sed -n l
                    44065                                                $
$
prompt$ od -An -N2 -i /dev/random | sed -n l
                    23733                                                $
$
prompt$ 

Acho que temos um vencedor! Um tr pra limpar a saída e está pronto (ignore o echo no final):

prompt$ od -An -N2 -i /dev/random | tr -d -c '[0-9]' ; echo
18598
prompt$ od -An -N2 -i /dev/random | tr -d -c '[0-9]' ; echo
37609
prompt$ od -An -N2 -i /dev/random | tr -d -c '[0-9]' ; echo
25501
@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 22, 2013

Contributor

Legal, é bom saber disso. Mas teste também e veja se existe o /dev/urandom.
Na verdade é que o /dev/random, em um loop, as vezes da uma engasgada, retardando consideravelmente o script e com o /dev/urandom isso não acontece. E pelo que vi o /dev/urandom é quase tão antigo quanto o /dev/random.
Se der certo também, é uma saída melhor.

No meu caso o od não gera a segunda linha, mas é bom saber.

Contributor

itamarnet commented Mar 22, 2013

Legal, é bom saber disso. Mas teste também e veja se existe o /dev/urandom.
Na verdade é que o /dev/random, em um loop, as vezes da uma engasgada, retardando consideravelmente o script e com o /dev/urandom isso não acontece. E pelo que vi o /dev/urandom é quase tão antigo quanto o /dev/random.
Se der certo também, é uma saída melhor.

No meu caso o od não gera a segunda linha, mas é bom saber.

@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 22, 2013

Contributor

Se puder testa também com "-d" ao invés de "-i" no comando od. Aqui a saída se comporta ligeiramente diferente no formato, mas também retorna um número inteiro aleatório.

Contributor

itamarnet commented Mar 22, 2013

Se puder testa também com "-d" ao invés de "-i" no comando od. Aqui a saída se comporta ligeiramente diferente no formato, mas também retorna um número inteiro aleatório.

@aureliojargas

This comment has been minimized.

Show comment
Hide comment
@aureliojargas

aureliojargas Mar 23, 2013

Member

/dev/urandom existe, confirmado.

prompt$ od -An -N2 -i /dev/urandom | tr -d -c '[0-9]' ; echo
44320
prompt$ od -An -N2 -i /dev/urandom | tr -d -c '[0-9]' ; echo
1147

A opção -d do od também funciona, e traz o resultado no mesmo formato do -i:

prompt$ od -An -N2 -d /dev/urandom | sed -n l
            32441                                                        $
$
prompt$ od -An -N2 -d /dev/urandom | sed -n l
            14212                                                        $
$
prompt$ 
Member

aureliojargas commented Mar 23, 2013

/dev/urandom existe, confirmado.

prompt$ od -An -N2 -i /dev/urandom | tr -d -c '[0-9]' ; echo
44320
prompt$ od -An -N2 -i /dev/urandom | tr -d -c '[0-9]' ; echo
1147

A opção -d do od também funciona, e traz o resultado no mesmo formato do -i:

prompt$ od -An -N2 -d /dev/urandom | sed -n l
            32441                                                        $
$
prompt$ od -An -N2 -d /dev/urandom | sed -n l
            14212                                                        $
$
prompt$ 
@itamarnet

This comment has been minimized.

Show comment
Hide comment
@itamarnet

itamarnet Mar 24, 2013

Contributor

Feita a inclusão para prevenir linha e espaços adicionais.
Mantive os vários testes, para ampliar possibilidades, na iminência de algum sistema não ter algum recurso.
Referência e7419d6

Contributor

itamarnet commented Mar 24, 2013

Feita a inclusão para prevenir linha e espaços adicionais.
Mantive os vários testes, para ampliar possibilidades, na iminência de algum sistema não ter algum recurso.
Referência e7419d6

@itamarnet itamarnet closed this Mar 24, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment