Ayuda en C que estoy reloco

Iniciado por Fumoffuw, 27 Mayo 2015, 05:36 AM

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

Fumoffuw

Hola amigos, tengo un ejercicio que tengo que sacar la cantidad de billetes de 200 100 50 20 10 5 2 1 y luego las monedas de 0.50, 0.10 y 0.05
Este es lo que he hecho en C aunque falta pulir un poco agregando algunos ifs

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

using namespace std;

int main()
{
   string nombre;
   int b200,b100,b50,b20,b10,b5,b2,b1,b05,b01,b005;
   float n;
   scanf("%f",&n);

   b200=n/200;
   printf("La cantidad de billetes de 200 es : %d\n",b200);
   n=n-200*b200;

   b100=n/100;
   printf("La cantidad de billetes de 100 es : %d\n",b100);
   n=n-100*b100;

   b50=n/50;
   printf("La cantidad de billetes de 50 es : %d\n",b50);
   n=n-50*b50;

   b20=n/20;
   printf("La cantidad de billetes de 20 es : %d\n",b20);
   n=n-20*b20;

   b10=n/10;
   printf("La cantidad de billetes de 10 es : %d\n",b10);
   n=n-10*b10;

   b5=n/5;
   printf("La cantidad de billetes de 5 es : %d\n",b5);
   n=n-5*b5;

   b2=n/2;
   printf("La cantidad de billetes de 2 es : %d\n",b2);
   n=n-2*b2;

   b1=n/1;
   printf("La cantidad de billetes de 1 es : %d\n",b1);
   n=n-1*b1;

   b05=n/0.50;
   printf("La cantidad de monedas de 0.50 es : %d\n",b05);
   n=n-0.50*b05;

   b01=n/0.10;
   printf("La cantidad de monedas de 0.10 es : %d\n",b01);
   n=n-0.10*b01;

   b005=n/0.05;
   printf("La cantidad de monedas de 0.05 es : %d\n",b005);


system("pause");
return(0);
}


El problema esta al final en la parte de los decimales (las monedas); si por ejemplo de entrada pongo el número 11.55 de salida me da los valores correctos en la parte de las monedas.
Pero si por ejemplo pongo otro numero por ejemplo 1.55 u algun otro numero siempre me da salidas incorrectas y no entiendo porqué.
Si alguien me da una mano lo agradeceria bastante que le he estado dando muchas vueltas en la parte de las monedas.

Mod: Lod códigos deben ir en etiquetas GeSHi

engel lex

creo... que es un problema de precisión... su usas el debugger de tu ide lo verás...

lo que debes hacer es usar double en lugar de float y la lectura la haces con "%lf" en lugar de "%f"
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

Fumoffuw

Amigo eres un genio!
En la parte de
float n;
scanf("%f",&n);


cambie float a double y %f a %lf y si me dió los resultados correctos(con el numero 1.55), pero cuando intenté con otros numeros todavia me salen errores.
No tenia mucha idea de eso de la presicion ya que llevo unos 2 meses estudiando y solo me dediqué a estudiar los algoritmos y el lenguaje en si.
Alguna manera de arreglar para que me acepten la mayoria de numeros posibles?

engel lex

el problema con los numeros flotantes es que ellos están representados como

(-1)s * c * be

donde s es 1 bit para el signo, c es el coeficiente, b es la base y e el exponente

en decimal es una nomenclatura cientifica normal
(-1)0*123*10-1 tambien se puede leer como 123x10e-1 que sería 1,23

esto normalmente en programación está en binario (base 2) y para float (32bit) son 24 bits para coeficiente y 6 bits de exponente si no me equivoco (siempre es uno para signo)... así que el numero puede no ser siempre exacto...

con double este rango se agranda a 64 bits, 53 para cociente, 10 para exponente y 1 para signo (creo que es así, no recuerdo exactamente), lo que da numeros de "doble precisión"

ahora dime

con cuales numeros falla?

sabes usar el debugger de tu ide? (por el conio.h creo que debe ser dev c++)
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

Fumoffuw

He probado con bastantes numeros y la gran mayoria falla en la ultima parte que es la de 0.05
Si pongo numeros como 76.35 , 123.75 ,35,25 no me cuenta la parte de 005 me sale
"La cantidad de monedas de 0.05 es : 0 "
Pero algo curioso si pongo 123.15 (que se parece bastante a 123.75) me sale :
"La cantidad de monedas de 0.05 es : 1 "

Yo uso el codeblocks y no uso debugger, aunque tengo una idea vaga de que es eso.

engel lex

una solución que no quería tocar por ser un poco chapuzera pero puede arreglar el problema es bajar la presición del calculo... es decir...


en lugar de

Código (cpp) [Seleccionar]
b05=n/0.50;
    printf("La cantidad de monedas de 0.50 es : %d\n",b05);
    n=n-0.50*b05;

    b01=n/0.10;
    printf("La cantidad de monedas de 0.10 es : %d\n",b01);
    n=n-0.10*b01;

    b005=n/0.05;
    printf("La cantidad de monedas de 0.05 es : %d\n",b005);


hacemos

Código (cpp) [Seleccionar]

    n *= 100;//los decimales pasan a ser enteros
    b05=n/50;
    printf("La cantidad de monedas de 0.50 es : %d\n",b05);
    n=n-50*b05;

    b01=n/10;
    printf("La cantidad de monedas de 0.10 es : %d\n",b01);
    n=n-10*b01;

    b005=n/5;
    printf("La cantidad de monedas de 0.05 es : %d\n",b005);


de resto ahorita estoy muy oxidado en c (ando pendiente de muchas cosas ahorita) y no sabría como resolver


por cierto, el debug es algu muy simple pero util para programar... en code blocks sería, vas a la pestaña debug, y le das click en debug project (o similar), allí arrancará el programa, pero no hará nada, verás en el editor como la primera linea de ti main estará resaltada de un color, esa es la linea que se va a ejecutar a continuacion, deben tener unos botones para avanzar paso a paso, saltar, etc... busca la ventana "watches" o "variables" para ver las variables del programa en tiempo real

para más info seguro en youtube hay bastante al respecto :P
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

Peregring-lk

#6
Cuando tú trabajas con números de precisión flotante, tienes que tener en cuenta bastantes cosas, pero por norma general, es como dice engel lex, problemas de precisión. Ejemplo bastante ilustrador:


printf("%f", 0.5);


Verás que imprime 0.5 sin problemas. Pero ahora, incrementale la precisión de impresión:


printf("%.20f", 0.5);


Ahora hemos imprimido 0.5 con una precisión de 20 cifras decimales, y seguramente verás un valor como: 0.05000000000000000278. Es decir, en realidad `0.5` representa a un número un poquito más grande, ya que es imposible garantizar precisión exácta cuando se tratan de números flotantes (verás, de todas formas, que el error es muy muy muy pequeño).

Pues eso es fundamentalmente lo que te está pasando, que esas diferencias de precisión te están jugando una mala pasada. En el caso concreto de 1.55, si imprimes el valor que `scanf` ha leído:


float n;
scanf("%f",&n);
printf("%.20f", n);


Te imprimirá algo como: 1.54999995231628417969 (un valor ligeramente menor a 1.55; y por eso te devuelve 0 en la última división). Incrementar la precisión ayuda, pero no resuelve el problema:


double n;
scanf("%lf",&n);
printf("%.20f", n);


Ahora a mí me imprime algo como: 1.55000000000000004441 (un número ligeramente superior). Pero como verás, sigue sin ser exáctamente el mismo número.

Por otro lado, en ésta división (supón que `n` es `float` como en tu caso original):


b05=n/0.50;


Si escribes un "literal de número flotante", como `0.50`, por defecto, dicho literal `0.50` tiene tipo `double`. Por tanto, `n` se transforma en un `double` antes de hacer la división. Luego, se hace una división entre `double`s y se transforma el valor en un entero para asignarlo a `b05`. Para realizar una división `float` y no `double`, debes especificar que tu literal lo es: `0.50f`, y así no habrá conversiones de `n`.

Ésta conversiones implícitas puede incrementar (¡o disminuir, no se sabe!) la precisión, añadiendo más caos al asunto.

Si la precisión es fija, trabaja con números enteros y te quitas de en medio a los flotantes, tal y como propuso engel lex:


int main()
{
   int b200,b100,b50,b20,b10,b5,b2,b1,b05,b01,b005;
   float naux;
   int n;

   scanf("%f", &naux);
   n = naux * 100;
   
   b200=n/20000;
   printf("La cantidad de billetes de 200 es : %d\n",b200);
   n=n-20000*b200;

   b100=n/10000;
   printf("La cantidad de billetes de 100 es : %d\n",b100);
   n=n-10000*b100;

   // etc...
   
   b1=n/100;
   printf("La cantidad de billetes de 1 es : %d\n",b1);
   n=n-100*b1;
   
   b05=n/50;
   printf("La cantidad de monedas de 0.50 es : %d\n",b05);
   n=n-50*b05;
   
   b01=n/10;
   printf("La cantidad de monedas de 0.10 es : %d\n",b01);
   n=n-10*b01;
   
   b005=n/5;
   printf("La cantidad de monedas de 0.05 es : %d\n",b005);

   system("pause");

   return 0;
}


O, para rematar la faena, hazlo con un bucle:


#include <stdio.h>

int main()
{
   float faux;
   int n, naux;
    unsigned i;
   
   scanf("%f", &faux);
   n = faux * 100;
       
   int vec[] = { 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5 };
   int prec[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2 };
   
   for (i = 0; i < 11; ++i) {
       naux = n / vec[i];
       
       printf("La cantidad de monedas de %.*f es %d\n", prec[i], vec[i] / 100.0, naux);
       n = n - vec[i] * naux;
   }
   
   return 0;
}


Explicación de mi `printf`: Si yo en el `printf` pusiera algo como: "%f" sin más, se mostraría en la salida algo como:


La cantidad de monedas de 200.000000 es 4
La cantidad de monedas de 100.000000 es 1
// etc...
La cantidad de monedas de 0.050000 es 4


Por que por defecto, la precisión de un `printf` es de 6 cifras decimales. Para "personalizar" la precisión, existe el modificar `.*` que permite pasarle la precisión como parámetro, antes del número que quiero imprimir.

Por ese motivo, he creado otro vector, llamado `prec`, que indica la precisión que quiero para cada elemento de la lista (ninguna para los números mayores a 0.5, de 1 cifra para 0.5 y 0.1, y de dos para 0.05), y ya se imprime bonito:


La cantidad de monedas de 200 es 4
La cantidad de monedas de 100 es 1
// etc...
La cantidad de monedas de 0.05 es 4

Fumoffuw

Muchas gracias a los dos por responder, yo me acuerdo que leí eso de las precisiones (no me acuerdo de donde la verdad) pero no le tomé mucha importancia, ahora veo que si importa  ;D
Yo estudio C de un libro que se llama "Programacion en C"  de Luis Joyanes e Ignazion Zahonero que el profesor de la facultad nos dijo que lo compremos,en el índice busqué sobre la precision pero no lo encontré, la verdad es que el libro no me gusta mucho, siento que no da las ideas tan claras.
Me recomendarian algun libro o de algún lugar para repasar estas partes teóricas lo agradecería bastante

Peregring-lk


Hay tantas situaciones que no creo que exista ningún libro lo suficientemente bueno, y para los detalles "de nivel medio", cualquiera te puede valer.

Lo más importante es saber "qué está pasando" en tu programa, y conocer bien `printf` es un buen comienzo, así que repasa todas sus opciones con detalle. ¡O utilizar un debuggeador como `gdb`!