Perdonad que publique aquí mi problema, pero es una de las comunidades de programación en las que más confío y que más seguridad me da, además de que contestan muy bien.
Tengo este programa, el problema está en la funcion que devuelve el cambio. A veces dice, por ejemplo, si elijes 1 (0.70) e introduces una moneda de 2 euros, te dice que el cambio es de 1.30, pero te de vuelve 1$ una de 0.20 y una de 0.5. Este problema me lo da en el ordenador del salon (compilado con dev). Si lo pruebo en otro compilador dev también, pero con extensión .c (en el del salon, el conio2.h si lo compilo como c me da error) el error solo me lo da si elijo el 3 (0.45) y pagando con monedas de 0.05 me devuelve mal, y acepta monedas de mas.
LOS CONTROLES:
0-5 Elegir bebida
1-6 INTRODUCIR MONEDA 1$ 2$ 0.5$ 0.2$ 0.1$ 0.05$ (una vez elegida la bebida)
Probad esas dos combinaciones, pedid un 3 y pagad con monedas de 0.05 y pedid un 1 y pagad con una moneda de 2$
[code language="c"]#include <stdio.h>
#include <stdlib.h>
#include <conio2.h>
#define eleccion 30,4
#define rojo textcolor(12);
#define azul 9
#define blanco textcolor(15);
#define verde textcolor(10);
#define amarillo textcolor(14);
//FONDOS
#define fgris textbackground(7);
#define fmarron textbackground(6);
#define fazul 1
char name[][13]={"Cola","Refresco","Cerveza","Agua","Agua","Cocolatina"};
float precio[]={.75,.70,.60,.45,.90,.80};
int dos=50,uno=60,cincuenta=100,veinte=80,diez=60,cinco=100;
void pared(){
for(int x=0;x<30;x++){
for(int j=0;j<20;j++){
for(int i=1;i<4;i++){
fmarron;
printf(" ");
}//for i
fgris;
printf(" ");
fmarron;
printf(" "); printf(" "); printf(" ");
}//for j
printf(" ");
}//for x
}// pared
float menu(){
char seleccion;
int sel;
do{
seleccion=getch();
sel=atoi(&seleccion);
}while(sel>5 || sel<0);
textcolor(azul);
gotoxy(eleccion);
printf("Ha elegido %s",name[sel]);
return precio[sel];
}
float aceptar_monedas(float precio){
int in; //el valor numerico de la moneda introducida
char introducido; //la moneda que se introduce
float metido=0.0; //la cantidad que se ha metido hasta ahora
//---------- LO QUE FALTA POR INTRODUCIR ----------------//
gotoxy(30,8);
printf("Queda por introducir:");
gotoxy(58,8); verde; printf("Introducido: ");
gotoxy(52,8);
rojo;
printf("%.2f",precio);
gotoxy(70,8);
printf("%.2f",metido);
while(precio>0.0){
introducido=getch();
in=atoi(&introducido);
//-------Linea que borra el mensaje de moneda no valida---------//
gotoxy(30,6); // en caso de que existiera el mensaje de moneda no valida
printf(" "); //lo borramos nada más capturar la moneda siguiente
//-------Lo hacemos nada más capturar la moneda siguiente -----//
switch(in){
case 1:
uno++;
precio-=1.0;
metido+=1.0;
break;
case 2:
dos++;
precio-=2.0;
metido+=2.0;
break;
case 3:
cincuenta++;
precio-=0.5;
metido+=0.5;
break;
case 4:
veinte++;
precio-=0.2;
metido+=0.2;
break;
case 5:
diez++;
precio-=0.1;
metido+=0.1;
break;
case 6:
cinco++;
precio-=0.05;
metido+=0.05;
break;
default:
rojo;
gotoxy(30,6);
printf("Debe introducir una moneda valida!!"); //Línea a modificar para hacerlo estético
}
gotoxy(52,8);
rojo;
printf("%.2f",precio);
gotoxy(70,8);
printf("%.2f",metido);
}//while
return(-precio); //devuelve lo que ha introducido de más, es decir, cúanto se ha pasado del precio introducido
}//aceptar monedas
float dar_cambio(float cantidad){
int ent;
gotoxy(30,10);
if(cantidad>=1.0){
ent=(int)cantidad/1;
if(ent>=uno){
cantidad-=uno;
blanco; printf(" %d X ",uno);
amarillo; printf("1$ ");
}else{
uno-=ent;
cantidad-=ent;
blanco; printf(" %d X ",ent);
amarillo; printf("1$ ");
}//else
}//if
if(cantidad>=0.5){
ent=(int)(cantidad/0.5);
if(ent>=cincuenta){
cantidad-=(cincuenta*0.5);
blanco; printf(" %d X ",cincuenta);
amarillo; printf("0.50$ ");
}else{
cincuenta-=ent;
cantidad-=(ent*0.5);
blanco; printf(" %d X ",ent);
amarillo; printf("0.50$ ");
}
}
if(cantidad>=0.2){
ent=(int)(cantidad/0.2);
if(ent>=veinte){
cantidad-=(veinte*0.2);
blanco; printf(" %d X ",veinte);
amarillo; printf("0.20$ ");
}else{
veinte-=ent;
cantidad-=(ent*0.2);
blanco; printf(" %d X ",ent);
amarillo; printf("0.20$ ");
}
}
if(cantidad>=0.108){
ent=(int)(cantidad/0.1);
if(ent>=diez){
cantidad-=(diez*0.1);
blanco; printf(" %d X ",diez);
amarillo; printf("0.10$ ");
}else{
diez-=ent;
cantidad-=(ent*0.1);
blanco; printf(" %d X ",ent);
amarillo; printf("0.10$ ");
}//else
}//if
if(cantidad>=0.05){
ent=(int)(cantidad/0.05);
if(ent>=cinco){
cantidad-=(cinco*0.05);
blanco; printf(" %d X ",cinco);
amarillo; printf("0.05$ ");
}else{
cinco-=ent;
cantidad-=(ent*0.05);
blanco; printf(" %d X ",ent);
amarillo; printf("0.05$ ");
}//else
}//if
} //dar cambio
int main( )
{
float precio,cambio;
//pared();
precio=menu();
gotoxy(30,5);
verde;
printf("PRECIO: %.2f\n",precio);
cambio=aceptar_monedas(precio); //funcion que acepta monedas y escribe la cantidad restante
//--- Borrar cantidad restante por introducir --- //
gotoxy(52,8); // una vez llegados a este punto, ya no queda nada por introducir, y puesto que la funcion anterior..
printf("0.00"); //..muere antes de refrescar la cantidad a introducir, lo hacemos manualmente :P
gotoxy(30,9);
printf("Su cambio es: %.2f",cambio);
dar_cambio(cambio);
getch();
} [/code]
conoces elrincondelc ¿no?
Si no recuerdo mal este problema o uno parecido se resolvió hace tiempo.
Voy a compilarlo a ver si veo algo así rápidamente, saludos.
Lo tenía que haber visto antes sin hacer pruebas. Cachis, que lento soy.
Es el problema de siempre, nada de floats en C, dan problemas de redondeo, usa siempre doubles y fin del problema. resulta que un float 0.10 entre /0.5 da 1.999 que al truncar es 1, e ahí el problema.
Solución, redondear los floats(un poquito cutrecillo diría yo) o usar doubles.
He tenido que rehacer por completo tu forma de mostrar la información, la conio no es standar, no se de donde te pillaste la conio2, yo la he bajado de una página y no se ve un pirulo al ejecutar tu codigo. Te dejo aqui el mamotreto que he formado para poder jugar a tu mini juego de "vending" :D.
#include <stdio.h>
#include <stdlib.h>
#define eleccion 30,4
#include <math.h>
char
name[][13] = { "Cola", "Refresco", "Cerveza", "Agua", "Agua",
"Cocolatina" };
float ar_precio[] = { .75, .70, .60, .45, .90, .80 };
int dos = 50, uno = 60, cincuenta = 100, veinte = 80, diez = 60, cinco = 100;
float monedas[8]={0.0,1.0,2.0,0.5,0.2,0.1,0.05};
float menu() {
char seleccion;
int sel;
do {
seleccion = getchar();
getchar();
sel = atoi(&seleccion);
} while (sel > 5 || sel < 0);
printf("Ha elegido %s\n", name[sel]);
return ar_precio[sel];
}
float aceptar_monedas(float precio) {
int in; //el valor numerico de la moneda introducida
char introducido; //la moneda que se introduce
float metido = 0.0; //la cantidad que se ha metido hasta ahora
printf("Queda por introducir: ");
printf("%.2f\n", precio);
printf("Introducido: ");
printf("%.2f\n", metido);
while (precio > 0.0) {
introducido = getchar();
getchar();
in = atoi(&introducido);
switch (in) {
case 1:
uno++;
precio -= 1.0;
metido += 1.0;
break;
case 2:
dos++;
precio -= 2.0;
metido += 2.0;
break;
case 3:
cincuenta++;
precio -= 0.5;
metido += 0.5;
break;
case 4:
veinte++;
precio -= 0.2;
metido += 0.2;
break;
case 5:
diez++;
precio -= 0.1;
metido += 0.1;
break;
case 6:
cinco++;
precio -= 0.05;
metido += 0.05;
break;
default:
printf("Debe introducir una moneda valida!!\n"); //Línea a modificar para hacerlo estético
}
printf("Queda por introducir: ");
printf("%.2f\n", precio);
printf("Introducido: ");
printf("%.2f\n", metido);
}//while
return (-precio); //devuelve lo que ha introducido de más, es decir, cúanto se ha pasado del precio introducido
}//aceptar monedas
void dar_cambio(float cantidad) {
int ent;
if (cantidad >= 1.0) {
ent = (int) cantidad / 1;
if (ent >= uno) {
cantidad -= uno;
printf("%d X 1$\n", uno);
} else {
uno -= ent;
cantidad -= ent;
printf("%d X 1$\n", ent);
}//else
}//if
if (cantidad >= 0.5) {
ent = (int) (cantidad / 0.5);
if (ent >= cincuenta) {
cantidad -= (cincuenta * 0.5);
printf("%d X 0.50$\n", cincuenta);
} else {
cincuenta -= ent;
cantidad -= (ent * 0.5);
printf("%d X 0.50$\n", ent);
}
}
if (cantidad >= 0.2) {
ent = (int) (cantidad / 0.2);
if (ent >= veinte) {
cantidad -= (veinte * 0.2);
printf("%d X 0.20$\n", veinte);
} else {
veinte -= ent;
cantidad -= (ent * 0.2);
printf("%d X 0.20$\n", ent);
}
}
if (cantidad >= 0.108) {
ent = (int) (cantidad / 0.1);
if (ent >= diez) {
cantidad -= (diez * 0.1);
printf("%d X 0.10$\n", diez);
} else {
diez -= ent;
cantidad -= (ent * 0.1);
printf("%d X 0.10$\n", ent);
}//else
}//if
if (cantidad >= 0.05) {
printf("cantidad: %f\n",cantidad);
printf("cantidad/0.05: %f\n",cantidad / 0.05);
ent = (int) (cantidad / 0.05) ;
printf("ent(truncado): %d\n",ent);
ent = (int) round(cantidad / 0.05) ;
printf("ent(redondeado): %d\n",ent);
if (ent >= cinco) {
cantidad -= (cinco * 0.05);
printf("%d X 0.05$\n", cinco);
} else {
cinco -= ent;
cantidad -= (ent * 0.05);
printf("%d X 0.05$\n", ent);
}//else
}//if
} //dar cambio
int main() {
float precio, cambio;
for (int i=0; i<5;i++)
printf("%d.-%s: %.2f$\n",i,name[i],ar_precio[i]);
precio = menu();
printf("\nMonedas\n");
for (int i=1; i<7;i++)
printf("%d.-%.2f\n",i,monedas[i]);
cambio = aceptar_monedas(precio); //funcion que acepta monedas y escribe la cantidad restante
printf("Su cambio es: %.2f\n", cambio);
dar_cambio(cambio);
getchar();
}
Dcelso, muchas gracias por contestar, pero el mat.h, me redondea y me trunca igual, en los dos vale 1.
Si quieres te mando el conio, tal como lo he descargado. Voy a poner también aquí mi codigo para que lo compiles, con devC++ una vez instalada conio. Esta conio es autoejecutable, solo abrir y doble click.
Luego en opciones del linker pon -lconio.
Tutorial:
http://www.programacionenc.net/modules.php?name=Tutoriales&d_op=vertuto&lid=28 (http://www.programacionenc.net/modules.php?name=Tutoriales&d_op=vertuto&lid=28)
Prueba a pedir un dos y pagar con un dos. Verás que se te queda con 5 centimos, además de que te da en vez de dos monedas de .20 (para hacer 0.4) te da una de .20 una de .10 y una de .5 y eso antes no me pasaba.
Muchas muchas gracias por tu ayuda.
Un saludo.
Ni float ni doubles... para importes, usa enteros multiplicados por 100 (2 digitos decimales) por ejemplo, si necesitas decir 1€ pone 100, 0.50€ es 50... trabaja asi que no vas a tener problemas... los numeros de coma flotante tienen problemas de precision...
tambien hay librerias especificas para manejar numeros con decimales sin errores, pero lo mas simple es usar enteros.
Ostras, muy buena idea Splinter, no lo pensé así derepente, pero sí recuerdo haberlo empleado alguna que otra vez. :D
killo, prueba tu código, también pasa lo mismo, es culpa de los floats, 0.40/0.20 no da 2, sino 1.999 y al truncar queda 1. Pasa también con doubles.
#include <stdio.h>
#include <stdlib.h>
#define eleccion 30,4
char
name[][13] = { "Cola", "Refresco", "Cerveza", "Agua", "Agua",
"Cocolatina" };
double ar_precio[] = { .75, .70, .60, .45, .90, .80 };
int dos = 50, uno = 60, cincuenta = 100, veinte = 80, diez = 60, cinco = 100;
double monedas[8]={0.0,1.0,2.0,0.5,0.2,0.1,0.05};
double menu() {
char seleccion;
int sel;
do {
seleccion = getchar();
getchar();
sel = atoi(&seleccion);
} while (sel > 5 || sel < 0);
printf("Ha elegido %s\n", name[sel]);
return ar_precio[sel];
}
double aceptar_monedas(double precio) {
int in; //el valor numerico de la moneda introducida
char introducido; //la moneda que se introduce
double metido = 0.0; //la cantidad que se ha metido hasta ahora
printf("Queda por introducir: ");
printf("%.2f\n", precio);
printf("Introducido: ");
printf("%.2f\n", metido);
while (precio > 0.0) {
introducido = getchar();
getchar();
in = atoi(&introducido);
switch (in) {
case 1:
uno++;
precio -= 1.0;
metido += 1.0;
break;
case 2:
dos++;
precio -= 2.0;
metido += 2.0;
break;
case 3:
cincuenta++;
precio -= 0.5;
metido += 0.5;
break;
case 4:
veinte++;
precio -= 0.2;
metido += 0.2;
break;
case 5:
diez++;
precio -= 0.1;
metido += 0.1;
break;
case 6:
cinco++;
precio -= 0.05;
metido += 0.05;
break;
default:
printf("Debe introducir una moneda valida!!\n"); //Línea a modificar para hacerlo estético
}
printf("Queda por introducir: ");
printf("%.2f\n", precio);
printf("Introducido: ");
printf("%.2f\n", metido);
}//while
return (-precio); //devuelve lo que ha introducido de más, es decir, cúanto se ha pasado del precio introducido
}//aceptar monedas
void dar_cambio(double cantidad) {
int ent;
if (cantidad >= 1.0) {
ent = (int) cantidad / 1;
if (ent >= uno) {
cantidad -= uno;
printf("%d X 1$\n", uno);
} else {
uno -= ent;
cantidad -= ent;
printf("%d X 1$\n", ent);
}//else
}//if
if (cantidad >= 0.5) {
ent = (int) (cantidad / 0.5);
if (ent >= cincuenta) {
cantidad -= (cincuenta * 0.5);
printf("%d X 0.50$\n", cincuenta);
} else {
cincuenta -= ent;
cantidad -= (ent * 0.5);
printf("%d X 0.50$\n", ent);
}
}
if (cantidad >= 0.2) {
ent = (int) (cantidad / 0.2);
printf("cantidad:%f\n",cantidad);
printf("ent:%d\n",ent);
if (ent >= veinte) {
cantidad -= (veinte * 0.2);
printf("%d X 0.20$\n", veinte);
} else {
veinte -= ent;
cantidad -= (ent * 0.2);
printf("%d X 0.20$\n", ent);
}
}
if (cantidad >= 0.1) {
ent = (int) (cantidad / 0.1);
if (ent >= diez) {
cantidad -= (diez * 0.1);
printf("%d X 0.10$\n", diez);
} else {
diez -= ent;
cantidad -= (ent * 0.1);
printf("%d X 0.10$\n", ent);
}//else
}//if
if (cantidad >= 0.05) {
ent = (int) (cantidad / 0.05) ;
if (ent >= cinco) {
cantidad -= (cinco * 0.05);
printf("%d X 0.05$\n", cinco);
} else {
cinco -= ent;
cantidad -= (ent * 0.05);
printf("%d X 0.05$\n", ent);
}//else
}//if
} //dar cambio
int main() {
double precio, cambio;
for (int i=0; i<5;i++)
printf("%d.-%s: %.2f$\n",i,name[i],ar_precio[i]);
precio = menu();
printf("\nMonedas\n");
for (int i=1; i<7;i++)
printf("%d.-%.2f\n",i,monedas[i]);
cambio = aceptar_monedas(precio); //funcion que acepta monedas y escribe la cantidad restante
printf("Su cambio es: %.2f\n", cambio);
dar_cambio(cambio);
getchar();
}
En cuanto a usar conio, no se que narices pasa pero en cygwin/gcc no va lo que me pasas, se ve mal.
Ya me habeis picado y la he optimizado y pasado a enteros, me ha quedado este codiguillo.
#include <stdio.h>
#include <stdlib.h>
char
name[][13] = { "Cola", "Refresco", "Cerveza", "Agua", "Agua",
"Cocolatina" };
int ar_precio[] = { 75, 70, 60, 45, 90, 80 };
int monedas[8]={0,100,200,50,20,10,5};
int menu() {
char seleccion;
int sel;
do {
seleccion = getchar();
getchar();
sel = atoi(&seleccion);
} while (sel > 5 || sel < 0);
printf("Ha elegido %s\n", name[sel]);
return ar_precio[sel];
}
int aceptar_monedas(int precio) {
int in; //el valor numerico de la moneda introducida
char introducido; //la moneda que se introduce
int metido = 0; //la cantidad que se ha metido hasta ahora
printf("Queda por introducir: ");
printf("%.2f\n", precio/100.0);
printf("Introducido: ");
printf("%.2f\n", metido/100.0);
while (precio > 0) {
introducido = getchar();
getchar();
in = atoi(&introducido);
if (in >0 && in<7){
precio -=monedas[in];
metido +=monedas[in];
}else
printf("Debe introducir una moneda valida!!\n"); //Línea a modificar para hacerlo estético
printf("Queda por introducir: ");
printf("%.2f\n", precio/100.0);
printf("Introducido: ");
printf("%.2f\n", metido/100.0);
}//while
return (-precio); //devuelve lo que ha introducido de más, es decir, cúanto se ha pasado del precio introducido
}//aceptar monedas
void dar_cambio(int cantidad) {
int ent;
for (int i=1;i<7;i++)
if (cantidad >= monedas[i]) {
ent = (int) cantidad / monedas[i];
cantidad -= ent*monedas[i];
printf("%d X %.2f$\n", ent,monedas[i]/100.0);
}
} //dar cambio
int main() {
int precio, cambio;
for (int i=0; i<5;i++)
printf("%d.-%s: %.2f$\n",i,name[i],ar_precio[i]/100.0);
precio = menu();
printf("\nMonedas\n");
for (int i=1; i<7;i++)
printf("%d.-%.2f\n",i,monedas[i]/100.0);
cambio = aceptar_monedas(precio); //funcion que acepta monedas y escribe la cantidad restante
printf("Su cambio es: %.2f\n", cambio/100.0);
dar_cambio(cambio);
getchar();
}
cuidado tambien con la impresion del entero /100.0, yo diria hacerte una funcion que pase el entero a string y luego ahi entre los ultimos 2 digitos le colocas el punto decimal... no es algo muy bonito ni optimo, pero es preciso.
Resumiendo, si se trata de importe, no usar numeros de punto flotante para nada.
Splinter... ... Eres el mejor!! Y Dcelso También por supuesto!! Ya funciona perfecto!! No he podido postear antes porque me he ido a trabajar.
Este mismo post está en otros foros de c/c++ específicos y aún no me han contestado. Sabía que hacía bien poniendolo aquí. Muchas Muchas Gracias a todos.
Como bonus track, el programilla compilado para que podais verlo con colorines y pijadas.
;)
A todo esto, por que en C y no en Bennu? :)
;).
Ya te digo, en bennu estaría curuioso, ya con imagenes y sonido :D.
A que lo hago :D.
con bennu tambien se pueden hacer programas de consola... sin problemas... cierto es que no hay funciones para posicionar el cursor y colores de texto, pero si se puede usar consola sin graficos.
Que yo sepa si se pueden poner colores de texto no? y posicionar el cursor. ¿O te refieres a que bennu tiene un modo especial de consola? Si es así no tenía ni idea. Pero... el problema de bennu es la captura de datos desde teclado, que es un poco coñazo... ¿o se ha mejorado esto ultimamente?
Por cierto, tengo un problema con el buffer de entrada en mi programa, y es que no consigo limpiarlo!!! Uso la función getch y por lo visto, captura cosas un poco atiguas, tecleadas hace un rato.
fflush(stdin) antes y despues de getch te soluciona el problema.
un tanto en cuanto forzado pero es bastante práctico, eliminas el buffer antes de leer del teclado y después de leer de éste.
Sí, es verdad, la captura de teclado es un poco rollo.
Podría estar bien una función sencilla que facilitara las cosas, no?
Digo yo, por pedir...
Sip cierto siempre a sido un poco (bastante) rollo, cuando yo usaba turbo pascal (hace la tira de años), yo me atrevia un poco con el codigo maquina, pues para mis juegos programados en turbo pascal necesitaba lectura "continua" de teclado (lectura instantanea sin buffer), pues tuve que suplantar varias veces las rutinas del Msdos por rutinas "made in Kim-elet-o", y me acuerdo que era un pelin rollito.
en modo consola...
Quote from: kim-elet-o on February 06, 2009, 10:01:22 AM
Sip cierto siempre a sido un poco (bastante) rollo, cuando yo usaba turbo pascal (hace la tira de años), yo me atrevia un poco con el codigo maquina, pues para mis juegos programados en turbo pascal necesitaba lectura "continua" de teclado (lectura instantanea sin buffer), pues tuve que suplantar varias veces las rutinas del Msdos por rutinas "made in Kim-elet-o", y me acuerdo que era un pelin rollito.
Los buenos juegos no usaban lectura desde el buffer de teclado, eso no es util... en esos casos habia que hacer una propia version de la int9 para procesar el teclado... que si mal no recuerdo era el irq1...
He creado una base de lo que seria el interfaz en bennu para este "juego" en la sección <<projects>>.
A ver que te parece danielo, se evita así la necesidad de leer de teclado :D.