Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: ciquee en 16 Mayo 2019, 20:42 pm



Título: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 16 Mayo 2019, 20:42 pm
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:

Código:
#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!!


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 17 Mayo 2019, 00:11 am
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
Código:
potencia de 2 := 4
numero primo := 2
4² - 1 = 15 = 3*5 -> 15 no es primo

Siguiente problema. Esa función <esPrimo()>...
Código:
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
  1. if(x == a)
  2.    return 1;
  3. else if(x == b)
  4.    return 2;
  5. else
  6.    return 3;
  7.  
  8. // Se puede dejar en
  9. if(x == a) return 1;
  10. if(x == b) return 2;
  11. 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
  1. // Cuidado que en el prototipo tienes un parametro y en la implementacion otro (unsigned int != unsigned long long)
  2. // Funcion que calcula la potencia indicada en el parametro de 2, es decir, 2^exponente
  3. 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
  1. unsigned long long Potencia2(int exponente); // dejar claro que esa funcion calcula potencias de 2
  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:
Código:
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
Código:
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


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: @XSStringManolo 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
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. unsigned long long Potencia (unsigned int Base, unsigned int Exponente)
  5. {
  6. unsigned long long potencia = 1;
  7. int i;
  8. if (Exponente==0) return 1; //Error.
  9. else
  10. {
  11. for(i=0;i<Exponente;++i)
  12. {
  13. potencia*=Base;
  14. }
  15. }
  16. return potencia;
  17. }
  18.  
  19. bool EsPrimo (unsigned long long Numero)
  20. {
  21. int Contador = 0;
  22. bool esPrimo = false;
  23. for (int i=1;i<(Numero+1); ++i)
  24. {
  25. if(Numero%i==0)
  26. {
  27. ++Contador;
  28. }
  29. }
  30. if(Contador!=2)
  31. {
  32. //Mete un cout por aqui de Numero si quieres para ver el numero que no es primo.
  33. return esPrimo;
  34. }
  35. else
  36. {
  37. esPrimo = true; //Mete un cout por aqui de Numero si quieres, para ver el numero que si es primo.
  38. return esPrimo;
  39. }
  40. }
  41.  
  42. int main()
  43. {
  44. unsigned int Numero = 1; //Numero a comprobar si es primo.
  45. unsigned int Contador = 1; //Contador para bucle do while.
  46. unsigned long long NumeroPrimoM;
  47. unsigned long long NumeroPerfecto;
  48. do {
  49.   if ( EsPrimo(Numero) ) //Funcion EsPrimo retorna true si el valor de Numero es primo.
  50.   {
  51.   NumeroPrimoM = Potencia(2,Numero) -1; //Formula para sacar primo de Mersenne.
  52. //Mete un cout aqui de NumeroPrimoM si quieres conocer a los primos de Mersenne.
  53.   NumeroPerfecto = (NumeroPrimoM*(NumeroPrimoM +1))/2; //Formula para sacar numero perfecto utilizando numero primo de Mersenne.
  54.   cout << Contador << " - Numero Perfecto: " << NumeroPerfecto << endl;
  55.   ++Contador; //Para el bucle while y seguir calculando hasta 10.
  56.   ++Numero;//Probemos si el siguiente numero es primo.
  57.     }
  58.  
  59.   else
  60.   {
  61.   ++Numero; //Si el valor en Numero no es primo, prueba el siguiente.
  62.   }
  63.  
  64. } while (Contador != 11);
  65. return 0;
  66. }
Si no entiendes algo pregunta.


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 17 Mayo 2019, 08:55 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
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. unsigned long long Potencia (unsigned int Base, unsigned int Exponente)
  5. {
  6. unsigned long long potencia = 1;
  7. int i;
  8. if (Exponente==0) return 1; //Error.
  9. else
  10. {
  11. for(i=0;i<Exponente;++i)
  12. {
  13. potencia*=Base;
  14. }
  15. }
  16. return potencia;
  17. }
  18.  
  19. bool EsPrimo (unsigned long long Numero)
  20. {
  21. int Contador = 0;
  22. bool esPrimo = false;
  23. for (int i=1;i<(Numero+1); ++i)
  24. {
  25. if(Numero%i==0)
  26. {
  27. ++Contador;
  28. }
  29. }
  30. if(Contador!=2)
  31. {
  32. //Mete un cout por aqui de Numero si quieres para ver el numero que no es primo.
  33. return esPrimo;
  34. }
  35. else
  36. {
  37. esPrimo = true; //Mete un cout por aqui de Numero si quieres, para ver el numero que si es primo.
  38. return esPrimo;
  39. }
  40. }
  41.  
  42. int main()
  43. {
  44. unsigned int Numero = 1; //Numero a comprobar si es primo.
  45. unsigned int Contador = 1; //Contador para bucle do while.
  46. unsigned long long NumeroPrimoM;
  47. unsigned long long NumeroPerfecto;
  48. do {
  49.   if ( EsPrimo(Numero) ) //Funcion EsPrimo retorna true si el valor de Numero es primo.
  50.   {
  51.   NumeroPrimoM = Potencia(2,Numero) -1; //Formula para sacar primo de Mersenne.
  52. //Mete un cout aqui de NumeroPrimoM si quieres conocer a los primos de Mersenne.
  53.   NumeroPerfecto = (NumeroPrimoM*(NumeroPrimoM +1))/2; //Formula para sacar numero perfecto utilizando numero primo de Mersenne.
  54.   cout << Contador << " - Numero Perfecto: " << NumeroPerfecto << endl;
  55.   ++Contador; //Para el bucle while y seguir calculando hasta 10.
  56.   ++Numero;//Probemos si el siguiente numero es primo.
  57.     }
  58.  
  59.   else
  60.   {
  61.   ++Numero; //Si el valor en Numero no es primo, prueba el siguiente.
  62.   }
  63.  
  64. } while (Contador != 11);
  65. return 0;
  66. }
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.


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: @XSStringManolo en 17 Mayo 2019, 09:42 am
+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.


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 17 Mayo 2019, 10:25 am
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.



Título: Re: Un programa con varias funciones y sin entradas
Publicado por: @XSStringManolo 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.


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 17 Mayo 2019, 16:32 pm
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!!


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: @XSStringManolo en 17 Mayo 2019, 18:03 pm
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;



Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 17 Mayo 2019, 22:33 pm
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:
Código:
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.

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:
Código:
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


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 18 Mayo 2019, 17:47 pm
Buenas!
YreX-DwX no entiendo muy bien el pseudocódigo que me pones para EsPrimo:
Código:
para i := 2 hasta numero-1
    si numero % i == 0
        return true
    fin si
fin para
return numero == 2

Acabando con return == 2 no devolverá siempre "2"?
¿Me la podrías explicar un poco más porfa?

Bueno, de momento he puesto la que decía string Manolo, que yo también sabía (aunque es contando los múltiplos y la tengo que cambiar) para probar el funcionamiento o no funcionamiento del programa. Y no sé que es lo que está mal pero este es mí código
Código:
#include <iostream>
#include <math.h>

using namespace std;

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

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

while (perf < 10){

if (EsPrimo(primo)){
mersenne = Potencia(primo)-1;

if (EsPrimo(mersenne)){
perf = mersenne * Potencia(primo-1);
cout << perf << endl;
perf = perf + 1;
}
}
primo = primo + 1;
}

cin.get();
return 0;
}

// Esta funcion nos dice si un numero es primo o no
bool EsPrimo (unsigned long long num) {

int contador = 0;
bool es_primo = false;

for (int i=1; i < (num + 1); ++i)
{
if (num % i == 0)
{
contador++;
}
}

if (contador != 2)
{
return es_primo;
}

else
{
es_primo = true;
return es_primo;
}
}


// Esta función "Potencia" eleva una base entera (2) a una potencia entera y devuelva un 'unsigned long long
unsigned long long Potencia (int exponente){
unsigned long long res = 2;

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

return res;
}


Y no me saca nada más que los dos primeros números perfectos usando los primos de Mersenne, o sea el 6 y el 28 nada mas ¿que es lo que tengo mal?


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 18 Mayo 2019, 19:50 pm
Citar
Buenas!
YreX-DwX no entiendo muy bien el pseudocódigo que me pones para EsPrimo:
Código:
para i := 2 hasta numero-1
    si numero % i == 0
        return false
    fin si
fin para
return numero >= 2
¿Me la podrías explicar un poco más porfa?
Acabo de ver que le di la vuelta a lo que es ser primo en esa función por lo que no es correcta, ahora te la corrijo (está corregida en la cita)
Un número es primo si solo es divisible por si mismo y la unidad (no se considera al 1 primo). Entonces en vez de contar los divisores desde 1 hasta n y comprobar si el número de divisores es 2 (es primo) o es >2 (no primo); lo que hacemos es evitar esas dos divisiones. En lugar de empezar en 1 hasta n, empezamos en 2 hasta n-1. De esta forma se define como número primo todo aquel número que no es divisible por ningún número entre 2 y n-1 (excepto el 2 que es divisible por 2 y es primo).
El 1, en cambio, no es primo y el bucle no llega a ejecutarse para números < 3. Entonces en caso de que el bucle no se ejecute (esto sucede si los números son 1 o 2) tenemos que el 1 no es primo y el 2 sí.
Para tratar esa excepción usaremos <return (numero >= 2)> (date cuenta de que es una expresión booleana cuyo valor siempre es true/false, no son asignaciones).
Funcionamiento:
Se ejecuta el bucle (para números > 2) y si encuentra un divisor devuelve <false> (fallo mío que puse <true> lo voy a corregir en los otros mensajes) .
Si no encuentra un divisor podemos tener 2 motivos:
  • El número es < 3: {0, 1, 2} en cuyo caso el único primo es el 2
  • El número es > 2 y es primo: {3, 5, 7, 11, ...}
Entonces con la condición <return (numero >= 2)> obtendremos <true> (para el 2 y todos los primos) y <false> (para el 0 y el 1). Ahora sí está correcta la función y disculpas por el error... :-X

Citar
Y no me saca nada más que los dos primeros números perfectos usando los primos de Mersenne, o sea el 6 y el 28 nada mas ¿que es lo que tengo mal?
Eso es porque estás usando la variable <perf> para guardar la cantidad de números perfectos que llevas y el número perfecto actual. Entonces en el momento que el número perfecto supera el 10 (28 en este caso) termina. Usa dos variables distintas, una para el número perfecto y otra para la cantidad de números perfectos que llevas.


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 20 Mayo 2019, 21:10 pm
Por fin lo conseguí!!í Muchas gracias!! Aunque solo me saca 8 números perfectos, pero a todos los compañeros les pasa igual, del 7º al 8º tarda bastante, igual si lo dejo mucho tiempo mas saca el 9º y el 10º o igual mi ordenador no es potente ni para eso! jajja.

Bueno, ahora estoy con otro ejercicio que lo tengo casi casi, o eso creo, del mismo estilo, aunque sin formulas ni nada, solo que se han de usar mas funciones para estructurarlo. El enunciado me pide esto:

Realiza un programa en C++ que lea números enteros de un fichero y nos diga de cada uno de ellos si es primo o no lo es, utilizando en este la función EsPrimo que hiciste para un ejercicio anterior. El programa principal debe seguir
el siguiente esquema:

Código:
void AnalizarFichero(string nombre);
int main (void)
{
int num;
MostrarPresentacionPrograma ();
num = PedirNumeroPositivo ();
if (EsPrimo (num) )
cout << "El numero es primo.\n";
else
cout << "El numero NO es primo.\n";
return 0;
}
void AnalizarFichero(string nombre)
{
// Abrir Fichero
...
// Comprobar la correcta apertura del
// fichero
...
// Mientras sea posible leer
// un entero num del fichero
...
if (EsPrimo (num) )
{
cout << "El numero " << num;
cout << " es primo.\n";
}
else
{
cout << "El numero " << num;
cout << " NO es primo.\n";
}
// Cerrar Fichero
return;
}

Y la salida debería ser algo así:
Este programa determina si los numeros enteros positivos de un fichero son o no primos
- Dame nombre del fichero: enteros.dat
- El numero 23 es primo
- El numero 6 NO es primo
- El numero 3 es primo
- El numero 27 NO es primo
- El numero 20 NO es primo

Vale, y ahora va lo que yo tengo hecho:

Código:
#include <iostream>
#include <fstream>

using namespace std;

void AnalizarFichero(string);
int PedirNumeroPositivo (int);
bool EsPrimo(int);
void MostrarPresentacionPrograma (void);

int main (void) {

int num;
MostrarPresentacionPrograma ();
void AnalizarFichero (string nombre);
num = PedirNumeroPositivo (num);
if (EsPrimo (num) == 1)
cout << "El numero es primo.\n";
else
cout << "El numero NO es primo.\n";

cin.get();
return 0;
}


void AnalizarFichero(string nombre) {
ifstream archivo;
string nombreArchivo;

cout << "Introduzca el nombre del archivo: " << endl;
getline (cin,nombreArchivo);

archivo.open (nombreArchivo.c_str());

if(!archivo){
cout << "No se pudo abrir el archivo" << endl;
}

while (!archivo.eof())
{

archivo.close ();
return;
}


int PedirNumeroPositivo(int num) {
string archivo;

archivo >> num;
}

return 0;
}


int MostrarPresentacionPrograma (int){

cout << "Este programa determina si los numeros enteros positivos de un fichero son o no primos" << endl;

return num;
}


bool EsPrimo (int num) {
bool es_primo = false;

for (int i = 2; i <= num-1; i++){
if (num % i == 0){
return false;
}
}

return num >= 2;
}

Creía que le había pillado ya el truquillo a trabajar con varias funciones, pero cuando entran en juego más de 2 me pierdo. Además de que me lio a la hora de declararlas, y no sé como hacerlo bien, por ejemplo aquí seguro que tengo mal alguna (espero que no todas!). En la función PedirNumeroPositivo no tengo ni idea de como hacerlo, teniendo en cuenta que se lo pedimos a un archivo, y como lo he hecho no puede ser porque la función no conoce a "archivo".

Espero que me podáis orientar un poco por favor!!
Gracias!!


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 21 Mayo 2019, 06:30 am
Para problemas diferentes mejor abrir un tema nuevo Por si a alguien más le interesa uno de los dos temas...
Lo primero que tienes que pensar es qué funciones quieres usar. Es decir, piensa quiero una función que haga tal cosa y luego piensa cómo implementarla, por ejemplo, quiero una función que me diga si el fichero se pudo abrir correctamente.
  • Qué necesito? Pasarle el nombre del fichero o el propio fichero (yo diría que mejor el nombre).
Código
  1. <retorno> ficheroAbiertoCorrectamente(string nombre_fichero);
Ahora miramos el retorno.
  • Qué va a hacer la función? Dos posibilidades:
- El fichero se abre correctamente.
- El fichero no se abre correctamente.
Idea 1:
Código
  1. bool ficheroAbiertoCorrectamente(string nombre_fichero);
  2. // Comprueba si se abrio bien y devuelve true si se abrio bien o false si no se abrio
  3. // Problema: Tenemos que abrir el fichero en la funcion para comprobar si se abrio bien y al salir de la funcion volver a abrirlo otra vez
  4.  
  5. ifstream abrirFichero(string nombre_fichero);
  6. // Comprueba si se pudo abrir el fichero y en caso de que si, lo devuelve abierto
  7. // Problema: y si no lo pudo abrir? Tendremos que hacer que el programa termine si no se pudo abrir
Si quieres puedes pensar tu propia alternativa, no tiene que ser una de esas dos, pero es para que te hagas una idea. Haz eso con cada función que vayas a crear. Piensa en grande, es decir, piensa en que cada función tiene que hacer una cosa específica y de la mejor forma posible.

Un truco es escribir el <main> de forma que se entienda a simple vista, por ejemplo:
Código
  1. int main(){
  2.    fichero = abrirFichero();
  3.    numero = leerNumero();
  4.    if(esPrimo(numero))
  5.        cout << numero << " es primo" << endl;
  6.    else
  7.        cout << numero << " no es primo" << endl;
  8. }
Y en base a eso crear las funciones añadiendo los parámetros que veas que necesitas, poniendo los retornos que necesitas, etc.
Tampoco te pases con las funciones, es decir, no empieces a meter una función dentro de otra y esta dentro de otra... Porque se hará demasiado lioso y no te valdrá la pena encapsular tanto. Tienes que encontrar el término medio. Piensa que una función es un trozo de código que puedes usar muchas veces en diferentes programas. Haz funciones que sean reutilizables.
Por ejemplo, puedes pensar en hacer una función que te muestre por pantalla si un número es primo o no, pero... y si en algún momento quieres saber si el número es primo pero no quieres mostrarlo por pantalla? (como en tu ejercicio anterior). Pues mejor hacer una función que te diga si es primo o no, sin mostrar nada y tú verás en cada situación si quieres mostrar por pantalla el resultado obtenido o no.

Comenta los avances que consigas empleando esta técnica y cuando pueda te seguiré ayudando. Suerte :-X


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 22 Mayo 2019, 21:06 pm
Buenas! Gracias YreX-DwX! y perdón por no abrir un nuevo tema, pero como es un ejercicio que trata de lo mismo que el anterior... no lo volveré a hacer!

Con tu explicación he entendido más o menos lo de los retornos y las funciones que quiero que haga cada función, aunque en este ejercicio está claro las funciones a utilizar porque me lo piden en el enunciado.
- La función MostrarPresentacionPrograma creo que esta claro que debe ser void ya que no nos devuelve nada, solo nos tiene que mostrar los "cout".
- La función AnalizarFichero qué creo que también puede ser void ya que necesitamos que nos abra el fichero solamente.
- La función PedirNumeroPositivo (que más bien se debería llamar CogerNumeroPositivo) ya que los va a extraer del fichero, la cual debe retornar un int.
- Y la función EsPrimo, la cual ya tenemos, y será bool.

Vale, la función EsPrimo ya la tengo, y las demás por más vueltas que le dé no consigo hacerlas. Además, la función AnalizarFichero me abre el fichero pero también me lo cierra, no sé cómo hacer para que lo deje abierto (porque podría obviar la linea de archivo.close() pero luego de pasarle la siguiente función PedirNumeroPositivo ¿cómo la cierro?).

Con la función PedirNumeroPositivo tampoco sé cómo proceder, ya que como tiene que ser independiente de las demás debería abrir el archivo dentro de esta para poder coger los números positivos. Y esto que yo he hecho como que no lo veo...

Código:
int PedirNumeroPositivo(int num) {
string archivo;

archivo >> num; // Guardamos en num un numero entero del fichero
}

return 0;
}

En cuanto a la función "MostrarPresentacionPrograma" bastaría con un cout que diga lo que va a hacer el programa ¿no? algo así...:

Código:
void MostrarPresentacionPrograma (){

cout << "Este programa determina si los numeros enteros positivos de un fichero son o no primos" << endl;

return 0;
}

Y luego una duda que me surge a la hora de hacer las funciones, mi profesor califica de "Mala práctica" el utilizar más de un Return en cada función, y en por ejemplo en la función EsPrimo (utilizada ya en el ejercicio anterior) he usado 2, pero no sabría como hacerla sin ambos ¿sabes porque es una mala práctica?


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: @XSStringManolo en 23 Mayo 2019, 01:53 am
Si declaras una función como void no puede retornar un valor y tu le tienes return 0 Si quieres que retorne usa int, short. bool o lo que necesites.
El tipo que ponga la funcion es lo que tiene que devolver.
En el caso de void no hay return.

Te voy a dejar codigos de ejemplos en un documento de apuntes que estoy haciendo. Así ves diversos métodos y como no abuso del return:

Código
  1. //Pasar parametros a funciones:
  2. void imprimirSuma(int sumando1, int sumando2)
  3. {
  4. cout sumando1+sumando2;
  5. }
  6.  
  7. int main()
  8. {
  9. imprimirSuma(3,5);
  10. return 0;
  11. }
  12.  
  13.  
  14. //Retornar Valores:
  15. int retornarSuma(int sumando1, int sumando2)
  16. {
  17. return sumando1+sumando2;
  18. }
  19.  
  20. int main()
  21. {
  22. int sum = retornarSuma(3,5);
  23. cout<<sum;
  24. return 0;
  25.  
  26.  
  27. //Pasar por punteros:
  28. void retornarSuma(int sumando1, int sumando2, int* retornarValor)
  29. {
  30. *retornarValor = sumando1+sumando2;
  31. }
  32.  
  33. int main()
  34. {
  35. int suma=0;
  36. retornarSuma(sumando1,sumando2, &suma)
  37. cout <<suma;
  38. return 0;
  39. }
  40.  
  41.  
  42. //Pasar por referencia:
  43. void retornarSuma(int sumando1, int sumando2, int& retornarValor)
  44. {
  45. retornarValor = sumando1+sumando2;
  46. }
  47.  
  48. int main()
  49. {
  50. int suma =0;
  51. retornarSuma(sumando1, sumando2, suma)
  52. cout << suma;
  53. return 0;
  54. }
  55.  
  56.  
  57.  
  58. //Pasar estructuras. Esto te lo dejo para que no te suene a chino si te lo piden en algun momento.
  59. struct ParametrosParaSumar
  60. {
  61. int a;
  62. int b;
  63. int resultado;
  64. };
  65.  
  66. void sumarNumeros(ParametrosParaSumar& parametros)
  67. {
  68. parametros.resultado = parametros.a + parametros.b;
  69. }
  70.  
  71. int main()
  72. {
  73. ParametrosParaSumar suma;
  74. suma.a = 3;
  75. suma.b = 6;
  76. suma.resultado = 0;
  77.  
  78. sumarNumeros(suma); //Se pasa suma por referencia
  79.  
  80. cout << suma.resultado;
  81. return 0;
  82. }
  83.  


Que funciones tienes que hacer que no te salen? Te ayudo.

Por cierto te recomiendo que vayas por adelantado a la clase? Así te sirve de repaso, entenderás lo que no te quedó claro en casa y podrás hacer preguntas a cerca de cosas que te surgan.
Si vas al día de la clase no te enterarás de nada de lo que te expliquen hasta que llegues a casa y te rompas los codos. A parte no habrás preguntado dudas que te van a surgir durante los ejercicios y no vas a encontrar la respuesta en casa. Solo te romperás la cabeza y perderás el tiempo.
Si haces esto un par de semanas verás como la constumbre de llevar las cosas por adelantado no se te pierde nunca. Podrás ayudar a los compañeros, estarás menos estresado y podrás tener una mejor relación con tu profesor al ver este que tienes interés, y sentirá que está haciendo las cosas bien motivando al alumnado. A parte de que podrás intimar mejor con la programación y dejarás de verla como un jodecabezas xD Dale una oportunidad ahora que aún estás al principio, lo agradecerás mucho cuando empieces con Plantillas, Clases, Metodos, Objetos... Porque son temas que se suelen dar practicamente juntos.

Te recomiendo un libro sencillo e interesante con explicaciones claras y concisas llamado Apress Learn C++ for Game Development 2014.

Después puedes ir a algo más teórico y extenso como C++ Primer fifth edition. O a algo mas práctico teórico como Programing Principles and Practice using C++.


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 23 Mayo 2019, 02:34 am
Citar
Y luego una duda que me surge a la hora de hacer las funciones, mi profesor califica de "Mala práctica" el utilizar más de un Return en cada función, y en por ejemplo en la función EsPrimo (utilizada ya en el ejercicio anterior) he usado 2, pero no sabría como hacerla sin ambos ¿sabes porque es una mala práctica?
Se considera mala práctica en ocasiones porque puede que se te olvide algún <return>. Para evitar esto se suele usar una variable de tipo <bool> (la que tú habías creado en tu código "es_primo" pero que no usabas en la función).
Código
  1. bool esPrimo(unsigned int numero){
  2.    bool es_primo = true; // suponemos que es primo
  3.    size_t i = 2;
  4.    while(i < numero and es_primo){ // mientras i < numero y numero sea primo
  5.        es_primo = (numero % i != 0); // es primo si el resto es distinto de 0
  6.        i++;
  7.    }
  8.    // llegas aqui cuando i == numero o cuando es_primo = false
  9.    return es_primo;
  10. }

La función para mostrar la presentación del programa está casi bien. Está bien que sea de tipo <void> pero las funciones de tipo <void> no retornan nada. Siempre pones un <return 0>  en todas las funciones y eso solo se pone en el <main>. No tiene sentido hacer funciones que siempre devuelvan 0 y menos si son de tipo <void>.

La función <AnalizarFichero()> es mejor que le añadas algo más como una de las opciones que te di en el mensaje anterior:
Citar
Código
  1. bool ficheroAbiertoCorrectamente(string nombre_fichero);
  2. // Comprueba si se abrio bien y devuelve true si se abrio bien o false si no se abrio
  3. // Problema: Tenemos que abrir el fichero en la funcion para comprobar si se abrio bien y al salir de la funcion volver a abrirlo otra vez
  4.  
  5. ifstream abrirFichero(string nombre_fichero);
  6. // Comprueba si se pudo abrir el fichero y en caso de que si, lo devuelve abierto
  7. // Problema: y si no lo pudo abrir? Tendremos que hacer que el programa termine si no se pudo abrir
Yo por ejemplo usaría la segunda opción. Si se abre el fichero correctamente, lo devuelve como parámetro y sino termina el programa con <exit()> (de <cstdlib>).

La función <leerNumero()> la haría que reciba el fichero y devuelva el siguiente valor a leer.
Código
  1. int leerNumero(ifstream &fichero);


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 23 Mayo 2019, 17:26 pm
Muchas gracias a los dos! Manolo me apunto tus apuntes y libros! Y gracias por el consejo, se hace lo que se puede, estoy haciendo la carrera ya un poco mayor y además soy deficiente visual así que me entero más buscando por mi cuenta y preguntando por aquí después de clase, no lo puedo hacer de otra manera... pero muchas gracias!

A ver, pues yo sigo atascado, porque mi principal bloqueo es al dividir en dos funciones las tareas de abrir un fichero, y leer de este mismo. Y es que por más que lo miro y le doy vueltas no sé hacer lo que me dices YreX-DwX, no sé como es eso de devolver como parámetro. Si me lo pudierais explicar... además luego como cierro el fichero?

Y respecto al resto de funciones a ver como están ahora, he hecho algún cambio pero no se...

Código:
#include <iostream>
#include <fstream>

using namespace std;

bool AnalizarFichero(string);
int PedirNumeroPositivo (int);
bool EsPrimo(int);
void MostrarPresentacionPrograma (void);

int main (void) {

int num;
MostrarPresentacionPrograma ();
bool AnalizarFichero (string nombre);
num = PedirNumeroPositivo (num);
if (EsPrimo (num) == 1)
cout << "El numero " << num << "es primo.\n";
else
cout << "El numero " << num << " NO es primo.\n";

cin.get();
return 0;
}


bool AnalizarFichero(string) {
ifstream archivo;
string nombreArchivo;

cout << "Introduzca el nombre del archivo: " << endl;
getline (cin,nombreArchivo);

archivo.open (nombreArchivo.c_str());

if(!archivo){
return 0;
}

else {
PedirNumeroPositivo(int num);
}

archivo.close ();
}


int PedirNumeroPositivo(int num) {
string archivo;

while (!archivo.eof())
{
archivo >> num;
}
}


void MostrarPresentacionPrograma (){
cout << "Este programa determina si los numeros enteros positivos de un fichero son o no primos" << endl;
}


bool EsPrimo (int num) {
bool es_primo = false;
for (int i = 2; i <= num-1; i++){
if (num % i == 0){
return false;
}
}

return num >= 2;
}

A ver qué me decís!!


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 23 Mayo 2019, 21:54 pm
No voy por orden, la verdad no sé por qué pero te voy comentando las funciones:
Citar
Código
  1. bool EsPrimo (int num) {
  2.    bool es_primo = false;  
  3.    for (int i = 2; i <= num-1; i++){
  4.       if (num % i == 0){
  5.           return false;
  6.       }
  7.    }
  8.    return num >= 2;
  9. }
En esta función estás creando una variable <bool es_primo = false> que no llegas a usar. Si la creas es para usarla y no usar más de 1 <return> en ese caso como ya te dije, la función quedaría así:
Código
  1. bool esPrimo(unsigned int numero){
  2.    bool es_primo = true; // suponemos que es primo
  3.    // for(size_t i = 2; i < numero and es_primo; ++i){ // se puede poner asi o como viene a continuacion
  4.    // el for o el while depende de si quieres/te dejan poner dos condiciones dentro del for
  5.    size_t i = 2;
  6.    while(i < numero and es_primo){ // mientras i < numero y numero sea primo
  7.        es_primo = (numero % i != 0); // es primo si el resto es distinto de 0
  8.        i++;
  9.    }
  10.    // llegas aqui cuando i == numero o cuando es_primo = false
  11.    return es_primo;
  12. }
Aquí ves que solo haces un <return> ya que usas la variable <es_primo> como condición de salida o de fin. En el momento que sabes que no es primo, terminas el bucle y retornas el valor que es <false> en ese caso. Si es primo hasta el final, retornas la misma variable que en este caso valdrá <true>.
La línea:
Código
  1. es_primo = (numero % i != 0);
Es lo mismo que poner:
Código
  1. if(numero % i == 0)
  2.    es_primo = false;
Por si así lo ves mejor.

En mi caso le estoy pasando como parámetro un <unsigned int numero>, es decir, que no tiene signo, por lo que siempre va a ser positivo. Si a esa función le pasas un <int> (puede ser negativo) te va a salir que cualquier número negativo es primo. Tenlo en cuenta. Esto lo puedes arreglar poniendo:
Código
  1. bool es_primo = num > 0;
  2. // donde pone
  3. bool es_primo = true;
Para considerar los negativos como no primos. Esto ya a tu gusto o al nivel de lo que te pidan.

Siguiente función:
Citar
Código
  1. int PedirNumeroPositivo(int num) {
  2.    string archivo;
  3.    while (!archivo.eof()){
  4.        archivo >> num;
  5.    }
  6. }
Aquí tienes varios problemas. Uno es que no puedes aplicar la función <eof()> a <archivo> que es un <string>. Además <num> no es algo que necesites pasar como parámetro. Y esa función retorna un <int> y ahí no retorna nada.
Para poder usar esta función, la función debe conocer el fichero (ifstream) <archivo>. Entonces eso necesitas pasarlo como parámetro. El <num> lo creas dentro de la función y lo retornas al finalizar esta.
Código
  1. int devolverNumero(ifstream &fichero){
  2.    int numero = 0; // le ponemos un 0 (o lo que queramos) para saber que cuando retorne ese valor es porque el fichero ha llegado a su fin
  3.    if(!fichero.eof())
  4.        fichero >> numero;
  5.    return numero;
  6. }
Esta función devuelve el siguiente número del fichero de entrada <fichero> o 0 si ha llegado al final del fichero. La posición en la que vas del fichero se guarda. Entonces cada vez que llames a esta función, devolverá el número siguiente al que retornó la última vez.
El tema de dónde cerrar el fichero te lo comento más abajo.

La siguiente función es la de <AnalizarFichero()>. Aquí tienes dos opciones que yo veo buenas y no muy complicadas:
  • Opción 1: Pasar el <ifstream> por referencia y devolver un <bool> de si se abrió correctamente o no.
Parámetros necesarios: ifstream &fichero (le podríamos pasar también el string con el nombre del fichero o se lo podemos pedir dentro de la función al usuario)
Retorno de la función: bool fichero_correcto
Código
  1. bool analizarFichero(ifstream &fichero){
  2.    string nombre_fichero;
  3.    bool fichero_correcto = true; // suponemos que se va a abrir bien...
  4.    // pedimos el nombre del fichero
  5.    fichero.open(nombre_fichero.c_str());
  6.    if(!fichero) // ...y si no es asi, cambiamos el valor a esa variable <fichero_correcto>
  7.        fichero_correcto = false;
  8.    return fichero_correcto;
  9. }
Si quieres pedir el nombre del fichero en el <main> y pasarlo como parámetro, te recomiendo que lo intentes tú. Incluso aunque no lo vayas a usar así, leyendo código no se aprende, se aprende escribiendo código porque ahí es dónde se ven los errores que comete uno y que en código ajeno no ve.
  • Opcion 2: Pasar el nombre como parámetro (o no pasar nada y pedirlo dentro de la función) y retornar un fichero abierto.
En este caso podemos hacerlo simple, recibimos el nombre como parámetro, creamos un <ifstream> con dicho nombre y lo devolvemos y se acabó.
Código
  1. ifstream abrirFichero(string nombre_fichero){
  2.    ifstream fichero(nombre_fichero.c_str()); // lo mismo que crear el fichero y hacer fichero.open(...)
  3.    // podemos hacer que si el fichero no es valido, termine el programa
  4.    if(!fichero)
  5.        exit(1); // exit termina el programa desde cualquier funcion en la que se ejecute. Pertenece a la libreria <cstdlib>
  6.    // y si no se cumple la condicion anterior, devolvemos el fichero
  7.    return fichero;
  8. }

También podemos pedirle nombres al usuario hasta que uno sea correcto:
Código
  1. ifstream abrirFichero(){
  2.    ifstream fichero; // aqui como no conocemos el nombre del fichero todavia usamos open(...) mas abajo
  3.    string nombre_fichero;
  4.    do{ // hacer esto de dentro...
  5.        // pedir nombre fichero y guardarlo en nombre_fichero
  6.        fichero.open(nombre_fichero);
  7.    }   while(!fichero); // ... mientras el fichero no se haya abierto
  8.    // llegamos aqui cuando por fin se ha abierto un fichero de entrada. Entonces lo devolvemos
  9.    return fichero;
  10. }

Puedes crear muchas alternativas más, como a ti se te ocurran. Así que te dejo que sigas investigando por tu cuenta. No te limites o copiar y pegar lo que yo he hecho porque así no vas a saber el porqué de cada cosa que hice, ni vas a ver los fallos que cometes al hacerlo tú.

Por último te dejo algún ejemplo de <main> para que veas como usar las funciones:
Código
  1. int main(){
  2.    // si le vamos a pasar el nombre del fichero como parametro, tendremos que declararlo aqui y pedirselo al usuario
  3.    // como abrir el fichero usando <ifstream abrirFichero()> (el ultimo ejemplo)
  4.    ifstream fichero = abrirFichero(); // sin parametros porque dentro de la funcion es donde le pediremos al usuario el nombre del fichero
  5.    // cuando estemos aqui el fichero ya esta bien abierto
  6.    // como sabemos segun la funcion <int devolverNumero(ifstream &fichero)> que hice arriba que retorna 0 cuando el fichero termina hacemos...
  7.    int numero = devolverNumero(fichero);
  8.    while(numero != 0){
  9.        cout << "El siguiente numero es: " << numero << endl;
  10.        if(esPrimo(numero)) // no hace falta poner == 1 o == true. Ya se entiende si no se pone nada que tiene que valer 1/true
  11.            cout << "El numero " << numero << " es primo" << endl;
  12.        else
  13.            cout << "El numero " << numero << " no es primo" << endl;
  14.        numero = devolverNumero(fichero);
  15.    }
  16.    // el fichero abierto es <fichero> entonces lo cerramos aqui
  17.    fichero.close(); // si se te olvida y no lo cierras tu, ya lo hace el programa al terminar
  18. }

Dale vueltas a todo esto que no es poco y practica. Es posible que me haya comido alguna palabra o me haya confundido al escribir algo pero no me apetece revisar todo el mensaje. Suerte :-X :-X


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: ciquee en 24 Mayo 2019, 12:17 pm
Nada, ya le puedo dar todas las vueltas que quiera que me da errores con la función AnalizarFichero y PedirNumeroPositivo. Yo no me limito a copiar y pegar, como bien dices para aprender hay que entender el código, pero no entiendo porque me da error, pongo en negrita los errores que me indica mi programa:

Código:
#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;

void MostrarPresentacionPrograma (void);
ifstream AnalizarFichero(string);
int PedirNumeroPositivo (ifstream);
bool EsPrimo(int);


int main (void) {

int num;
MostrarPresentacionPrograma ();
ifstream fichero = AnalizarFichero(string);
[b]num = PedirNumeroPositivo (ifstream);[/b]

while (num != 0){
if (EsPrimo (num) == 1)
cout << "El numero " << num << "es primo.\n";
else
cout << "El numero " << num << " NO es primo.\n";
[b]num = PedirNumeroPositivo(fichero);[/b]
}

fichero.close();
cin.get();
return 0;
}


ifstream AnalizarFichero(string nombreFichero) {
ifstream fichero;

cout << "Introduzca el nombre del fichero: " << endl;
getline (cin,nombreFichero);

fichero.open (nombreFichero.c_str());

if(!fichero){
exit (1);
}

return fichero;
}


int PedirNumeroPositivo(ifstream fichero) {
int numero = 0;

if(!fichero.eof())
fichero >> numero;

return numero;
}

void MostrarPresentacionPrograma (){
cout << "Este programa determina si los numeros enteros positivos de un fichero son o no primos" << endl;
}


bool EsPrimo (int num) {
for (int i = 2; i <= num-1; i++){
if (num % i == 0){
return false;
}
}

return num >= 2;
}

No he cambiado la función EsPrimo porque he estado probando con la que me dices y no me da bien algunos resultados, pero no pasa nada, dejo esta que tengo quitando la variable que no usaba.

Y también he probado a hacer la función AnalizarFichero de esta otra forma y nada...
Código:
bool AnalizarFichero(ifstream &fichero) {
string nombreFichero;
bool fichero_ok = true;

cout << "Introduzca el nombre del fichero: " << endl;
getline (cin,nombreFichero);

fichero.open (nombreFichero.c_str());

if(!fichero){
fichero_ok = false;
}

return fichero_ok;
}

Y respecto a a la función MostrarPresentacionPrograma ¿esta bien ahora? porque no entiendo muy bien para que sirve, ya que no es reutilizaba para otros programas ni nada, y me cuesta menos poner un cout con lo que hace el programa que llamar a la función... no se...


Título: Re: Un programa con varias funciones y sin entradas
Publicado por: K-YreX en 25 Mayo 2019, 08:24 am
El problema que tienes es que en el <main> estás pasando como parámetro el tipo de dato, cuando lo que tienes que pasar es el nombre del dato. El tipo solo se indica en el prototipo de la función y en su implementación.
Eso es algo muy muy básico.

En la función <analizarFichero(string)> si le estás pasando el nombre como parámetro, no pidas el nombre dentro de la función. Si lo vas a pedir dentro de la función no se lo pases como parámetro, no sirve de nada.
El <exit (1)> va sin espacio. Es una función que tiene un número como parámetro, no es lo mismo que un <return 1>.

En la función <pedirNumeroPositivo(ifstream)> tienes que pasar el fichero por referencia usando también &.

No te vuelvo a poner ejemplos de cada función porque ya lo hice en el mensaje anterior que publiqué.

Y sí, la función <mostrarPresentacionPrograma()> está bien. Es cierto que no tiene mucho sentido para un <cout> pero normalmente se suele usar para explicar el funcionamiento del programa o cómo hay que usarlo y en caso de que el usuario lo use mal pues se llama a la función de nuevo para que vea cómo se usa.