Un programa con varias funciones y sin entradas

Iniciado por ciquee, 16 Mayo 2019, 20:42 PM

0 Miembros y 1 Visitante están viendo este tema.

ciquee

Buenas a todos!

Que lio tengo con un ejercicio, y es que ya llevo dos días bloqueado y nada, a ver si me podéis guiar hacia La Luz... jajaja

Necesito hacer un programa que muestre los 10 primeros números perfectos tomando como referencia los números de Mersenne.

Yo no soy muy bueno en mates y he tenido que buscar a Mersenne y he averiguado que "una potencia de 2 elevada a un número primo, menos uno, da como resultado otro número primo".

Este es el enunciado de mi problema:
Realiza un programa que nos diga los 10 primeros números perfectos utilizando para ello los números primos de Mersenne.
- Utiliza una función 'EsPrimo' que determine si un número es o no primo (NO debe contar los divisores, sino determinar si el número es o no primo)
- Cómo vamos a utilizar potencias enteras de 2 con resultados elevados, diseña, para ayudarte, una función 'Potencia' que eleve una base entera a una potencia entera y devuelva un 'unsigned long long' (¡no utilices la función 'pow'!).

Ya he hecho la función "EsPrimo" y la función "Potencia" y debería hacer una también para determinar cuando el numero es perfecto, pero investigando he descubierto que según Euclides: "Siempre que (2^n)-1 sea primo, la fórmula (2^n)–1 * (2^(n – 1)) genera un nº perfecto. Con lo cual bastará con multiplicar los 10 primeros números de Mersenne por 2^(n-1). Vale, pero ahora no tengo ni idea de como sacar los números de Mersenne para pasarlos por un bucle y hacerlos perfectos y después pasarlos por la función "Potencia"... y es que nunca he hecho un problema sin que el usuario tenga que introducir algún dato.

Os pongo mí código, pero como no tengo nada claro, solo ideas sueltas, la función main no hay por donde cogerla:


#include <iostream>
#include <math.h>

using namespace std;

bool EsPrimo(unsigned long long);
unsigned long long Potencia (unsigned long long);

int main(void) {
unsigned long long primo = 0, mersenne = 0, mersenne_perf = 0;

for (int i = 1; i >= 2210; i++)
if (EsPrimo(i) == 0)

Mersenne = (pow (2,n)-1);

/*for (int i = 1; i < pot; i++){
res = res * 2;
cout<<
}
*/

// Para hacerlos perfectos supongo que es así: pow (2, n-1) * Mersenne;


cout << "Estos son los 10 primeros números perfectos de los números primos de Mersenne" << m_perf << endl;


return 0;
}


bool EsPrimo (unsigned long long num) {

if (num != 2 && num % 2 == 0){
return 0;
}

else if (num != 3 && num % 3 == 0) {
return 0;
}

else if (num != 5 && num % 5 == 0) {
return 0;
}

else {
return 1;
}
}


unsigned long long Potencia (unsigned int pot){
unsigned long long res = 2;

for (int i = 1; i < pot; i++){
res = res * 2;
}

return res;
}


Por favor, que alguien me ayude!! O me diga si tengo que dejarme esto de la programación, porque menudo follón tengo en la cabeza con este ejercicio.

Siento que me haya quedado tan larga la entrada!!
Gracias de antemano!!

K-YreX

Lo primero, cuidado con esas suposiciones...
Citar
una potencia de 2 elevada a un número primo, menos uno, da como resultado otro número primo

potencia de 2 := 4
numero primo := 2
4² - 1 = 15 = 3*5 -> 15 no es primo


Siguiente problema. Esa función <esPrimo()>...

numero := 49
49 = 7² -> 49 no es primo
Segun la funcion: EsPrimo(49) = true

Es decir esa función no es correcta. Tienes que echarle un vistazo a ver si eres capaz de solucionarlo antes de que te diga cómo se hace.
Aparte y esto es más tontería, como son <return> no hacen falta los <else> ya que si se ejecuta un <return>, va a salir de la función y no sé ejecuta el resto:
Código (cpp) [Seleccionar]

if(x == a)
   return 1;
else if(x == b)
   return 2;
else
   return 3;

// Se puede dejar en
if(x == a) return 1;
if(x == b) return 2;
return 3;

Así queda más limpio y más simple al compilarlo.

Luego veamos la función <Potencia()>
Según el enunciado se te pide lo siguiente:
Citar
diseña, para ayudarte, una función 'Potencia' que eleve una base entera a una potencia entera y devuelva un 'unsigned long long' (¡no utilices la función 'pow'!).
Y tú creas esto:
Código (cpp) [Seleccionar]

// Cuidado que en el prototipo tienes un parametro y en la implementacion otro (unsigned int != unsigned long long)
// Funcion que calcula la potencia indicada en el parametro de 2, es decir, 2^exponente
unsigned long long Potencia(unsigned int exponente); // lo llamo exponente para que se entienda mejor

No has creado una función que eleve una base entera a una potencia entera. Has creado una función que eleva el 2 a una potencia NATURAL/entera positiva (0 incluido) (unsigned). Solo te lo comento para que veas la diferencia entre lo que te piden y lo que implementas. Lo suyo sería algo así:
Código (cpp) [Seleccionar]

unsigned long long Potencia2(int exponente); // dejar claro que esa funcion calcula potencias de 2
unsigned long long Potencia(int base, int exponente); // lo que te pide el enunciado



Y después de todo esta parrafada, te comento lo que tienes que hacer. Los números perfectos se pueden obtener a partir de la fórmula que has comentado arriba aunque primero dejemos claro un par de notaciones para poder explicarte el ejercicio:

Pi := numero perfecto i
Mi(p) := numero de Mersenne i cuya formula es 2^p-1. Se suele representar como Mp, por ejemplo, M7 = 2⁷-1 = 127 pero te lo representare como M4(7), es decir, el 4º numero primo de Mersenne (que se calcula con p = 7)
Entonces tenemos que: Pi = Mi(p) * 2^p

Un número se considera de Mersenne si p es primo y 2^p-1 también es primo. Los 10 primeros p que cumplen esta condición son {2, 3, 5, 7, 13, 17, 19, 31, 61, 89} y los números de Mersenne que genera cada p son {3, 7, 31, 127, 8191, 131071, 524287, 2147483647, 2305843009213693951, 618970019...449562111} respectivamente (están en Wikipedia estos datos: https://es.wikipedia.org/wiki/N%C3%BAmero_primo_de_Mersenne)

Te pongo una forma de hacerlo para que tengas una idea

p := 2 // uso el mismo nombre que en las formulas anteriores
num_perfectos := 0
mientras num_perfectos < 10
   si esPrimo(p)
       numero_mersenne := Potencia(2,p)-1
       si esPrimo(numero_mersenne)
           numero_perfecto[num_perfecto] := numero_mersenne * Potencia(2, p-1)
           num_perfecto := num_perfecto + 1
       fin si
   fin si
   p := p + 1
fin mientras


Lo siento por el mensaje tan largo pero espero haberlo explicado todo con claridad. :-X
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

@XSStringManolo

Vaia coñazo de trabajos os mandan hacer. No tengo ni zorra de mates, pero es solo seguir las pautas del ejercicio y preguntarle las formulas a wikipedia. Haciendo estos ejercicios no aprendes nada. Buscate un libro teorico de C++. Te recomiendo Apress Learn C++ Game Development 2014. Cuando lo acabes pasate por la web https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list y pilla el libro de 1000 hojas que es el asco teorico más grande. Ve haciendo programas que se te ocurran mientras vas asimilando conceptos.

No hagas copia y pega que si tu profesor busca en google el codigo le saldra este post xD
Código (cpp) [Seleccionar]

#include <iostream>
using namespace std;

unsigned long long Potencia (unsigned int Base, unsigned int Exponente)
{
unsigned long long potencia = 1;
int i;
if (Exponente==0) return 1; //Error.
else
{
for(i=0;i<Exponente;++i)
{
potencia*=Base;
}
}
return potencia;
}

bool EsPrimo (unsigned long long Numero)
{
int Contador = 0;
bool esPrimo = false;
for (int i=1;i<(Numero+1); ++i)
{
if(Numero%i==0)
{
++Contador;
}
}
if(Contador!=2)
{
//Mete un cout por aqui de Numero si quieres para ver el numero que no es primo.
return esPrimo;
}
else
{
esPrimo = true; //Mete un cout por aqui de Numero si quieres, para ver el numero que si es primo.
return esPrimo;
}
}

int main()
{
unsigned int Numero = 1; //Numero a comprobar si es primo.
unsigned int Contador = 1; //Contador para bucle do while.
unsigned long long NumeroPrimoM;
unsigned long long NumeroPerfecto;
do {
   if ( EsPrimo(Numero) ) //Funcion EsPrimo retorna true si el valor de Numero es primo.
   {
   NumeroPrimoM = Potencia(2,Numero) -1; //Formula para sacar primo de Mersenne.
//Mete un cout aqui de NumeroPrimoM si quieres conocer a los primos de Mersenne.
   NumeroPerfecto = (NumeroPrimoM*(NumeroPrimoM +1))/2; //Formula para sacar numero perfecto utilizando numero primo de Mersenne.
   cout << Contador << " - Numero Perfecto: " << NumeroPerfecto << endl;
   ++Contador; //Para el bucle while y seguir calculando hasta 10.
   ++Numero;//Probemos si el siguiente numero es primo.
       }

   else
   {
   ++Numero; //Si el valor en Numero no es primo, prueba el siguiente.
   }

} while (Contador != 11);
return 0;
}

Si no entiendes algo pregunta.

K-YreX

Cita de: string Manolo en 17 Mayo 2019, 08:07 AM
Vaia coñazo de trabajos os mandan hacer. No tengo ni zorra de mates, pero es solo seguir las pautas del ejercicio y preguntarle las formulas a wikipedia. Haciendo estos ejercicios no aprendes nada. Buscate un libro teorico de C++. Te recomiendo Apress Learn C++ Game Development 2014. Cuando lo acabes pasate por la web https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list y pilla el libro de 1000 hojas que es el asco teorico más grande. Ve haciendo programas que se te ocurran mientras vas asimilando conceptos.

No hagas copia y pega que si tu profesor busca en google el codigo le saldra este post xD
Código (cpp) [Seleccionar]

#include <iostream>
using namespace std;

unsigned long long Potencia (unsigned int Base, unsigned int Exponente)
{
unsigned long long potencia = 1;
int i;
if (Exponente==0) return 1; //Error.
else
{
for(i=0;i<Exponente;++i)
{
potencia*=Base;
}
}
return potencia;
}

bool EsPrimo (unsigned long long Numero)
{
int Contador = 0;
bool esPrimo = false;
for (int i=1;i<(Numero+1); ++i)
{
if(Numero%i==0)
{
++Contador;
}
}
if(Contador!=2)
{
//Mete un cout por aqui de Numero si quieres para ver el numero que no es primo.
return esPrimo;
}
else
{
esPrimo = true; //Mete un cout por aqui de Numero si quieres, para ver el numero que si es primo.
return esPrimo;
}
}

int main()
{
unsigned int Numero = 1; //Numero a comprobar si es primo.
unsigned int Contador = 1; //Contador para bucle do while.
unsigned long long NumeroPrimoM;
unsigned long long NumeroPerfecto;
do {
   if ( EsPrimo(Numero) ) //Funcion EsPrimo retorna true si el valor de Numero es primo.
   {
   NumeroPrimoM = Potencia(2,Numero) -1; //Formula para sacar primo de Mersenne.
//Mete un cout aqui de NumeroPrimoM si quieres conocer a los primos de Mersenne.
   NumeroPerfecto = (NumeroPrimoM*(NumeroPrimoM +1))/2; //Formula para sacar numero perfecto utilizando numero primo de Mersenne.
   cout << Contador << " - Numero Perfecto: " << NumeroPerfecto << endl;
   ++Contador; //Para el bucle while y seguir calculando hasta 10.
   ++Numero;//Probemos si el siguiente numero es primo.
       }

   else
   {
   ++Numero; //Si el valor en Numero no es primo, prueba el siguiente.
   }

} while (Contador != 11);
return 0;
}

Si no entiendes algo pregunta.

O sea estos trabajos que te ayudan a pensar de forma lógica y a saber implementar las ideas que tienes en la cabeza son un coñazo y leerte un libro de 1000 páginas que ya adelantas ser "el asco teórico más grande" es mejor para alguien que está empezando?? Será buena idea si lo que quieres es que abandone la programación por parecerle "un coñazo".

En esa función <Potencia()> si tomas el caso de que exponente valga 0 de forma aislada (y no es un error eso) no tienes que inicializar <potencia> a 1 sino a <base> (es más puedes usar la propia variable base que no está pasada por referencia ni es constante para ahorrarte una variable y una iteración). Tal y como está implementado ahí, el bucle funciona también para el exponente 0 por lo que no es necesario tratarlo de forma aislada.

La función <esPrimo()> aparte de hacer iteraciones de más de forma innecesaria usa una variable para guardar true/false antes de retornar cuando se puede retornar el valor directamente. Y el <else> tampoco es necesario.

Ese programa no calcula los primos de Mersenne, calcula los números de Mersenne (no aseguras en ninguna parte que sean primos, es más, no lo son) por lo que los resultados no son correctos tampoco.

Y el uso correcto del <do while> es para bloques que deben ejecutarse una vez antes de comprobar la condición siempre, lo cual no es el caso. Para este caso por convención se emplea un <while>.

Al final los trabajos "coñazo" van a servir para ver los fallos que comete uno.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

@XSStringManolo

#4
+O sea estos trabajos que te ayudan a pensar de forma lógica y a saber implementar las ideas que tienes en la cabeza son un coñazo y leerte un libro de 1000 páginas que ya adelantas ser "el asco teórico más grande" es mejor para alguien que está empezando?? Será buena idea si lo que quieres es que abandone la programación por parecerle "un coñazo".

-Sacar formulas de wikipedia no es implementar ideas que tienes en la cabeza. Hacer programas que se te ocurran tras leer un trozo pequeño de un libro teorico escrito por el creador de C++ sí. Asco de extenso, no asco de aburrido. Le recomendé uno más ameno de 296 paginas que explica absolutamente todo lo necesario para empezar mientras programas un videojuego. Quizás si lo primero que haces es crear un juego con una muy buena orientación le pilles más cariño al lenguaje que formulas matemáticas que de momento no te interesan para nada.

+En esa función <Potencia()> si tomas el caso de que exponente valga 0 de forma aislada (y no es un error eso) no tienes que inicializar <potencia> a 1 sino a <base> (es más puedes usar la propia variable base que no está pasada por referencia ni es constante para ahorrarte una variable y una iteración). Tal y como está implementado ahí, el bucle funciona también para el exponente 0 por lo que no es necesario tratarlo de forma aislada.

-Me refería a que el return 1 era para finalizar la funcion como un error. Aunque no sea eso lo que haga. No tenía ganas de incluir más codigo, ya que el programa imprime correctamente el resultado. Lo deje ahí como un complemento para si alguiem quiere tratar ese caso en específico de forma diferente a la implementada en el else.

+La función <esPrimo()> aparte de hacer iteraciones de más de forma innecesaria usa una variable para guardar true/false antes de retornar cuando se puede retornar el valor directamente. Y el <else> tampoco es necesario.

-Lo puse así para que entienda mejor el codigo.

+Ese programa no calcula los primos de Mersenne, calcula los números de Mersenne (no aseguras en ninguna parte que sean primos, es más, no lo son) por lo que los resultados no son correctos tampoco.

-Por lo que entendí de la formula en wikipedia, cualquier numero primo al que se le aplique la formula pasa a ser automáticamente un numero primo de Mersenne sin necesidad de nada mas. De no ser así con volver a llamar a la función EsPrimo ya estaría el problema solucionado. Pero consulte la salida de los valores de la variable que almacena los numeros primos de Mersenne y coincidian con los que encontre en google. Estás seguro de que son incorrectos? Porque también comprobé los 10 numeros perfectos en google y eran los mismos que me da la salida de mi programa.

+Y el uso correcto del <do while> es para bloques que deben ejecutarse una vez antes de comprobar la condición siempre, lo cual no es el caso. Para este caso por convención se emplea un <while>.

-Siempre uso el do while por si quiero meter en algún momento algún trozo de codigo que itere en caso de que no se cumpla la condición. Malos habitos.

+Al final los trabajos "coñazo" van a servir para ver los fallos que comete uno.

-Y los que no son coñazo tambien. Yo pico código palante, me da igual que no esté perfecto en uso de recursos. No trabajo ni voy a trabajar nunca para una empresa. Trabajo para mi y mis proyectos nunca van a requerir tanta eficiencia. Con que lo que salga en pantalla sea lo que quiero ver me vale.

K-YreX

Dejando a un lado las respuestas que no llevan a nada productivo pero que puedo resumir en "enseñar malas prácticas a alguien que está empezando genera otra persona que enseñará malas prácticas a otros que estén empezando".
Citar
Por lo que entendí de la formula en wikipedia, cualquier numero primo al que se le aplique la formula pasa a ser automáticamente un numero primo de Mersenne sin necesidad de nada mas. De no ser así con volver a llamar a la función EsPrimo ya estaría el problema solucionado. Pero consulte la salida de los valores de la variable que almacena los numeros primos de Mersenne y coincidian con los que encontre en google. Estás seguro de que son incorrectos? Porque también comprobé los 10 numeros perfectos en google y eran los mismos que me da la salida de mi programa.
Los números primos de Mersenne son números que se calculan con la fórmula M(p) = 2^p-1 donde p es primo y M(p) también lo es. Si cogemos p = 11, tenemos M(11) = 2047 = 23 * 89, por lo que p sí es primo pero M(p), no. No había comprobado lo del número perfecto pero lo hacemos ahora. 2047 * 2^10 = 2096128 que se encuentra entre el tercer número perfecto (8128) y el cuarto (33550336), por lo que no es un número perfecto... al menos en donde yo he comprobado esos resultados que no digo que sea una página 100% fiable pero una de las dos, la tuya o la mía, es incorrecta.

Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

@XSStringManolo

La formula que está en main es la que saqué de wikipedia. Tenia un problema con los resultados que no coincidian, concretamente a partir del 3 numero primo que me daba 9 y en wikipedia me salia que era 31 cambie mi función Potencia por pow en el main para ver si implementara mal la funcion y todos los resultados coincidian, primos y perfectos. Entonces arreglé mi función Potencia y los resultados eran los mismos que con pow.

ciquee

Hola!! Buenas tardes y muchas gracias a los dos!!

string Manolo muchas gracias por tus recomendaciones de libros, los tendré en cuenta. Decirte que yo también pensaba como tu, cuando empecé a resolver problemas en los que tenía que averiguar fórmulas y demás, pero que con el paso del tiempo he aprendido a valorar, ya que indagando sobre esas cosas a priori "externas" a la programación, se aprende bastante, y se aprecia lo grande que es este mundo de la programación en el que se puede hacer prácticamente de todo. Además como me gusta ponerme a prueba e indagar me gusta hacer estos ejercicios, aunque si que es cierto que a veces me veo en un lio del que no se como salir, como era este caso jajaja.

YreX-DwX, eres un maquina tío, siempre estas ahí! gracias de nuevo. Aunque aún no me he puesto a resolver el ejercicio en sí, estoy asimilando la información que me habéis dado ambos. Pero ya he hecho algunos cambios siguiendo el primero de tus comentarios.

Con esta suposición:
Citar
una potencia de 2 elevada a un número primo, menos uno, da como resultado otro número primo
me equivoqué al expresarla, no quería decir una potencia de dos, sino una potencia de base 2.

Luego en la función EsPrimo, he quitado los else como me dijiste, ya que es cierto lo que dices, no había caído. Y he aunque he añadido otro if con el 7 sigue sin ser correcta porque siempre me dará error al escribir múltiplos de los números primos, como es el caso del 11, 13... así que no tengo ni idea de como hacerlo, ya que de la forma que dice storing Manolo si que sé, pero en el ejercicio me piden que lo averigüe sin contar los divisores... ayuda!!

Respecto a la función "Potencia":
Citar
Cómo vamos a utilizar potencias enteras de 2 con resultados elevados, diseña, para ayudarte, una función 'Potencia' que eleve una base entera a una potencia entera y devuelva un 'unsigned long long' (¡no utilices la función 'pow'!).
Al decirme que vamos a usar potencias enteras de base 2, yo he hecho la función ya dando por hecho esa valor en la base, lo cual no esta mal ¿no?, lo que si que voy a hacer es aclarar en un comentario lo que me dices, que es una función que eleva, únicamente el 2, a una potencia. y en cuanto a esto:
Citar
No has creado una función que eleve una base entera a una potencia entera. Has creado una función que eleva el 2 a una potencia NATURAL/entera positiva (0 incluido) (unsigned). Solo te lo comento para que veas la diferencia entre lo que te piden y lo que implementas.
Ok, ya he entendido en que me equivocaba!

Y ahora me voy a poner con el problema en si, y los números primos de Mersenne y los perfectos! Si no me aclaro vuelvo a escribir por aquí!!

Saludos!!

@XSStringManolo

Orientate por mi funcion Potencia, si no te fias de si funciona correctamente compruebalo de la siguiente manera.
resultado = pow(base, exponente);
cout << resultado;
resultado = Potencia(base, exponente);
cout <<endl << resultado;


K-YreX

#9
EDITO: Se ha corregido el pseudocódigo para ver si un número es primo <return true> por <return false> y <return numero == 2> por <return numero >= 2>.

Citar
me equivoqué al expresarla, no quería decir una potencia de dos, sino una potencia de base 2.
Creo que sigue sin ser eso :xD. Creo que lo que quieres decir no es "una potencia de base 2 elevada a un número primo, menos 1, da como resultado otro número primo" sino que los números primos de Mersenne son los números primos que resultan de elevar un 2 a una potencia prima y restarle 1. Pero no todos cumplen tu suposición como he mostrado antes por ejemplo con el 11.

Citar
Luego en la función EsPrimo, he quitado los else como me dijiste, ya que es cierto lo que dices, no había caído. Y he aunque he añadido otro if con el 7 sigue sin ser correcta porque siempre me dará error al escribir múltiplos de los números primos, como es el caso del 11, 13... así que no tengo ni idea de como hacerlo, ya que de la forma que dice storing Manolo si que sé, pero en el ejercicio me piden que lo averigüe sin contar los divisores... ayuda!!
En lugar de empezar dividiendo por 1 (que siempre va a ser divisible) y terminar dividiendo por el propio número (que siempre va a ser divisible) y comprobar que para que sea primo se tiene que poder dividir exactamente por 2. Reduce las iteraciones innecesarias. Si el 1 siempre es divisible y el propio número también haz:

para i := 2 hasta numero-1
   si numero % i == 0
       return false
   fin si
fin para
return numero >= 2

Este pseudocódigo te sirve para una función que indica si el número es primo sin contar los divisores y teniendo en cuenta que el 2 es el primer primo.

Cita de: string Manolo en 17 Mayo 2019, 10:41 AM
La formula que está en main es la que saqué de wikipedia. Tenia un problema con los resultados que no coincidian, concretamente a partir del 3 numero primo que me daba 9 y en wikipedia me salia que era 31 cambie mi función Potencia por pow en el main para ver si implementara mal la funcion y todos los resultados coincidian, primos y perfectos. Entonces arreglé mi función Potencia y los resultados eran los mismos que con pow.
Respecto a esto, tenemos el desarrollo de la wikipedia: https://es.wikipedia.org/wiki/N%C3%BAmero_perfecto en la sección de "Son Números Triangulares".
Según lo que me dices de que tus resultados son los mismos, tenemos la siguiente tabla:

NP: Numeros primos
NPX: Numeros primos generadores de los numeros primos de Mersenne
NPerfecto: Numeros perfectos usando los NP
NPerfectoX: Numeros perfectos usando los NPx
NPerfectoO: Numeros perfectos originales

NP  NPX    NPerfecto                              NPerfectoX = NPerfectoO
2     2         6                                             6
3     3         28                                           28
5     5         496                                         496
7     7         8128                                       8128
11   13       2096128                                 33550306
13   17       33550306                               8589869056
17   19       8589869056                           137438691328
19   31       137438691328                       2305843008139952128
23   61       35184367894528                   2658455991569831744654692615953842176
29   89       144115187807420420           191561942608236107294793378084303638130997321548169216
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;