В этом коде есть ошибка

Я - решатель проблем начального уровня в этом онлайн-судье. Я неплохо справился с первыми 20 задачами. Но нет. 21 Я застрял. Я написал этот код:

#include <stdio.h>
#include <math.h>
int main()
{
    double notes[] = {100, 50, 20, 10, 5, 2};
    double moedas[] = {1, 0.50, 0.25, 0.10, 0.05, 0.01};
    int amount_of_notes[6];
    int amount_of_moedas[6];
    double n, x;
    int i, j;
    scanf("%lf", &n);
    printf("NOTAS: \n");
    for(i = 0; i < 6; i++)
    {
        x = fmod(n, notes[i]);
        amount_of_notes[i] = n/notes[i];
        n = x;
        printf("%d nota(s) de R$ %.2lf\n", amount_of_notes[i], notes[i]);
    }
    printf("MOEDAS: \n");
    for(j = 0; j < 6; j++)
    {
        amount_of_moedas[j] = n/moedas[j];
        x = fmod(n, moedas[j]);
        n = x;
        printf("%d moeda(s) de R$ %.2lf\n", amount_of_moedas[j], moedas[j]);
    }
    return 0;
}

Этот код находится в C. Этот код преобразует число в некоторые банкноты и монеты. Но когда я ввожу 54.54 вывод приходит так:

NOTAS: 
0 nota(s) de R$ 100.00
1 nota(s) de R$ 50.00
0 nota(s) de R$ 20.00
0 nota(s) de R$ 10.00
0 nota(s) de R$ 5.00
2 nota(s) de R$ 2.00
MOEDAS: 
0 moeda(s) de R$ 1.00
1 moeda(s) de R$ 0.50
0 moeda(s) de R$ 0.25
0 moeda(s) de R$ 0.10
0 moeda(s) de R$ 0.05
3 moeda(s) de R$ 0.01

как вы можете видеть, что только в последней строке 3 показывает, где он должен показывать 4, Я так старался найти ошибку в коде. Я провалил. Пожалуйста, помогите найти ошибку этого кода!

2 ответа

Избегайте переменных с плавающей точкой для всего, что требует точности. Поплавки не точны, и вы столкнетесь с ошибками округления. В вашем случае вы ожидаете 4, но получаете 3 из-за ошибок округления.

Вместо этого делайте все вычисления, используя целые числа, и используйте центы в качестве базовой единицы.

Что-то вроде:

#include <stdio.h>
#include <math.h>
int main()
{
    int notes[] = {10000, 5000, 2000, 1000, 500, 200}; // Unit is cents
    int moedas[] = {100, 50, 25, 10, 5, 1};            // Unit is cents
    int amount_of_notes[6];
    int amount_of_moedas[6];
    double n;
    int x;
    int n_int;
    int i, j;
    scanf("%lf", &n);
    n_int = 100 * n;                                  // Unit is cents
    printf("NOTAS: \n");
    for(i = 0; i < 6; i++)
    {
        x = n_int / notes[i];
        amount_of_notes[i] = x;
        n_int -= x * notes[i];
        printf("%d nota(s) de R$ %.2lf\n", amount_of_notes[i], notes[i]/100.0);
    }
    printf("MOEDAS: \n");
    for(j = 0; j < 6; j++)
    {
        x = n_int / moedas[j];
        amount_of_moedas[j] = x;
        n_int -= x * moedas[j];
        printf("%d moeda(s) de R$ %.2lf\n", amount_of_moedas[j], moedas[j]/100.0);
    }
    return 0;
}

Входные данные:

54.54

Выход:

NOTAS: 
0 nota(s) de R$ 100.00
1 nota(s) de R$ 50.00
0 nota(s) de R$ 20.00
0 nota(s) de R$ 10.00
0 nota(s) de R$ 5.00
2 nota(s) de R$ 2.00
MOEDAS: 
0 moeda(s) de R$ 1.00
1 moeda(s) de R$ 0.50
0 moeda(s) de R$ 0.25
0 moeda(s) de R$ 0.10
0 moeda(s) de R$ 0.05
4 moeda(s) de R$ 0.01

Ошибка связана с тем, как компьютеры обрабатывают числа с плавающей запятой. Этот ресурс имеет хорошее объяснение по теме.

http://floating-point-gui.de/

Есть несколько способов решения этой проблемы, в вашем случае я считаю использование целых чисел лучшим вариантом. Вы можете начать со своих значений "notes" и "moedas" в виде целых чисел (умножив их все на 100) и сделать то же самое с вводом. Это не изменит конечный результат, но вы будете иметь дело с целыми числами вместо чисел с плавающей запятой. И так как целые числа точны (без ошибок округления), результат будет тем, что вы ожидаете.

Здесь есть подтверждение концепции на основе вашего кода. Обратите внимание, что я внес только минимальные изменения, которые могли бы заставить его работать, есть много возможностей для улучшения.

https://repl.it/Lxg0/2

Другие вопросы по тегам