Ir ao conteúdo
  • Cadastre-se
DL.Fernandes

Números aleatórios em uma faixa limitada

Recommended Posts

Boa noite, tudo bem? :wiggle:

 

Estou com uma dúvida aqui.. queria fazer um programa da qual eu informe um valor inteiro positivo X, um valor inteiro positivo Y e a quantidade de números aleatórios que eu quero. Ai o programa tem que me retornar, na faixa entre X a Y, sem repetição, a quantidade de nºs aleatórios que eu disse que gostaria. Isso em C. 

 

Por exemplo: eu informo lá como sendo X = 2 e Y = 10, com 4 aleatórios (essas perguntas o programa quem me faz). Ai o computador me informa, aleatoriamente e sem repetição, 04 valores entre 2 e 10..

 

Sou iniciante em C, estava tentando aqui com o comando rand(), mas ele gera começando do 0.. não estou conseguindo colocar o limite final, quiçá a quantidade de aleatórios.. Alguém tem alguma ideia de como escrever esse código ?

 

Valeu pessoal 

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Caro usuário,

 

Seja bem-vindo ao Fórum do Clube do Hardware.

 

No intuito de servir como fonte de pesquisa no caso de instituições de ensino, informamos que incorrer no resolvimento por completo de questões relacionadas a disciplinas escolares de cursos técnicos e faculdades podem ser revistas e removidas pela Equipe de Moderação do Clube do Hardware.

 

Para sanar dúvidas sobre esse tipo de problema, por gentileza, publique o passo a passo do desenvolvimento da questão, projeto, monografia ou conteúdo em dúvida para que possamos analisar se a resposta está correta ou não, ou para que possa ser auxiliado com a dúvida no desenvolvimento do exercício.

 

Infelizmente, não há como resolver os trabalhos pelos usuários. O objetivo do Fórum do Clube do Hardware é auxiliar seus usuários a encontrar soluções para que possam sanar suas dúvidas, e não de trazer soluções prontas para seus usuários.. Além disso, copiar e colar respostas que não são de autoria própria do qualquer usuário é considerado plágio, o que é ilegal.

 

Esperamos que compreenda.

 

Atenciosamente,

Equipe Clube do Hardware

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@DL.Fernandes    digamos que o x seja o valor inicial e o y o valor final, então coloque o rand() % com o valor y e somado o valor x assim ele gera números na faixa estipulada, entre x e y,  agora para que não haja números repetidos, precisa ir guardando os números gerados em um vetor,  ou pode ser em variáveis mas serão muitas variáveis,    e usar um loop, para assim ir comparando o número gerado com todos os números que estão no vetor, e se o número for igual à algum que já esteja lá, então descarta esse número duplicado e gera outro , e a cada número gerado e testado que não estiver no vetor você decrementa o total de quantidade de números que você pediu , assim enquanto essa quantidade for maior que zero ele repete e escolhe outro número, e quando for  menor ou igual a zero ele passa e imprime os números gerados . 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Basicamente:

numero = x + rand() % (y-x+1)

Gera um número aleatório entre x e y (com ambos x e y inclusos no intervalo).

  • Curtir 1
  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante

Olá. Segue um algoritmo relativamente simples q você pode usar nos seus projetos p criar números aleatórios entre uma determinada faixa, como está o exercício, por exemplo, entre 30 e 40

 

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int gerarInt(int inicio, int fim)
{
    int intervalo = (++fim - inicio);
    int n = (rand() % intervalo) + inicio;
    return n;
}


int main()
{
    srand(time(NULL));

    int x = gerarInt(30, 40);

    printf("%d\n", x);

    return 0;
}

Caso, baseado no exemplo acima, não queira que o número 40 seja impresso e sim números entre 30 e 39 é só tirar o pré-incremento na 1ª linha dentro da função gerarInt(), que nesse caso seria "++fim"

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@giu_d Se usar só o seu código ele pode gerar números repetidos dentro do intervalo, mas o enunciado pede sem repetição.

  • Curtir 1
  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante
Em 20/04/2018 às 11:04, isrnick disse:

Basicamente:


numero = x + rand() % (y-x+1)

Gera um número aleatório entre x e y (com ambos x e y inclusos no intervalo).

 

Olá, postei antes d testar sua fórmula. Realmente funciona e é bem mais simples q a minha

adicionado 3 minutos depois

Não vi essa parte d não poder haver números repetidos 

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Um jeito eficiente de resolver isso seria gerar uma lista dos números no intervalo (preenche um vetor com os números no intervalo), depois usa uma algoritmo para embaralhar os números (ex: algoritmo Knuth Fisher-Yates), aí os N primeiros números da lista seriam os números aleatórios sem repetição dentro do intervalo.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante

Sim. Como achei interessante sua lógica resolvi pesquisar a respeito do algoritmo Knuth Fisher-Yates. Deu para encontrar algo até meio pronto, só fiz algumas alterações, mas a lógica permaneceu a mesma. Só q ficou um código muito complexo já que ele está apenas iniciando em C. E ainda tem a questão de resolver o preenchimento do vetor com os valores na faixa dos valores de x e y conforme o usuário fornecer. 

Mas, como gostei do código, resolvi postar. Já iniciei um vetor com alguns números:

 

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void imprimeElementos(int *vetor, int qtde)
{
    int i;
    for (i = 0; i < qtde; i++) { printf("%d ", vetor[i]); }
}

int main()
{
    int N = 9, i;
    int elementos[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int elementosRestantes = N;

    srand(time(NULL));

    while (elementosRestantes > 0)
    {
        int k = rand() % (elementosRestantes);

        int temp = elementos[k];
        elementos[k] = elementos[elementosRestantes - 1];
        elementos[elementosRestantes - 1] = temp;

        elementosRestantes--;
    }

    printf("Numeros: ");

    imprimeElementos(elementos, 4);

    printf("\n");

    return 0;
}

Só que, como falei, ficou um código bem complexo e extenso.

Creio q deve ter alguma forma de fazer a mesma coisa d maneira mais simples

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não achei complexo ou extenso, mas isso é questão de opinião. Segue minha solução:

#include <stdio.h>
#include <time.h>

int main()
{
    srand(time(NULL));
    
    int i, v[1000], x, y, k, n, m;
    
    x = 2;
    y = 10;
    k = 4;
    
    //Preenche vetor com todos os números no intervalo [x, y]
    for (i=0; i <= y-x; i++)
        v[i] = x+i;
    
    //Embaralha os números no vetor (algoritmo Knuth Fisher-Yates)
    for (i = y-x; i>0; i--){
        n = rand() % (i+1);
        m = v[i];
        v[i] = v[n];
        v[n] = m;
    }
    
    //Os k primeiros números do vetor são números aleatórios
    //no intervalo sem repetição
    for (i = 0; i<k; i++)
        printf(" %d", v[i]);
    printf("\n");
    
    return 0;
}

 

Nesse caso o tamanho do vetor limita o intervalo a ter no máximo 1000 números (ou seja, y-x+1 <= 1000), mas isso poderia ser estendido para qualquer intervalo de números usando alocação dinâmica (malloc).

 

Se achar uma maneira mais simples por favor compartilhe, eu também gostaria de saber.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tenho impressão de que é possível obter o mesmo resultado só que com menos processos lógicos.

Em 20/04/2018 às 11:04, isrnick disse:

numero = x + rand() % (y-x+1)

Quando combinar a expressão acima com loop de tamanho igual quantidade de valores aleatórios desejados, resolve o problema!

adicionado 18 minutos depois
18 horas atrás, giu_d disse:

int gerarInt(int inicio, int fim) { int intervalo = (++fim - inicio); int n = (rand() % intervalo) + inicio; return n; }

Esse método também, pois tanto a expressão quanto o método acima estão próximos.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@AnsiC Não resolve o problema pois isso geraria números repetidos dentro do intervalo, e o problema pede números sem repetição.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
agora, isrnick disse:

Não resolve o problema pois isso geraria números repetidos dentro do intervalo, e o problema pede números sem repetição.

Exatamente, não considerei essa parte e fiquei martelando a cabeça aqui!

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Se fosse em C++ ficaria mais fácil fazer isso, mas até que não ficou tão ruim:

#include <stdio.h>
#include <Windows.h>
#include <time.h>

bool numJaFoiGerado(int* vet, int size, int num)
{
	for (int i = 0; i < size; i++) 
		if (vet[i] == num)
			return true;

	return false;
}

int gerarNum(int min, int max)
{
	return rand() % (max - min + 1) + min;
}

int main()
{
	srand((unsigned int)GetTickCount());

	int tam = sizeof(int) * 2; // * 2 para ficar uma posição livre no vetor, ficando equivalente a int vet[1] em vez de int vet[0]
	int* vet = (int*)malloc(tam);
	int qntNum = 0;

	while (qntNum < 30) // Gera 30 números
	{
		int num = gerarNum(1, 50); // Gera números entre 1 e 50

		while (numJaFoiGerado(vet, qntNum, num)) // Verifica se o número gerado já existe no vetor, se existir gera novamente um número
			num = gerarNum(1, 50); // Gera novamente números entre 1 e 50

		// Número gerado não existe ainda no vetor, então adiciona no vetor e aloca mais memória para o vetor
		vet[qntNum++] = num;

		tam += sizeof(int);

		// Realoca uma nova posição para o vetor
		vet = (int*)realloc(vet, tam);

		// Mostra o número
		printf("%i\n", num);

		Sleep(200);
	}

	// Libera memória que foi alocada para o vetor
	free(vet);

	system("pause");

	return 0;
}


Saída:

1
44
20
48
37
50
4
24
7
28
16
40
32
38
30
36
39
5
6
15
23
11
9
27
29
13
49
10
41
14
Pressione qualquer tecla para continuar. . .

 

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@cyer Esse método é muito ineficiente, imagine por exemplo que o intervalo vai de 1 até 1000, e deseja-se escolher 980 números aleatórios sem repetição, nesse caso seu algoritmo vai ficar gerando um novo número novamente centenas até milhares de vezes pois já existe o número na lista. Além do algoritmo precisar checar o vetor inteiro de números já gerados toda vez que um novo número é gerado.

 

O método usando um vetor embaralhado definitivamente é uma opção melhor.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
6 minutos atrás, isrnick disse:

@cyer Esse método é muito ineficiente, imagine por exemplo que o intervalo vai de 1 até 1000, e deseja-se escolher 980 números aleatórios sem repetição, nesse caso seu algoritmo vai ficar gerando um novo número novamente centenas até milhares de vezes pois já existe o número na lista. Além do algoritmo precisar checar o vetor inteiro de números já gerados toda vez que um novo número é gerado.

 

O método usando um vetor embaralhado definitivamente é uma opção melhor.

 

Com esse algoritmo vai acabar passando da faixa limitada(com muitos números gerados), tentei rodar com o Visual Studio, gerava exceção para números grandes.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Imaginem que não exista C++, somente C e as ferramentas que poderem desenvolver a partir dela. 

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

O código pode facilmente ser adaptado para não ter limite de intervalo usando alocação dinâmica:

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    srand(time(NULL));
    
    int i, x, y, k, n, m;

    x = 1;
    y = 1000;
    k = 980;
    
    int *v = malloc((y-x+1)*sizeof(int));
    
    //Preenche vetor com todos os números no intervalo [x, y]
    for (i=0; i <= y-x; i++)
        v[i] = x+i;
    
    //Embaralha os números no vetor (algoritmo Knuth Fisher-Yates)
    for (i = y-x; i>0; i--){
        n = rand() % (i+1);
        m = v[i];
        v[i] = v[n];
        v[n] = m;
    }
    
    //Os k primeiros números do vetor são números aleatórios
    //no intervalo sem repetição
    for (i = 0; i<k; i++)
        printf(" %d", v[i]);
    printf("\n");
    
    free(v);
    
    return 0;
}

 

  • Curtir 3

Compartilhar este post


Link para o post
Compartilhar em outros sites
#include <stdio.h>
#include <stdlib.h>

void meu_rand( int inic, int fim, int quant ){
	unsigned int const LISTA_SIZE = (unsigned int const)( fim - inic - 1 );
	int r, elem;
	
	int lista_vet [LISTA_SIZE];
	
	srand( inic + fim + rand() );
	
	elem = 0;
	inic ++;
	
	while( elem < LISTA_SIZE ){
		lista_vet [elem ++] = inic + elem;
		}
	while( quant -- ){
		r = rand() % elem;
		printf( "%d ", lista_vet [r] );
		
		lista_vet [r] = lista_vet [-- elem];
		}
		
	return;
	}
		
int main ( void ){
	meu_rand( 2, 10, 4 );
	
	printf( "\nlista entre 2 e 100\n" );
	meu_rand( 2, 100, 40 );
	return 0;
	}

Então vou contribuir com um também.

 

 

  • Curtir 2

Compartilhar este post


Link para o post
Compartilhar em outros sites

percebi agora que minha proposta de resolução não incluiu os  extremos. Mas é fácil de corrigir.

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante

@isrnick  Olá. Resolvi reaproveitar seu código para criar um gerador de senha em C. Bastou algumas alterações e tudo ok.

Basicamente ficou o mesmo código:

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int i, n, x, y;
    char temp;
    char *vet = NULL;

    srand(time(NULL));

    x = 33;
    y = 126;

    vet = (char *) malloc((y - x + 1) * sizeof(char));

    char *senha = (char *) malloc((y - x + 1) * sizeof(char));


    for (i = 0; i <= y - x; i++)
        vet[i] = (x + i);

    for (i = y - x; i > 0; i--)
    {
        n = rand() % (i + 1);

        temp = vet[i];
        vet[i] = vet[n];
        vet[n] = temp;
    }

    for (i = 0; i < 12; i++)
    {
        senha[i] = vet[i];
    }

    printf("\nSenha: %s\n\n", senha);

    free(vet);
    free(senha);

    vet = NULL;
    senha = NULL;

    return 0;
}

Apenas armazenei os dígitos em uma string, caso seja preciso usar esse código em uma função e para retornar essa string

Usei os valores da tabela ASCII para essa senha

adicionado 2 minutos depois

Mas senão bastaria muda o valor de x para 33 e y para 126 e imprimir os dígitos como sendo um char

adicionado 3 minutos depois

Sem querer acabou me ajudando muito! hehe

  • Curtir 2

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante

Apenas a título d curiosidade. Se usar esse gerador de senha e criar uma senha com ele de 60 dígitos, seriam precisos algo em torno de "7 GOOGOL YEARS" (7 anos Googol)  para q alguém pudesse quebrar sua senha, segundo esse site:

https://howsecureismypassword.net

Para ser ter uma ideia, 1 Googol é um número tão grande q até serviu de inspiração para o nome Google.

Atualmente o Google conta com alguns trilhões de sites hospedados em seus servidores. Uma mixaria perto d um Googol 

 

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×