Небольшая ошибка в моем коротком C-коде. Почему?

Я не могу понять, почему это работает для 90% входов, но не для других. Он предназначен для того, чтобы рассказать вам, сколько монет вы получите в обмен. Большинство тестовых сумм работают нормально, но если вы введете 4,20 (или 4,20 долл. США), он вернет 23 монеты ... это должно быть 18 монет (16 кварталов и 2 никеля). Где ошибка? Вот мой код:

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

int main(void){

    float change = 0.00;

    printf("How much change is owed? ");
    change = GetFloat();

    float quarters = change/.25;
    change-= (int)quarters*.25;

    float dimes = change/.10;
    change-= (int)dimes*.10;

    float nickels = change/.05;
    change-= (int)nickels*.05;

    float pennies = (change+.005)/.01;
    change-=(int)pennies*.01;

    int total = (int)quarters+(int)dimes+(int)nickels+(int)pennies;

    printf("%d\n", total);

    return 0;
    }
 Fantastic Mr Fox16 авг. 2016 г., 00:22
@kallikak Назовите денежную оценку в вопросе, который не ...?
 kallikak29 окт. 2012 г., 22:54
все не кратно 1 центу
 user14201929 окт. 2012 г., 20:51
Вы никогда не должны использовать числа с плавающей запятой, чтобы представлять деньги в первую очередь.
 Dave Helmig29 окт. 2012 г., 21:08
Это домашнее задание, которое должно научить функциям с плавающей точкой, и это единственная причина, по которой оно написано так, как оно есть. Просто странно, что большинство входных данных работает нормально, только определенные числа - нет. Я не могу переписать его, используя разные классы или что-то еще, потому что именно так профессор хочет это видеть.
 1''29 окт. 2012 г., 20:59
Поскольку все кратно 1 центу, почему бы не хранить все как целое число центов? Таким образом вы избежите всех проблем, связанных с плавающей точкой.

Ответы на вопрос(3)

Решение Вопроса

ется на сотых долях, поэтому просто используйте целочисленное деление / по модулю.Никогда полагаться на идеальную точность в числах с плавающей точкой.

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

int main(void){

    float fchange = 0.00;
    int change = 0;

    printf("How much change is owed? ");
    fchange = GetFloat();

    change = (int)roundf(fchange*100.0);

    int quarters = change/25;
    change = change % 25;

    int dimes = change/10;
    change = change % 10;

    int nickels = change/5;
    change = change % 5;

    printf("%d quarters, %d dimes, %d nickels, %d pennies\n", quarters, dimes, nickels, change);

    return 0;
}
 Daniel Fischer29 окт. 2012 г., 21:03
change = (int)(fchange * 100.0); <- вам нужно округлить, усечение приводит к неверным результатам для некоторых входных данных (например, 4.20).
 Daniel Fischer29 окт. 2012 г., 21:05
Многозадачность? Я хотел бы сделать это.
 Daniel Fischer29 окт. 2012 г., 21:13
floor неправильно. Вы могли быfloor после умножения на 100, но нет необходимости, если все входы неотрицательны (если возможны отрицательные входы, что-то вродеfloor было бы необходимо). Я бы использовалchange = (int)roundf(fchange*100); хотя.
 WhozCraig29 окт. 2012 г., 21:09
@DanielFischer Всегда с тех пор, как я работал с поплавками. Ты хочешь проверить это для меня? Спасибо.
 WhozCraig29 окт. 2012 г., 21:04
@DanielFischer Спасибо, Даниэль. Я полностью отвечал на другой вопрос, когда я отправил это, не заканчивая это (phat пальцы).

float значение для4.20 немного меньше, чем это (4.19999980926513671875, для обычного 32-разрядного IEEE754floatс). Таким образом, после того, как вы вычли 4 доллара из 16 кварталов, у вас осталось немного меньше, чем 0,2. Разделив это на 0,1, получим значение, немного меньшее 2, так что вашnickels значение равно 1. То же самое происходит тогда, когда вы вычитаете свой никель, значение немного меньше 0,1, деление на 0,05 приводит к тому, что коэффициент немного меньше 2.

Вы должны использовать целые числа только для такого вычисления, вычисляя в центах.

 WhozCraig29 окт. 2012 г., 21:35
Напомните мне, чтобы получить один из них (калькулятор). И мои друзья зовутменя ботаник .. = P
 Daniel Fischer29 окт. 2012 г., 21:00
Я позволил моему интерпретатору Haskell вычислить это,fromRational преобразует рациональное число в ближайшее представимое число с плавающей точкой.
 1''29 окт. 2012 г., 20:58
+1 для точного значения IEEE. Вы рассчитали это вручную или с веб-сайта?
 Tommy29 окт. 2012 г., 20:57
В Objective-CNSDecimalNumber Класс также вариант, но это было бы гораздо больше хлопот.

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

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
    float change = atof(argv[1]);
    int work = (int)(100*change+0.5);
    int quarters, dimes, nickels, pennies;
    quarters = work/25; work %= 25;
    dimes    = work/10; work %= 10;
    nickels  = work/5;  work %=  5;
    pennies  = work;
    printf("%.2f dollars = %d quarters, %d dimes, %d nickels and %d pennies: %d coins total\n",
    change, quarters, dimes, nickels, pennies, quarters+dimes+nickels+pennies);
    return 0;
 }

Например:

./change 4.20
4.20 dollars = 16 quarters, 2 dimes, 0 nickels and 0 pennies: 18 coins total

Ваш ответ на вопрос