Como reiniciar o loop em C ++ (Finding única Sequence Sobre aleatoriamente Executa)
Pergunta
Os seguintes códigos tentar gerar seqüências aleatórias sobre K é executado. Mas queremos que as cordas recém-gerados para ser totalmente diferente com sua seqüência de referência.
Para que eu tentei usar "continuar" para reiniciar o aleatório processo de geração de string. No entanto, não parece trabalho. O que há de errado com a minha abordagem a seguir?
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <time.h>
using namespace std;
// In this code we want to print new string that is entirely different with
// with those in initVector
template <typename T> void prn_vec(std::vector < T >&arg, string sep="")
{ // simple function for printing vector
for (int n = 0; n < arg.size(); n++) {
cout << arg[n] << sep;
}
}
int main ( int arg_count, char *arg_vec[] ) {
// This is reference string
vector <string> initVec;
initVec.push_back("A");
initVec.push_back("A");
initVec.push_back("A");
initVec.push_back("A");
vector <string> DNA;
DNA.push_back("A");
DNA.push_back("C");
DNA.push_back("G");
DNA.push_back("T");
for (unsigned i =0; i< 10000; i++) {
vector <string> newString;
for(unsigned j=0; j<initVec.size(); j++) {
int dnaNo = rand() % 4;
string newBase = DNA[dnaNo];
string oldBase = initVec[j];
int sameCount = 0;
if (newBase == oldBase) {
sameCount++;
}
if (sameCount == initVec.size()) {
continue;
}
newString.push_back(newBase);
}
cout << "Run " << i << " : ";
prn_vec<string>(newString);
cout << endl;
}
return 0;
}
Solução
Seu código parece bem à primeira vista, a menos que eu estou faltando uma grande parte de suas necessidades.
Leia este antes de usar rand()
. Exceto, é claro, a parte continue
. O que você está tentando fazer é ver se este é o mesmo que o initVector
ou não, certo? Uma simples comparação faria antes de empurrá-lo ou imprimir para o console.
int sameCount = 0;
if (newBase == oldBase) {
sameCount++;
}
// sameCount can be 1 at most, 0 otherwise
// this check never return true
if (sameCount == initVec.size()) {
continue;
}
A variável sameCount
é inicializado cada vez que você criar uma nova entrada para o newString
e sai do escopo no }
fechamento do loop for
. Assim, não será incrementado de funcionar como uma verificação adequada contra a geração duplicado. Você deve idealmente, usar um std::set
e manter inserindo nele. Duplicatas não são permitidas e você está salvo de um monte de problemas.
Mais sobre o uso rand()
srand()
e geração de números aleatórios:
Desde o FAQ comp.lang.c:
[...] os bits de baixa ordem de muitos geradores de números aleatórios são distressingly não aleatória
Se você quiser manter seus números randome na faixa
[0, 1, ... N - 1]
um método melhor em comparação com o rand() % N
simples (como recomendado no link) é usar o seguinte:
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
Agora, se você fosse para executar o programa, cada vez que você vai ter o mesmo conjunto de 10000 filamentos de DNA aleatórias ímpares. Acontece que isso é porque:
É uma característica da maioria dos geradores de números pseudo-aleatórios (e uma propriedade definida do rand biblioteca C) que eles sempre começam com o mesmo número e passe pela mesma seqüência.
FAQ de comp.lang.c.
Para obter diferentes vertentes entre corridas tente o seguinte:
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main ( int arg_count, char *arg_vec[] ) {
// most pseudo-random number generators
// always start with the same number and
// go through the same sequence.
// coax it to do something different!
srand((unsigned int)time((time_t *)NULL));
// This is reference string
string initVec("AAAA");
// the family
string DNA("ACGT");
for (unsigned i =0; i< 5; i++) {
string newString;
for(unsigned j=0; j<initVec.size(); j++) {
int dnaNo = (int)((double)rand() / ((double)RAND_MAX + 1) * 4);
char newBase = DNA[dnaNo];
newString += newBase;
}
// ideally push in a std::set
// for now keep displaying everything
if (newString != initVec) {
cout << "Run " << i << " : " << newString << endl;
}
}
return 0;
}
Outras dicas
Seu algoritmo é falso. Tudo o que você está tentando fazer, você não está fazendo isso, e porque não há um único comentário lá, eu realmente não posso dizer onde você errou.
O loop interno:
for each element of initVec (4)
create a random element
set sameCount to 0
if random element == current element of initVec, set sameCount to 1
if sameCount == 4, do something (pointless as this never happens)
add random element to newString
Somando a isso, o seu "newString" não é uma string em tudo, mas um vetor de strings.
Então, o problema não é nem mesmo o uso de continue
, é que seu algoritmo é FUBAR.
continue
não pular a parte incremento do loop for
. Tudo que faz é ir diretamente a ele, ignorando o resto do corpo do loop.
for(int i = 0; i < 10; i++)
{
if(i == 3)
continue;
printf("%d ", i);
}
É equivalente a:
int i = 0;
while(i < 10)
{
if(i == 3)
goto increment;
printf("%d ", i);
increment:
i++;
}
No barra invertida na printf()
desde que eu não conseguia descobrir como fazer com que o editor de texto, deixe-me escrever um. :)
Você percebeu que sameCount nunca se torna mais de 1? Desde initVec.size () é maior do que 1 execução nunca bate continuar.
int sameCount = 0;
//sameCount is 0
if (newBase == oldBase) { // if it is true sameCount is 1
sameCount++;
}
// sameCount is 1 or 0
if (sameCount == initVec.size()) { //this expression is always false if initVec longer than 1
continue;
}
Como outros já disse que é difícil descobrir qual era a sua intenção com este código. Você poderia nos dizer por favor, como é que você quer dizer "totalmente diferente", por exemplo?
dirkgentlys resposta é bastante abrangente para o que eu estava tentando dizer agora.
Eu gostaria de recomendar que você não use continuam porém, a maioria padrões de codificação recomendo contra o uso de continuar por um bom motivo, pois faz o controle de fluxo mais difícil de seguir.