CS50 Жадный Нужен совет

Я делаю набор задач cs50 "Жадный". В основном спрашивают пользователя, сколько сдачи ему причитается, а затем выводят минимальное количество монет, которое может равняться введенной сумме. Он работает отлично, за исключением того, что когда я ввожу 4.2, он выводит 22, когда должен выводить 18.

#include <cs50.h>
#include <stdio.h>


int main(void)
{
    float n;
    do
    {
        n = get_float("How much change is owed?\n");
    }
    while(n == EOF);

    int cents = (int)(n * 100);
    int minimumamountofcoins = 0;
    if (cents/25 >= 1){
        while (cents/25 >= 1)
        {
            cents -= 25;
            minimumamountofcoins++;
        }

    }
    if (cents/10 >= 1){
        while (cents/10 >= 1)
        {
            cents -= 10;
            minimumamountofcoins++;
        }
    }
    if(cents/5 >= 1){
        while (cents/5 >= 1)
        {
            cents -= 5;
            minimumamountofcoins++;
        }
    }
    if (cents/1 >= 1){
        while (cents/1 >= 1)
        {
            cents -= 1;
            minimumamountofcoins++;
        }
    }
    printf("The minimum amount of coins is %d\n", minimumamountofcoins);
}

person R_C    schedule 17.08.2017    source источник
comment
попробуй пройти через отладчик. Вы также можете отказаться от предложений if перед циклом while, они в основном проверяют одно и то же.   -  person Mathieu Borderé    schedule 17.08.2017
comment
Еще один вопрос об изменении среди тысяч. Держитесь подальше от плавающей запятой и проведите небольшое исследование, пожалуйста.   -  person Weather Vane    schedule 17.08.2017
comment
Аналогично stackoverflow.com/q/45703316/2410359   -  person chux - Reinstate Monica    schedule 17.08.2017
comment
Используйте int вместо float для ввода.   -  person BLUEPIXY    schedule 17.08.2017
comment
Попробуйте напечатать центы после int cents = (int)(n * 100);. Также все if условия избыточны, их можно убрать.   -  person kocica    schedule 17.08.2017
comment
1) Не конвертируйте и не масштабируйте float деньги в int с int cents = (int)(n * 100); long cents = lround(n * 100.0); лучше. 2) Не используйте float с деньгами. Типичные типы данных C все имеют проблемы с деньгами - float/char самые худшие.   -  person chux - Reinstate Monica    schedule 17.08.2017
comment
Кстати, была ли изменена спецификация get_float?   -  person BLUEPIXY    schedule 17.08.2017
comment
Да, еще до того, как я открыл его, я ждал 'float n;' :(   -  person Martin James    schedule 18.08.2017


Ответы (2)


Похоже, это проблема с преобразованием из float в int. Когда вы пытаетесь конвертировать доллары в центы, вы делаете это с помощью этой строки кода:

int cents = (int)(n * 100);

Однако эта строка кода за 4,20 доллара возвращает значение в центах, равное 419. Это проблема с округлением и числами с плавающей запятой, поскольку 4,2 * 100 возвращает 419,99999999 вместо 420,0000000, а целочисленное приведение усекает вместо округления. Эта проблема также возникает с $ 4,18 и, возможно, с другими значениями.

Чтобы предотвратить это, добавьте 0,5 перед приведением, например:

int cents = (int)(n * 100 + 0.5);

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

Используя библиотеку math.h, вы также можете использовать функцию roundf(), которая на всякий случай будет работать в случае отрицательных чисел.

int cents = (int)(roundf(n*100));
person Lavaman65    schedule 17.08.2017
comment
(int)(n * 100 + 0.5), скорее всего, удовлетворит основные потребности, но не сработает при различных условиях, включая отрицательные значения, большие числа и другие. C имеет около дюжины функций округления в <math.h>. Используйте лучший инструмент в сарае. - person chux - Reinstate Monica; 17.08.2017
comment
Справедливо. Поскольку спрашивающий использует доллары, я предположил, что они никогда не могут быть отрицательными, но я отредактирую пост, чтобы включить лучший метод округления. - person Lavaman65; 17.08.2017
comment
Второстепенное: целочисленное приведение округляется в меньшую сторону --› целочисленное приведение усекает дробь Это отличается, опять же, с - числами. - person chux - Reinstate Monica; 17.08.2017
comment
Тоже верно, исправим - person Lavaman65; 17.08.2017
comment
Некоторые числовые мелочи для UnknowableIneffable: рассмотрим разницу между roundf(n*100) и round(n*100.0). Со значениями, близкими к +/-x,xx5, первое может округлить неправильно из-за неточности some_float_n*some_int_100, где n*100.0 будет вычисляться как double, а типичная дополнительная точность обеспечивает правильные результаты. - person chux - Reinstate Monica; 17.08.2017
comment
я вообще об этом не знала! Спасибо за информацию, хотя я не буду менять пост, так как в данном случае это не обязательно. - person Lavaman65; 17.08.2017

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

int cents = (int)(n * 100);

Это должно быть так:

cents = round(n * 100);

Если у вас есть другие подобные проблемы, вы можете использовать отладчик, такой как debug50, в котором вы ставите точку останова, щелкая справа от номера строки, а затем в своем окне терминала (то, где вы выполняете clang) вы должны ввести:

~/pset1/cash/ $ debug50 ./cash

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

person Lost in code    schedule 17.08.2020