Weird sum value for CS50 pset1- Greedy challenge - c

I have finished my code for Greedy challenge in PSET1's CS50
However, the total count of coins returns is quite large. When I look further into it, it seems that my nickels coins count is huge (4381344 coins for 0.48 cent).
Call me stupid but I have been pulling my hair for a while because of this. Anyone can point out why?
#include <cs50.h>
#include <stdio.h>
#include <math.h>
// You want to:
// get user input of a float
// check float
// Loop: minus money with biggest coins unit until negative
// then loop and loop
// until 1
// then count the number of loop (by assign a variable to count)
int main(void)
{
float money_give;
int quarters= 25, qc, dimes = 10, dc, nickels= 5, nc,pennies= 1, pc;
do
{
printf("O hai! How much change is owed?\n");
money_give = get_float();
}
while (money_give <= 0.0);
money_give = money_give * 100;
int money = (int)round(money_give);
while (money >= quarters)
{
qc = money / quarters;
money = money % quarters;
}
while (money >= dimes)
{
dc = money / dimes;
money = money % dimes;
}
while (money >= nickels)
{
nc = money / nickels;
money = money % nickels;
}
while (money >= pennies)
{
pc = money / pennies;
money = money % pennies;
}
printf("%i\n",pc+ nc+ qc +dc);
printf("%i\n",nc);
printf("%i\n",qc);
printf("%i\n",dc);
printf("%i\n",pc);
}
Oh and the output is:
O hai! How much change is owed?
0.48
4381350
4381344
1
2
3

You forgot to initialize your variables. Change:
int quarters= 25, qc, dimes = 10, dc, nickels= 5, nc,pennies= 1, pc;
into:
int quarters= 25, qc = 0, dimes = 10, dc = 0, nickels= 5, nc = 0, pennies= 1, pc = 0;
What happened was that because nc had not been initialized, then it started with being equal to whatever garbage was already there in the memory where it was being stored.
Then when you came to this part, it did not get a new value because money was less than nickels:
while (money >= nickels)
{
nc = money / nickels;
money = money % nickels;
}
Therefore it never got assigned a new value instead of the garbage it started with.
The lesson from this: Always initialize your variables.

Related

Integer overflow in greedy coin counting

#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main (void) {
printf ("Enter amount: ");
float amount = GetFloat();
int coins = 0;
while (amount != 0) {
if (fmod(amount, 0.25) == 0) {
amount = amount - 0.25;
coins += 1;
}
else if (fmod(amount, 0.10) == 0) {
amount = amount - 0.10;
coins += 1;
}
else if (fmod(amount, 0.05) == 0) {
amount = amount - 0.05;
coins += 1;
}
else {
amount = amount - 0.01;
coins += 1;
}
}
printf ("Coins : %d\n", coins);
}
I'm trying to implement a small greedy algorithm, in which a user inputs an amount of money ( Ex: 9.25 ) and we output the least amount of coins that it takes for us to exchange it in change( 25 cents, 10 cents, 5 cents and 1 cent only).
This algorithm works with int amounts like 10 or 20 and with amounts that only requires the program to use the 25 cents coins.
If I try an amount like 9.10 or 9.01, I get a runtime error, signed integer overflow. I understand what it means, but I don't understand how can the value of coins go so high all of a sudden.
As Danial Tran said it is better to use int when you do logical operations. Please read Why not use Double or Float to represent currency? Also you can avoid while loop.
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main (void) {
printf ("Enter amount: ");
//float amount = GetFloat(); //Please refer to chqrlie's comments below.
double amount = 0.0;
scanf("%lf",&amount); //I don't know GetFloat() equivalent for double. So using scanf().
long long int amountInt = (long long int) (amount * 100.0);
int coins = 0;
if (25 <= amountInt) {
coins += (amountInt/25);
amountInt = amountInt % 25;
}
if (10 <= amountInt) {
coins += (amountInt/10);
amountInt = amountInt % 10;
}
if (5 <= amountInt) {
coins += (amountInt/5);
amountInt = amountInt % 5;
}
if (1 <= amountInt) {
coins += amountInt;
}
printf ("Coins : %d\n", coins);
}
It seems that no one has answered the particular question
If i try an amount like 9.10 or 9.01, i get a runtime error,signed integer overflow, i understand what it means, but i don't understand how can the value of coins go so high all of a sudden.
so for the sake of completeness, partially as an exercise:
You can find the reason using a debugger. I copied your code and found that it runs for very long. Interrupting it a moment after start revealed that the code freezes repeating this check:
if (fmod(amount, 0.25) == 0) {
amount = amount - 0.25;
coins += 1;
}
At the moment of the interruption amount was about minus 1.2 million and coins almost 5 million. This clearly shows one thing you failed to check: negativity. It can happen easily with floats that you miss the exact zero, as the others have correctly reasoned, no need to repeat that. But if that happens, your program should get worried the moment amount gets negative. Otherwise, under the right conditions, it may as well keep subtracting its way towards negative infinity, and yes, integer overflow will happen in coins.
This is because the computer represent the decimals in binary (power of 2)
For 0.25, the computer can represent it properly in binary. This is because we can obtain 0.25 exactly using power of 2's.
However for 0.10 ( or other denominations mentioned ), they cannot be expressed exactly in powers of 2.
Suppose you try to obtain 0.1 using power of 2's , you won't be able to obtain it exactly. You can just go near it.
0.1 = 0.0625 ( 2^4 ) + 0.03125 ( 2^5 ) + 0.00390625 ( 2^-8) +...
You will approach 0.1 , but you'll never reach 0.1 exactly.
Float, double everyone has a fixed number of bits to represent a decimal. So it will keep only those many bits, whose sum would be slightly less than 0.1
If you want to follow the same approach, you can have 2 possible solutions :-
Use (amount > 0) instead of (amount != 0), or
Use currencies which can be expressed easily in powers of 2 e.g. 0.25, 0.125 , 0.375 , 0.06125.
Your algorithm is not correct:
For example with 30 cents you can exchange to: 25+5 (2 coins) with your algorithm it would be 10+10+10 (3 coins). So greedy means why it's greater than 25 cents then exchange to 25 cents first.
while (amount != 0) {
if (amount >= 0.25) {
amount = amount - 0.25;
coins += 1;
}
else if (amount >= 0.10) {
amount = amount - 0.10;
coins += 1;
}
else if (amount >= 0.05) {
amount = amount - 0.05;
coins += 1;
}
else {
amount = amount - 0.01;
coins += 1;
}
}
If you want to do that way.
Better way:
int coinTypes[] = {0.25, 0.1, 0.05, 0.01};
for (int i = 0; i < 4; i++) {
coins += floor(amount / coinTypes[i];
amount -= coins * coinsTypes[i];
}
The main problem with your algorithm is invalid usage of fmod function. According to definition the result of fmod(num, denom) is
fmod = num - floor(num/denom) * denom
where floor(num/denom) is integer.
Thus, fmod(9.10, 0.25) == 0.1, fmod(9.10, 0.10) == 0.1.
In addition, the manipulation with floating point number rarely gives exact results. so amount is never 0.
You cannot compute this with the float type. Amounts that are not exact multiples of 0.25 cannot be represented exactly in either the float or the double type.
You can fix this problem by computing an exact number of cents and dispatch it using integer arithmetics:
#include <stdio.h>
#include <math.h>
void print_coins(int coins, const char *singular, const char *plural) {
if (coins > 0)
printf(" %d %s", coins, coins > 1 ? plural : singular);
}
int main(void) {
for (;;) {
double amount;
int amountInt, coins, quarters, dimes, nickels, pennies;
printf("Enter amount: ");
if (scanf("%lf", &amount) != 1 || amount <= 0)
break;
amountInt = (int)(amount * 100.0 + 0.5);
quarters = amountInt / 25;
amountInt %= 25;
dimes = amountInt / 10;
amountInt %= 10;
nickels = amountInt / 5;
amountInt %= 5;
pennies = amountInt;
amountInt = 0;
coins = quarters + dimes + nickels + pennies;
printf("coins returned: %d:", coins);
print_coins(quarters, "quarter", "quarters");
print_coins(dimes, "dime", "dimes");
print_coins(nickels, "nickel", "nickels");
print_coins(pennies, "penny", "pennies");
printf("\n");
}
return 0;
}
Notes:
Using float without the + 0.5, the change is incorrect for as little as 100.10: one penny short.
Using float, the change is incorrect for 1000000.10: 3 extra pennies.
To handle amounts above 20 million dollars, you need a larger integral type such as long long int. With that, you can handle amounts exceeding the US national debt.

C program to calculate change

I am trying to write a program to calculate change, but it doesn't seem to work.
I think that the problem is the owed 1/ paid 1; when I tried to print there values I got nothing (0).
Any help ?
#include <stdio.h>
int main()
{
double owed, paid;
int dollars, quarters, dimes, nickels, cents, remainder, owed1, paid1;
printf("how much did the customer have to pay ?\n");
scanf("%f",&owed);
printf("how much did the customer pay ?\n");
scanf("%f",&paid);
owed1 = owed * 100;
paid1 = paid * 100;
int change = paid1 - owed1;
dollars = change / 100;
remainder = change % 100;
quarters = remainder / 25;
remainder = remainder % 25;
dimes = remainder / 10;
remainder = remainder % 10;
nickels = remainder / 5;
remainder = remainder % 5;
cents = remainder;
printf("%d",dollars);
printf("Dollars:%d, Quarters:%d, Dimes:%d, Nickels:%d, Cents:%d", dollars , quarters , dimes , nickels , cents );
return 0;
}
You're using %f in your scanf, which is the format specifier for a float, but your variables are doubles. You should use %lf instead:
scanf("%lf",&owed);
Same thing for paid. You should be getting warning from your compiler about that.

C calculation result incomprehensible

Why I can not get a result of 2 while giving input of 2.2 as a float.
With my code, 2.2 should get converted to 220, and when it goes through the first for loop I should get a remainder of 20 (which is fine as it gives me 8 coins).
But when it goes through the second loop, I can not get 20/10 = 2, I always get 1.
By the way if I just put dime <= 20, I will get 2 hmm. I don't understand why since the remainder is equal to 20 as well.
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
float change ;
float quarter ;
float dime ;
float nickel ;
float penny = 1;
int coins = 0;
int coins1 = 0;
int coins2 = 0;
int coins3 = 0;
int sum = 0;
int remainder ;
do
{
printf("What is the owed change: \n");
change = GetFloat();
change = round(change * 100);
printf("%f\n", change);
}
while(change < 0);
for(quarter = 25; quarter <= change; quarter+=25)
{
remainder = change - quarter;
coins++;
}
printf("%d,%d\n", remainder,coins);
for (dime = 10; dime <= remainder; dime += 10) //This is where the problem starts.
{
remainder = remainder - dime;
coins1++;
}
printf("%d,%d\n", remainder,coins1);
for (nickel = 5; nickel < remainder; nickel += 5)
{
remainder = remainder - nickel;
coins2++;
}
printf("%d,%d\n", remainder,coins2);
for (penny = 1; penny < remainder; penny += 1)
{
remainder = remainder - penny;
coins3++;
}
printf("%d,%d\n", remainder,coins3);
printf("\n%d\n", sum = coins + coins1 + coins2 + coins3);
}
You're subtracting dime from remainder during each run of the for loop, while dime is being increased during each iteration of the loop. Let's suppose that change is initially 20 before the second for loop. The first loop execution will subtract 10, leaving remainderas 10. Then dime is incremented by 10 and is now 20. The loop condition fails because 20 > 10, and the loop runs only once.
My advice is to give your variables more intuitive names, like i or x for basic loop counters and dimes_needed instead of coins1

Error: invalid operands to binary expression ('float' and 'float')

I apologize if this question has been asked before. I looked around and was not able to find a solution, I am new to C.
I understand that I am not able to get a % from a float. How would I be able to capture the remainder of this math, if I am using 2 floats?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
/*
** Always use the largest coin possible
** keep track of coins used
** Print the final amount of coins
*/
int main (void)
{
float change;
int counter = 0;
int division;
//float rem;
float quarter = 0.25;
//float quarter = 0.25, dime = 0.10, nickel = 0.05, penny = 0.01;
/* Prompt user for an amont of change*/
do{
printf("How much do we owe you in change? ");
change = GetFloat();
}
while (change <= 0);
if (change >= quarter)
{
division = (change / quarter);
counter += division;
//change = (int)(change % quarter);
printf("change: %.2f\n", change);
printf("counter: %d\n ", counter);
}
return (0);
}
You may want to check
fmod.
You can also do something like change = change - (int)(change / quarter) * quarter
You could implement the modulo yourself:
https://en.wikipedia.org/wiki/Modulo_operation
int a = (int)(change / quarter);
int mod = (int)(change - (quarter * a));
Also it might be possible to do it this way:
long mod = ((long)(change * 1000) % (long)(quater * 1000));
depending on the precision of your floats modify the 1000 and think about dividing the result by 1000!
But maybe it would be better to rethink what you really want as result?
Just scale up all your variable by 100 and then use integers instead of float.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
/*
** Always use the largest coin possible
** keep track of coins used
** Print the final amount of coins
*/
int main (void)
{
float change_f;
int change;
int counter = 0;
int division;
//float rem;
int quarter = 25;
//int quarter = 25, dime = 10, nickel = 5, penny = 1;
/* Prompt user for an amont of change*/
do{
printf("How much do we owe you in change? ");
change_f = GetFloat();
}
while (change_f <= 0);
change = (int)(change_f*100);
if (change >= quarter)
{
division = (change / quarter);
counter += division;
//change = (int)(change % quarter);
printf("change: %.2f\n", change_f);
printf("counter: %d\n ", counter);
}
return (0);
}
NOTE: Choose scale factor according to the input precision i.e if it is 3 decimal digits then choose 1000 and so on.

I need help getting this program to properly print my outputs

#include <stdio.h> /*printf and scanf option*/
#include <math.h>
void change(double coin_change, int *quarters, int *dimes, int *nickels, int *pennies); /*function protype*/
int main(void)
{
int fifties = 0, twenties = 0, tens = 0, fives = 0, dollars = 0, quarters = 0, dimes = 0, nickels = 0, pennies = 0;
double amt_paid = 0, amt_due = 0, amt_change = 0, coin_change = 0; /*declared avriables*/
printf("Enter the amount paid> "); /*Prompt user to enter amount paid*/
scanf("%lf", &amt_paid);
printf("Enter the amount due> "); /*Prompt user to enter amount due*/
scanf("%lf", &amt_due);
amt_change = amt_paid - amt_due; /*Formula for amount of change to be given*/
dollars = (amt_change);
coin_change = (int)((amt_change - (amt_change)) * 100 + 0.5);
coin_change = coin_change * 100;
printf("\n%f\n", coin_change);
change(coin_change, &quarters, &dimes, &nickels, &pennies);
printf("Change is fifties: %d$, twenties: %d$, tens: %d$, fives: %d$, dollars: %d$, quarters: %d, dimes: %d, nickels: %d,\
pennies: %d", fifties, twenties, tens, fives, dollars, quarters, dimes, nickels, pennies);
return(0);
}
void change(double coin_change, int *quarters, int *dimes, int *nickels, int *pennies)
{
int q = 1, d = 1, n = 1, p = 1;
do {
if(coin_change >= 25){
*quarters = *quarters + q;
coin_change = coin_change - 25;
}
else if (coin_change >= 10) {
*dimes = *dimes + d;
coin_change = coin_change - 10;
}
else if (coin_change >= 5) {
*nickels = *nickels + n;
coin_change = coin_change - 5;
}
else if (coin_change >= 1) {
*pennies = *pennies + p;
coin_change = coin_change - 1;
}
} while (coin_change >= 1);
}
I'm sorry I wasn't very clear the first time. What I need is to create what is basically a cash register program. When given the amount due, and the amount paid from the user, i should receive output that tell me how many 50 dollar bills, 20s, 10s, 5s, 1s, quarters, dimes, nickels, and pennies I should be receiving as change. As I am new to programming, the code you see is what is to the best of my knowledge. I do need to improve or even completely change it. What I am really looking to do is pinpoint my mistakes, and fix them. I am hoping to have this code done soon. I feel that I am close, but only just missing it. Maybe I am wrong, but that is what I am coming to you guys for.
A couple of things:
you have many unused variables: fifties, twenties, tens, fives, dollars, etc.
The lines here:
coin_change = (int)((amt_change - (amt_change)) * 100 + 0.5);
coin_change = coin_change * 100;
Are wrong. They should be replaced with something like the following:
coin_change = (100 * amt_change).
Have you heard of the += / -= operators? They'd turn these lines:
*quarters = *quarters + q;
coin_change = coin_change - 25;
Into this:
*quarters += q;
coin_change -= 25;
After I fixed those things, your code worked fine.
I don't want to write the code for you because this smells like homework, but here's the algorithm:
read_from_keyboard(amount_due)
read_from_keyboard(amount_paid)
change = amount_paid - amount_due
for each denomination in (
fifties, twenties, tens, fives, ones, quarters, dimes, nickels, pennies) {
while (change >= value of denomination) {
increment counter for denomination
subtract value of denomination from change
}
print counter + name of denomination // Ex: "4 twenties"
}
The "trick" is to realize that you can treat whole dollar values and coins in exactly the same way -- part of the art of programming is being able to find a generic solution that you can re-use, rather than handling each situation as a special case.
You may want to convert the change to an integer that represents the value in cents, so you can avoid the rounding errors that floating-point arithmetic creates.
Good luck!

Resources