Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Henrigeek

Problema com valores em C

Recommended Posts

Está ocorrendo o seguinte problema: A função "while" está sendo ignorada aparentemente:

/*CC50 GREEDY Project*/

#include <stdio.h>

int main (void)
{
  float value,
        coin_01 = 0.01, 
        coin_05 = 0.05, 
        coin_10 = 0.10, 
        coin_25 = 0.25,
        div_coin_25 = (value / coin_25), //div = division of values
        div_coin_10 = (value / coin_10),
        div_coin_05 = (value / coin_05),
        div_coin_01 = (value / coin_01);

    int num_coins_01 = 0, //num = numbers of coins 
        num_coins_05 = 0, 
        num_coins_10 = 0, 
        num_coins_25 = 0,
        num_total_coins = 0;   
        
  printf("Digite o valor do troco: ");
  scanf("%f",&value);
   
   while (div_coin_25 >= 1)
    {
      num_coins_25++ && num_total_coins++ && value-0.25;
    }
    while (div_coin_10 >= 1)
    {
      num_coins_10++ && num_total_coins++ && value-0.10;
    }
    while (div_coin_05 >= 1)
    {
      num_coins_05++ && num_total_coins++ && value-0.05;
    }
     while (div_coin_01 >= 1)
    {
      num_coins_01++ && num_total_coins++ && value-0.01;
    }

  printf("O numero minimo de moedas que equivale ao valor de %f de troco pode ser dado = %i. E isso eh igual a %i moedas de 01 centavo,%i moedas de 05 centavos,%i moedas de 10 centavos e a %i moedas de 25 centavos\n",value, num_total_coins, num_coins_01, num_coins_05, num_coins_10, num_coins_25);
   
  return 0;
}

O programa era para fazer com que o software desse o troco em moedas de 25,10,05,01 centavos na menor quantidade de moedas possíveis. O que está saindo errado?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bem-vindo(a)!

 

Sugiro escrever com mais clareza. Seu código possui incoerências como:

 

 

 
      num_coins_25++ && num_total_coins++ && value-0.25;

 

Você sabe o que isto faz?


Talvez você esteja tentando dizer o seguinte:

 

 

 
      num_coins_25++;
      num_total_coins++;
      value -= 0.25;

Compartilhar este post


Link para o post
Compartilhar em outros sites
float value, ...
... coin_25 = 0.25, ...
div_coin_25 = (value / coin_25)

Sabe lá qual número sairá desta divisão. Afinal, que valor tem "value" para ele ser dividido por "coin_25" ? Você está realizando a operação na declaração da variável, isto é, antes mesmo de ler seu valor. Não terminei de ler o código, mas aparentemente isto já está errado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Bem-vindo(a)!

 

Sugiro escrever com mais clareza. Seu código possui incoerências como:

 

 

 
      num_coins_25++ && num_total_coins++ && value-0.25;

 

Você sabe o que isto faz?

 

Talvez você esteja tentando dizer o seguinte:

 

 

 
      num_coins_25++;
      num_total_coins++;
      value -= 0.25;

Na verdade "presupuis" que o códifo deveria ser deste jeito, mas depois vi que assim não adicona os valores que eu quero.

 

 

float value, ...
... coin_25 = 0.25, ...
div_coin_25 = (value / coin_25)

Sabe lá qual número sairá desta divisão. Afinal, que valor tem "value" para ele ser dividido por "coin_25" ? Você está realizando a operação na declaração da variável, isto é, antes mesmo de ler seu valor. Não terminei de ler o código, mas aparentemente isto já está errado.

Cara, os value o usuário vai digitar e será armazenado com "scanf".

Compartilhar este post


Link para o post
Compartilhar em outros sites

O valor é lido depois do uso do objeto. Por definição, o valor inicial dele é indeterminado. Usá-lo (como você fez) gera, também por definição, comportamento indefinido.

 

Não adianta pressupor.

 

Sim, agora meu código pede o número mas não realiza nenhuma ação com ele:

/*CC50 GREEDY Project*/

#include <stdio.h>

int main (void)
{
  float value,
        coin_25 = 0.25, 
        coin_10 = 0.10, 
        coin_05 = 0.05, 
        coin_01 = 0.01;
      /*neg_coin_25 = -0.25, //neg = negative values. 
        neg_coin_10 = -0.10, 
        neg_coin_05 = -0.05, 
        neg_coin_01 = -0.01,*/

    int num_coins_25 = 0, //num = numbers of coins.
        num_coins_10 = 0, 
        num_coins_05 = 0, 
        num_coins_01 = 0,
        num_total_coins = 0;   

   do 
   {
    printf("Digite o valor do troco: ");
    scanf("%f",&value);
    
  float div_coin_25 = (value / 0.25/*coin_25*/), //div = division of values.
        div_coin_10 = (value / 0.10/*coin_10*/),
        div_coin_05 = (value / 0.05/*coin_05*/),
        div_coin_01 = (value / 0.01/*coin_01*/);

    if (div_coin_25 >= 1)
    {
     while (div_coin_25 >= 1)
     {
      num_coins_25++; 
      num_total_coins++;
      value-=0.25;
     }
    }

    else if (div_coin_10 >= 1)
    {
     while (div_coin_10 >= 1)
     {
      num_coins_10++; 
      num_total_coins++;
      value-=0.10;
     }
    }

    else if (div_coin_05 >= 1)
    {
     while (div_coin_05 >= 1)
     {
      num_coins_05++; 
      num_total_coins++;
      value-=0.05;
     }
    }

    else if (div_coin_01 >= 1)
    {
     while (div_coin_01 >= 1)
     {
      num_coins_01++; 
      num_total_coins++;
      value-=0.01;
     }
    }
      else
      printf("Invalido\n");
   } while(!value == 0);  
        
   
   /*  while (div_coin_10 >= 1)
    { 
      num_coins_10++;
      num_total_coins++;
    }
    while (div_coin_05 >= 1)
    { 
      num_coins_05++;
      num_total_coins++; 
    }
     while (div_coin_01 >= 1)
    {
      num_coins_01++;
      num_total_coins++; 
    } */
  printf("O numero minimo de moedas que equivale ao valor de %f de troco pode ser dado = %i. E isso eh igual a %i moedas de 01 centavo,%i moedas de 05 centavos,%i moedas de 10 centavos e a %i moedas de 25 centavos\n",value, num_total_coins, num_coins_01, num_coins_05, num_coins_10, num_coins_25);
  printf("Value = %f \n",value);
   
  return 0;
}

Ainda está com o problema de não passar da parte do 'scanf".

Compartilhar este post


Link para o post
Compartilhar em outros sites

E de novo o depurador que ninguém usa salvando o dia...

Ele passa sim do scanf. Se não eu não iria ver isso aqui no GDB:

 

Breakpoint 3, main() at coins.c:29

29 while (div_coin_25 >= 1) {

3: div_coin_25 = 20

2: num_coins_25 = 21

1: value = -0.25

 

Vc acabou de conhecer o loop infinito, porque as condições dos whiles estão erradas, já que o div_coin_25 sempre vai ser positivo e não é alterado dentro desses blocos.

Compartilhar este post


Link para o post
Compartilhar em outros sites

E de novo o depurador que ninguém usa salvando o dia...

Ele passa sim do scanf. Se não eu não iria ver isso aqui no GDB:

 

 

 

Vc acabou de conhecer o loop infinito, porque as condições dos whiles estão erradas, já que o div_coin_25 sempre vai ser positivo e não é alterado dentro desses blocos.

O você acha então? A melhor solução seria usar a função "for"?

Compartilhar este post


Link para o post
Compartilhar em outros sites
É seguinte: meu código está funcionando de maneira quase perfeita, mas com as moedas de 01 centavos então dando problema quando são digitados alguns valores como 1.26 reais... Dependendo do valor sobra sempre 0.01 reais:
/*CC50 GREEDY Project*/

#include <stdio.h>

int main (void)
{
  float value,
        coin_25 = 0.25, 
        coin_10 = 0.10, 
        coin_05 = 0.05, 
        coin_01 = 0.01;

    int num_coins_25 = 0, //num = numbers of coins.
        num_coins_10 = 0, 
        num_coins_05 = 0, 
        num_coins_01 = 0,
        num_total_coins = 0;   

    printf("Digite o valor do troco: ");
    scanf("%f",&value);

  do
   {
    if (value >= coin_25)
    { 
     value-=coin_25;
     num_coins_25++; 
     num_total_coins++;
    }
   } while (value >= coin_25);

  do
   {
    if (value >= coin_10)
    { 
     value-=coin_10;
     num_coins_10++; 
     num_total_coins++;
    }
   } while (value >= coin_10);

  do
   {
    if (value >= coin_05)
    { 
     value -= coin_05;
     num_coins_05 ++; 
     num_total_coins ++;
    } 
   } while (value >= coin_05);

  do
   {
    if (value >= coin_01)
    { 
     value -= coin_01;
     num_coins_01++; 
     num_total_coins++;
    }
   } while (value >= coin_01);  
                          
                            
  printf("O numero minimo desse troco pode ser dado = %i. E isso eh igual a:\n",num_total_coins); 

  printf("%i moedas de 01 centavo.\n",num_coins_01);
  printf("%i moedas de 05 centavos.\n",num_coins_05);
  printf("%i moedas de 10 centavos.\n",num_coins_10);
  printf("%i moedas de 25 centavos\n",num_coins_25);
  printf("Value = %.2f \n",value);
   
  return 0;
}

 

Coloquei um "Value" ni final para identificar se realmente zerou para dar o troco certo. Olhem só o erro:

 

 

root@henrique-desktop:/home/cc50/pset1# gcc -o greedy greedy.c
root@henrique-desktop:/home/cc50/pset1# ./greedy
Digite o valor do troco: 1.26
O numero minimo desse troco pode ser dado = 5. E isso eh igual a:
0 moedas de 01 centavo.
0 moedas de 05 centavos.
0 moedas de 10 centavos.
5 moedas de 25 centavos
Value = 0.01

 

Como arrumar esse bug de sempre (dependendo do valor, como 1.26) sobrar 01 centavo?

Compartilhar este post


Link para o post
Compartilhar em outros sites

O você acha então? A melhor solução seria usar a função "for"?

 

 

Não falei que o uso do while é errado. Falei que a condição do while está errada. E 'while' e 'for' não são funções.

Fiz uma versão aqui no bloco de notas do windows, mas estou sem compilador (assim que instalar corrijo se algo errado passou):

 

 

#include <stdio.h>
int calcula_troco(const float valor_moeda, float valor_considerado);
 
int main(void) {
   const float moedas[] = {0.25F, 0.10F, 0.05F, 0.01F};
   int qtde_moedas[] = {0, 0, 0, 0};
   float troco_a_receber = 0.0F;
 
   do {
      printf("Digite o valor do troco: ");
      scanf("%f", &troco_a_receber);
      if (troco_a_receber <= 0.00)
         puts("Valor inválido.");
   } while (troco_a_receber < 0.00);
 
   for(int i=0; i<4; i++) {
      qtde_moedas[i] = calcula_troco(moedas[i], troco_a_receber);
      troco_a_receber -= (qtde_moedas[i] * moedas[i]);
      printf("Moedas de %.2f: %d\n", moedas[i], qtde_moedas[i]);
   }
   return 0;
}
 
/*
 * Calcula a quantidade de moedas de um determinado valor que compõe o troco.
 * 
 * Parâmetros
 * const float valor_moeda -- valor fixo da moeda a ser utilizado no cálculo.
 * float valor_considerado -- valor que será decomposto em frações especificadas pelo parâmetro "valor_moeda".
 */
int calcula_troco(const float valor_moeda, float valor_considerado) {
   int total_moedas = 0;
 
   if (!valor_considerado || valor_considerado < valor_moeda)
      return total_moedas;
 
   return (int) (valor_considerado/valor_moeda);
   
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Escrevi quando criaram o tópico. Estava esperando a solução.

 

Isis:

 

O código tem undefined behavior por não terminar em newline.

Fora isso, nenhum warning com -Wall, -Wextra, -pedantic.

 

Talvez valha a pena explicitar a pré-condição da calcula_troco de que os valores de moeda são ordenados do maior para o menor.

Outro problema em potencial é a aritmética de ponto flutuante:

 

 

 
guidjos@gdjs:~/Desktop> ./isis 
Digite o valor do troco: 1.30
Moedas de 0.25: 5
Moedas de 0.10: 0
Moedas de 0.05: 0
Moedas de 0.01: 4

 

Sugiro trabalhar com valores em centavos. Podemos lê-los diretamente nesta ordem de grandeza, ou multiplicar o valor em reais por 100. Segue minha sugestão de implementação:

 

// gcc -std=c99 -Wall -Wextra -pedantic greedy.c -o greedy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define a_size(b) (sizeof b / sizeof *b)


static int compare(const void *one, const void *other)
{
    return *(unsigned int *) other - *(unsigned int *) one;
}

static void greedy_change(unsigned int amount_cents, unsigned int *coin_values, size_t values_sz, unsigned int *coin_counts)
{
    qsort(coin_values, values_sz, sizeof *coin_values, compare);
    memset(coin_counts, 0, values_sz * sizeof *coin_counts);

    for (size_t i = 0; i < values_sz; i++)
    {
        coin_counts[i] = amount_cents >= coin_values[i] ? 
                            amount_cents / coin_values[i] :
                            0;

        amount_cents -= coin_counts[i] * coin_values[i];
    }
}

static unsigned long long int sum(unsigned int *counts, size_t size)
{
    unsigned long long int s = 0;
    
    while (size > 0)
    {
        s += counts[size - 1];
        size--;
    }

    return s;
}

static void print_result(unsigned int amount, unsigned int *coin_counts, unsigned int *coin_values, size_t size)
{
    printf("\n\tSão necessárias, no minimo, %llu moedas para trocar %.2F reais.\n\n", sum(coin_counts, size), amount / 100.0);

    while (size > 0)
    {
        printf(" - %u de %u centavo%s\n", 
                coin_counts[size - 1], 
                coin_values[size - 1], 
                coin_values[size - 1] > 1 ? "s" : "");
        size--;
    }

    puts("");
}

int main (void)
{
    unsigned int coins[] = { 1, 5, 10, 50, 25, 100 },
                 amount  = 456,
                 coin_counts[a_size(coins)];

    greedy_change(amount, coins, a_size(coins), coin_counts);

    print_result(amount, coin_counts, coins, a_size(coins));
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Quanto ao ponto flutuante: não resolve muito se o enunciado pedir explicitamente p/ ler no formato comum. Como não temos ele, dá pra fazer qualquer coisa no código.

 

 

[Conversa chata sobre padrões. Pule se vc é um usuário que não quer participar]

 

O código tem undefined behavior por não terminar em newline.

 

Nem dou mais atenção p/ esse UB porque o que a ISO fez foi estúpido: o C++11 diz que os arquivos que não terminam com \n (entre outras condições) devem ser processados como se tivessem um \n, mas o C11 manteve a restrição. O C++11 foi publicado em Set/2011 e o C11, em Dez/2011. Poderiam muito bem ter explicitado a regra do C++11 no C11; uma diferença a menos p/ se lembrar. Não é difícil entender porque os novatos acham ruim a gente pegar no pé quanto a padrões.

 

Fui ver a seção undefined behavior do C11 e diz lá:

 

"A nonempty source file does not end in a new-line character which is not immediately preceded by a backslash character or ends in a partial preprocessing token or comment".

 

Fora de contexto e confuso, então fui ler a seção que define isso (5.1.1.2):

 

"1.Physical source file multibyte characters are mapped, in an implementation-defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary."

 

"2.Each instance of a backslash character immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice. A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place."

 

Essas misturebas fazem com que eu passe raiva com os padrões. Em um dos bug reports do GCC (4.4, um dos poucos que consegui achar reclamando da falta de warnings em arquivos sem \n na última linha), um desenvolvedor comentou que a primeira fase pode adicionar o \n, então, muito provavelmente, desde o GCC 4.4 isso é feito "por baixo dos panos". O ruim é que eu não consigo confirmar isso num tempo decente (é uma extensão? é a implementação da primeira fase? não foi implementado? desabilitaram uma flag a pedido de alguém?)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Só queria uma solução dentro do meu próprio código, não queria um novo, e o seu ISIS, está dando problema com C99 no meu compilador (Ubuntu 2008). Eu não entendi algumas funções dentro dos códigos de vocês. Alguém sabe como usar o Makefile no Linux-Ubuntu?

 

 

EDIT:@Isis, esses "F" na lista da variável depois do número são para indicar que são 'float'?

 

 

 

@Isis onde está a varável "i"?

 

OBS: Por que não tem como editar o o post e tem que fazer double post?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Buenas!

 

Isis: independente do que o GCC faz, ou do que o mais recente padrão de C++ define, precisamos evitar o comportamento indefinido descrito em C (que é vigente). Sim, a linguagem não é tão simples quanto deveria - na verdade, o padrão todo é muito ruim. Ainda assim, a definição atual é de que o comportamento é indefinido se algum dos arquivos de código-fonte não terminar em newline.

 

Neelix: static faz com que as declarações em file scope tenham internal linkage. Isto é uma defesa contra dois possíveis problemas graves:

 

1. Undefined behavior quando outras unidades de tradução/compilação forem adicionadas ao conjunto de códigos-fonte, alguma(s) das quais tenha(m) alguma declaração com mesmo nome de alguma das minhas funções, mas linkage diferente.

 

2. Definição indevida de uma declaração com external linkage em algum arquivo de código-fonte, de outra unidade de compilação, que possa ser adicionado ao conjunto do programa.

 

É por isso que se diz que o storage-class specifier static "esconde" as declarações, retendo-as na unidade de compilação em que estão.

 

O fenômeno-chave a entender aqui é linkage, definido em 6.2.2 (n1570).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Seria o mesmo que os namespace de C++??

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tudo certo, GBecker?

 

Não são a mesma coisa. Escopo e linkage são completamente diferentes. Namespaces tratam de escopo - são agrupamentos de nomes sob uma denominação ("qualificação") comum. Linkage é o processo através do qual múltiplas declarações de um mesmo nome fazem referência a um mesmo objeto. Se isto ocorrer através de unidades de compilação diferentes, isto é chamado de external linkage. Caso contrário, de internal linkage.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Desculpe, Neelix, me esqueci.

 

size_t é o tipo usado para representar tamanhos de objetos. Você com certeza já usou valores deste tipo, em chamadas a funções como malloc.

 

a_size é uma macro que defini para obter o número de elementos de um vetor a partir de seu nome:

 

 

 
#define a_size(b) (sizeof b / sizeof *b)

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Topic, retomando ao principal, alguém sabe o problema do meu novo código?

 

 

É seguinte: meu código está funcionando de maneira quase perfeita, mas com as moedas de 01 centavos então dando problema quando são digitados alguns valores como 1.26 reais... Dependendo do valor sobra sempre 0.01 reais:
/*CC50 GREEDY Project*/

#include <stdio.h>

int main (void)
{
  float value,
        coin_25 = 0.25, 
        coin_10 = 0.10, 
        coin_05 = 0.05, 
        coin_01 = 0.01;

    int num_coins_25 = 0, //num = numbers of coins.
        num_coins_10 = 0, 
        num_coins_05 = 0, 
        num_coins_01 = 0,
        num_total_coins = 0;   

    printf("Digite o valor do troco: ");
    scanf("%f",&value);

  do
   {
    if (value >= coin_25)
    { 
     value-=coin_25;
     num_coins_25++; 
     num_total_coins++;
    }
   } while (value >= coin_25);

  do
   {
    if (value >= coin_10)
    { 
     value-=coin_10;
     num_coins_10++; 
     num_total_coins++;
    }
   } while (value >= coin_10);

  do
   {
    if (value >= coin_05)
    { 
     value -= coin_05;
     num_coins_05 ++; 
     num_total_coins ++;
    } 
   } while (value >= coin_05);

  do
   {
    if (value >= coin_01)
    { 
     value -= coin_01;
     num_coins_01++; 
     num_total_coins++;
    }
   } while (value >= coin_01);  
                          
                            
  printf("O numero minimo desse troco pode ser dado = %i. E isso eh igual a:\n",num_total_coins); 

  printf("%i moedas de 01 centavo.\n",num_coins_01);
  printf("%i moedas de 05 centavos.\n",num_coins_05);
  printf("%i moedas de 10 centavos.\n",num_coins_10);
  printf("%i moedas de 25 centavos\n",num_coins_25);
  printf("Value = %.2f \n",value);
   
  return 0;
}

 

Coloquei um "Value" ni final para identificar se realmente zerou para dar o troco certo. Olhem só o erro:

 

 

Como arrumar esse bug de sempre (dependendo do valor, como 1.26) sobrar 01 centavo?

 

????????????????????????????????????

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.